简体   繁体   English

在瀑布对话框中使用 luis 验证提示(Bot 框架 V4)

[英]Validate prompt with luis in waterfall dialog (Bot framework V4)

I am building a bot with the Bot Dialogs extension, but i'm having an issue on a Waterfall Dialog in my project.我正在构建一个带有 Bot Dialogs 扩展的机器人,但我在我的项目中遇到了一个关于瀑布对话框的问题。 If the user says to the bot "i want to enter a new message" the bot will respond with a series of questions like "when do you want the message to be delivered to the user", "what do you want the message to say", etc. What i'm searching for is that when the user is asked for a date, if it responds "tomorrow" luis will return the respective date, but if the user says "foo" the bot will ask for a date again.如果用户对机器人说“我想输入一条新消息”,机器人将回答一系列问题,例如“您希望何时将消息发送给用户”、“您希望消息说什么” “等。我正在寻找的是,当用户被要求约会时,如果它响应“明天”,luis 将返回相应的日期,但如果用户说“foo”,机器人将再次要求约会.

What i've come to do this is a code like this:我要做的是这样的代码:

public class NewMessageDialog : ComponentDialog
{
    private readonly BotStateService _botStateService;
    private readonly BotServices _botServices;
    public NewMessageDialog(string dialogId, BotStateService botStateService, BotServices botServices) : base(dialogId)
    {
        _botStateService = botStateService ?? throw new ArgumentNullException(nameof(botStateService));
        _botServices = botServices ?? throw new ArgumentNullException(nameof(botServices));

        InitializeWaterfalls();
    }
    private void InitializeWaterfalls()
    {
        var waterfallSteps = new WaterfallStep[]
        {
            DateToSendStep,
            ExpirationTimeStep,
            BodyContentStep,
            SummaryStep
        };
        AddDialog(new WaterfallDialog($"{nameof(NewMessageDialog)}.mainFlow", waterfallSteps));
        AddDialog(new DateTimePrompt($"{nameof(NewMessageDialog)}.dateCreation")); //tb
        AddDialog(new NumberPrompt<double>($"{nameof(NewMessageDialog)}.expirationTime"));
        AddDialog(new TextPrompt($"{nameof(NewMessageDialog)}.body.content"));

        InitialDialogId = $"{nameof(NewMessageDialog)}.mainFlow";
    }
    private async Task<DialogTurnResult> DateCreatedStep(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        return await stepContext.PromptAsync($"{nameof(NewMessageDialog)}.dateCreation", new PromptOptions
            {
                Prompt = MessageFactory.Text("What is the date you want to send the message?"),
                RetryPrompt = MessageFactory.Text("Please enter a date")
            }, cancellationToken);
    }
    private async Task<DialogTurnResult> ExpirationTimeStep(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {
        stepContext.Values["dateToSend"] = Convert.ToDateTime(((List<DateTimeResolution>)stepContext.Result).FirstOrDefault().Value);
        return await stepContext.PromptAsync($"{nameof(NewMessageDialog)}.expirationTime", new PromptOptions
        {
            Prompt = MessageFactory.Text("What is the expiration time?"),
            RetryPrompt = MessageFactory.Text("Please enter a decimal number")
        }, cancellationToken);
    }

    private async Task<DialogTurnResult> BodyContentStep(WaterfallStepContext stepContext, CancellationToken cancellationToken)
    {

        stepContext.Values["expirationTime"] = Convert.ToDateTime(((List<DateTimeResolution>)stepContext.Result).FirstOrDefault().Value);
        return await stepContext.PromptAsync($"{nameof(NewMessageDialog)}.body.content", new PromptOptions
        {
            Prompt = MessageFactory.Text("What is the message body?")
        }, cancellationToken);
    }

And so on...等等...

I haven't come to a proper way to do this: I could ask LUIS twice (once in a validator to see if the intent is to set a date, and once in the next step to get the correct datetime from an entity), I could ask luis in the validator and then save it into a class property to finally get the date value from there... Is there an efficient way to do this?我还没有找到正确的方法来做到这一点:我可以问 LUIS 两次(一次在验证器中查看意图是否设置日期,一次在下一步中从实体获取正确的日期时间),我可以在验证器中询问 luis,然后将其保存到类属性中以最终从那里获取日期值......有没有一种有效的方法来做到这一点?

Also I don't know anything about chat maker, I have seen it in another websites while searching...另外我对聊天工具一无所知,我在搜索时在其他网站上看到过...

I recommend using a timex recognizer, like the one used in Core-Bot in the official samples repo:我建议使用 timex 识别器,就像官方示例存储库中Core-Bot中使用的那样:

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Schema;
using Microsoft.Recognizers.Text.DataTypes.TimexExpression;

namespace Microsoft.BotBuilderSamples.Dialogs
{
    public class DateResolverDialog : CancelAndHelpDialog
    {
        private const string PromptMsgText = "When would you like to travel?";
        private const string RepromptMsgText = "I'm sorry, to make your booking please enter a full travel date including Day Month and Year.";

        public DateResolverDialog(string id = null)
            : base(id ?? nameof(DateResolverDialog))
        {
            AddDialog(new DateTimePrompt(nameof(DateTimePrompt), DateTimePromptValidator));
            AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
            {
                InitialStepAsync,
                FinalStepAsync,
            }));

            // The initial child Dialog to run.
            InitialDialogId = nameof(WaterfallDialog);
        }

        private async Task<DialogTurnResult> InitialStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            var timex = (string)stepContext.Options;

            var promptMessage = MessageFactory.Text(PromptMsgText, PromptMsgText, InputHints.ExpectingInput);
            var repromptMessage = MessageFactory.Text(RepromptMsgText, RepromptMsgText, InputHints.ExpectingInput);

            if (timex == null)
            {
                // We were not given any date at all so prompt the user.
                return await stepContext.PromptAsync(nameof(DateTimePrompt),
                    new PromptOptions
                    {
                        Prompt = promptMessage,
                        RetryPrompt = repromptMessage,
                    }, cancellationToken);
            }

            // We have a Date we just need to check it is unambiguous.
            var timexProperty = new TimexProperty(timex);
            if (!timexProperty.Types.Contains(Constants.TimexTypes.Definite))
            {
                // This is essentially a "reprompt" of the data we were given up front.
                return await stepContext.PromptAsync(nameof(DateTimePrompt),
                    new PromptOptions
                    {
                        Prompt = repromptMessage,
                    }, cancellationToken);
            }

            return await stepContext.NextAsync(new List<DateTimeResolution> { new DateTimeResolution { Timex = timex } }, cancellationToken);
        }

