Invocar y descartar diálogos en el SDK de Teams

En este artículo se explica cómo invocar y descartar diálogos (anteriormente conocidos como módulos de tareas) mediante el SDK de Teams (Biblioteca de inteligencia artificial de Teams). En el SDK de Teams, los diálogos se invocan desde acciones de tarjeta adaptable mediante TaskFetchAction y se controlan mediante el cuadro de diálogo abrir y enviar eventos en la App clase.

El registro de eventos varía según el idioma:

  • TypeScript: app.on('dialog.open', ...) y app.on('dialog.submit', ...)
  • C#: teamsApp.OnTaskFetch(...) y teamsApp.OnTaskSubmit(...)
  • Python: @app.on_dialog_open y @app.on_dialog_submit

El contenido del cuadro de diálogo puede ser una tarjeta adaptable o una página web basada en url.

Los diálogos también se pueden invocar a través de otros enfoques en función de la arquitectura de la aplicación:

Para obtener instrucciones sobre la migración de Bot Framework al SDK de Teams, consulte Migración desde BotBuilder.

En la tabla siguiente se resume cómo funcionan los diálogos en el SDK de Teams:

Paso Cuadro de diálogo con tarjeta adaptable Cuadro de diálogo con la dirección URL de la página web
Desencadenar el cuadro de diálogo 1. Enviar una tarjeta adaptable con un TaskFetchAction botón al usuario. Los datos de la value acción especifican el tipo de diálogo que se va a abrir.

2. Cuando el usuario selecciona el botón, Teams envía una invocación de captura de tarea a la aplicación.
1. Enviar una tarjeta adaptable con un TaskFetchAction botón al usuario.

2. Cuando el usuario selecciona el botón, Teams envía una invocación de captura de tarea a la aplicación.
Controlar el evento de apertura del cuadro de diálogo 3. En el controlador de apertura del cuadro de diálogo, devuelve una respuesta de continuación del módulo de tareas que contiene los metadatos del cuadro de diálogo (título, dimensiones y la tarjeta adaptable que se va a mostrar). En C#, use TaskInfo con un ContinueTask contenedor. En TypeScript, use CardTaskModuleTaskInfo. En Python, use CardTaskModuleTaskInfo dentro de .TaskModuleContinueResponse 3. En el controlador de apertura del cuadro de diálogo, devuelve una respuesta de continuación del módulo de tareas que contiene metadatos del cuadro de diálogo con una url propiedad que apunta a la página web. El dominio de dirección URL debe estar en la validDomains matriz del manifiesto de la aplicación. En C#, use TaskInfo. En TypeScript, use UrlTaskModuleTaskInfo. En Python, use UrlTaskModuleTaskInfo dentro de .TaskModuleContinueResponse
Controlar el envío del cuadro de diálogo 4. Cuando el usuario presiona un Action.Submit botón, Teams envía una invocación de envío de tarea a la aplicación con los datos del formulario.

