Bot Framework v4 .NET обрабатывает пользовательские прерывания путем перенаправления в другой диалог - PullRequest
1 голос
/ 28 сентября 2019

Я занимаюсь разработкой бота с использованием Bot Framework v4 с .NET.Разговор ведется на норвежском языке и является строгим с различными вариантами меню, за которыми может следовать пользователь.Например, в меню приветствия пользователь может выбрать между «связаться с нами», «показать продукты», «подписаться на рассылку» и следовать диалогам для этих трех.Теперь я хочу, чтобы пользователь мог написать, например, «продукты» в любой части беседы, даже если он находится в диалоговом окне «подписаться на рассылку», а затем перенаправлен на мой ProductDialog.

Я следовал документации Microsoft по обработке пользовательских прерываний и использовал Core-bot в качестве основы.Тот же самый подход работал в моем коде, и я успешно смог прервать и написать «помощь» в любой момент разговора или получить ответ.Но я не могу найти простой способ перейти к другому диалогу, хотя, когда CancelAndHelpDialog запускается словом прерывания.

Вот моя версия CancelAndHelpDialog от CoreBot, ядобавили BookingDialog в конструктор и добавили BeginDialog, когда пользователь пишет слово help в диалоге.Остальные файлы такие же, как в CoreBot.

public class CancelAndHelpDialog : ComponentDialog
{
    public CancelAndHelpDialog(string id)
        : base(id)
    {
        AddDialog(new BookingDialog());
    }

    protected override async Task<DialogTurnResult> OnBeginDialogAsync(DialogContext innerDc,
        object options, CancellationToken cancellationToken = default(CancellationToken))
    {
        var result = await InterruptAsync(innerDc, cancellationToken);
        if (result != null)
        {
            return result;
        }

        return await base.OnBeginDialogAsync(innerDc, options, cancellationToken);
    }

    protected override async Task<DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc,
        CancellationToken cancellationToken)
    {
        var result = await InterruptAsync(innerDc, cancellationToken);
        if (result != null)
        {
            return result;
        }

        return await base.OnContinueDialogAsync(innerDc, cancellationToken);
    }

    private async Task<DialogTurnResult> InterruptAsync(DialogContext innerDc, CancellationToken cancellationToken)
    {
        if (innerDc.Context.Activity.Type == ActivityTypes.Message)
        {
            var text = innerDc.Context.Activity.Text.ToLowerInvariant();

            switch (text)
            {
                case "help":
                case "?":
                    await innerDc.Context.SendActivityAsync($"Show Help...", cancellationToken: cancellationToken);
                    //return new DialogTurnResult(DialogTurnStatus.Waiting);
                    return await innerDc.BeginDialogAsync(nameof(BookingDialog), cancellationToken);

                case "cancel":
                case "quit":
                    await innerDc.Context.SendActivityAsync($"Cancelling", cancellationToken: cancellationToken);
                    return await innerDc.CancelAllDialogsAsync();
            }
        }

        return null;
    }
}

1 Ответ

0 голосов
/ 30 сентября 2019

Я реализовал нечто подобное через старую версию Core-Bot, но он проверяет прерывание в моем намерении, а не как отдельный диалог.Это также node.js, но приведенный здесь пример, так как я думаю, что он может помочь вам найти рабочее решение для вашего варианта использования.

После того, как я вернусь, я вызываю функцию для запуска соответствующего диалога.или действие.Но перед ними я проверяю прерывание:

async dispatchToTopIntentAsync(context, intent, recognizerResult) {
    const dc = await this.dialogs.createContext(context);
    const userDialog = await this.userDialogStateAccessor.get(context, {});
        if (context.activity.type === ActivityTypes.Message) {
            let dialogResult;
            const interrupted = await this.isTurnInterrupted(dc, recognizerResult);
            if (interrupted) {
                if (dc.activeDialog !== undefined) {
                    // issue a re-prompt on the active dialog
                    dialogResult = await dc.repromptDialog();
                } // Else: We dont have an active dialog so nothing to continue here.
            } else {
                // No interruption. Continue any active dialogs.
                dialogResult = await dc.continueDialog();
            }

И функцию прерывания:

    async isTurnInterrupted(dc, luisResults) {
        const topIntent = LuisRecognizer.topIntent(luisResults);
        const topIntentScore = luisResults.intents[topIntent].score;

        // see if there are any conversation interrupts we need to handle
        if (topIntent === CANCEL_INTENT & topIntentScore > 0.6) {
            if (dc.activeDialog) {
                // cancel all active dialog (clean the stack)
                await dc.cancelAllDialogs();
                await dc.context.sendActivity('Ok. I\'ve cancelled our last activity.');
            } else {
                await dc.context.sendActivity('I don\'t have anything to cancel. If you\'re not trying to cancel something, please ask your question again.');
            }
            return true; // this is an interruption
        }

        if (topIntent === HELP_INTENT & topIntentScore > 0.5) {
            await dc.context.sendActivity('Let me try to provide some help.');
            await dc.context.sendActivity('Right now I am trained to help you with order status and tracking. If you are stuck in a conversation, type "Cancel" to start over.');
            return true; // this is an interruption
        }

        if (topIntent === EXPEDITE_INTENT & topIntentScore > 0.5) {
            await dc.beginDialog(INTERRUPT_DIALOG, topIntent);
            return false; // pushing new dialog so not an interruption
        }

        if (topIntent === ESCALATE_INTENT & topIntentScore > 0.5) {
            await dc.beginDialog(INTERRUPT_DIALOG, topIntent);
            return false; // pushing new dialog so not an interruption
        }

        return false; // this is not an interruption
    }

Обратите внимание, что в первых двух прерываниях я отправляю сообщение напрямую и впоследние два я начинаю новый диалог.Я возвращаю false в этих случаях, потому что я не хочу перекомпоновывать диалог, который я помещаю в стек.

В этом случае я нажимаю, но вы также можете заменить текущий активныйили отмените все диалоги и запустите новый.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...