簡體   English   中英

在瀑布對話框中使用 luis 驗證提示(Bot 框架 V4)

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

我正在構建一個帶有 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,然后將其保存到類屬性中以最終從那里獲取日期值......有沒有一種有效的方法來做到這一點?

另外我對聊天工具一無所知,我在搜索時在其他網站上看到過...

我建議使用 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);
        }
    }
}

這不是對 LUIS 的調用,它只是檢查您是否輸入了有效的日期時間,並將其設置為自己的小瀑布對話框。 正如您從以下檢查中看到的,它適用於您解釋的測試用例('tomorrow' vs 'foo'):

示例聊天

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM