C# 对话通过意图中断启动,只有在没有活动对话时,QnaMaker才会回答

C# 对话通过意图中断启动,只有在没有活动对话时,QnaMaker才会回答,c#,botframework,azure-language-understanding,qnamaker,C#,Botframework,Azure Language Understanding,Qnamaker,我不知道我是否能很好地解释这一点,但请容忍我。下面有代码和图像 因此,我正在将代码从Bot Framework V4的第一个版本迁移到最新版本 我正试图为一个机器人打下基础,它可以随时调用其他对话框并取消当前对话框。并在没有活动对话框时使用QnAMaker回答问题 没有错误,但bot的行为不符合预期 期望:当用户第一次与Get Started交互时,将调用主菜单,因为我在主菜单的意图中添加了Get Started。 实际结果:主菜单被调用了两次 期望:当我通过intent从中断调用DialogA

我不知道我是否能很好地解释这一点,但请容忍我。下面有代码和图像

因此,我正在将代码从Bot Framework V4的第一个版本迁移到最新版本

我正试图为一个机器人打下基础,它可以随时调用其他对话框并取消当前对话框。并在没有活动对话框时使用QnAMaker回答问题

没有错误,但bot的行为不符合预期

期望:当用户第一次与Get Started交互时,将调用主菜单,因为我在主菜单的意图中添加了Get Started。 实际结果:主菜单被调用了两次

期望:当我通过intent从中断调用DialogA时。将调用dialogA,如果有任何活动对话框,将取消该对话框。 实际结果:对话框A被调用,当前活动的对话框结束,但对话框A也突然结束。即使您尚未回答其选择提示。 注意:当我通过主菜单中的选择提示调用dialogA时。对话框A正常启动,但未结束

期望:当没有活动对话框时,例如如果取消对话框,用户可以提问,机器人会在QnaMaker中检查答案。实际结果:机器人回答问题,然后启动主菜单。即使有激活的对话,机器人仍然会回答问题

代码如下:

对话机器人:

    namespace SabikoBotV2.Bots
{
    public class DialogBot<T> : ActivityHandler
        where T : Dialog
    {
        public readonly IStatePropertyAccessor<DialogState> _dialogAccessor;
        protected readonly Dialog Dialog;
        protected readonly BotState ConversationState;
        protected readonly BotState UserState;
        protected readonly ILogger Logger;
        private readonly IBotServices BotServices;

        private DialogSet Dialogs { get; set; }

        public DialogBot(IBotServices botServices, ConversationState conversationState, UserState userState, T dialog, ILogger<DialogBot<T>> logger)
        {
            ConversationState = conversationState;
            UserState = userState;
            Dialog = dialog;
            Logger = logger;
            BotServices = botServices;
            Dialogs = new DialogSet(conversationState.CreateProperty<DialogState>(nameof(DialogBot<T>)));
            RegisterDialogs(Dialogs);
        }

        public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
        { 
            await base.OnTurnAsync(turnContext, cancellationToken);

            await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
            await UserState.SaveChangesAsync(turnContext, false, cancellationToken);
        }

        protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            Logger.LogInformation("Running dialog with Message Activity.");

            string text = string.IsNullOrEmpty(turnContext.Activity.Text) ? string.Empty : turnContext.Activity.Text.ToLower();

            string topIntent = string.Empty;
            RecognizerResult luisRecognizerResult = null;

            string topDispatch = string.Empty;
            RecognizerResult dispatchRecognizerResult = null;

            if (!string.IsNullOrEmpty(text))
            {
                dispatchRecognizerResult = await BotServices.DispatchService.RecognizeAsync(turnContext, cancellationToken);
                var topScoringDispatch = dispatchRecognizerResult?.GetTopScoringIntent();
                topDispatch = topScoringDispatch.Value.intent;

                luisRecognizerResult = await BotServices.LuisService.RecognizeAsync(turnContext, cancellationToken);
                var topScoringIntent = luisRecognizerResult?.GetTopScoringIntent();
                topIntent = topScoringIntent.Value.intent;

                turnContext.TurnState.Add("topDispatch", topDispatch);
                turnContext.TurnState.Add("dispatchRecognizerResult", dispatchRecognizerResult);
                turnContext.TurnState.Add("botServices", BotServices);
                turnContext.TurnState.Add("topIntent", topIntent);
            }

            var dc = await Dialogs.CreateContextAsync(turnContext, cancellationToken);
            var dialogResult = await dc.ContinueDialogAsync();

            if (!dc.Context.Responded)
            {
                switch (dialogResult.Status)
                {
                    case DialogTurnStatus.Empty:
                        await DispatchToTopIntentAsync(turnContext, topDispatch, dispatchRecognizerResult, cancellationToken);
                        break;

                    case DialogTurnStatus.Waiting:
                        break;

                    case DialogTurnStatus.Complete:
                        await dc.EndDialogAsync();
                        break;

                    default:
                        await dc.CancelAllDialogsAsync();
                        break;
                }
            }

            await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>("DialogState"), cancellationToken);
        }

        private void RegisterDialogs(DialogSet dialogs)
        {
            dialogs.Add(new MainDialog());
            dialogs.Add(new DialogA());
            dialogs.Add(new DialogB());
        }

        private async Task DispatchToTopIntentAsync(ITurnContext turnContext, string intent, RecognizerResult recognizerResult, CancellationToken cancellationToken)
        {
            switch (intent)
            {
                case QnAModel:
                    await DispatchToQnAMakerAsync(turnContext, cancellationToken);
                    break;
            }
        }

        private async Task DispatchToQnAMakerAsync(ITurnContext turnContext, CancellationToken cancellationToken)
        {
            if (!string.IsNullOrEmpty(turnContext.Activity.Text))
            {
                var results = await BotServices.QnaService.GetAnswersAsync(turnContext);
                if (results.Any())
                {
                    await turnContext.SendActivityAsync(MessageFactory.Text(results.First().Answer), cancellationToken);
                }
                else
                {
                    await turnContext.SendActivityAsync(MessageFactory.Text("Sorry, could not find an answer in the Q and A system."), cancellationToken);
                }
            }
        }

    }
}
启动

    namespace SabikoBotV2
{
    public class Startup
    {
        public Startup()
        {

        }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<ICredentialProvider, ConfigurationCredentialProvider>();

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();

