Compartir a través de


Extensión de mensaje basada en API

Nota:

Las extensiones de mensaje basadas en API solo admiten comandos de búsqueda.

Las extensiones de mensaje creadas mediante API (basada en API) usan un servicio web para administrar las solicitudes y respuestas de los usuarios y no requieren un registro de bot. Las extensiones de mensajes basadas en API son una funcionalidad de aplicación de Microsoft Teams que integra las API externas directamente en Teams, lo que mejora la facilidad de uso de la aplicación y ofrece una experiencia de usuario sin problemas. Las extensiones de mensajes basadas en API admiten comandos de búsqueda y se pueden usar para capturar y mostrar datos de servicios externos dentro de Teams, lo que simplifica los flujos de trabajo al reducir la necesidad de cambiar entre aplicaciones. Las extensiones de mensajes basadas en API ayudan a las aplicaciones a interactuar directamente con datos, aplicaciones y servicios de terceros, lo que mejora sus funcionalidades. Con la extensión de mensaje basada en API, puede hacer lo siguiente:

  • Recupere información en tiempo real, como la cobertura de noticias más reciente en el lanzamiento de un producto.
  • Recuperar información basada en conocimientos, por ejemplo, los archivos de diseño de mi equipo en Figma

Vea el vídeo para obtener más información sobre la creación de una extensión de mensaje basada en API mediante el kit de herramientas de Teams:


Extensiones de mensajes tradicionales basadas en bots Extensiones de mensajes basadas en API
Los desarrolladores deben compilar, implementar y mantener un servicio para controlar comandos de invocación desde el cliente de Teams. Si las API del servicio final se pueden describir mediante la especificación de OpenAPI, los desarrolladores pueden eliminar la necesidad del servicio de control de nivel intermedio.
Este servicio procesa la consulta entrante y realiza una llamada al servicio final del desarrollador. Teams puede usar directamente la especificación de OpenAPI para compilar solicitudes y comunicarse con el servicio final del desarrollador.

En las imágenes siguientes se muestra el flujo de consultas de usuario a través de extensiones de mensajes tradicionales y extensiones de mensaje de API:

Captura de pantalla que muestra el flujo de consulta de usuario entre un usuario, el cliente de Teams y el servicio de bots de Teams mediante extensiones de mensajes tradicionales. En el diagrama también se muestra cómo se relacionan entre sí la especificación de API, las plantillas de representación y la API. Flujo de consulta de usuario mediante extensiones de mensaje tradicionales. El desarrollador debe mantener un servicio de controlador de bot personalizado, que controla las solicitudes de un bot de Teams. El servicio de controlador envía una solicitud al servicio del desarrollador cuando se invoca una consulta.


Captura de pantalla que muestra el flujo de consulta entre un usuario, el cliente de Teams y el servicio de bots de Teams mediante extensiones de mensaje de API. En el diagrama también se muestra cómo se relacionan entre sí la especificación de API, las plantillas de representación y la API. Flujo de consulta de usuario mediante extensiones de mensaje de API. No es necesario un servicio de controlador mantenido por el desarrollador siempre y cuando la interacción se describa claramente en la especificación de OpenAPI del paquete de aplicaciones.



Esta es una secuencia de alto nivel de eventos que se producen durante una invocación de comando de consulta:

  1. Cuando un usuario invoca un comando de consulta, el Bot Service de Teams recibe los parámetros del comando de consulta.

  2. El comando de consulta se define dentro del archivo de manifiesto de la aplicación. La definición de comando contiene una referencia a dentro del operationId archivo de especificación de OpenAPI junto con los detalles de los parámetros que el cliente de Teams representa para ese comando. Como referencia, dentro operationId del archivo de especificación de OpenAPI es único para una operación HTTP determinada.

  3. A continuación, teams Bot Service usa los parámetros proporcionados por el usuario junto con la copia de la especificación de OpenAPI para el asociado operationId para crear una solicitud HTTP para el punto de conexión del desarrollador.

  4. Si se requiere autenticación y se configura en el manifiesto. Se resuelve en el token o la clave adecuados. Este token o clave se usa como parte de la solicitud saliente. [Opcionalmente]

  5. El servicio bot de Teams realiza la solicitud HTTP al servicio del desarrollador.

  6. El servicio del desarrollador debe responder de acuerdo con el esquema descrito en la especificación de OpenAPI. Está en formato JSON.

  7. El cliente de Teams debe mostrar los resultados al usuario. Para convertir los resultados JSON del paso anterior a la interfaz de usuario, el servicio bot de Teams usa la plantilla de representación de respuesta para crear una tarjeta adaptable para cada resultado.

  8. Las tarjetas adaptables se envían al cliente, lo que las representa en la interfaz de usuario.

