コード例 #1
0
        public async Task <QueryResult[]> GetAnswersAsync(ITurnContext turnContext, IMessageActivity messageActivity, QnAMakerOptions options)
        {
            var result = await this.GetAnswersRawAsync(turnContext, messageActivity, options).ConfigureAwait(false);

            return(result.Answers);
        }
コード例 #2
0
 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);
 }
コード例 #3
0
        /// <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;
        }
コード例 #4
0
 /// <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)
 {
 }
コード例 #5
0
        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);
        }
コード例 #6
0
        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));
        }
コード例 #7
0
 /// <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));
 }
コード例 #8
0
 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);
コード例 #9
0
 /// <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)
 {
 }
コード例 #10
0
 /// <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)
 {
 }
コード例 #11
0
        /// <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);
        }
コード例 #12
0
        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);
        }
コード例 #13
0
        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);
        }
コード例 #14
0
 public Task <QueryResult[]> GetAnswersAsync(ITurnContext turnContext, QnAMakerOptions options, Dictionary <string, string> telemetryProperties, Dictionary <string, double> telemetryMetrics = null)
 {
     throw new NotImplementedException();
 }
コード例 #15
0
        /// <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);
        }
コード例 #16
0
 /// <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)
 {
 }
コード例 #17
0
        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);
        }
コード例 #18
0
        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));
        }