Я создал DispatchBot с использованием Luis и QnA, и я хочу дополнительно использовать несколько диалогов (по одному для каждого намерения.
Все работает, кроме случаев, когда диалоговое окно должно запрашивать вопрос. Если вы получаетевсе сущности в первом высказывании, на которые вы можете ответить, и все в порядке, однако, если вам нужно запросить дополнительную информацию, когда происходит сбой. Когда пользователь отвечает, он возвращается к OnMessageActivityAsync и затем забывает о диалоге.
Я понимаю, что мне нужно запустить RunAsync (..), чтобы снова открыть диалоговое окно, однако я не могу получить правильный контекст. Все, что я пробовал, либо открывает диалоговое окно с нулевыми Accessors / DialogState, либо не может открыть диалоговое окно.
Я очень новичок в Azure Bot Framework, и я потратил дни на поиски в Google, но каждый пример не делает всего, что мне нужно.
Мой бот выглядит следующим образом:
public class DispatchBot : ActivityHandler
{
private readonly ILogger<DispatchBot> _logger;
private readonly IBotServices _botServices;
private readonly DialogSet _dialogSet;
private readonly MilaAccessors _milaAccessors;
private readonly BotState _userState;
public DispatchBot(IBotServices botServices, ILogger<DispatchBot> logger, MilaAccessors accessors)
{
_logger = logger;
_botServices = botServices;
_dialogSet = new DialogSet(accessors.ConversationDialogState);
_milaAccessors = accessors;
_userState = accessors.UserState;
}
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
await base.OnMessageActivityAsync(turnContext, cancellationToken);
await _milaAccessors.ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
List<Dialog> dialogs = _dialogSet.GetDialogs().ToList();
if (dialogs.Any()) //This is always false
{
//If count is greater than zero, then you can continue dialog conversation.
await dialogs.First().RunAsync(turnContext, _milaAccessors.ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
}
else
{
// First, we use the dispatch model to determine which cognitive service (LUIS or QnA) to use.
var recognizerResult = await _botServices.Dispatch.RecognizeAsync(turnContext, cancellationToken);
// Top intent tell us which cognitive service to use.
var topIntent = recognizerResult.GetTopScoringIntent();
// Next, we call the dispatcher with the top intent.
if (topIntent.score > 0.5)
{
await DispatchToTopIntentAsync(turnContext, topIntent.intent, recognizerResult, cancellationToken);
}
else
{
await ProcessQnAAsync(turnContext, cancellationToken);
}
}
}
private async Task DispatchToTopIntentAsync(ITurnContext<IMessageActivity> turnContext, string intent, RecognizerResult recognizerResult, CancellationToken cancellationToken)
{
switch (intent)
{
case "Form15":
await Form15IntentAsync(turnContext, recognizerResult.Properties["luisResult"] as LuisResult, cancellationToken);
break;
case "Layouts":
await ProcessLayoutsAsync(turnContext, recognizerResult.Properties["luisResult"] as LuisResult, cancellationToken);
break;
case "Weather":
await ProcessWeatherAsync(turnContext, recognizerResult.Properties["luisResult"] as LuisResult, cancellationToken);
break;
default:
await ProcessQnAAsync(turnContext, cancellationToken);
break;
}
}
}
И диалоги имеют вид:
public class Form15Dialog : ComponentDialog
{
private const string UserInfo = "form15-userInfo";
private readonly MilaAccessors _milaAccessors;
private readonly string DlgAddressId = "AddressDlg";
private readonly string Form15Id = "Form15DialogName";
private readonly BotState _userState;
private readonly BotState _conversationState;
public Form15Dialog(MilaAccessors milaAccessors) : base(nameof(Form15Dialog))
{
_milaAccessors = milaAccessors;
_userState = milaAccessors.UserState;
_conversationState = milaAccessors.ConversationState;
AddDialog(new TextPrompt(DlgAddressId, AddressValidation));
AddDialog(new WaterfallDialog(nameof(Form15Id), new WaterfallStep[]
{
InitialiseStepAsync,
GetAddressStepAsync,
DisplayForm15StepAsync
}));
InitialDialogId = nameof(Form15Id);
}
private async Task<DialogTurnResult> InitialiseStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
stepContext.Values["MilaAccessors"] = _milaAccessors;
UserProfile userProfile = _milaAccessors.UserProfile.GetAsync(stepContext.Context, () => new UserProfile(), cancellationToken).Result;
Form15DialogValues userInfo = new Form15DialogValues {Name = userProfile.Name, MilaSessionId = userProfile.SessionId};
IList<EntityModel> options = (IList<EntityModel>)stepContext.Options;
foreach (EntityModel model in options)
{
switch (model.Type)
{
case "JobNumber":
userInfo.JobNumber = model.Entity;
break;
case "Sections":
userInfo.Sections = model.Entity;
break;
case "StreetAddress":
userInfo.StreetAddress = model.Entity;
break;
case "Suburb":
userInfo.Suburb = model.Entity;
break;
case "PostCode":
userInfo.PostCode = model.Entity;
break;
}
}
// Create an object in which to collect the user's information within the dialog.
stepContext.Values[UserInfo] = userInfo;
if (UpdateUserInfoFromWebService(userInfo))
{
stepContext.Values[UserInfo] = userInfo;
return await stepContext.NextAsync(new List<string>(), cancellationToken);
}
await _userState.SaveChangesAsync(stepContext.Context, false, cancellationToken);
await _conversationState.SaveChangesAsync(stepContext.Context, false, cancellationToken);
PromptOptions promptOptions = new PromptOptions { Prompt = MessageFactory.Text("Could you give me the full Job Address?") };
return await stepContext.PromptAsync(DlgAddressId, promptOptions, cancellationToken);
}
private async Task<DialogTurnResult> GetAddressStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
Form15DialogValues userInfo = (Form15DialogValues)stepContext.Values[UserInfo];
if (!(stepContext.Result is string[] results) || results.Length == 0)
{
return await stepContext.NextAsync(new List<string>(), cancellationToken);
}
userInfo.JobNumber = null;
userInfo.StreetAddress = results[0];
userInfo.Suburb = null;
if (UpdateUserInfoFromWebService(userInfo))
{
stepContext.Values[UserInfo] = userInfo;
return await stepContext.NextAsync(new List<string>(), cancellationToken);
}
await _userState.SaveChangesAsync(stepContext.Context, false, cancellationToken);
await _conversationState.SaveChangesAsync(stepContext.Context, false, cancellationToken);
var promptOptions = new PromptOptions { Prompt = MessageFactory.Text("I'm unable to find that address. Could you please enter the job number?") };
return await stepContext.PromptAsync(nameof(TextPrompt), promptOptions, cancellationToken);
}
Я следил за информацией в https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-dialog-manage-conversation-flow?view=azure-bot-service-4.0&tabs=csharp однако я не могу получить "Dialog.RunAsync ".
Любая помощь / ссылки / указатели, которые вы могли бы дать мне, была бы очень признательна.