private async Task <QueryResult> GetGeneralResponseFromKB(ITurnContext turnContext, ShowQnAResultState qnaStatus, bool considerActiveLearning = false, CancellationToken cancellationToken = default(CancellationToken)) { var qnaOptions = new QnAMakerOptions(); if (considerActiveLearning) { qnaOptions.Top = Constants.ActiveLearningTop; qnaOptions.ScoreThreshold = Constants.ActiveLearningThreshold; } else { qnaOptions.Top = Constants.DefaultTop; qnaOptions.ScoreThreshold = Constants.DefaultThreshold; } var response = await _services.QnAServices[QnAMakerKey].GetAnswersAsync(turnContext, qnaOptions); if (response != null && response.GetLength(0) != 0 && response[0].Score >= Constants.DefaultThreshold) { if (response.GetLength(0) == 1 || !considerActiveLearning || response[0].Score > 0.95F) { return(response[0]); } var activeLearningResponse = HandleActiveLearning(response, qnaStatus, turnContext.Activity.Text); TelemetryUtils.LogActiveLearningResponse(this._services.TelemetryClient, TelemetryConstants.ActiveLearningEvent, turnContext.Activity, activeLearningResponse); return(activeLearningResponse); } return(null); }
private async Task HandleFeedbackFlow(ShowQnAResultState qnastatus, ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken)) { var isValidFeedback = await this.IsValidFeedback(turnContext); if (isValidFeedback) { TelemetryUtils.LogFeedbackResponse(this._services.TelemetryClient, TelemetryConstants.FeedbackEvent, turnContext.Activity, qnastatus); turnContext.Activity.Text = qnastatus.QnaAnswer.Requery ?? null; } qnastatus.ConsiderState = false; qnastatus.IsFeedback = false; qnastatus.NeuroconCount = 0; }
private async Task <string> GetLuisIntent(ITurnContext turnContext, bool enableLuis, CancellationToken cancellationToken = default(CancellationToken)) { if (!enableLuis) { return("None"); } try { var luisResult = await _services.LuisServices[LuisKey].RecognizeAsync(turnContext, cancellationToken); var topIntent = luisResult?.GetTopScoringIntent(); TelemetryUtils.LogLuisResponse(this._services.TelemetryClient, TelemetryConstants.LuisEvent, turnContext.Activity, topIntent.Value.intent + " score : " + topIntent.Value.score.ToString()); return(topIntent.Value.intent); } catch (Exception e) { TelemetryUtils.LogException(this._services.TelemetryClient, turnContext.Activity, e, "luis", "expection while getting luis intent"); return("None"); } }
/// <summary> /// Every conversation turn for our QnA bot will call this method. /// There are no dialogs used, the sample only uses "single turn" processing, /// meaning a single request and response, with no stateful conversation. /// </summary> /// <param name="turnContext">A <see cref="ITurnContext"/> containing all the data needed /// for processing this conversation turn. </param> /// <param name="cancellationToken">(Optional) A <see cref="CancellationToken"/> that can be used by other objects /// or threads to receive notice of cancellation.</param> /// <returns>A <see cref="Task"/> that represents the work queued to execute.</returns> /// <seealso cref="BotStateSet"/> /// <seealso cref="ConversationState"/> /// <seealso cref="IMiddleware"/> public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken)) { // Handle Message activity type, which is the main activity type for shown within a conversational interface // Message activities may contain text, speech, interactive cards, and binary or unknown attachments. // see https://aka.ms/about-bot-activity-message to learn more about the message and other activity types if (turnContext.Activity.Type == ActivityTypes.Message) { var dialogContext = await dialogs.CreateContextAsync(turnContext, cancellationToken); var qnastatus = await _accessors.QnAResultState.GetAsync(turnContext, () => new ShowQnAResultState()); if (qnastatus.IsFeedback) { await HandleFeedbackFlow(qnastatus, turnContext, cancellationToken); } string requery = null; if (qnastatus.ConsiderState) { // Call Active Learning Train API if (qnastatus.ActiveLearningAnswer) { _services.QnAServices.TryGetValue(QnAMakerKey, out var qnaservice); var activeLearningData = new ActiveLearningDTO() { hostName = qnaservice.Endpoint.Host, endpointKey = qnaservice.Endpoint.EndpointKey, kbid = qnaservice.Endpoint.KnowledgeBaseId, userId = turnContext.Activity.From.Id, userQuestion = qnastatus.ActiveLearningUserQuestion, }; requery = Utils.GetRequery(qnastatus, turnContext.Activity.Text, activeLearningData); if (requery != null) { TelemetryUtils.LogTrainApiResponse(this._services.TelemetryClient, TelemetryConstants.TrainApiEvent, turnContext.Activity, activeLearningData, requery); } } else { requery = Utils.GetRequery(qnastatus, turnContext.Activity.Text); } if (requery != null) { turnContext.Activity.Text = requery; } } QueryResult responseGeneral = null, responseLuis = null; // Get QnA Answer for multiturn var responseMultiturn = await GetMultiturnResponseFromKB(turnContext, qnastatus.QnaAnswer); if (responseMultiturn == null) { // Get general response from KB responseGeneral = await GetGeneralResponseFromKB(turnContext, qnastatus, true); if (responseGeneral == null) { // Get LUIS intent var luisIntent = await GetLuisIntent(turnContext, Constants.EnableLuis); if (!luisIntent.Equals("None")) { // Get Luis response responseLuis = await GetResponseWithLuisIntent(turnContext, luisIntent); } } } // choose response var qnaresponse = Utils.SelectResponse(responseMultiturn, responseGeneral, responseLuis, qnastatus.QnaAnswer); if (qnaresponse != null) { if (qnaresponse.Options != null && qnaresponse.Options.Count != 0) { await ShowQnAResponseWithOptions(turnContext, qnaresponse, qnastatus); } else { await ShowQnAResponseWithText(turnContext, qnaresponse, qnastatus); } if (qnastatus.QnaAnswer.Name == Constants.MetadataValue.Redirection) { await ShowRedirection(Constants.RedirectionType.GuidedFlow, turnContext, cancellationToken); } if (qnastatus.NeuroconCount >= Constants.ConsecutiveNeuroconAnswersAllowed) { await ShowRedirection(Constants.RedirectionType.Neurocon, turnContext, cancellationToken); } } else { // get answer from Nurocon var personalitychatanswer = await SendCognitiveServicesResponse(turnContext, cancellationToken, Constants.EnablePersonalityChat); if (personalitychatanswer == string.Empty || personalitychatanswer.Equals(@"Sorry, I don't have a response for that.", StringComparison.OrdinalIgnoreCase)) { var msg = @"I don't have an answer for that. Try typing MENU to go back to the main menu"; TelemetryUtils.LogNoAnswerEvent(this._services.TelemetryClient, turnContext.Activity); qnastatus.NeuroconCount++; await _accessors.QnAResultState.SetAsync(turnContext, qnastatus); await _accessors.ConversationState.SaveChangesAsync(turnContext); await turnContext.SendActivityAsync(msg, cancellationToken : cancellationToken); if (qnastatus.NeuroconCount >= Constants.ConsecutiveNeuroconAnswersAllowed) { await ShowRedirection(Constants.RedirectionType.Neurocon, turnContext, cancellationToken); } } else { personalitychatanswer = personalitychatanswer + " [🛈](https://labs.cognitive.microsoft.com/en-us/project-personality-chat \"Auto generated answer using Personality chat. Click to know more\")"; qnastatus.ConsiderState = false; qnastatus.QnaAnswer = null; qnastatus.NeuroconCount++; TelemetryUtils.LogNeuroconResponse(this._services.TelemetryClient, TelemetryConstants.NeuroconEvent, turnContext.Activity, qnastatus, personalitychatanswer); await _accessors.QnAResultState.SetAsync(turnContext, qnastatus); await _accessors.ConversationState.SaveChangesAsync(turnContext); await turnContext.SendActivityAsync(personalitychatanswer, cancellationToken : cancellationToken); if (qnastatus.NeuroconCount >= Constants.ConsecutiveNeuroconAnswersAllowed) { await ShowRedirection(Constants.RedirectionType.Neurocon, turnContext, cancellationToken); } } } } else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate) { return; } else if (turnContext.Activity.Type == ActivityTypes.Event) { // Send a welcome message to the user. var eventActivity = turnContext.Activity.AsEventActivity(); if (eventActivity.Name == Constants.EventWelcomeMessage) { TelemetryUtils.LogWelcomeResponse(this._services.TelemetryClient, "Welcome Event Detected", turnContext.Activity); var dialogContext = await dialogs.CreateContextAsync(turnContext, cancellationToken); var qnastatus = await _accessors.QnAResultState.GetAsync(turnContext, () => new ShowQnAResultState()); qnastatus.ConsiderState = false; qnastatus.QnaAnswer.Text = Constants.WelcomeQuestion; qnastatus.QnaAnswer.Name = Constants.MetadataValue.Welcome; await _accessors.QnAResultState.SetAsync(turnContext, qnastatus); await _accessors.ConversationState.SaveChangesAsync(turnContext); await SendWelcomeMessageAsync(turnContext, cancellationToken); } } else { await turnContext.SendActivityAsync($"{turnContext.Activity.Type} event detected", cancellationToken : cancellationToken); } }