Diagrama que muestra el flujo de secuencia de alto nivel cuando se invoca una consulta en una extensión de mensaje basada en API.

Requisitos previos

El paquete de definición de aplicación incluye varios artefactos atractivos que admiten la funcionalidad de esta característica. Antes de empezar, asegúrese de que tiene un conocimiento básico de los siguientes archivos:

Descripción de OpenAPI (OAD)

La descripción de OpenAPI documenat es un estándar del sector adoptado para describir las API. Permite abstraer las API de su implementación, proporcionando definiciones independientes del lenguaje que son legibles por el usuario y legibles por máquina. En la descripción de OpenAPI documenat se describen las interacciones que admite la extensión, lo que permite a Teams crear solicitudes y comunicarse directamente con el servicio sin necesidad de un servicio de control de nivel intermedio.

Un documento de descripción de OpenAPI contiene detalles para comunicarse con el servicio del desarrollador. Asegúrese de cumplir las siguientes directrices para el documento de descripción de OpenAPI (OAD):

  • Se admiten las versiones 2.0 y 3.0.x de OpenAPI.
  • JSON y YAML son los formatos admitidos.
  • El cuerpo de la solicitud, si está presente, debe ser application/Json.
  • Defina una dirección URL del servidor de protocolo HTTPS para la servers.url propiedad .
  • Solo se admiten los métodos HTTP POST y GET.
  • El documento Descripción de OpenAPI debe tener un .operationId
  • Solo se permite un parámetro necesario sin un valor predeterminado.
  • Un parámetro obligatorio con un valor predeterminado se considera opcional.
  • Los usuarios no deben especificar un parámetro para un encabezado o cookie.
  • La operación no debe tener un encabezado o parámetros de cookie necesarios sin valores predeterminados.
  • Asegúrese de que no haya referencias remotas en el documento Descripción de OpenAPI.
  • No se admite la construcción de matrices para la solicitud; sin embargo, se admiten objetos anidados dentro de un cuerpo de solicitud JSON.
  • Teams no admite las oneOfconstrucciones , anyOf, allOfy not (swagger.io).

El código siguiente es un ejemplo de un documento de descripción de OpenAPI:

Documento de descripción de OpenAPI de ejemplo
openapi: 3.0.1
info:
title: OpenTools Plugin
description: A plugin that allows the user to find the most appropriate AI tools for their use cases, with their pricing information.
version: 'v1'
servers:
- url: https://gptplugin.opentools.ai
paths:
/tools:
 get:
   operationId: searchTools
   summary: Search for AI Tools
   parameters:
     - in: query
       name: search
       required: true
       schema:
         type: string
       description: Used to search for AI tools by their category based on the keywords. For example, ?search="tool to create music" will give tools that can create music.
   responses:
     "200":
       description: OK
       content:
         application/json:
           schema:
             $ref: '#/components/schemas/searchToolsResponse'
     "400":
       description: Search Error
       content:
         application/json:
           schema:
             $ref: '#/components/schemas/searchToolsError'
components:
schemas:
 searchToolsResponse:
   required:
     - search
   type: object
   properties:
     tools:
       type: array
       items:
         type: object
         properties:
           name:
             type: string
             description: The name of the tool.
           opentools_url:
             type: string
             description: The URL to access the tool.
           main_summary:
             type: string
             description: A summary of what the tool is.
           pricing_summary:
             type: string
             description: A summary of the pricing of the tool.
           categories:
             type: array
             items:
               type: string
             description: The categories assigned to the tool.
           platforms:
             type: array
             items:
               type: string
             description: The platforms that this tool is available on.
       description: The list of AI tools.
 searchToolsError:
   type: object
   properties:
     message:
       type: string
       description: Message of the error.

