C# 对话通过意图中断启动,只有在没有活动对话时,QnaMaker才会回答
我不知道我是否能很好地解释这一点,但请容忍我。下面有代码和图像 因此,我正在将代码从Bot Framework V4的第一个版本迁移到最新版本 我正试图为一个机器人打下基础,它可以随时调用其他对话框并取消当前对话框。并在没有活动对话框时使用QnAMaker回答问题 没有错误,但bot的行为不符合预期 期望:当用户第一次与Get Started交互时,将调用主菜单,因为我在主菜单的意图中添加了Get Started。 实际结果:主菜单被调用了两次 期望:当我通过intent从中断调用DialogA时。将调用dialogA,如果有任何活动对话框,将取消该对话框。 实际结果:对话框A被调用,当前活动的对话框结束,但对话框A也突然结束。即使您尚未回答其选择提示。 注意:当我通过主菜单中的选择提示调用dialogA时。对话框A正常启动,但未结束 期望:当没有活动对话框时,例如如果取消对话框,用户可以提问,机器人会在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
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);
}