简体   繁体   English

瀑布对话框中的C#Bot V4文本提示

[英]C# bot V4 Text Prompt inside a waterfall dialog

I need to add a question 'Did this help?' 我需要添加一个问题“这个帮助了吗?” after getting the response from QnA and take the feedback from user. 从QnA获得响应后,并从用户那里获取反馈。 If there is no response for this and if the next input is a completely new query, the flow should restart from bot.cs 如果对此没有响应,并且下一个输入是一个全新的查询,则该流程应从bot.cs重新启动

I tried using a textprompt, but when tested in emulator, bot doesn't wait for user input after the prompt. 我尝试使用textprompt,但是在模拟器中进行测试时,bot不会在提示后等待用户输入。

Bot.cs Bot.cs

public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
    var activity = turnContext.Activity;
    var dc = await _dialogs.CreateContextAsync(turnContext);

    if (turnContext == null)
    {
        throw new ArgumentNullException(nameof(turnContext));
    }

    if (turnContext.Activity.Type == ActivityTypes.Message)
    {
        if (turnContext.Activity.Text != null)
        {                   
            var luisResults = await _services.LuisServices[LuisConfiguration].RecognizeAsync(dc.Context, cancellationToken);                    
            var luisProperties = LuisEntities.FromLuisResults(luisResults);                  
            await _luisEntitiesAccessor.SetAsync(turnContext, luisProperties);                   
            var topScoringIntent = luisResults?.GetTopScoringIntent();
            var topIntent = topScoringIntent.Value.intent;

            switch (topIntent)
            {
                case NoneIntent:
                    await dc.BeginDialogAsync(QnADialog.Name);
                    break;
                case GreetingsIntent:
                    await dc.BeginDialogAsync(QnAGreetingsDialog.Name);                                       
                    break;
                case CredentialsIntent:
                    await dc.BeginDialogAsync(CredentialsDialog.Name);
                    break;
                case ContactusIntent:                                       
                    await dc.BeginDialogAsync(FeedbackDialog.Name);
                    break;
                case FeedbackIntent:
                    await dc.BeginDialogAsync(FeedbackDialog.Name);                                       
                    break;
                default:                                        
                    await dc.Context.SendActivityAsync("I didn't understand what you just said to me.");                                       
                    break;
            }
        }
        else if (string.IsNullOrEmpty(turnContext.Activity.Text))
        {
            await HandleSubmitActionAsync(turnContext, userProfile);
        }
    }
    else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate)
    {
        if (turnContext.Activity.MembersAdded != null)
        {
            await SendWelcomeMessageAsync(turnContext);
        }
    }
    else if (turnContext.Activity.Type == ActivityTypes.Event)
    {
        await SendWelcomeMessageAsync(turnContext);
    }
    else
    {
        await turnContext.SendActivityAsync($"{turnContext.Activity.Type} event detected");
    }

    // Save the dialog state into the conversation state.
    await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
}

QnADialog.cs - dialog in which I want the prompt to work QnADialog.cs-我希望在其中运行提示的对话框

public class QnADialog : ComponentDialog
{        
    public const int QnaNumResults = 1;
    public const double QnaConfidenceThreshold = 0.5;

    public const string QnaConfiguration = "QnAFaqSubscriptionKey";
    private const string QnAFeedbackDialog = "qnaDialog";
    public const string Name = "QnA";
    public const string TextPrompt = "textPrompt";

    private readonly BotServices _services;
    private readonly IStatePropertyAccessor<UserProfile> _userProfileAccessor;

    Action<string, string, bool, int, int> updateQna;
    private int InvalidMessageCount = 0;
    string Query = string.Empty;
    List<int> qnaIdStorage;
    UserProfile userProfile = new UserProfile();

    public QnADialog(Action<string, string, bool, int, int> updateQna, bool isCollection, List<int> rotationTemStorage, BotServices services, UserProfile _userProfile, IStatePropertyAccessor<UserProfile> userProfileAccessor, int invalidMessageCount = 0, string dialogId = null)
        : base(Name)
    {
        _services = services ?? throw new ArgumentNullException(nameof(services));
        _userProfileAccessor = userProfileAccessor ?? throw new ArgumentNullException(nameof(userProfileAccessor));
        userProfile = _userProfile;

        this.updateQna = updateQna;
        this.InvalidMessageCount = invalidMessageCount;
        qnaIdStorage = rotationTemStorage;

        var waterfallSteps = new WaterfallStep[]
        {
            BeginStepAsync,
            FetchFAQResultStepAsync,
            FeedbackStepAsync,                                                                 
            FeedbackResponseStepAsync,                       

        };           

        AddDialog(new WaterfallDialog(QnAFeedbackDialog, waterfallSteps));            
        AddDialog(new TextPrompt("userFeed"));      
    }