Para obtener más información sobre cómo escribir definiciones de OpenAPI en YAML, consulte Estructura de OpenAPI.

Manifiesto de la aplicación

El manifiesto de aplicación es un plano técnico para la aplicación de Teams, que define cómo y dónde se invoca la extensión de mensaje dentro del cliente de Teams. Incluye los comandos que admite la extensión y las ubicaciones desde las que se puede acceder a ellos, como el área del mensaje de redacción, la barra de comandos y el mensaje. El manifiesto se vincula a la especificación de OpenAPI y a la plantilla de representación de respuesta para garantizar la funcionalidad adecuada.

El manifiesto de la aplicación contiene la definición del comando de consulta. Asegúrese de cumplir las siguientes directrices para el manifiesto de la aplicación:

  • Establezca la versión del manifiesto de la aplicación en 1.17.
  • Establezca en composeExtensions.composeExtensionTypeapiBased.
  • Defina composeExtensions.apiSpecificationFile como la ruta de acceso relativa al documento Descripción de OpenAPI dentro de la carpeta. Esto vincula el manifiesto de aplicación a la especificación de API.
  • Defina apiResponseRenderingTemplateFile como la ruta de acceso relativa a la plantilla de representación de respuesta. Esto especifica la ubicación de la plantilla que se usa para representar las respuestas de la API.
  • Cada comando debe tener un vínculo a la plantilla de representación de respuesta. Esto conecta cada comando a su formato de respuesta correspondiente.
  • La Commands.id propiedad del manifiesto de la aplicación debe coincidir con en operationId el documento Descripción de OpenAPI.
  • Si un parámetro necesario no tiene un valor predeterminado, el comando parameters.name del manifiesto de la aplicación debe coincidir con el parameters.name del documento de descripción de OpenAPI.
  • Si no hay ningún parámetro necesario, el comando parameters.name del manifiesto de la aplicación debe coincidir con el opcional parameters.name del documento Descripción de OpenAPI.
  • Asegúrese de que el nombre de los parámetros de cada comando del manifiesto de la aplicación coincida exactamente con el nombre correspondiente del parámetro definido para la operación en el documento Descripción de OpenAPI.
  • Se debe definir una plantilla de representación de respuesta por comando, que se usa para convertir respuestas desde una API.
  • Las descripciones de comandos y parámetros no deben superar los 128 caracteres.

A continuación se muestra un ejemplo de manifiesto de aplicación con definiciones para extensiones de mensajes basadas en API:

Ejemplo de manifiesto de aplicación
 {
 "$schema": "https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.schema.json",
 +  "manifestVersion": "devPreview",
 "version": "1.0.0",
 "id": "04805b4b-xxxx-xxxx-xxxx-4dbc1cac8f89",
 "packageName": "com.microsoft.teams.extension",
 "developer": {
    "name": "Teams App, Inc.",
    "websiteUrl": "https://www.example.com",
    "privacyUrl": "https://www.example.com/termofuse",
    "termsOfUseUrl": "https://www.example.com/privacy"
 },
 "icons": {
    "color": "color.png",
    "outline": "outline.png"
 },
 "name": {
    "short": "AI tools",
    "full": "AI tools"
 },
 "description": {
    "short": "AI tools",
    "full": "AI tools"
 },
 "accentColor": "#FFFFFF",
 "composeExtensions": [
    {
 +      "composeExtensionType": "apiBased",
 +      "authorization": {
 +        "authType": "apiSecretServiceAuth ",
 +        "apiSecretServiceAuthConfiguration": {
 +            "apiSecretRegistrationId": "96270b0f-7298-40cc-b333-152f84321813"
 +        }
 +      },
 +      "apiSpecificationFile": "aitools-openapi.yml",
       "commands": [
       {
          "id": "searchTools",
          "type": "query",
          "context": [
             "compose",
             "commandBox"
          ],
          "title": "search for AI tools",
          "description": "search for AI tools",
          "parameters": [
             {
             "name": "search",
             "title": "search query",
             "description": "e.g. search='tool to create music'"
             }
          ],
 +          "apiResponseRenderingTemplateFile": "response-template.json"
       }
       ]
    }
 ],
 "validDomains": []
 }

