Подтвердите подсказку с помощью luis в диалоговом окне водопада - PullRequest
1 голос
/ 23 февраля 2020

Я строю бота с расширением Bot Dialogs, но у меня возникла проблема с Waterfall Dialog в моем проекте. Если пользователь говорит боту «я хочу ввести новое сообщение», бот ответит серией вопросов, таких как «когда вы хотите, чтобы сообщение было доставлено пользователю», «что вы хотите, чтобы сообщение говорило ", et c. Что я ищу, так это то, что когда пользователя просят о дате, если он отвечает «завтра», 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 в валидаторе, а затем сохраните его в свойстве класса, чтобы наконец получить значение даты оттуда ... Есть ли эффективный способ сделать это?

Также я ничего не знаю о создателе чата, я видел это на других сайтах во время поиска ...

1 Ответ

0 голосов
/ 06 апреля 2020

Я рекомендую использовать распознаватель 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, это просто убедитесь, что вы ввели правильное время и дату, установите для него диалог с небольшим водопадом. Как видно из следующей проверки, она работает для тестового примера, который вы объяснили («завтра» против «foo»):

example chat

...