        private async Task<DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            var timex = ((List<DateTimeResolution>)stepContext.Result)[0].Timex;
            return await stepContext.EndDialogAsync(timex, cancellationToken);
        }

        private static Task<bool> DateTimePromptValidator(PromptValidatorContext<IList<DateTimeResolution>> promptContext, CancellationToken cancellationToken)
        {
            if (promptContext.Recognized.Succeeded)
            {
                // This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop the Time part.
                // TIMEX is a format that represents DateTime expressions that include some ambiguity. e.g. missing a Year.
                var timex = promptContext.Recognized.Value[0].Timex.Split('T')[0];

                // If this is a definite Date including year, month and day we are good otherwise reprompt.
                // A better solution might be to let the user know what part is actually missing.
                var isDefinite = new TimexProperty(timex).Types.Contains(Constants.TimexTypes.Definite);

                return Task.FromResult(isDefinite);
            }

            return Task.FromResult(false);
        }
    }
}

This is not a call to LUIS, it's just a check that you've entered a valid datetime, set it it's own small waterfall dialog.这不是对 LUIS 的调用,它只是检查您是否输入了有效的日期时间,并将其设置为自己的小瀑布对话框。 As you can see from the following check, it works for the test case you explained ('tomorrow' vs 'foo'):正如您从以下检查中看到的,它适用于您解释的测试用例('tomorrow' vs 'foo'):

示例聊天

暂无
暂无

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

相关问题 瀑布对话框中的C#Bot V4文本提示 - C# bot V4 Text Prompt inside a waterfall dialog 通过跳过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 如何验证自适应卡片机器人框架 v4(瀑布模型)c# 中的输入字段 - How to validate input fields in adaptive card bot framework v4 (waterfall model) c# 接受瀑布对话框上的附件并将它们本地存储在机器人框架 v4 中 - Accepting attachments on a waterfall dialog and storing them locally in bot framework v4 具有复杂对话流的顺序瀑布模型Bot Framework C#v4 - Sequential Waterfall Models with Complex Dialog flows Bot Framework C# v4 如何从机器人框架 v4 中的 ActivityHandler.OnMessageActivityAsync 启动瀑布对话框 - How to start a waterfall dialog from ActivityHandler.OnMessageActivityAsync in bot framework v4 如何在C#[Bot Framework v4]中从QnaBot(qna制造商api)调用瀑布对话框? - How to call waterfall dialog from QnaBot (qna maker api) in C# [Bot Framework v4]? 如何在使用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 和 WaterFall 对话框的 Azure Bot Framework Bot 以异常方式执行。 意外的对话流程 - Azure Bot Framework Bot with LUIS and WaterFall Dialogs executing in abnormal manner. Unexpected dialog flow Bot Framework v4圆形对话框参考 - Bot framework v4 circular dialog reference
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM