public async Task <QueryResult[]> GetAnswersAsync(ITurnContext turnContext, IMessageActivity messageActivity, QnAMakerOptions options) { var result = await this.GetAnswersRawAsync(turnContext, messageActivity, options).ConfigureAwait(false); return(result.Answers); }
private async Task EmitTraceInfoAsync(ITurnContext turnContext, Activity messageActivity, QueryResult[] result, QnAMakerOptions options) { var traceInfo = new QnAMakerTraceInfo { Message = (Activity)messageActivity, QueryResults = result, KnowledgeBaseId = _endpoint.KnowledgeBaseId, ScoreThreshold = options.ScoreThreshold, Top = options.Top, StrictFilters = options.StrictFilters, Context = options.Context, QnAId = options.QnAId, IsTest = options.IsTest, RankerType = options.RankerType }; var traceActivity = Activity.CreateTraceActivity(QnAMaker.QnAMakerName, QnAMaker.QnAMakerTraceType, traceInfo, QnAMaker.QnAMakerTraceLabel); await turnContext.SendActivityAsync(traceActivity).ConfigureAwait(false); }
/// <summary> /// Initializes a new instance of the <see cref="GenerateAnswerUtils"/> class. /// </summary> /// <param name="telemetryClient">Telemetry client.</param> /// <param name="endpoint">QnA Maker endpoint details.</param> /// <param name="options">QnA Maker options.</param> /// <param name="httpClient">Http client.</param> public GenerateAnswerUtils(IBotTelemetryClient telemetryClient, QnAMakerEndpoint endpoint, QnAMakerOptions options, HttpClient httpClient) { this.telemetryClient = telemetryClient; this._endpoint = endpoint; this.Options = options ?? new QnAMakerOptions(); ValidateOptions(this.Options); this.httpClient = httpClient; }
/// <summary> /// Initializes a new instance of the <see cref="QnAMaker"/> class. /// </summary> /// <param name="endpoint">The endpoint of the knowledge base to query.</param> /// <param name="options">The options for the QnA Maker knowledge base.</param> /// <param name="httpClient">An alternate client with which to talk to QnAMaker. /// If null, a default client is used for this instance.</param> public QnAMaker(QnAMakerEndpoint endpoint, QnAMakerOptions options = null, HttpClient httpClient = null) : this(endpoint, options, httpClient, null) { }
private async Task <QueryResults> QueryQnaServiceAsync(Activity messageActivity, QnAMakerOptions options) { var requestUrl = $"{_endpoint.Host}/knowledgebases/{_endpoint.KnowledgeBaseId}/generateanswer"; var jsonRequest = JsonConvert.SerializeObject( new { question = messageActivity.Text, top = options.Top, strictFilters = options.StrictFilters, scoreThreshold = options.ScoreThreshold, context = options.Context, qnaId = options.QnAId, isTest = options.IsTest, rankerType = options.RankerType }, Formatting.None); var httpRequestHelper = new HttpRequestUtils(httpClient); var response = await httpRequestHelper.ExecuteHttpRequestAsync(requestUrl, jsonRequest, _endpoint).ConfigureAwait(false); var result = await FormatQnaResultAsync(response, options).ConfigureAwait(false); return(result); }
private async Task <DialogTurnResult> CallGenerateAnswerAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var qnaMakerOptions = new QnAMakerOptions { ScoreThreshold = DefaultThreshold, Top = DefaultTopN }; 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 }; if (previousContextData.TryGetValue(stepContext.Context.Activity.Text, out var currentQnAId)) { qnaMakerOptions.QnAId = currentQnAId; } } } } // Calling QnAMaker to get response. var response = await _qnaMakerClient.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. // 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 = _qnaMakerClient.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)); }
/// <summary> /// Generates an answer from the knowledge base. /// </summary> /// <param name="turnContext">The Turn Context that contains the user question to be queried against your knowledge base.</param> /// <param name="options">The options for the QnA Maker knowledge base. If null, constructor option is used for this instance.</param> /// <returns>A list of answers for the user query, sorted in decreasing order of ranking score.</returns> public Task <QueryResult[]> GetAnswersAsync(ITurnContext turnContext, QnAMakerOptions options = null) { return(GetAnswersAsync(turnContext, options, null)); }
private async Task <QueryResults> QueryQnaServiceAsync(Activity messageActivity, QnAMakerOptions options) { var requestUrl = $"{_endpoint.Host}/knowledgebases/{_endpoint.KnowledgeBaseId}/generateanswer"; var jsonRequest = JsonConvert.SerializeObject( new { question = messageActivity.Text, top = options.Top, strictFilters = GetMetadataFromFilters(options.Filters), scoreThreshold = Math.Round(options.ScoreThreshold * 100.0f, 2), context = options.Context, qnaId = options.QnAId, isTest = options.IsTest, rankerType = options.RankerType, StrictFiltersCompoundOperationType = Enum.TryParse(options.Filters?.MetadataFilter?.LogicalOperation, out JoinOperator operation) ? operation : JoinOperator.AND, }, Formatting.None);
/// <summary> /// Initializes a new instance of the <see cref="QnAMaker"/> class. /// </summary> /// <param name="service">QnA service details from configuration.</param> /// <param name="options">The options for the QnA Maker knowledge base.</param> /// <param name="httpClient">An alternate client with which to talk to QnAMaker. /// If null, a default client is used for this instance.</param> /// <param name="telemetryClient">The IBotTelemetryClient used for logging telemetry events.</param> /// <param name="logPersonalInformation">Set to true to include personally identifiable information in telemetry events.</param> public QnAMaker(QnAMakerService service, QnAMakerOptions options, HttpClient httpClient, IBotTelemetryClient telemetryClient, bool logPersonalInformation = false) : this(new QnAMakerEndpoint(service), options, httpClient, telemetryClient, logPersonalInformation) { }
/// <summary> /// Initializes a new instance of the <see cref="CustomQuestionAnswering"/> class. /// </summary> /// <param name="endpoint">The <see cref="QnAMakerEndpoint"/> of the knowledge base to query.</param> /// <param name="options">The <see cref="QnAMakerOptions"/> for the Custom Question Answering Knowledge Base.</param> /// <param name="httpClient">An alternate client with which to talk to Language Service. /// If null, a default client is used for this instance.</param> public CustomQuestionAnswering(QnAMakerEndpoint endpoint, QnAMakerOptions options = null, HttpClient httpClient = null) : this(endpoint, options, httpClient, null) { }
/// <summary> /// Generates an answer from the knowledge base. /// </summary> /// <param name="turnContext">The Turn Context that contains the user question to be queried against your knowledge base.</param> /// <param name="options">The options for the QnA Maker knowledge base. If null, constructor option is used for this instance.</param> /// <returns>A list of answers for the user query, sorted in decreasing order of ranking score.</returns> public async Task <QueryResult[]> GetAnswersAsync(ITurnContext turnContext, QnAMakerOptions options = null) { if (turnContext == null) { throw new ArgumentNullException(nameof(turnContext)); } if (turnContext.Activity == null) { throw new ArgumentNullException(nameof(turnContext.Activity)); } if (options == null) { options = _options; } ValidateOptions(options); var messageActivity = turnContext.Activity.AsMessageActivity(); if (messageActivity == null) { throw new ArgumentException("Activity type is not a message"); } if (string.IsNullOrEmpty(turnContext.Activity.Text)) { throw new ArgumentException("Null or empty text"); } var requestUrl = $"{_endpoint.Host}/knowledgebases/{_endpoint.KnowledgeBaseId}/generateanswer"; var request = new HttpRequestMessage(HttpMethod.Post, requestUrl); var jsonRequest = JsonConvert.SerializeObject( new { question = messageActivity.Text, top = options.Top, strictFilters = options.StrictFilters, metadataBoost = options.MetadataBoost, }, Formatting.None); request.Content = new StringContent(jsonRequest, System.Text.Encoding.UTF8, "application/json"); var isLegacyProtocol = _endpoint.Host.EndsWith("v2.0") || _endpoint.Host.EndsWith("v3.0"); if (isLegacyProtocol) { request.Headers.Add("Ocp-Apim-Subscription-Key", _endpoint.EndpointKey); } else { request.Headers.Add("Authorization", $"EndpointKey {_endpoint.EndpointKey}"); } AddUserAgent(request); var response = await _httpClient.SendAsync(request).ConfigureAwait(false); if (!response.IsSuccessStatusCode) { return(null); } var jsonResponse = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var results = isLegacyProtocol ? ConvertLegacyResults(JsonConvert.DeserializeObject <InternalQueryResults>(jsonResponse)) : JsonConvert.DeserializeObject <QueryResults>(jsonResponse); foreach (var answer in results.Answers) { answer.Score = answer.Score / 100; } var result = results.Answers.Where(answer => answer.Score > options.ScoreThreshold).ToArray(); var traceInfo = new QnAMakerTraceInfo { Message = (Activity)messageActivity, QueryResults = result, KnowledgeBaseId = _endpoint.KnowledgeBaseId, ScoreThreshold = options.ScoreThreshold, Top = options.Top, StrictFilters = options.StrictFilters, MetadataBoost = options.MetadataBoost, }; var traceActivity = Activity.CreateTraceActivity(QnAMakerName, QnAMakerTraceType, traceInfo, QnAMakerTraceLabel); await turnContext.SendActivityAsync(traceActivity).ConfigureAwait(false); return(result); }
private async Task <QueryResult[]> FormatQnaResultAsync(HttpResponseMessage response, QnAMakerOptions options) { var jsonResponse = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var results = _isLegacyProtocol ? ConvertLegacyResults(JsonConvert.DeserializeObject <InternalQueryResults>(jsonResponse)) : JsonConvert.DeserializeObject <QueryResults>(jsonResponse); foreach (var answer in results.Answers) { answer.Score = answer.Score / 100; } var result = results.Answers.Where(answer => answer.Score > options.ScoreThreshold).ToArray(); return(result); }
private async Task <QueryResult[]> QueryQnaServiceAsync(Activity messageActivity, QnAMakerOptions options) { var request = BuildRequest(messageActivity, options); var response = await _httpClient.SendAsync(request).ConfigureAwait(false); response.EnsureSuccessStatusCode(); var result = await FormatQnaResultAsync(response, options).ConfigureAwait(false); return(result); }
public Task <QueryResult[]> GetAnswersAsync(ITurnContext turnContext, QnAMakerOptions options, Dictionary <string, string> telemetryProperties, Dictionary <string, double> telemetryMetrics = null) { throw new NotImplementedException(); }
/// <summary> /// Generates an answer from the knowledge base. /// </summary> /// <param name="turnContext">The Turn Context that contains the user question to be queried against your knowledge base.</param> /// <param name="messageActivity">Message activity of the turn context.</param> /// <param name="options">The options for the QnA Maker knowledge base. If null, constructor option is used for this instance.</param> /// <returns>A list of answers for the user query, sorted in decreasing order of ranking score.</returns> public async Task <QueryResults> GetAnswersRawAsync(ITurnContext turnContext, IMessageActivity messageActivity, QnAMakerOptions options) { if (turnContext == null) { throw new ArgumentNullException(nameof(turnContext)); } if (turnContext.Activity == null) { throw new ArgumentNullException(nameof(turnContext.Activity)); } if (messageActivity == null) { throw new ArgumentException("Activity type is not a message"); } var hydratedOptions = HydrateOptions(options); ValidateOptions(hydratedOptions); var result = await QueryQnaServiceAsync((Activity)messageActivity, hydratedOptions).ConfigureAwait(false); await EmitTraceInfoAsync(turnContext, (Activity)messageActivity, result.Answers, hydratedOptions).ConfigureAwait(false); return(result); }
/// <summary> /// Initializes a new instance of the <see cref="QnAMaker"/> class. /// </summary> /// <param name="service">QnA service details from configuration.</param> /// <param name="options">The options for the QnA Maker knowledge base.</param> /// <param name="httpClient">An alternate client with which to talk to QnAMaker. /// If null, a default client is used for this instance.</param> public QnAMaker(QnAMakerService service, QnAMakerOptions options = null, HttpClient httpClient = null) : this(new QnAMakerEndpoint(service), options, httpClient, null) { }
private static async Task <QueryResults> FormatQnaResultAsync(HttpResponseMessage response, QnAMakerOptions options) { var jsonResponse = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var results = JsonConvert.DeserializeObject <QueryResults>(jsonResponse); foreach (var answer in results.Answers) { answer.Score = answer.Score / 100; } results.Answers = results.Answers.Where(answer => answer.Score > options.ScoreThreshold).ToArray(); return(results); }
private async Task <DialogTurnResult> ExecuteAdaptiveQnAMakerDialog(DialogContext dc, IQnAMakerClient qnaMaker, QnAMakerOptions qnamakerOptions, CancellationToken cancellationToken = default(CancellationToken)) { var dialog = new QnAMakerActionBuilder(qnaMaker).BuildDialog(dc); // Set values for active dialog. var qnaDialogResponseOptions = new QnADialogResponseOptions { NoAnswer = NoAnswer ?? new StaticActivityTemplate(null), ActiveLearningCardTitle = ActiveLearningCardTitle ?? QnAMakerActionBuilder.DefaultCardTitle, CardNoMatchText = CardNoMatchText ?? QnAMakerActionBuilder.DefaultCardNoMatchText, CardNoMatchResponse = CardNoMatchResponse ?? new StaticActivityTemplate(null) }; var dialogOptions = new Dictionary <string, object> { [QnAMakerActionBuilder.QnAOptions] = qnamakerOptions, [QnAMakerActionBuilder.QnADialogResponseOptions] = qnaDialogResponseOptions }; return(await dc.BeginDialogAsync(QnAMakerActionBuilder.QnAMakerDialogName, dialogOptions, cancellationToken).ConfigureAwait(false)); }