我希望我的机器人在没有活动对话框时处理用户的LUIS和QnAMaker话语。
我最终得到了这段代码,它的工作正常,唯一的问题是,它只能工作一转。用户第二次键入任何内容时,机器人会再次启动主对话框。
此处结束是取消所有对话框。来自谁的答案来自QnAMaker。
如何防止漫游器自动启动主对话框?
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
await base.OnTurnAsync(turnContext, cancellationToken);
var recognizerResult = turnContext.TurnState.Get<RecognizerResult>("recognizerResult");
var topIntent = turnContext.TurnState.Get<string>("topDispatchIntent");
var dc = await Dialogs.CreateContextAsync(turnContext, cancellationToken);
var dialogResult = await dc.ContinueDialogAsync();
if (!dc.Context.Responded)
{
switch (dialogResult.Status)
{
//dispatch to luis or qna when there is no active dialog
case DialogTurnStatus.Empty:
await DispatchToLUISorQnAMakerAsync(turnContext, topIntent, recognizerResult, 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);
}
private async Task DispatchToTopIntentAsync(ITurnContext turnContext, string intent, RecognizerResult recognizerResult, CancellationToken cancellationToken)
{
switch (intent)
{
case "none":
await turnContext.SendActivityAsync("Sorry i did not get that.");
break;
case "q_SabikoKB":
await DispatchToQnAMakerAsync(turnContext, cancellationToken);
break;
case "l_SabikoV2":
await DispatchToLuisModelAsync(turnContext, recognizerResult.Properties["luisResult"] as LuisResult, 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);
}
}
}
private async Task DispatchToLuisModelAsync(ITurnContext turnContext, LuisResult luisResult, CancellationToken cancellationToken)
{
var result = luisResult.ConnectedServiceResult;
var topIntent = result.TopScoringIntent.Intent;
switch (topIntent)
{
case "Greeting":
//..
default:
break;
}
}
主对话框
namespace BotV2.DialogsV2.Main_Menu
{
public class MainDialog : InterruptDialog
{
private const string InitialId = nameof(MainDialog);
private readonly IStatePropertyAccessor<BasicUserState> _userProfileAccessor;
public MainDialog(UserState userState, ConversationState conversationState, IConfiguration config)
: base(nameof(MainDialog),userState)
{
_userProfileAccessor = userState.CreateProperty<BasicUserState>("UserProfile");
InitialDialogId = InitialId;
WaterfallStep[] waterfallSteps = new WaterfallStep[]
{
CheckWelcomeMessageStepAsync,
FirstStepAsync,
SecondStepAsync,
};
AddDialog(new WaterfallDialog(InitialId, waterfallSteps));
//AddDialogs..
}
private async Task<DialogTurnResult> CheckWelcomeMessageStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var userstate = await _userProfileAccessor.GetAsync(stepContext.Context, () => new BasicUserState(), cancellationToken);
if (!userstate.DialogCheckers.SentWelcomeMessage)
{
return await stepContext.BeginDialogAsync(nameof(WelcomeMessageDialog));
}
return await stepContext.NextAsync(cancellationToken: cancellationToken);
}
private async Task<DialogTurnResult> FirstStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var userstate = await _userProfileAccessor.GetAsync(stepContext.Context, () => new BasicUserState(), cancellationToken);
//only suggestions, interruption will trigger the dialog to begin them.
return await stepContext.PromptAsync(
nameof(TextPrompt),
new PromptOptions
{
Prompt = new Activity
{
Type = ActivityTypes.Message,
Text = $"So {userstate.FirstName}, What can i do for you?",
SuggestedActions = new SuggestedActions()
{
Actions = new List<CardAction>()
{
new CardAction() { Title = "Financial Literacy", Type = ActionTypes.ImBack, Value = "Financial Literacy" },
new CardAction() { Title = "My Compass", Type = ActionTypes.ImBack, Value = "My Compass" },
},
},
},
});
}
private static async Task<DialogTurnResult> SecondStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
return await stepContext.EndDialogAsync();
}
}
}
启动
services.AddSingleton<ICredentialProvider, ConfigurationCredentialProvider>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();
services.AddSingleton<IBotServices, BotServices>();
services.AddSingleton<ConcurrentDictionary<string, ConversationReference>>();
services.AddTransient<MainDialog>();
services.AddTransient<WelcomeMessageDialog>();
services.AddTransient<IBot, DialogBot<MainDialog>>();
答案 0 :(得分:0)
MainDialog自动重新启动,因为在DialogBot.cs -> OnMessageActivityAsync()
中,您具有:
await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>("DialogState"), cancellationToken);
这会在用户发出的每条消息上调用MainDialog。
您可以很好地检查用户是否已完成MainDialog的一部分:
if (!userstate.DialogCheckers.SentWelcomeMessage)
[...]
if (!userstate.DialogCheckers.AskedDiagnosticQuestion)
但是对话框本身本身仍将在每条消息上调用。
我认为您误解了CancelAllDialogs()
来表示他们从未解雇。相反,它只会清除您的对话框堆栈,但仍然可以再次调用它们。
您有两个不同的选项可用于“修复”此问题:
您可能具有某种hasCancelledDialogs
这样的userState标志,当用户调用意图取消所有对话框,在MainDialog
中进行检查的意图时是否设置该标志;如果第一步发现EndDialog()
。
从Dialog.RunAsync
中删除DialogBot.cs
调用,而是根据调度意图和/或成员关系仅路由到适当的对话框。
我还注意到,您使用多种方法来路由对话框。两者都有:
var dc = await Dialogs.CreateContextAsync(turnContext, cancellationToken);
var dialogResult = await dc.ContinueDialogAsync();
if (!dc.Context.Responded)
[...]
和
await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>("DialogState"), cancellationToken);
RunAsync
takes care of most of that first code block for you。
这也可能导致您遇到一些问题。最有可能的是,您开始使用第一个代码块来开发您的机器人,然后我们转向第二种风格,并且您尝试在不完全了解幕后情况的情况下对其进行了集成。
您的漫游器开始变得非常复杂,将很难解决这类问题。我建议将所有内容都转换为Dialog.RunAsync
样式,并删除较旧的样式。重构需要大量的工作,但是可以节省大量的调试和故障排除时间。
所有这些,我只能确定约80%的人了解您的问题。同样,您的机器人非常复杂,有很多循环和分支,因此我不确定这个答案是否能解决您的问题。如果没有,请提供非常详细的描述,说明您预期会发生什么。