Con los diálogos de componentes se pueden crear diálogos independientes para controlar escenarios concretos, y dividir un conjunto de diálogos grande en elementos más manejables. Cada uno de estos elementos tiene su propio conjunto de diálogos y evita los conflictos de nombres con los conjuntos de diálogos exteriores. Los cuadros de diálogo de componentes son reutilizables porque se pueden:
Agregar a otro ComponentDialog o DialogSet en el bot.
Exportar como parte de un paquete.
Utilizar en otros bots.
Nota:
Los SDK de JavaScript, C# y Python de Bot Framework seguirán siendo compatibles, pero el SDK de Java se va a retirar con la compatibilidad final a largo plazo que finaliza en noviembre de 2023.
Los bots existentes creados con el SDK de Java seguirán funcionando.
En el ejemplo de solicitud de varios turnos, usamos un diálogo en cascada, algunas solicitudes y un diálogo de componente para crear una interacción que formula al usuario una serie de preguntas. El código usa un diálogo para desplazarse por estos pasos:
Pasos
Tipo de solicitud
Pedir al usuario su modo de transporte
Solicitud de elección
Pedir al usuario su nombre
Solicitud de texto
Pedir al usuario si desea proporcionar su edad
Solicitud de confirmación
Si responde Sí, solicitar su edad
Solicitud numérica con validación para que solo acepte edades mayores que 0 y menores de 150.
Preguntar si la información recopilada es correcta
Reutilización de la solicitud de confirmación
Por último, si responde Sí, mostrar la información recopilada; de lo contrario, indicar al usuario que no se conservará su información.
Implementar la lógica del diálogo del componente
En el ejemplo de solicitud de varios turnos, usamos un diálogo en cascada, algunas solicitudes y un diálogo de componente para crear una interacción que formula al usuario una serie de preguntas.
Un diálogo de componente encapsula uno o varios diálogos. El diálogo de componente tiene un conjunto de diálogos interno y tanto los diálogos como las solicitudes que agregue a dicho conjunto tienen sus propios identificadores, que solo se pueden ver desde el diálogo de componente.
Para usar diálogos, instale el paquete de NuGet Microsoft.Bot.Builder.Dialogs.
Dialogs\UserProfileDialog.cs
Aquí la UserProfileDialog clase deriva de ka ComponentDialog clase.
public class UserProfileDialog : ComponentDialog
Dentro del constructor, el método AddDialog agrega diálogos y solicitudes al diálogo de componente. El primer elemento que agregue con este método se establece como el diálogo inicial. Puede cambiar el diálogo inicial definiendo explícitamente la propiedad InitialDialogId. Al iniciar un diálogo de componente, se iniciará su initial dialog.
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);
}
El código siguiente representa el primer paso del diálogo en cascada.
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 diálogos, el proyecto debe instalar el paquete de npm botbuilder-dialogs.
dialogs/userProfileDialog.js
Aquí la clase UserProfileDialog extiende ComponentDialog.
class UserProfileDialog extends ComponentDialog {
Dentro del constructor, el método AddDialog agrega diálogos y solicitudes al diálogo de componente. El primer elemento que agregue con este método se establece como el diálogo inicial. Puede cambiar el diálogo inicial definiendo explícitamente la propiedad InitialDialogId. Al iniciar un diálogo de componente, se iniciará su initial dialog.
El código siguiente representa el primer paso del diálogo en cascada.
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'])
});
}
Aquí la UserProfileDialog clase deriva de ka ComponentDialog clase.
public class UserProfileDialog extends ComponentDialog {
Dentro del constructor, el método addDialog agrega diálogos y solicitudes al diálogo de componente. El primer elemento que agregue con este método se establece como el diálogo inicial. Puede cambiar el diálogo inicial llamando al método setInitialDialogId y proporcionando el nombre del diálogo inicial. Al iniciar un diálogo de componente, se iniciará su initial dialog.
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");
}
El código siguiente representa el primer paso del diálogo en cascada.
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 los paquetes de PyPI botbuilder-dialogs y botbuilder-ai mediante la ejecución de pip install botbuilder-dialogs y pip install botbuilder-ai desde un terminal.
dialogs/user_profile_dialog.py
Aquí la clase UserProfileDialog extiende ComponentDialog.
class UserProfileDialog(ComponentDialog):
Dentro del constructor, el método add_dialog agrega diálogos y solicitudes al diálogo de componente. El primer elemento que agregue con este método se establece como el diálogo inicial. Puede cambiar el diálogo inicial definiendo explícitamente la propiedad initial_dialog_id. Al iniciar un diálogo de componente, se iniciará su initial dialog.
El código siguiente representa el primer paso del diálogo en cascada.
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")],
),
)
En tiempo de ejecución, el diálogo de componente mantiene su propia pila de diálogos. Cuando el diálogo de componente se inicia:
Se crea una instancia y se agrega a la pila de diálogos externa
Crea una pila de diálogos interna que agrega a su estado
Comienza su diálogo inicial y lo agrega a la pila de diálogos interna.
El contexto primario ve el componente como el diálogo activo. Sin embargo, para el contexto dentro del componente, parece que el diálogo inicial es el activo.
Llamar al diálogo desde el bot
En el conjunto de diálogos externo, al que ha agregado el diálogo de componente, el diálogo de componente tiene el identificador con el que lo creó. En el conjunto externo, el componente parece un diálogo individual, como si fuera una solicitud.
Para usar un diálogo de componente, agregue una instancia de él al conjunto de diálogos del bot.
En el ejemplo, esto se hace con el método RunAsync al que se llama desde el método OnMessageActivityAsync del 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
En el ejemplo, se ha agregado un método run al diálogo del perfil de usuario.
Se llama al método run desde el método onMessage del 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
En el ejemplo, esto se hace con el método run al que se llama desde el método onMessageActivity del 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
En el ejemplo, se ha agregado un método run_dialog al diálogo del perfil de usuario.
Inicie el emulador, conéctese al bot y envíe mensajes como se muestra a continuación.
Información adicional
Funcionamiento de la cancelación en los diálogos de componentes
Si se llama a cancelar todos los diálogos desde el contexto del diálogo del componente, dicho diálogo cancelará todos los diálogos de su pila interna y, después, finalizará, con lo que devolverá el control al siguiente diálogo de la pila externa.
Si se llama a cancelar todos los diálogos desde el contexto externo, se cancelan tanto el componente como el resto de los diálogos del contexto externo.
Pasos siguientes
Obtenga información sobre cómo crear conversaciones complejas que se ramifican y se repiten.