Parameters

Nombre Descripción
composeExtensions.composeExtensionType Compose tipo de extensión. Actualice el valor a apiBased.
composeExtensions.authorization Información relacionada con la autorización para la extensión de mensaje basada en API
composeExtensions.authorization.authType Enumeración de posibles tipos de autorización. Los valores admitidos son none, apiSecretServiceAuthy microsoftEntra.
composeExtensions.authorization.apiSecretServiceAuthConfiguration Detalles de captura de objetos necesarios para realizar la autenticación del servicio. Solo se aplica cuando el tipo de autenticación es apiSecretServiceAuth.
composeExtensions.authorization.apiSecretServiceAuthConfiguration.apiSecretRegistrationId Id. de registro devuelto cuando el desarrollador envía la clave de API a través del Portal para desarrolladores.
composeExtensions.apiSpecificationFile Hace referencia a un archivo de descripción de OpenAPI en el paquete de la aplicación. Incluya cuando el tipo es apiBased.
composeExtensions.commands.id Identificador único que se asigna al comando de búsqueda. La solicitud de usuario incluye este id. El identificador debe coincidir con el operationId disponible en la descripción de OpenAPI.
composeExtensions.commands.context Matriz donde se definen los puntos de entrada de la extensión de mensaje. Los valores predeterminados son compose y commandBox.
composeExtensions.commands.parameters Define una lista estática de parámetros para el comando. El nombre debe asignarse a en parameters.name la descripción de OpenAPI. Si hace referencia a una propiedad en el esquema del cuerpo de la solicitud, el nombre debe asignarse a properties.name los parámetros de consulta o .
composeExtensions.commands.apiResponseRenderingTemplateFile Plantilla usada para dar formato a la respuesta JSON de la API del desarrollador a la respuesta de tarjeta adaptable. [Obligatorio]

Para obtener más información, vea composeExtensions.

Plantilla de representación de respuesta

Nota:

Teams admite tarjetas adaptables hasta la versión 1.5. Al usar el diseñador de tarjetas adaptables, asegúrese de cambiar la versión de destino a 1.5.

La plantilla de representación de respuesta es un formato predefinido que determina cómo se muestran los resultados de la API en Teams. Usa plantillas para crear tarjetas adaptables u otros elementos de interfaz de usuario a partir de la respuesta de la API, lo que garantiza una experiencia de usuario integrada y sin problemas en Teams. La plantilla define el diseño y el estilo de la información presentada, que puede incluir texto, imágenes y componentes interactivos. Asegúrese de cumplir las siguientes directrices para la plantilla de representación de respuestas:

  • Defina la dirección URL de referencia del esquema en la $schema propiedad para establecer la estructura de la plantilla en el esquema de la plantilla de representación de respuesta.
  • Los valores admitidos para responseLayout son list y grid, que determinan cómo se presenta visualmente la respuesta. Para obtener más información sobre el diseño, vea Responder a solicitudes de usuario.
  • Se vuelve a solicitar para jsonPath las matrices o cuando los datos de la tarjeta adaptable no son el objeto raíz. Por ejemplo, si los datos están anidados en productDetails, la ruta de acceso JSON sería productDetails.
  • Defina jsonPath como la ruta de acceso a los datos o matriz pertinentes en la respuesta de la API. Si la ruta de acceso apunta a una matriz, cada entrada de la matriz se enlaza con la plantilla tarjeta adaptable y devuelve como resultado independiente. [Opcional]
  • Obtenga una respuesta de ejemplo para validar la plantilla de representación de respuesta. Esto sirve como prueba para asegurarse de que la plantilla funciona según lo esperado.
  • Use herramientas como Fiddler o Postman para llamar a la API y asegurarse de que la solicitud y la respuesta son válidas. Este paso es fundamental para solucionar problemas y confirmar que la API funciona correctamente.
  • Puede usar la tarjeta adaptable Designer para enlazar la respuesta de la API a la plantilla de representación de respuesta y obtener una vista previa de la tarjeta adaptable. Inserte la plantilla tarjeta adaptable en el EDITOR DE CARGA DE TARJETA e inserte la entrada de respuesta de ejemplo en EL EDITOR DE DATOS DE EJEMPLO.