    public async Task<DialogTurnResult> BeginStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken = default(CancellationToken))
    {
        var messageToForward = stepContext.Context.Activity;
        UserProfile.previousQuestion = messageToForward.Text;

        string[] supportList = { "HELP", "FEEDBACK", "SUPPORT", "ESCALATE", "AGENT" };

        if (messageToForward.Text == null || messageToForward.Text.ToLower() == "no")
        {
            await stepContext.Context.SendActivityAsync("Sorry, I was not able to help you.");
            return await stepContext.EndDialogAsync();
        }
        else if (messageToForward.Text == null || supportList.Any(x => x == messageToForward.Text.ToUpper()))
        {
            await stepContext.Context.SendActivityAsync("Please reach out to... ");
            return await stepContext.EndDialogAsync();
        }
        else
        {
            return await stepContext.NextAsync();
        }
    }

    private async Task<DialogTurnResult> FetchFAQResultStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        var message = stepContext.Context.Activity;

        var qnaResult = await FaqQnaMakerService.GetQnaResult(_services, stepContext, this.Query);
        var qnaIdColl = GetQnaIdColl(this.Query, qnaResult);
        int qnaPreviousId = 0;
        int qnaNewId = 0;

        if (qnaIdColl != null && qnaIdColl.Count > 1)
        {
            qnaIdColl = qnaIdColl.Distinct().OrderBy(x => x).ToList();
            //Compare the previous Qnaid collection and existing collection , if it is matching produce the result.
            var matchItem = qnaIdColl.Intersect(qnaIdStorage);

            if (matchItem.Count() == 0)
            {
                //If there is no previous collection Qna id then take the first item from the existing Qna collection
                qnaNewId = qnaIdColl.FirstOrDefault();
            }
            else
            {
                //If there any previous Qnaid that contain in the existing collection then pick the next value and generate a new qna result.
                qnaPreviousId = matchItem.FirstOrDefault();
                qnaNewId = GetNextRotationKey(qnaIdColl, qnaPreviousId);
            }

            //Create a new response based on selected new qna id.                
            qnaResult = new[] { qnaResult.Where(x => x.Id == qnaNewId).Single() };                
        }

        if (qnaResult.First().Answer.Length > 0)
        {
            if (qnaResult.First().Score > 0)
            {
                updateQna(this.Query, qnaResult.First().Answer, false, qnaPreviousId, qnaNewId);
                InvalidMessageCount = 0;
                var QuestionCollection = TextFormatter.FormattedQuestionColl(qnaResult.First().Answer);

                if (QuestionCollection != null)
                {
                    userProfile.IsAswerCollection = true;
                    updateQna(this.Query, qnaResult.First().Answer, true, qnaPreviousId, qnaNewId);
                    var replyMessage = stepContext.Context.Activity.CreateReply();
                    replyMessage.Attachments = new List<Attachment>() { AllAdaptiveCard.QnaAttachment(new Tuple<string, string[]>(QuestionCollection.Item2, QuestionCollection.Item3)) };

                    if (!string.IsNullOrEmpty(QuestionCollection.Item1))
                    {
                        await stepContext.Context.SendActivityAsync(QuestionCollection.Item1);
                    }

                    await stepContext.Context.SendActivityAsync(replyMessage);
                    return await stepContext.EndDialogAsync();                      
                }
                else
                {
                    await stepContext.Context.SendActivityAsync(qnaResult.First().Answer);
                }                   
            }             
            else
            {
                InvalidMessageCount++;
                return await stepContext.ContinueDialogAsync();                   
            }
        }          

        return await stepContext.NextAsync();
    }

    private async Task<DialogTurnResult> FeedbackStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        return await stepContext.PromptAsync("userFeed", new PromptOptions
        {
            Prompt = stepContext.Context.Activity.CreateReply("Did this help?")                
        });
    }

    private async Task<DialogTurnResult> FeedbackResponseStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        var message = stepContext.Context.Activity;
        var mesgActivity = message as Activity;

        string var = userProfile.qnaData;
        var qnaResultModel = new { InvalidMessageCount = 0, originalQueryText = string.Empty };
        NeedMoreInformation needmoreInfo = NeedMoreInformation.NotSelected;

        if (message != null && message.Text == null && message.Value != null)
        {
            dynamic value = mesgActivity.Value.ToString();
            UserReply response = JsonConvert.DeserializeObject<UserReply>(value);
            if (!string.IsNullOrEmpty(response.Reply))
            {
                mesgActivity.Text = response.Reply;
            }

        }

        //This if condition work only the user reply back to the question "Did this help?"
        if (userProfile.needMoreInformation == true && message?.Text?.ToLower() != "yes" && message?.Text?.ToLower() != "no")
        {
            //The response message pass to LUIS service to understand the intention of the conversation is “yes” or “no” 
            bool? moreInformationYes = await LUISService.GetResultAESChatBotYesNo(message?.Text);

            if (moreInformationYes != null && moreInformationYes == true)
            {
                //Once the LUIS understand the conversation change the original message to yes.
                message.Text = "yes";
                //needmoreInfo = NeedMoreInformation.Yes;
            }
            else if (moreInformationYes != null && moreInformationYes == false)
            {
                ////Once the LUIS understand the conversation change the original message to no.
                message.Text = "no";
                needmoreInfo = NeedMoreInformation.No;
            }
            else
            {
                needmoreInfo = NeedMoreInformation.None;
            }
        }

        if (userProfile.needMoreInformation == true && message?.Text?.ToLower() == "yes")
        {                   
            userProfile.qnaInvalidMessageCount = 0;
            userProfile.needMoreInformation = false;
            dynamic value = stepContext.Context.Activity.Value;
            var output = JsonConvert.DeserializeObject<UserReply>(stepContext.Context.Activity.Value.ToString());
            if (userProfile.feedbackCard == false)
            {
                var replyMessage = stepContext.Context.Activity.CreateReply();
                replyMessage.Attachments = new List<Attachment>() { AllAdaptiveCard.FeedbackAdapativecard() };
                await stepContext.Context.SendActivityAsync(replyMessage);
            }
            if (output.Reply != "yes")
            {
                await AdaptiveCardReplyAsync(_services, stepContext, userProfile);
            }                   
        }
        else if (userProfile.needMoreInformation == true && message?.Text?.ToLower() == "no")
        {
            userProfile.qnaInvalidMessageCount = 0;
            userProfile.needMoreInformation = false;
            dynamic value = stepContext.Context.Activity.Value;

            if (value.Type == "GetMoreContent")
            {
                await AdaptiveCardGetMoreContent(_services, stepContext, userProfile);
            }
            else if (value.Type == "GetHelpSubmit")
            {
                await AdaptiveCardReplyAsync(_services, stepContext, userProfile);
            }
            else if (userProfile.getMoreContentCard == false)
            {
                var replyMessage = stepContext.Context.Activity.CreateReply();
                replyMessage.Attachments = new List<Attachment>() { AllAdaptiveCard.GetMoreContent() };
                await stepContext.Context.SendActivityAsync(replyMessage);
            }

            // context.Wait(AdaptiveCardGetMoreContent);
        } 
        else
        { 
            await stepContext.BeginDialogAsync(nameof(Bot.cs));                    
        }

        return await stepContext.EndDialogAsync();
    }
}

