【问题标题】:Validate prompt with luis in waterfall dialog (Bot framework V4)在瀑布对话框中使用 luis 验证提示(Bot 框架 V4)
【发布时间】:2020-04-07 02:25:54
【问题描述】:

我正在使用 Bot Dialogs 扩展构建一个机器人,但我的项目中的瀑布对话框出现问题。如果用户对机器人说“我想输入一条新消息”,机器人会回答一系列问题,例如“你希望什么时候将消息传递给用户”、“你想让消息说什么” “等等。我正在寻找的是,当用户被要求提供日期时,如果它响应“明天”,luis 将返回相应的日期,但如果用户说“foo”,机器人将再次要求日期.

我来做的是这样的代码:

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);
    }

等等……

我还没有找到正确的方法来执行此操作:我可以询问 LUIS 两次(一次在验证器中查看是否要设置日期,一次在下一步中从实体),我可以在验证器中询问 luis,然后将其保存到类属性中以最终从那里获取日期值......有没有一种有效的方法来做到这一点?

另外我对聊天工具一无所知,我在其他网站上搜索时看到过...

【问题讨论】:

  • 一般情况下,你可以为所有的提示编写验证函数,当响应正常时返回true,否则返回false。你有没有尝试过这样的事情?

标签: c# botframework azure-language-understanding


【解决方案1】:

我建议使用 timex 识别器,例如官方示例 repo 中 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);
        }
    }
}

这不是对 LUIS 的调用,它只是检查您是否输入了有效的日期时间,并将其设置为自己的小型瀑布对话框。正如您从以下检查中看到的那样,它适用于您解释的测试用例('tomorrow' vs 'foo'):

【讨论】:

  • 谢谢!但我不明白...promptContext.Recognized 自动检测到大多数类似日期的输入?再说一次,我正在用西班牙语制作一个程序,它也适用吗?
猜你喜欢
  • 2019-11-22
  • 2019-10-11
  • 1970-01-01
  • 1970-01-01
  • 2017-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多