El código siguiente es un ejemplo de una plantilla de representación de respuesta:

Ejemplo de plantilla de representación de respuesta
{
"version": "1.0",
"$schema": "developer.microsoft.com/json-schemas/teams/v1.17/MicrosoftTeams.ResponseRenderingTemplate.schema.json",
"jsonPath": "repairs",
"responseLayout": "grid",
"responseCardTemplate": {
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.4",
  "body": [
    {
      "type": "Container",
      "items": [
        {
          "type": "ColumnSet",
          "columns": [
            {
              "type": "Column",
              "width": "stretch",
              "items": [
                {
                  "type": "TextBlock",
                  "text": "Title: ${if(title, title, 'N/A')}",
                  "wrap": true
                },
                {
                  "type": "TextBlock",
                  "text": "Description: ${if(description, description, 'N/A')}",
                  "wrap": true
                },
                {
                  "type": "TextBlock",
                  "text": "Assigned To: ${if(assignedTo, assignedTo, 'N/A')}",
                  "wrap": true
                },
                {
                  "type": "Image",
                  "url": "${image}",
                  "size": "Medium",
                  "$when": "${image != null}"
                }
              ]
            },
            {
              "type": "Column",
              "width": "auto",
              "items": [
                {
                  "type": "Image",
                  "url": "${if(image, image, '')}",
                  "size": "Medium"
                }
              ]
            }
          ]
        },
        {
          "type": "FactSet",
          "facts": [
            {
              "title": "Repair ID:",
              "value": "${if(id, id, 'N/A')}"
            },
            {
              "title": "Date:",
              "value": "${if(date, date, 'N/A')}"
            }
          ]
        }
      ]
    }
  ]
  },
  "previewCardTemplate": {
  "title": "Title: ${if(title, title, 'N/A')}",
  "subtitle": "Description: ${if(description, description, 'N/A')}",
  "text": "Assigned To: ${if(assignedTo, assignedTo, 'N/A')}",
  "image": {
    "url": "${image}",
    "$when": "${image != null}"
    }
  }
 }

Tarjeta de vista previa

Se usa una plantilla de tarjeta de vista previa en el esquema de plantilla de representación de respuesta para asignar respuestas JSON a una tarjeta de vista previa que los usuarios ven cuando seleccionan un resultado de búsqueda. A continuación, la tarjeta de vista previa se expande en una tarjeta adaptable en el cuadro de redacción del mensaje. La plantilla de tarjeta de vista previa forma parte de la plantilla de representación de respuesta, que también incluye una plantilla de tarjeta adaptable y metadatos.

Captura de pantalla que muestra un ejemplo de extensión de redacción que muestra una matriz de tarjetas de vista previa al buscar una palabra específica. En este caso, la búsqueda de 'a' en la 'aplicación de prueba' devuelve cinco tarjetas que muestran las propiedades y valores 'Title', 'Description' (truncado) y 'AssignedTo' en cada una de ellas.

Tarjeta adaptable expandida

Ejemplo de cómo se ve la tarjeta adaptable expandida una vez que un usuario selecciona una tarjeta de vista previa. La tarjeta adaptable muestra los valores Título, Descripción completa, AssignedTo, RepairId y Fecha.

Parameters

Propiedad Tipo Descripción Obligatorio
version string Versión del esquema de la plantilla de representación de respuesta actual. Yes
jsonPath string Ruta de acceso a la sección pertinente en los resultados a los que se deben aplicar responseCardTemplate y previewCardTemplate. Si no se establece, el objeto raíz se trata como la sección pertinente. Si la sección pertinente es una matriz, cada entrada se asigna a responseCardTemplate y previewCardTemplate. No
responseLayout responseLayoutType Especifica el diseño de los resultados en el control flotante de la extensión de mensaje. Los tipos admitidos son list y grid. Yes
responseCardTemplate adaptiveCardTemplate Plantilla para crear una tarjeta adaptable a partir de una entrada de resultado. Yes
previewCardTemplate previewCardTemplate Plantilla para crear una tarjeta de vista previa a partir de una entrada de resultado. La tarjeta de vista previa resultante se muestra en el menú desplegable extensión de mensaje. Yes