After this prompt it should go to the next step as added in the waterfall steps but it does not. 出现此提示后,应转到瀑布步骤中添加的下一个步骤,但不这样做。 Any possible suggestions/help would be greatly appreciated. 任何可能的建议/帮助将不胜感激。 Thanks in advance! 提前致谢!

Without seeing the code for your other steps inside the Waterfall such as BeginStepAsync and FetchFAQResultStepAsync it is difficult to give you an exact answer for your scenario. 如果看不到Waterfall中其他步骤的代码,例如BeginStepAsyncFetchFAQResultStepAsync ,则很难为您的方案提供确切的答案。

How I would suggest you accomplish this is through the use of a message with suggested actions underneath this message, once either of this actions is clicked both options will disappear, thus removing the potential for multiple submissions by the same user for the same answer reply. 我建议您如何实现此目标,是通过使用一条消息以及该消息下方的建议操作来实现的,一旦单击任一操作,两个选项都将消失,从而消除了同一用户针对同一答案做出多次提交的可能性。

You have a couple of options here: 您可以在此处选择两个选项:

1) Use this dated sample that uses v3.9.0 of the Microsoft.Bot.Builder NuGet package, the meat of which is in the QnADialog and FeedbackDialog classes. 1)使用此过时的示例 ,该示例使用Microsoft.Bot.Builder NuGet软件包的QnADialog ,其QnADialogQnADialogFeedbackDialog类中。

The important part is that the QnADialog implements QnAMakerDialog . 重要的是QnADialog实现QnAMakerDialog

2) Right after where you send the reply to the user with the answer (inside FetchFAQResultsStepAsync I assume) you could add the following code: 2)在将答案和答案发送给用户之后(在我认为的FetchFAQResultsStepAsync内部),您可以添加以下代码:

var feedback = ((Activity)context.Activity).CreateReply("Did you find what you need?");

feedback.SuggestedActions = new SuggestedActions()
{
    Actions = new List<CardAction>()
    {
        new CardAction(){ Title = "Yes", Type=ActionTypes.PostBack, Value=$"yes-positive-feedback" },
        new CardAction(){ Title = "No", Type=ActionTypes.PostBack, Value=$"no-negative-feedback" }
    }
};

await context.PostAsync(feedback);