            services.AddSingleton<IStorage, MemoryStorage>();

            services.AddSingleton<UserState>();

            services.AddSingleton<ConversationState>();

            services.AddSingleton<IBotServices, BotServices>();

            services.AddTransient<MainDialog>();
            services.AddTransient<DialogA>();
            services.AddTransient<DialogB>();

            services.AddTransient<IBot, DialogBot<MainDialog>>();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }

            app.UseDefaultFiles();
            app.UseStaticFiles();

            app.UseMvc();
        }
    }
}
取消和帮助对话框

    namespace SabikoBotV2.DialogsV2
{
    public class CancelAndHelpDialog : ComponentDialog
    {
        public CancelAndHelpDialog(string id)
            : base(id)
        {
        }

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

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

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

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

        protected virtual async Task<DialogTurnResult> IsTurnInterruptedAsyncHelpAndCancel(DialogContext innerDc, CancellationToken cancellationToken)
        {
            var topIntent = innerDc.Context.TurnState.Get<string>("topIntent");
            var text = innerDc.Context.TurnState.Get<string>("text");

            if (topIntent.Equals("Cancel"))
            {
                if (innerDc.ActiveDialog != null)
                {
                    await innerDc.CancelAllDialogsAsync();
                    await innerDc.Context.SendActivityAsync("Hello I managed to fix my problem. For future reference of others here is how i fixed it.

I fixed the running of dialog via intent interruption by adding this line in the cancelandhelpdialog

return new DialogTurnResult(DialogTurnStatus.Waiting);

            if (topIntent.Equals("MainDialog"))
        {
            if (innerDc.ActiveDialog != null)
            {
                await innerDc.CancelAllDialogsAsync();
                await innerDc.BeginDialogAsync(nameof(MainDialog));
            }
            else
            {
                await innerDc.BeginDialogAsync(nameof(MainDialog));
            }

            return new DialogTurnResult(DialogTurnStatus.Waiting);
        }
名称空间SabikoBotV2.DialogsV2 { 公共类CancelAndHelpDialog:ComponentDialog { 公共CancelAndHelpDialogstring id :baseid { } 受保护的重写异步任务OnBeginDialogGasyncDialogContext innerDc,对象选项,CancellationToken CancellationToken=defaultCancellationToken { var result=等待IsTurnInterruptedAsyncHelpAndCancelinnerDc,cancellationToken; 如果结果为!=null { 返回结果; } return wait base.onbegindialogasyncinerdc、options、cancellationToken; } 受保护的覆盖异步任务OnContinueDialogAsyncDialogContext innerDc,CancellationToken CancellationToken=默认值 { var result=等待IsTurnInterruptedAsyncHelpAndCancelinnerDc,cancellationToken; 如果结果为!=null { 返回结果; } return wait base.OnContinueDialogAsyncinnerDc,cancellationToken; } 受保护的虚拟异步任务为InterruptedSyncHelpandCancelDialogContext innerDc,CancellationToken CancellationToken { var topIntent=innerDc.Context.TurnState.GettopIntent; var text=innerDc.Context.TurnState.Gettext; 如果topIntent.equals取消 { 如果innerDc.ActiveDialog!=null { 等待innerDc.CancelAllDialogsAsync;
Wait innerDc.Context.SendActivityAsync您好,我已设法解决了我的问题。以下是我如何解决的,供其他人参考

通过在cancelandhelpdialog中添加这一行,我修复了通过意图中断运行dialog的问题

返回新对话框TurnResultDialogTurnStatus.Waiting

QnaMaker在OnTurnAsync中执行此操作,仅在没有活动对话框时进行应答:

希望这能帮助别人

    public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
    { 
        await base.OnTurnAsync(turnContext, cancellationToken);

        var topDispatch = turnContext.TurnState.Get<string>("topDispatch");
        var dispatchRecognizerResult = turnContext.TurnState.Get<RecognizerResult>("dispatchRecognizerResult");
        var dc = await Dialogs.CreateContextAsync(turnContext, cancellationToken);
        var dialogResult = await dc.ContinueDialogAsync();

        if (!dc.Context.Responded)
        {
            switch (dialogResult.Status)
            {
                case DialogTurnStatus.Empty:
                    await DispatchToTopIntentAsync(turnContext, topDispatch, dispatchRecognizerResult, cancellationToken);
                    break;

                case DialogTurnStatus.Waiting:
                    break;

                case DialogTurnStatus.Complete:
                    await dc.EndDialogAsync();
                    break;

                default:
                    await dc.CancelAllDialogsAsync();
                    break;
            }
        }

        // Save any state changes that might have occured during the turn.
        await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
        await UserState.SaveChangesAsync(turnContext, false, cancellationToken);
    }