Ruta de acceso json

La ruta de acceso JSON es opcional, pero debe usarse para matrices o donde el objeto que se va a usar como datos de la tarjeta adaptable no es el objeto raíz. La ruta de acceso JSON debe seguir el formato definido por Newtonsoft. Esta herramienta se puede usar. Puede usar la herramienta JSON para validar si una ruta de acceso JSON es correcta. Si la ruta de acceso JSON apunta a una matriz, cada entrada de esa matriz se enlaza con la plantilla tarjeta adaptable y devuelve como resultados independientes.

Ejemplo Supongamos que tiene el siguiente JSON para una lista de productos y desea crear un resultado de tarjeta para cada entrada.

{
   "version": "1.0",
   "title": "All Products",
   "warehouse": {
      "products": [
        ...
      ]
   }
}

Como puede ver, la matriz de resultados está en "products", que está anidada en "warehouse", por lo que la ruta de acceso JSON sería "warehouse.products".

Use https://adaptivecards.io/designer/ para obtener una vista previa de la tarjeta adaptable insertando la plantilla en la carga útil de la tarjeta Editor, tome una entrada de respuesta de ejemplo de la matriz o del objeto e insértelo en el editor Same Data de la derecha. Asegúrese de que la tarjeta se representa correctamente y es a su gusto. Teams admite tarjetas hasta la versión 1.5, mientras que el diseñador admite la versión 1.6.

Conversión de esquema de OpenAPI

Nota:

Enviamos un encabezado accept-language en la solicitud HTTP que se envía al punto de conexión definido en el documento de descripción de OpenAPI. El lenguaje de aceptación se basa en la configuración regional del cliente de Teams y el desarrollador puede usarlo para devolver una respuesta localizada.

Los siguientes tipos de datos del documento de descripción de OpenAPI se convierten en elementos dentro de una tarjeta adaptable como se indica a continuación:

  • string, number, integer, boolean los tipos se convierten en textblock.

    Ejemplo
    • Esquema de origen: string, number, integery boolean

       name:
         type: string
         example: doggie
      
    • Esquema de destino: Textblock

      {
      "type": "TextBlock",
      "text": "name: ${if(name, name, 'N/A')}",
      "wrap": true
      }
      
  • array: una matriz se convierte en un contenedor dentro de la tarjeta adaptable.

    Ejemplo
    • Esquema de origen: array

          type: array
                    items:
                    required:
                      - name
                    type: object
                      properties:
                      id:
                        type: integer
                      category:
                        type: object
                        properties:
                        name:
                          type: string
      
    • Esquema de destino: Container

          {
                    "type": "Container",
                    "$data": "${$root}",
                    "items": [
                      {
                        "type": "TextBlock",
                        "text": "id: ${if(id, id, 'N/A')}",
                        "wrap": true
                      },
                      {
                        "type": "TextBlock",
                        "text": "category.name: ${if(category.name, category.name, 'N/A')}",
                        "wrap": true
                      }
                    ]
                  }
      
      
  • object: un objeto se convierte en una propiedad anidada en la tarjeta adaptable.

    Ejemplo
    • Esquema de origen: object

      components:
        schemas:
          Pet:
              category:
                type: object
              properties:
                id:
                  type: integer
                name:
                  type: string
      
      
    • Esquema de destino: propiedad anidada en una tarjeta adaptable

      {
        "type": "TextBlock",
        "text": "category.id: ${if(category.id, category.id, 'N/A')}",
        "wrap": true
      },
      {
        "type": "TextBlock",
        "text": "category.name: ${if(category.name, category.name, 'N/A')}",
        "wrap": true
      }
      
      
  • image: si una propiedad es una dirección URL de imagen, se convierte en un elemento Image de la tarjeta adaptable.

    Ejemplo
    • Esquema de origen: image

          image:
            type: string
            format: uri
            description: The URL of the image of the item to be repaired
      
      
    • Esquema de destino: "Image"

      {
            "type": "Image",
            "url": "${image}",
            "$when": "${image != null}"
          }
      
      

Paso siguiente