EDIT 编辑

Thank you for providing the full code for your QnADialog class, unfortunately I cannot run it locally because the implementations for methods such as GetQnaIdColl , GetNextRotationKey , TextFormatter.FormattedQuestionColl among other methods and classes that you call but haven't provided. 感谢您为QnADialog类提供完整的代码,不幸的是,我无法在本地运行它,因为您调用但尚未提供的其他方法和类中,诸如GetQnaIdCollGetNextRotationKeyTextFormatter.FormattedQuestionColl类的方法的实现。 Your code for prompting a user for a response looks right but it sounds like you're not even getting the feedback prompt to show, or you're getting the feedback prompt to show but you get stuck on there - can you confirm which it is? 您的提示用户响应的代码看起来正确,但听起来您甚至没有显示反馈提示,或者您似乎正在显示反馈提示,但您被困在那里,您可以确认它是哪个吗? ? Have you tried stepping through the code to see which path it takes? 您是否尝试单步执行代码以查看采用哪条路径?

Another suggestion would be to separate out your QnA step and Feedback steps into separate Dialogs, I have proved and example feedback dialog below. 另一个建议是将您的QnA步骤和“反馈”步骤分离到单独的对话框中,我已经证明了下面的示例反馈对话框。

using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using System.Threading;
using System.Threading.Tasks;

namespace ChatBot.VirtualAssistant.Dialogs
{
    public class RateAnswerDialog : ComponentDialog
    {
        public RateAnswerDialog()
            : base(nameof(RateAnswerDialog))
        {
            InitialDialogId = nameof(RateAnswerDialog);

            var askToRate = new WaterfallStep[]
            {
                AskRating,
                FinishDialog
            };

            AddDialog(new TextPrompt(nameof(TextPrompt)));
            AddDialog(new WaterfallDialog(InitialDialogId, askToRate));
        }

        private async Task<DialogTurnResult> AskRating(WaterfallStepContext sc, CancellationToken cancellationToken)
        {
            PromptOptions promptOptions = new PromptOptions
            {
                Prompt = MessageFactory.Text("Was this helpful?")
            };

            return await sc.PromptAsync(nameof(TextPrompt), promptOptions);
        }

        private async Task<DialogTurnResult> FinishDialog(WaterfallStepContext sc, CancellationToken cancellationToken)
        {
            return await sc.EndDialogAsync(sc);
        }

        protected override async Task<DialogTurnResult> EndComponentAsync(DialogContext outerDc, object context, CancellationToken cancellationToken)
        {
            var waterfallContext = (WaterfallStepContext)context;

            var userResponse = ((string)waterfallContext.Result).ToLowerInvariant();

            if (userResponse == "yes")
            {
                await waterfallContext.Context.SendActivityAsync("Thank you for your feedback");
            }
            else if (userResponse == "no")
            {
                await waterfallContext.Context.SendActivityAsync("Sorry I couldn't help you");
            }
            else
            {
                await waterfallContext.Context.SendActivityAsync("The valid answers are 'yes' or 'no'");

                // TODO reprompt if required
            }

            return await outerDc.EndDialogAsync();
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在使用C#创建的SDK V4 bot中的瀑布式对话框中使用oauth提示修复下一步导航而不键入任何内容? - How to fix next step navigation with oauth prompt in waterfall dialog in SDK V4 bot created using C# without typing anything? 在瀑布对话框中使用 luis 验证提示(Bot 框架 V4) - Validate prompt with luis in waterfall dialog (Bot framework V4) 具有复杂对话流的顺序瀑布模型Bot Framework C#v4 - Sequential Waterfall Models with Complex Dialog flows Bot Framework C# v4 如何在C#[Bot Framework v4]中从QnaBot(qna制造商api)调用瀑布对话框? - How to call waterfall dialog from QnaBot (qna maker api) in C# [Bot Framework v4]? Bot Framework C#v4的动态提示 - Dynamic Prompt with Bot Framework C# v4 Bot Framework V4 Choice Prompt with Hero Card c# - Bot Framework V4 Choice Prompt with Hero Card c# 如何验证自适应卡片机器人框架 v4(瀑布模型)c# 中的输入字段 - How to validate input fields in adaptive card bot framework v4 (waterfall model) c# [BotFrameWork]:如何在使用V4开发的C#Webchat机器人中同时显示文本提示和选择提示? - [BotFrameWork]:How to have text prompt and choice prompt both at a time in C# Webchat bot developed using V4? 通过跳过bot框架v4中第一个对话的第一步,将第一个对话的瀑布步骤调用到另一个对话中 - Invoke the steps of waterfall of first dialog into other dialog by skipping the first step of a first dialog in bot framework v4 Botframework v4:如何简化这个瀑布式对话框? - Botframework v4: How to simplify this waterfall dialog?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM