Компонентные диалоги позволяют создавать независимые диалоги для обработки определенных сценариев, разбивая большие наборы диалогов на более управляемые фрагменты. Каждый из этих компонентов имеет отдельный набор диалогов, что позволяет избежать конфликтов имен с внешними наборами диалогов. Компонентные диалоги можно использовать многократно для:
добавления в другой ComponentDialog или DialogSet в боте;
экспорта как части пакета;
использования в других ботах.
Примечание.
Пакеты SDK для JavaScript, C# и Python для Bot Framework по-прежнему будут поддерживаться, однако пакет SDK java отменяется с окончательной долгосрочной поддержкой, заканчивающейся в ноябре 2023 года.
Существующие боты, созданные с помощью пакета SDK для Java, будут продолжать функционировать.
Копия примера запроса с несколькими поворотами в C#, JavaScript, JavaScript или Python.
Сведения о примере
В примере запроса с несколькими поворотами мы используем каскадное диалоговое окно, несколько запросов и диалоговое окно компонента для создания взаимодействия, которое задает пользователю ряд вопросов. Код диалога циклически перебирает следующие действия:
Шаги
Тип запроса
Запрос к пользователю о режиме транспортировки
Запрос выбора
Запрос имени пользователя
Запрос текста
Запрос к пользователю, готов ли он указать свой возраст
Запрос подтверждения
Если они ответили да, попросите их возраст
Запрос числа с проверкой, при которой принимается возраст только в диапазоне от 0 до 150.
Спросите, является ли собранная информация "ок"
Повторный запрос подтверждения
Наконец, если они ответили да, отобразите собранные сведения; в противном случае сообщите пользователю, что их сведения не будут храниться.
Реализация диалогового окна компонента
В примере запроса с несколькими поворотами мы используем каскадное диалоговое окно, несколько запросов и диалоговое окно компонента для создания взаимодействия, которое задает пользователю ряд вопросов.
Компонентный диалог включает один или несколько диалогов. Компонентный диалог содержит внутренний набор диалогов, в котором все добавляемые к диалоги и запросы имеют собственные идентификаторы, доступные только для компонентного диалога.
Чтобы использовать диалоги, установите пакет NuGet Microsoft.Bot.Builder.Dialogs.
Dialogs\UserProfileDialog.cs
Класс UserProfileDialog является производным от класса ComponentDialog.
public class UserProfileDialog : ComponentDialog
В конструкторе метод AddDialog добавляет диалоги и запросы в компонентный диалог. Первый элемент, добавляемый с помощью этого метода, задается как начальное диалоговое окно. Вы можете изменить начальное диалоговое окно, явно задав InitialDialogId свойство. При запуске компонентного диалога будет запущен начальный диалог.
public UserProfileDialog(UserState userState)
: base(nameof(UserProfileDialog))
{
_userProfileAccessor = userState.CreateProperty<UserProfile>("UserProfile");
// This array defines how the Waterfall will execute.
var waterfallSteps = new WaterfallStep[]
{
TransportStepAsync,
NameStepAsync,
NameConfirmStepAsync,
AgeStepAsync,
PictureStepAsync,
SummaryStepAsync,
ConfirmStepAsync,
};
// Add named dialogs to the DialogSet. These names are saved in the dialog state.
AddDialog(new WaterfallDialog(nameof(WaterfallDialog), waterfallSteps));
AddDialog(new TextPrompt(nameof(TextPrompt)));
AddDialog(new NumberPrompt<int>(nameof(NumberPrompt<int>), AgePromptValidatorAsync));
AddDialog(new ChoicePrompt(nameof(ChoicePrompt)));
AddDialog(new ConfirmPrompt(nameof(ConfirmPrompt)));
AddDialog(new AttachmentPrompt(nameof(AttachmentPrompt), PicturePromptValidatorAsync));
// The initial child Dialog to run.
InitialDialogId = nameof(WaterfallDialog);
}
Следующий код представляет первый шаг каскадного диалога.
private static async Task<DialogTurnResult> NameStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
stepContext.Values["transport"] = ((FoundChoice)stepContext.Result).Value;
return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = MessageFactory.Text("Please enter your name.") }, cancellationToken);
}
Чтобы использовать диалоги, в проект следует установить пакет npm botbuilder-dialogs.
dialogs/userProfileDialog.js
Класс UserProfileDialog является расширением ComponentDialog.
class UserProfileDialog extends ComponentDialog {
В конструкторе метод AddDialog добавляет диалоги и запросы в компонентный диалог. Первый элемент, добавляемый с помощью этого метода, задается как начальное диалоговое окно. Вы можете изменить начальное диалоговое окно, явно задав InitialDialogId свойство. При запуске компонентного диалога будет запущен начальный диалог.
Следующий код представляет первый шаг каскадного диалога.
async transportStep(step) {
// WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
// Running a prompt here means the next WaterfallStep will be run when the user's response is received.
return await step.prompt(CHOICE_PROMPT, {
prompt: 'Please enter your mode of transport.',
choices: ChoiceFactory.toChoices(['Car', 'Bus', 'Bicycle'])
});
}
Класс UserProfileDialog является производным от класса ComponentDialog.
public class UserProfileDialog extends ComponentDialog {
В конструкторе метод addDialog добавляет диалоги и запросы в компонентный диалог. Первый элемент, добавляемый с помощью этого метода, задается как начальное диалоговое окно. Можно изменить начальное диалоговое окно, вызвав setInitialDialogId метод и указав имя начального диалогового окна. При запуске компонентного диалога будет запущен начальный диалог.
public UserProfileDialog(UserState withUserState) {
super("UserProfileDialog");
userProfileAccessor = withUserState.createProperty("UserProfile");
WaterfallStep[] waterfallSteps = {
UserProfileDialog::transportStep,
UserProfileDialog::nameStep,
this::nameConfirmStep,
this::ageStep,
UserProfileDialog::pictureStep,
this::confirmStep,
this::summaryStep
};
// Add named dialogs to the DialogSet. These names are saved in the dialog state.
addDialog(new WaterfallDialog("WaterfallDialog", Arrays.asList(waterfallSteps)));
addDialog(new TextPrompt("TextPrompt"));
addDialog(new NumberPrompt<Integer>("NumberPrompt", UserProfileDialog::agePromptValidator, Integer.class));
addDialog(new ChoicePrompt("ChoicePrompt"));
addDialog(new ConfirmPrompt("ConfirmPrompt"));
addDialog(new AttachmentPrompt("AttachmentPrompt", UserProfileDialog::picturePromptValidator));
// The initial child Dialog to run.
setInitialDialogId("WaterfallDialog");
}
Следующий код представляет первый шаг каскадного диалога.
private static CompletableFuture<DialogTurnResult> nameStep(WaterfallStepContext stepContext) {
stepContext.getValues().put("transport", ((FoundChoice) stepContext.getResult()).getValue());
PromptOptions promptOptions = new PromptOptions();
promptOptions.setPrompt(MessageFactory.text("Please enter your name."));
return stepContext.prompt("TextPrompt", promptOptions);
}
Чтобы использовать диалоги, установите пакеты PyPI botbuilder-dialogs и botbuilder-ai, выполнив pip install botbuilder-dialogs и pip install botbuilder-ai в терминале.
dialogs/user_profile_dialog.py
Класс UserProfileDialog является расширением ComponentDialog.
class UserProfileDialog(ComponentDialog):
В конструкторе метод add_dialog добавляет диалоги и запросы в компонентный диалог. Первый элемент, добавляемый с помощью этого метода, задается как начальное диалоговое окно. Вы можете изменить начальное диалоговое окно, явно задав initial_dialog_id свойство. При запуске компонентного диалога будет запущен начальный диалог.
Следующий код представляет первый шаг каскадного диалога.
async def transport_step(
self, step_context: WaterfallStepContext
) -> DialogTurnResult:
# WaterfallStep always finishes with the end of the Waterfall or with another dialog;
# here it is a Prompt Dialog. Running a prompt here means the next WaterfallStep will
# be run when the users response is received.
return await step_context.prompt(
ChoicePrompt.__name__,
PromptOptions(
prompt=MessageFactory.text("Please enter your mode of transport."),
choices=[Choice("Car"), Choice("Bus"), Choice("Bicycle")],
),
)
Во время выполнения компонентный диалог поддерживает собственный стек диалогов. При запуске компонентного диалога происходит следующее:
Создается экземпляр, который добавляется во внешний стек диалогов.
Создается внутренний стек диалогов, который добавляется в свое состояние.
Запускается начальный диалог, который добавляется во внутренний стек диалогов.
Родительский контекст отображает компонент как активное диалоговое окно. Однако для контекста внутри компонента он выглядит так, как начальное диалоговое окно является активным диалогом.
Вызов диалогового окна из бота
В внешнем наборе диалоговых окон, в который вы добавили диалоговое окно компонента, в диалоговом окне компонента есть идентификатор, с помощью которого вы создали его. Во внешнем наборе компонентный диалог выглядят как один диалог, похожий на обычные запросы.
Чтобы использовать диалоговое окно компонента, добавьте экземпляр в набор диалоговых окон бота.
В нашем примере это выполняется с помощью метода RunAsync, вызываемого из метода OnMessageActivityAsync бота.
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
Logger.LogInformation("Running dialog with Message Activity.");
// Run the Dialog with the new message Activity.
await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
}
dialogs/userProfileDialog.js
В этом примере мы добавили метод run в диалог профиля пользователя.
this.onMessage(async (context, next) => {
console.log('Running dialog with Message Activity.');
// Run the Dialog with the new message Activity.
await this.dialog.run(context, this.dialogState);
await next();
});
DialogBot.java
В нашем примере это выполняется с помощью метода run, вызываемого из метода onMessageActivity бота.
@Override
protected CompletableFuture<Void> onMessageActivity(
TurnContext turnContext
) {
LoggerFactory.getLogger(DialogBot.class).info("Running dialog with Message Activity.");
// Run the Dialog with the new message Activity.
return Dialog.run(dialog, turnContext, conversationState.createProperty("DialogState"));
}
helpers/dialog_helper.py
В этом примере мы добавили метод run_dialog в диалог профиля пользователя.
Если это еще не сделано, установите эмулятор Bot Framework.
Выполните этот пример на локальном компьютере.
Запустите эмулятор, подключитесь к боту и отправьте несколько сообщений, как показано ниже.
Дополнительная информация:
Как работает отмена для компонентных диалогов
Если вы вызовете метод отмены всех диалогов из контекста компонентного диалога, этот метод отменит все диалоги во внутреннем стеке и завершит работу, передав управление следующему диалогу во внешнем стеке.
При вызове всех диалоговых окон из внешнего контекста компонент отменяется вместе с остальными диалогами внешнего контекста.
Следующие шаги
Узнайте, как управлять сложными диалогами с ветвлениями и циклами.