Я работаю над тем, чтобы взломать пример кода GitHub 'CoreBot' для Bot Framework V4 (с LUIS) для моих собственных целей, и столкнулся с проблемой при выполнении шагов отклика и диалогового окна водопада.
У меня есть диалог верхнего уровня. Я ожидаю, что этот диалог делает первоначальный вызов LUIS на основе ввода и маршрутизирует в различные диалоги на основе этого ввода. На данный момент есть только возможность поприветствовать бота и сообщить об опасности. Мои настройки диалога такие же (игнорируйте BookingDialog, это часть образца).
public MainDialog(IConfiguration configuration, ILogger<MainDialog> logger)
: base(nameof(MainDialog))
{
Configuration = configuration;
Logger = logger;
AddDialog(new TextPrompt(nameof(TextPrompt)));
AddDialog(new BookingDialog());
AddDialog(new HazardDialog());
AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
{
MainStepAsync,
EndOfMainDialogAsync
}));
// The initial child Dialog to run.
InitialDialogId = nameof(WaterfallDialog);
}
Я ожидаю, что выполняется MainStepAsync, который выполняет следующее:
private async Task<DialogTurnResult> MainStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
CoreBot.StorageLogging.LogToTableAsync($"Main step entered. I am contacting LUIS to determine the intent");
string what_i_got = await LuisHelper.ExecuteMyLuisQuery(Configuration, Logger, stepContext.Context, cancellationToken);
CoreBot.StorageLogging.LogToTableAsync($"LUIS intent matched: {what_i_got}");
//await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = MessageFactory.Text($"Hi! My name is Sorella. Your intent was {what_i_got}") }, cancellationToken);
switch (what_i_got)
{
case "Hazard":
StorageLogging.LogToTableAsync($"We have been asked to report a hazard");
StorageLogging.LogToTableAsync(stepContext);
var hazardDetails = new ResponseSet.Hazard();
return await stepContext.BeginDialogAsync(nameof(HazardDialog), hazardDetails, cancellationToken);
case "Greeting":
StorageLogging.LogToTableAsync($"We have been asked to provide a greeting. After this greeting the waterfall will end");
StorageLogging.LogToTableAsync(stepContext);
await stepContext.Context.SendActivityAsync(MessageFactory.Text("Hi there! :). What can I help you with today? "), cancellationToken);
return await stepContext.EndDialogAsync(null, cancellationToken);
default:
StorageLogging.LogToTableAsync($"We got an intent we haven't catered for. After this the waterfall will end");
StorageLogging.LogToTableAsync(stepContext);
return await stepContext.NextAsync(null, cancellationToken);
}
}
Если целью является Harzard, тогда начните HazardDialog. В противном случае, если они приветствуют бота, просто поздоровайтесь и завершите диалог верхнего уровня с водопадом. Если пользователь перенаправлен на HazardDialog, запустите следующий водопад, настроив его следующим образом:
public class HazardDialog : CancelAndHelpDialog
{
public HazardDialog()
: base(nameof(HazardDialog))
{
AddDialog(new TextPrompt(nameof(TextPrompt)));
AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
{
GetInitialHazardInfoAsync,
GetHazardUrgencyAsync,
FinalStepAsync
}));
// The initial child Dialog to run.
InitialDialogId = nameof(WaterfallDialog);
}
Сначала их просят описать опасность:
private async Task<DialogTurnResult> GetInitialHazardInfoAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
CoreBot.StorageLogging.LogToTableAsync("Entered hazard step 1. Asking for hazard type");
var hazardDetails = (ResponseSet.Hazard)stepContext.Options;
hazardDetails.HazardType = (string)stepContext.Result;
if (hazardDetails.HazardType == null)
{
CoreBot.StorageLogging.LogToTableAsync($"No hazard type provided. Asking");
return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = MessageFactory.Text("What kind of hazard would you like to report? Provide me a brief description") }, cancellationToken);
}
else
{
CoreBot.StorageLogging.LogToTableAsync($"Hazard provided. Moving on");
return await stepContext.NextAsync(hazardDetails.HazardType, cancellationToken);
}
}
Тогда для срочности:
private async Task<DialogTurnResult> GetHazardUrgencyAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
CoreBot.StorageLogging.LogToTableAsync($"Entered hazard step 2. Asking for urgency");
var hazardDetails = (ResponseSet.Hazard)stepContext.Options;
hazardDetails.HazardType = (string)stepContext.Result;
var hazardAsJson = JsonConvert.SerializeObject(hazardDetails);
StorageLogging.LogToTableAsync(hazardAsJson);
if (hazardDetails.HarzardUrgency == null)
{
CoreBot.StorageLogging.LogToTableAsync($"No urgency provided. Asking");
return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = MessageFactory.Text($"Thanks. So your hazard is {hazardDetails.HazardType}? How urgent is it?") }, cancellationToken);
}
else
{
CoreBot.StorageLogging.LogToTableAsync($"Urgency given. We're all done");
var guid = Guid.NewGuid();
var ticketId = "HAZ" + Convert.ToString(guid).ToUpper().Substring(1,4);
await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Thanks! I've got all the informatio I need. I'll raise this with the API team on your behalf. Your Ticket ID is: {ticketId} "), cancellationToken);
return await stepContext.NextAsync(cancellationToken, cancellationToken);
}
}
Если у нас есть и срочность, и тип, мы «поднимаем заявку» и переходим к последнему шагу, который просто заканчивает стек.
private async Task<DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
CoreBot.StorageLogging.LogToTableAsync($"Entered hazard step 3. Final step");
var hazardDetails = (ResponseSet.Hazard)stepContext.Options;
hazardDetails.HarzardUrgency = (string)stepContext.Result;
var hazardAsJson = JsonConvert.SerializeObject(hazardDetails);
StorageLogging.LogToTableAsync(hazardAsJson);
return await stepContext.EndDialogAsync(hazardDetails, cancellationToken);
}
Я ожидаю, что окончание HarzardDialog должно затем вернуться к следующему шагу в диалоговом окне «Родительский водопад», то есть EndOfMainDialogAsync, который просто говорит, что мы все сделали, и могу ли я чем-нибудь помочь?
private async Task<DialogTurnResult> EndOfMainDialogAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
StorageLogging.LogToTableAsync($"Ending the main dialog");
StorageLogging.LogToTableAsync(stepContext);
await stepContext.Context.SendActivityAsync(MessageFactory.Text("Ok, I think we're all done with that. Can I do anything else to help?"), cancellationToken);
return await stepContext.EndDialogAsync(null, cancellationToken);
}
Тем не менее, в моем реальном разговоре поток заканчивается неправильным поведением, и фактически (если вы посмотрите на разговор ниже) запускает GetHazardUrgencyAsync из дочернего водопада, затем MainStepAsync из родительского водопада, а затем GetHazardUrgencyAsync из дочернего водопада. второй раз?
ОБНОВЛЕНИЕ: Согласно предложениям, я обновил свои WaterFallDialogs, чтобы иметь уникальные имена, и повторно протестировал. Я все еще веду себя неправильно. Смотрите скриншот ниже:
Я ожидаю, что после описания опасности меня спросят, насколько это срочно. Вместо этого я получаю следующие диалоговые ответы в виде «блока».
- На вопрос, насколько это срочно (правильно)
- Приветствую меня снова (Неверно - это от родительского водопада)
- На вопрос, насколько это срочно (неверно)
Я немного растерялся здесь. Я бы предположил / подумал из своего кода, что диалоговое окно дочернего водопада должно быть полностью выполнено / завершено перед возвратом к родительскому диалоговому окну.