5. Puede responder por:
• No hacer nada (tarea completada)
• Mostrar un mensaje (C#: MessageTask, TypeScript/Python: TaskModuleMessageResponse)
• Encadenamiento a otro cuadro de diálogo (C#: ContinueTask, TypeScript/Python: TaskModuleContinueResponse)
4. La página web llama a la biblioteca cliente js de Teams para devolver los datos. Teams envía una invocación de envío de tarea a la aplicación con el resultado.

En la sección siguiente se describen los metadatos del cuadro de diálogo que definen el contenido y la apariencia de un diálogo.

Metadatos del cuadro de diálogo

Los metadatos del cuadro de diálogo definen el contenido y la apariencia de un diálogo. Cada lenguaje usa sus propios tipos para representar estos metadatos:

  • C#: TaskInfo (de Microsoft.Teams.Api.TaskModules)
  • TypeScript: CardTaskModuleTaskInfo o UrlTaskModuleTaskInfo (desde @microsoft/teams.api)
  • Python: CardTaskModuleTaskInfo o UrlTaskModuleTaskInfo (desde microsoft_teams.api)

En la tabla siguiente se enumeran las propiedades comunes en todos los idiomas:

Atributo Tipo Descripción
title string Este atributo aparece debajo del nombre de la aplicación y a la derecha del icono de la aplicación.
height número o cadena Este atributo puede ser un número que representa el alto del cuadro de diálogo en píxeles, o small, mediumo large. En C#, use Union<int, Size>.
width número o cadena Este atributo puede ser un número que representa el ancho del cuadro de diálogo en píxeles, o small, mediumo large. En C#, use Union<int, Size>.
url string Dirección URL de la página cargada como dentro <iframe> del cuadro de diálogo. El dominio de la dirección URL debe estar en la matriz validDomains de la aplicación en el manifiesto de la aplicación. Use UrlTaskModuleTaskInfo en TypeScript/Python o establezca la Url propiedad en TaskInfo en C#.
card Datos adjuntos Tarjeta adaptable que se va a mostrar en el cuadro de diálogo. En C#, establezca la Card propiedad en TaskInfo con .Attachment En TypeScript, use cardAttachment() con CardTaskModuleTaskInfo. En Python, use card_attachment(AdaptiveCardAttachment(...)) con CardTaskModuleTaskInfo.

Nota:

La característica de diálogo requiere que los dominios de las direcciones URL que quiera cargar se incluyan en la matriz en el validDomains manifiesto de la aplicación.

En la sección siguiente se especifica el tamaño del cuadro de diálogo que permite al usuario establecer el alto y el ancho del cuadro de diálogo.

Tamaño del cuadro de diálogo

Los valores de width y height establecen el alto y el ancho del cuadro de diálogo en píxeles. En función del tamaño de la ventana de Teams y de la resolución de pantalla, estos valores pueden reducirse proporcionalmente mientras se mantiene la relación de aspecto.

Si width y height son small, medium o large, el tamaño del rectángulo rojo de la imagen siguiente es una proporción del espacio disponible, 20 %, 50 % y 60 % para width y 20 %, 50 % y 66 % para height:

ejemplo de tamaño del cuadro de diálogo

En la sección siguiente se proporcionan ejemplos de desencadenamiento y control de diálogos mediante el SDK de Teams.

Desencadenar un cuadro de diálogo con TaskFetchAction

Para abrir un cuadro de diálogo, envíe una tarjeta adaptable con un TaskFetchAction botón. Cuando el usuario selecciona el botón, Teams envía una invocación de captura de tarea a la aplicación. Los datos de value cada botón especifican el tipo de diálogo que se va a abrir (por ejemplo, { "data": "AdaptiveCard" }).

using Microsoft.Teams.Api.Activities;
using Microsoft.Teams.Cards;

teamsApp.OnMessage(async (context) =>
{
    var card = new AdaptiveCard
    {
        Body = new List<CardElement>
        {
            new TextBlock("Task Module Invocation from Adaptive Card")
            {
                Weight = TextWeight.Bolder,
                Size = TextSize.Large
            }
        },
        Actions = new List<Action>
        {
            new TaskFetchAction(new Dictionary<string, object?> { { "data", "AdaptiveCard" } })
            { Title = "Adaptive Card" },
            new TaskFetchAction(new Dictionary<string, object?> { { "data", "CustomForm" } })
            { Title = "Custom Form" },
            new TaskFetchAction(new Dictionary<string, object?> { { "data", "MultiStep" } })
            { Title = "Multi-step Form" }
        }
    };

    await context.Send(new MessageActivity
    {
        Attachments = new List<Attachment>
        {
            new Attachment
            {
                ContentType = new ContentType("application/vnd.microsoft.card.adaptive"),
                Content = card
            }
        }
    });
});

Controlar el evento de apertura del cuadro de diálogo

Cuando Teams envía una invocación de captura de tareas, la aplicación devuelve el contenido del cuadro de diálogo. El contenido puede ser una tarjeta adaptable o una dirección URL de página web. En C#, ajuste los metadatos del cuadro de diálogo en una ContinueTask respuesta. En TypeScript, devuelve con TaskModuleResponsetype: 'continue'. En Python, devuelve un InvokeResponse objeto que contiene .TaskModuleContinueResponse

using System.Text.Json;
using Microsoft.Teams.Api.TaskModules;
using Microsoft.Teams.Cards;
using Microsoft.Teams.Common;

teamsApp.OnTaskFetch(async (context) =>
{
    var activity = context.Activity;
    var json = JsonSerializer.Deserialize<JsonElement>(JsonSerializer.Serialize(activity));
    var data = json.GetProperty("value").GetProperty("data").GetProperty("data").GetString();

    TaskInfo taskInfo;

    if (data == "CustomForm")
    {
        taskInfo = new TaskInfo
        {
            Title = "Custom Form",
            Width = new Union<int, Size>(510),
            Height = new Union<int, Size>(450),
            Url = $"{botEndpoint}/customform",
            FallbackUrl = $"{botEndpoint}/customform"
        };
    }
    else if (data == "MultiStep")
    {
        var step1Card = new AdaptiveCard
        {
            Body = new List<CardElement>
            {
                new TextBlock("Step 1 of 2 - Your Name") { Size = TextSize.Large, Weight = TextWeight.Bolder },
                new TextInput { Id = "name", Label = "Name", Placeholder = "Enter your name", IsRequired = true }
            },
            Actions = new List<Action>
            {
                new SubmitAction().WithTitle("Next").WithData(
                    new Union<string, SubmitActionData>(new SubmitActionData
                    {
                        NonSchemaProperties = new Dictionary<string, object?> { { "submissiontype", "multi_step_1" } }
                    }))
            }
        };

        taskInfo = new TaskInfo
        {
            Title = "Multi-step Form",
            Width = new Union<int, Size>(400),
            Height = new Union<int, Size>(300),
            Card = new Attachment
            {
                ContentType = new ContentType("application/vnd.microsoft.card.adaptive"),
                Content = step1Card
            }
        };
    }
    else
    {
        var dialogCard = new AdaptiveCard
        {
            Body = new List<CardElement>
            {
                new TextBlock("Enter Text Here") { Weight = TextWeight.Bolder },
                new TextInput { Id = "usertext", Placeholder = "add some text and submit", IsMultiline = true }
            },
            Actions = new List<Action> { new SubmitAction { Title = "Submit" } }
        };

        taskInfo = new TaskInfo
        {
            Title = "Adaptive Card: Inputs",
            Width = new Union<int, Size>(400),
            Height = new Union<int, Size>(200),
            Card = new Attachment
            {
                ContentType = new ContentType("application/vnd.microsoft.card.adaptive"),
                Content = dialogCard
            }
        };
    }

    return new Response(new ContinueTask(taskInfo));
});

Controlar el envío del cuadro de diálogo

Cuando un usuario presiona Action.Submit en un cuadro de diálogo, Teams envía una invocación de envío de tarea a la aplicación. Puede responder completando la tarea, mostrando un mensaje o abriendo otro cuadro de diálogo (por ejemplo, para encadenar formularios de varios pasos).

using System.Text.Json;
using Microsoft.Teams.Api.TaskModules;
using Microsoft.Teams.Cards;
using Microsoft.Teams.Common;

teamsApp.OnTaskSubmit(async (context) =>
{
    var activity = context.Activity;
    var json = JsonSerializer.Deserialize<JsonElement>(JsonSerializer.Serialize(activity));
    var submitData = JsonSerializer.Deserialize<Dictionary<string, object>>(
        json.GetProperty("value").GetProperty("data").GetRawText());
    var submissionType = submitData?.GetValueOrDefault("submissiontype")?.ToString();

    if (submissionType == "multi_step_1")
    {
        var name = submitData["name"]?.ToString();
        var step2Card = new AdaptiveCard
        {
            Body = new List<CardElement>
            {
                new TextBlock("Step 2 of 2 - Your Email") { Size = TextSize.Large, Weight = TextWeight.Bolder },
                new TextInput { Id = "email", Label = "Email", Placeholder = "Enter your email", IsRequired = true }
            },
            Actions = new List<Action>
            {
                new SubmitAction().WithTitle("Submit").WithData(
                    new Union<string, SubmitActionData>(new SubmitActionData
                    {
                        NonSchemaProperties = new Dictionary<string, object?>
                        {
                            { "submissiontype", "multi_step_2" },
                            { "name", name! }
                        }
                    }))
            }
        };

        var taskInfo = new TaskInfo
        {
            Title = "Multi-step Form: Step 2",
            Width = new Union<int, Size>(400),
            Height = new Union<int, Size>(300),
            Card = new Attachment
            {
                ContentType = new ContentType("application/vnd.microsoft.card.adaptive"),
                Content = step2Card
            }
        };

        return new Response(new ContinueTask(taskInfo));
    }

    if (submissionType == "multi_step_2")
    {
        await context.Send($"Hi {submitData["name"]}, thanks for submitting! Your email is {submitData["email"]}");
        return new Response(new MessageTask("Multi-step form completed!"));
    }

    var usertext = submitData?.GetValueOrDefault("usertext")?.ToString();
    await context.Send($"You submitted: {usertext}");
    return new Response(new MessageTask("Thanks for submitting!"));
});

Instrucciones de teclado y accesibilidad

En el caso de los diálogos basados en url que cargan contenido HTML, asegúrese de la accesibilidad del teclado:

  • Use el atributo tabindex en las etiquetas HTML para controlar qué elementos se pueden centrar y definir la navegación secuencial del teclado con las teclas Tab y Mayús-Tab .
  • Controle la tecla Esc correctamente en javaScript de la página de diálogo.

Microsoft Teams garantiza que la navegación por teclado funciona correctamente desde el encabezado del cuadro de diálogo hasta el HTML y viceversa.

Ejemplo de código

Ejemplo de nombre Descripción .NET Node.js Python
Módulos de tareas de bot En esta aplicación de ejemplo se muestra cómo usar diálogos (denominados módulos de tareas en TeamsJS v1.x) mediante el SDK de IA de Teams. View View View

Paso siguiente

Vea también