public async Task JsonDialogLoad_QnAMakerDialog_ActiveLearning_WithNoneOfAboveQuery() { var suggestionList = new List<string> { "Q1", "Q2", "Q3" }; var suggestionActivity = QnACardBuilder.GetSuggestionsCard(suggestionList, "Did you mean:", "None of the above."); var qnAMakerCardEqualityComparer = new QnAMakerCardEqualityComparer(); await BuildQnAMakerTestFlow(nameof(JsonDialogLoad_QnAMakerDialog_ActiveLearning_WithNoneOfAboveQuery)) .Send("Q11") .AssertReply(suggestionActivity, equalityComparer: qnAMakerCardEqualityComparer) .Send("None of the above.") .AssertReply("Thanks for the feedback.") .StartTestAsync(); }
private async Task <DialogTurnResult> DisplayQnAResultAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var dialogOptions = ObjectPath.GetPathValue <QnAMakerDialogOptions>(stepContext.ActiveDialog.State, Options); var reply = stepContext.Context.Activity.Text; if (reply.Equals(dialogOptions.ResponseOptions.CardNoMatchText, StringComparison.OrdinalIgnoreCase)) { var activity = dialogOptions.ResponseOptions.CardNoMatchResponse; if (activity == null) { await stepContext.Context.SendActivityAsync(DefaultCardNoMatchResponse, cancellationToken : cancellationToken).ConfigureAwait(false); } else { await stepContext.Context.SendActivityAsync(activity, cancellationToken : cancellationToken).ConfigureAwait(false); } return(await stepContext.EndDialogAsync().ConfigureAwait(false)); } // If previous QnAId is present, replace the dialog var previousQnAId = ObjectPath.GetPathValue <int>(stepContext.ActiveDialog.State, PreviousQnAId, 0); if (previousQnAId > 0) { // restart the waterfall to step 0 return(await RunStepAsync(stepContext, index : 0, reason : DialogReason.BeginCalled, result : null, cancellationToken : cancellationToken).ConfigureAwait(false)); } // If response is present then show that response, else default answer. if (stepContext.Result is List <QueryResult> response && response.Count > 0) { var message = QnACardBuilder.GetQnADefaultResponse(response.First(), dialogOptions.ResponseOptions.DisplayPreciseAnswerOnly); await stepContext.Context.SendActivityAsync(message, cancellationToken).ConfigureAwait(false); } else { var activity = dialogOptions.ResponseOptions.NoAnswer; if (activity == null) { await stepContext.Context.SendActivityAsync(DefaultNoAnswer, cancellationToken : cancellationToken).ConfigureAwait(false); } else { await stepContext.Context.SendActivityAsync(activity, cancellationToken : cancellationToken).ConfigureAwait(false); } } return(await stepContext.EndDialogAsync().ConfigureAwait(false)); }
public async Task JsonDialogLoad_QnAMakerDialog_ActiveLearning_WithNoResponse() { var suggestionList = new List<string> { "Q1", "Q2", "Q3" }; var suggestionActivity = QnACardBuilder.GetSuggestionsCard(suggestionList, "Did you mean:", "None of the above."); var qnAMakerCardEqualityComparer = new QnAMakerCardEqualityComparer(); const string noAnswerActivity = "Answers not found in kb."; await BuildQnAMakerTestFlow(nameof(JsonDialogLoad_QnAMakerDialog_ActiveLearning_WithNoResponse)) .Send("Q11") .AssertReply(suggestionActivity, equalityComparer: qnAMakerCardEqualityComparer) .Send("Q12") .AssertReply(noAnswerActivity) .StartTestAsync(); }
public async Task JsonDialogLoad_QnAMakerDialog_ActiveLearning_WithProperResponse() { var suggestionList = new List <string> { "Q1", "Q2", "Q3" }; var suggestionActivity = QnACardBuilder.GetSuggestionsCard(suggestionList, "Did you mean:", "None of the above."); var qnAMakerCardEqualityComparer = new QnAMakerCardEqualityComparer(); await BuildQnAMakerTestFlow() .Send("Q11") .AssertReply(suggestionActivity, equalityComparer: qnAMakerCardEqualityComparer) .Send("Q1") .AssertReply("A1") .StartTestAsync(); }
private async Task <DialogTurnResult> CheckForMultiTurnPrompt(WaterfallStepContext stepContext, CancellationToken cancellationToken) { if (stepContext.Result is List <QueryResult> response && response.Count > 0) { // -Check if context is present and prompt exists // -If yes: Add reverse index of prompt display name and its corresponding qna id // -Set PreviousQnAId as answer.Id // -Display card for the prompt // -Wait for the reply // -If no: Skip to next step var answer = response.First(); if (answer.Context != null && answer.Context.Prompts.Count() > 0) { var dialogOptions = GetDialogOptionsValue(stepContext); var qnaDialogResponseOptions = dialogOptions[QnADialogResponseOptions] as QnADialogResponseOptions; var previousContextData = new Dictionary <string, int>(); if (dialogOptions.ContainsKey(QnAContextData)) { previousContextData = dialogOptions[QnAContextData] as Dictionary <string, int>; } foreach (var prompt in answer.Context.Prompts) { previousContextData.Add(prompt.DisplayText.ToLower(), prompt.QnaId); } dialogOptions[QnAContextData] = previousContextData; dialogOptions[PreviousQnAId] = answer.Id; stepContext.ActiveDialog.State["options"] = dialogOptions; // Get multi-turn prompts card activity. var message = QnACardBuilder.GetQnAPromptsCard(answer, qnaDialogResponseOptions.CardNoMatchText); await stepContext.Context.SendActivityAsync(message).ConfigureAwait(false); return(new DialogTurnResult(DialogTurnStatus.Waiting)); } } return(await stepContext.NextAsync(stepContext.Result, cancellationToken).ConfigureAwait(false)); }
private async Task <DialogTurnResult> CheckForMultiTurnPromptAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var dialogOptions = ObjectPath.GetPathValue <QnAMakerDialogOptions>(stepContext.ActiveDialog.State, Options); if (stepContext.Result is List <QueryResult> response && response.Count > 0) { // -Check if context is present and prompt exists // -If yes: Add reverse index of prompt display name and its corresponding QnA ID // -Set PreviousQnAId as answer.Id // -Display card for the prompt // -Wait for the reply // -If no: Skip to next step var answer = response.First(); if (answer.Context != null && answer.Context.Prompts.Count() > 0) { var previousContextData = ObjectPath.GetPathValue(stepContext.ActiveDialog.State, QnAContextData, new Dictionary <string, int>()); var previousQnAId = ObjectPath.GetPathValue <int>(stepContext.ActiveDialog.State, PreviousQnAId, 0); foreach (var prompt in answer.Context.Prompts) { previousContextData[prompt.DisplayText] = prompt.QnaId; } ObjectPath.SetPathValue(stepContext.ActiveDialog.State, QnAContextData, previousContextData); ObjectPath.SetPathValue(stepContext.ActiveDialog.State, PreviousQnAId, answer.Id); ObjectPath.SetPathValue(stepContext.ActiveDialog.State, Options, dialogOptions); // Get multi-turn prompts card activity. var message = QnACardBuilder.GetQnAPromptsCard(answer, dialogOptions.ResponseOptions.CardNoMatchText); await stepContext.Context.SendActivityAsync(message).ConfigureAwait(false); return(new DialogTurnResult(DialogTurnStatus.Waiting)); } } return(await stepContext.NextAsync(stepContext.Result, cancellationToken).ConfigureAwait(false)); }
private async Task <DialogTurnResult> CallGenerateAnswerAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var qnaMakerOptions = new QnAMakerOptions { ScoreThreshold = DefaultThreshold, Top = DefaultTopN, Context = new QnARequestContext(), QnAId = 0 }; var dialogOptions = GetDialogOptionsValue(stepContext); // Getting options if (dialogOptions.ContainsKey(QnAOptions)) { qnaMakerOptions = dialogOptions[QnAOptions] as QnAMakerOptions; qnaMakerOptions.ScoreThreshold = qnaMakerOptions?.ScoreThreshold ?? DefaultThreshold; qnaMakerOptions.Top = DefaultTopN; } // Storing the context info stepContext.Values[CurrentQuery] = stepContext.Context.Activity.Text; // -Check if previous context is present, if yes then put it with the query // -Check for id if query is present in reverse index. if (!dialogOptions.ContainsKey(QnAContextData)) { dialogOptions[QnAContextData] = new Dictionary <string, int>(); } else { var previousContextData = dialogOptions[QnAContextData] as Dictionary <string, int>; if (dialogOptions[PreviousQnAId] != null) { var previousQnAId = Convert.ToInt32(dialogOptions[PreviousQnAId]); if (previousQnAId > 0) { qnaMakerOptions.Context = new QnARequestContext { PreviousQnAId = previousQnAId }; qnaMakerOptions.QnAId = 0; if (previousContextData.TryGetValue(stepContext.Context.Activity.Text.ToLower(), out var currentQnAId)) { qnaMakerOptions.QnAId = currentQnAId; } } } } // Calling QnAMaker to get response. var response = await _services.QnAMakerService.GetAnswersRawAsync(stepContext.Context, qnaMakerOptions).ConfigureAwait(false); // Resetting previous query. dialogOptions[PreviousQnAId] = -1; stepContext.ActiveDialog.State["options"] = dialogOptions; // Take this value from GetAnswerResponse var isActiveLearningEnabled = response.ActiveLearningEnabled; stepContext.Values[QnAData] = new List <QueryResult>(response.Answers); // Check if active learning is enabled. if (isActiveLearningEnabled && response.Answers.Any() && response.Answers.First().Score <= maximumScoreForLowScoreVariation) { // Get filtered list of the response that support low score variation criteria. response.Answers = _services.QnAMakerService.GetLowScoreVariation(response.Answers); if (response.Answers.Count() > 1) { var suggestedQuestions = new List <string>(); foreach (var qna in response.Answers) { suggestedQuestions.Add(qna.Questions[0]); } // Get active learning suggestion card activity. var qnaDialogResponseOptions = dialogOptions[QnADialogResponseOptions] as QnADialogResponseOptions; var message = QnACardBuilder.GetSuggestionsCard(suggestedQuestions, qnaDialogResponseOptions.ActiveLearningCardTitle, qnaDialogResponseOptions.CardNoMatchText); await stepContext.Context.SendActivityAsync(message).ConfigureAwait(false); return(new DialogTurnResult(DialogTurnStatus.Waiting)); } } var result = new List <QueryResult>(); if (response.Answers.Any()) { result.Add(response.Answers.First()); } stepContext.Values[QnAData] = result; // If card is not shown, move to next step with top qna response. return(await stepContext.NextAsync(result, cancellationToken).ConfigureAwait(false)); }
private async Task <DialogTurnResult> CallGenerateAnswerAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var dialogOptions = ObjectPath.GetPathValue <QnAMakerDialogOptions>(stepContext.ActiveDialog.State, Options); // Resetting context and QnAId dialogOptions.QnAMakerOptions.QnAId = 0; dialogOptions.QnAMakerOptions.Context = new QnARequestContext(); // Storing the context info stepContext.Values[ValueProperty.CurrentQuery] = stepContext.Context.Activity.Text; // -Check if previous context is present, if yes then put it with the query // -Check for id if query is present in reverse index. var previousContextData = ObjectPath.GetPathValue <Dictionary <string, int> >(stepContext.ActiveDialog.State, QnAContextData, new Dictionary <string, int>()); var previousQnAId = ObjectPath.GetPathValue <int>(stepContext.ActiveDialog.State, PreviousQnAId, 0); if (previousQnAId > 0) { dialogOptions.QnAMakerOptions.Context = new QnARequestContext { PreviousQnAId = previousQnAId }; if (previousContextData.TryGetValue(stepContext.Context.Activity.Text, out var currentQnAId)) { dialogOptions.QnAMakerOptions.QnAId = currentQnAId; } } // Calling QnAMaker to get response. var qnaClient = await GetQnAMakerClientAsync(stepContext).ConfigureAwait(false); var response = await qnaClient.GetAnswersRawAsync(stepContext.Context, dialogOptions.QnAMakerOptions).ConfigureAwait(false); // Resetting previous query. previousQnAId = -1; ObjectPath.SetPathValue(stepContext.ActiveDialog.State, PreviousQnAId, previousQnAId); // Take this value from GetAnswerResponse var isActiveLearningEnabled = response.ActiveLearningEnabled; stepContext.Values[ValueProperty.QnAData] = new List <QueryResult>(response.Answers); // Check if active learning is enabled. // maximumScoreForLowScoreVariation is the score above which no need to check for feedback. if (isActiveLearningEnabled && response.Answers.Any() && response.Answers.First().Score <= maximumScoreForLowScoreVariation) { // Get filtered list of the response that support low score variation criteria. response.Answers = qnaClient.GetLowScoreVariation(response.Answers); if (response.Answers.Count() > 1) { var suggestedQuestions = new List <string>(); foreach (var qna in response.Answers) { suggestedQuestions.Add(qna.Questions[0]); } // Get active learning suggestion card activity. var message = QnACardBuilder.GetSuggestionsCard(suggestedQuestions, dialogOptions.ResponseOptions.ActiveLearningCardTitle, dialogOptions.ResponseOptions.CardNoMatchText); await stepContext.Context.SendActivityAsync(message).ConfigureAwait(false); ObjectPath.SetPathValue(stepContext.ActiveDialog.State, Options, dialogOptions); return(new DialogTurnResult(DialogTurnStatus.Waiting)); } } var result = new List <QueryResult>(); if (response.Answers.Any()) { result.Add(response.Answers.First()); } stepContext.Values[ValueProperty.QnAData] = result; ObjectPath.SetPathValue(stepContext.ActiveDialog.State, Options, dialogOptions); // If card is not shown, move to next step with top QnA response. return(await stepContext.NextAsync(result, cancellationToken).ConfigureAwait(false)); }
private async Task <DialogTurnResult> CallGenerateAnswerAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { // clear suggestedQuestions between turns. stepContext.State.RemoveValue($"this.suggestedQuestions"); var dialogOptions = ObjectPath.GetPathValue <QnAMakerDialogOptions>(stepContext.ActiveDialog.State, Options); ResetOptions(stepContext, dialogOptions); // Storing the context info stepContext.Values[ValueProperty.CurrentQuery] = stepContext.Context.Activity.Text; // Calling QnAMaker to get response. var qnaClient = await GetQnAMakerClientAsync(stepContext).ConfigureAwait(false); var response = stepContext.State.GetValue <QueryResults>($"turn.qnaresult{this.GetHashCode()}"); if (response == null) { response = await qnaClient.GetAnswersRawAsync(stepContext.Context, dialogOptions.QnAMakerOptions).ConfigureAwait(false); } // Resetting previous query. var previousQnAId = -1; ObjectPath.SetPathValue(stepContext.ActiveDialog.State, PreviousQnAId, previousQnAId); // Take this value from GetAnswerResponse var isActiveLearningEnabled = response.ActiveLearningEnabled; stepContext.Values[ValueProperty.QnAData] = new List <QueryResult>(response.Answers); // Check if active learning is enabled. // MaximumScoreForLowScoreVariation is the score above which no need to check for feedback. if (response.Answers.Any() && response.Answers.First().Score <= (ActiveLearningUtils.MaximumScoreForLowScoreVariation / 100)) { // Get filtered list of the response that support low score variation criteria. response.Answers = qnaClient.GetLowScoreVariation(response.Answers); if (response.Answers.Length > 1 && isActiveLearningEnabled) { var suggestedQuestions = new List <string>(); foreach (var qna in response.Answers) { suggestedQuestions.Add(qna.Questions[0]); } // Get active learning suggestion card activity. var message = QnACardBuilder.GetSuggestionsCard(suggestedQuestions, dialogOptions.ResponseOptions.ActiveLearningCardTitle, dialogOptions.ResponseOptions.CardNoMatchText); await stepContext.Context.SendActivityAsync(message).ConfigureAwait(false); ObjectPath.SetPathValue(stepContext.ActiveDialog.State, Options, dialogOptions); stepContext.State.SetValue($"this.suggestedQuestions", suggestedQuestions); return(new DialogTurnResult(DialogTurnStatus.Waiting)); } } var result = new List <QueryResult>(); if (response.Answers.Any()) { result.Add(response.Answers.First()); } stepContext.Values[ValueProperty.QnAData] = result; ObjectPath.SetPathValue(stepContext.ActiveDialog.State, Options, dialogOptions); // If card is not shown, move to next step with top QnA response. return(await stepContext.NextAsync(result, cancellationToken).ConfigureAwait(false)); }
private async Task <DialogTurnResult> CallGenerateAnswerAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var qnaMakerOptions = new QnAMakerOptions { ScoreThreshold = DefaultThreshold, Top = DefaultTopN, Context = new QnARequestContext(), QnAId = 0 }; var dialogOptions = GetDialogOptionsValue(stepContext); if (dialogOptions.ContainsKey(QnAOptions)) { qnaMakerOptions = dialogOptions[QnAOptions] as QnAMakerOptions; qnaMakerOptions.ScoreThreshold = qnaMakerOptions?.ScoreThreshold ?? DefaultThreshold; qnaMakerOptions.Top = DefaultTopN; } stepContext.Values[CurrentQuery] = stepContext.Context.Activity.Text; if (!dialogOptions.ContainsKey(QnAContextData)) { dialogOptions[QnAContextData] = new Dictionary <string, int>(); } else { var previousContextData = dialogOptions[QnAContextData] as Dictionary <string, int>; if (dialogOptions[PreviousQnAId] != null) { var previousQnAId = Convert.ToInt32(dialogOptions[PreviousQnAId]); if (previousQnAId > 0) { qnaMakerOptions.Context = new QnARequestContext { PreviousQnAId = previousQnAId }; qnaMakerOptions.QnAId = 0; if (previousContextData.TryGetValue(stepContext.Context.Activity.Text.ToLower(), out var currentQnAId)) { qnaMakerOptions.QnAId = currentQnAId; } } } } var response = await _services.QnAMakerService.GetAnswersRawAsync(stepContext.Context, qnaMakerOptions).ConfigureAwait(false); dialogOptions[PreviousQnAId] = -1; stepContext.ActiveDialog.State["options"] = dialogOptions; var isActiveLearningEnabled = response.ActiveLearningEnabled; stepContext.Values[QnAData] = new List <QueryResult>(response.Answers); if (isActiveLearningEnabled && response.Answers.Any() && response.Answers.First().Score <= maximumScoreForLowScoreVariation) { response.Answers = _services.QnAMakerService.GetLowScoreVariation(response.Answers); if (response.Answers.Count() > 1) { var suggestedQuestions = new List <string>(); foreach (var qna in response.Answers) { suggestedQuestions.Add(qna.Questions[0]); } var qnaDialogResponseOptions = dialogOptions[QnADialogResponseOptions] as QnADialogResponseOptions; var message = QnACardBuilder.GetSuggestionsCard(suggestedQuestions, qnaDialogResponseOptions.ActiveLearningCardTitle, qnaDialogResponseOptions.CardNoMatchText); await stepContext.Context.SendActivityAsync(message).ConfigureAwait(false); return(new DialogTurnResult(DialogTurnStatus.Waiting)); } } var result = new List <QueryResult>(); if (response.Answers.Any()) { result.Add(response.Answers.First()); } stepContext.Values[QnAData] = result; return(await stepContext.NextAsync(result, cancellationToken).ConfigureAwait(false)); }