Com os diálogos de componente, é possível criar diálogos independentes para lidar com cenários específicos, como dividir um conjunto de diálogos grande em partes mais gerenciáveis. Cada uma dessas partes tem seu próprio conjunto de diálogos e evita qualquer conflito de nome com o conjunto de diálogos que as contém. As caixas de diálogo de componente são reutilizáveis, pois podem ser:
Adicionadas a outro ComponentDialog ou DialogSet em seu bot.
Exportadas como parte de um pacote.
Usadas em outros bots.
Observação
Os SDKs JavaScript, C# e Python do Bot Framework continuarão a ser compatíveis. No entanto, o SDK Java está sendo desativado, com o suporte final de longo prazo terminando em novembro de 2023.
Os bots existentes criados com o SDK para Java continuarão a funcionar.
No exemplo de prompt multiturno, usamos um diálogo em cascata, alguns prompts e um diálogo de componente para criar uma interação que faz uma série de perguntas ao usuário. O código usa um diálogo para percorrer estas etapas:
Etapas
Tipo de prompt
Perguntar ao usuário qual é seu modo de transporte
Prompt de escolha
Perguntar o nome do usuário
Prompt de texto
Perguntar se o usuário deseja fornecer a idade
Prompt de confirmação
Se a resposta for afirmativa, pergunte a idade
Prompt de número com validação para aceitar somente idades entre 0 e 150.
Pergunte se as informações coletadas estão "ok"
Reutilizar prompt de confirmação
Por fim, se a resposta for afirmativa, exiba as informações coletadas. Caso contrário, informe ao usuário que suas informações não serão mantidas.
Implemente seu componente de diálogo
No exemplo de prompt multiturno, usamos um diálogo em cascata, alguns prompts e um diálogo de componente para criar uma interação que faz uma série de perguntas ao usuário.
Um diálogo de componente encapsula um ou mais diálogos. O diálogo de componente tem um conjunto de diálogos interno e os diálogos e prompts que você adiciona a esse conjunto têm IDs próprias, visíveis somente no diálogo de componente.
Para usar as caixas de diálogo, instale o pacote do NuGet, Microsoft.Bot.Builder.Dialogs.
Dialogs\UserProfileDialog.cs
Aqui, a classe UserProfileDialog é derivada da classe ComponentDialog.
public class UserProfileDialog : ComponentDialog
No construtor, o método AddDialog adiciona diálogos e prompts ao diálogo de componente. O primeiro item que você adiciona com esse método é definido como o diálogo inicial. Você pode alterar o diálogo inicial definindo explicitamente a propriedade InitialDialogId. Ao iniciar um diálogo de componente, ele iniciará seu diálogo inicial.
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);
}
O código a seguir representa a primeira etapa de diálogo em cascata.
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);
}
Para usar as caixas de diálogo, seu projeto precisa instalar o pacote do npm, botbuilder-dialogs.
dialogs/userProfileDialog.js
Aqui, a classe UserProfileDialog estende ComponentDialog.
class UserProfileDialog extends ComponentDialog {
No construtor, o método AddDialog adiciona diálogos e prompts ao diálogo de componente. O primeiro item que você adiciona com esse método é definido como o diálogo inicial. Você pode alterar o diálogo inicial definindo explicitamente a propriedade InitialDialogId. Ao iniciar um diálogo de componente, ele iniciará seu diálogo inicial.
O código a seguir representa a primeira etapa de diálogo em cascata.
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'])
});
}
Aqui, a classe UserProfileDialog é derivada da classe ComponentDialog.
public class UserProfileDialog extends ComponentDialog {
No construtor, o método addDialog adiciona diálogos e prompts ao diálogo de componente. O primeiro item que você adiciona com esse método é definido como o diálogo inicial. Você pode alterar o diálogo inicial chamando o método setInitialDialogId e fornecendo o nome do diálogo inicial. Ao iniciar um diálogo de componente, ele iniciará seu diálogo inicial.
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");
}
O código a seguir representa a primeira etapa de diálogo em cascata.
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);
}
Para usar diálogos, instale os pacotes PyPI botbuilder-dialogs e botbuilder-ai executando pip install botbuilder-dialogs e pip install botbuilder-ai em um terminal.
dialogs/user_profile_dialog.py
Aqui, a classe UserProfileDialog estende ComponentDialog.
class UserProfileDialog(ComponentDialog):
No construtor, o método add_dialog adiciona diálogos e prompts ao diálogo de componente. O primeiro item que você adiciona com esse método é definido como o diálogo inicial. Você pode alterar o diálogo inicial definindo explicitamente a propriedade initial_dialog_id. Ao iniciar um diálogo de componente, ele iniciará seu diálogo inicial.
O código a seguir representa a primeira etapa de diálogo em cascata.
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")],
),
)
Em tempo de execução, o diálogo de componente mantém sua própria pilha de diálogo. Quando o diálogo de componente é iniciado:
Uma instância é criada e adicionada à pilha de diálogo externa.
Ele cria uma pilha de diálogo interna que adiciona ao próprio estado.
Ele começa seu diálogo inicial e adiciona-o à pilha de diálogo interna.
O contexto pai vê o componente como o diálogo ativo. No entanto, para o contexto dentro do componente, parece que o diálogo inicial é o diálogo ativo.
Chamar o diálogo de seu bot
No conjunto de diálogos externos, aquele ao qual você adicionou o diálogo do componente, o diálogo do componente possui a ID com o qual você o criou. No conjunto externo, o componente tem a aparência de um único diálogo, muito semelhante aos prompts.
Para usar um diálogo de componente, adicione uma instância dele ao conjunto de diálogos do bot.
No exemplo, isso é feito usando o método RunAsync chamado do método OnMessageActivityAsync do bot.
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
No exemplo, adicionamos um método run ao diálogo de perfil do usuário.
O método run é chamado pelo método onMessage do bot.
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
No exemplo, isso é feito usando o método run chamado do método onMessageActivity do bot.
@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
No exemplo, adicionamos um método run_dialog ao diálogo de perfil do usuário.
Inicie o Emulador, conecte-se ao seu bot e envie mensagens conforme mostrado abaixo.
Informações adicionais
Como funciona o cancelamento nos diálogos de componente
Se você chamar cancel all dialogs pelo contexto do diálogo de componente, esse diálogo cancelará todos os diálogo de sua pilha interna e, em seguida, encerrará, devolvendo o controle ao próximo diálogo na pilha externa.
Se você chamar cancelar todas as caixas de diálogo do contexto externo, o componente será cancelado, juntamente com o restante das caixas de diálogo no contexto externo.
Próximas etapas
Saiba como criar conversas complexas que se ramificam e entram em loop.