Enviar y recibir archivos con un bot

Importante

Los ejemplos de código de esta sección se basan en 4,6 y versiones posteriores del SDK de bot Framework. Si está buscando documentación para versiones anteriores, vea la sección SDK de bots-V3 en la carpeta recursos de la documentación.

En este artículo se describe cómo intercambiar archivos con un usuario en una conversación de uno a uno con el bot. No puede usar esta funcionalidad para intercambiar archivos en un equipo o un chat en grupo.

Hay dos métodos para elegir:

  1. Las API de Microsoft Graph, que admiten los tres personalámbitos channel:, ygroupchat
  2. Las API de bot de Teams, personal que solo admiten el ámbito.

Nota

No se admite el envío y la recepción de archivos en bots en dispositivos móviles.

Uso de las API de Microsoft Graph

Puede publicar mensajes con datos adjuntos de tarjeta que hacen referencia a archivos existentes de SharePoint mediante las API de Microsoft Graph para OneDrive y SharePoint. El uso de las API de Graph requiere obtener acceso autenticado, a través del flujo de OAuth 2,0 estándar, para:

  • La carpeta de OneDrive de un usuario personal ( groupchat para y archivos).
  • O a los archivos de los canales de un equipo ( channel para archivos). Este método funciona en todos los ámbitos de Teams.

Uso de las API de bot de Teams

El bot puede enviar y recibir archivos directamente con usuarios en el personal contexto, también conocido como chats personales, mediante las API de Microsoft Teams. Esto le permite implementar escenarios como informes de gastos, reconocimiento de imágenes, archivado de archivos, firmas electrónicas y otros escenarios que impliquen la manipulación directa del contenido de los archivos. Los archivos compartidos en Microsoft Teams normalmente aparecen como tarjetas y permiten la visualización en una aplicación enriquecida. La API se proporciona como parte de la plataforma de robots de Microsoft Teams.

Nota

Este método sólo funciona en el personal contexto. No funciona en el channel contexto o. groupchat

Configurar el bot para que admita archivos

Para enviar y recibir archivos en el bot, debe establecer la supportsFiles propiedad en el manifiesto en. true Esta propiedad se describe en la sección bots de la referencia del manifiesto.

La configuración tiene un aspecto similar "supportsFiles": truea este:.

Invocar la actividad cuando el usuario acepta la carga de archivos

El archivo se carga en el almacenamiento de OneDrive del usuario después de que se emita el consentimiento para cargarlo. El bot recibirá una actividad de mensaje que contiene los metadatos del archivo, como su nombre y la dirección URL del contenido. Siga estos pasos:

  1. Envíe un mensaje al usuario que solicita permiso para escribir el archivo. Este mensaje debe contener FileConsentCard datos adjuntos con el nombre del archivo que se va a cargar.

    tarjeta de permisos de carga de archivos de bot

  2. Si el usuario acepta la carga de archivos, el bot recibirá una actividad de invocación con una dirección URL de ubicación.

  3. Para transferir el archivo, el bot realiza una HTTP POST directamente en la dirección URL de ubicación proporcionada.

  4. Opcionalmente, puede quitar la tarjeta de consentimiento original si no desea permitir que el usuario acepte más cargas del mismo archivo.

En el ejemplo siguiente se muestra una versión abreviada de la actividad Invoke que recibirá el bot:

{
    "name": "fileConsent/invoke",
    "type": "invoke",
    "timestamp": "2019-10-24T20:22:37.875Z",
    "localTimestamp": "2019-10-24T13:22:37.875-07:00",
    "id": "f:8805947989118514037",

    ...

    "value": {
        "type": "fileUpload",
        "action": "accept",
        "context": {
            "filename": "teams-logo.png"
        },
        "uploadInfo": {
            "contentUrl": "https://contoso.sharepoint.com//personal/<user alias>/Documents/Applications/TeamsFilesBot/teams-logo.png",
            "name": "teams-logo.png",
            "uploadUrl": "https://contoso.sharepoint.com//personal/<user alias>/_api/v2.0/drive/items/01FED6KHQXVVCUCI6XVJCZZMU2WMUSA6JS/uploadSession?guid=<GUID>",
            "uniqueId": "<Unique ID>",
            "fileType": "png"
        }
    },

    "locale": "en-US"
}

En la tabla siguiente se describen las propiedades de contenido de los datos adjuntos:

Propiedad Objetivo
uploadUrl Dirección URL de OneDrive para cargar el contenido del archivo.
uniqueId IDENTIFICADOR de archivo único. Este será el identificador de elemento de la unidad de OneDrive.
fileType Tipo de extensión de archivo, como PDF o * PNG * *.

Como práctica recomendada, debe confirmar la carga del archivo mediante el envío de un mensaje al usuario.

Si el usuario rechaza el archivo, el bot recibirá el evento siguiente, con el mismo nombre de actividad general:

{
  "name": "fileConsent/invoke",
  "value": {
    "type": "fileUpload",
    "action": "decline",
    "context": {
      ...
    }
  }
}

Notificar al usuario sobre un archivo cargado

Después de cargar un archivo en el OneDrive del usuario, debe enviar un mensaje de confirmación al usuario. Este mensaje debe contener FileCard datos adjuntos en los que el usuario puede hacer clic, ya sea para obtener una vista previa, abrirlo en OneDrive o descargarse de forma local. Este es un ejemplo.

{
  "attachments": [{
    "contentType": "application/vnd.microsoft.teams.card.file.info",
    "contentUrl": "https://contoso.sharepoint.com/personal/johnadams_contoso_com/Documents/Applications/file_example.txt",
    "name": "file_example.txt",
    "content": {
      "uniqueId": "<unique ID>",
      "fileType": "png",
    }
  }]
}

En la tabla siguiente se describen las propiedades de contenido de los datos adjuntos:

Propiedad Objetivo
uniqueId IDENTIFICADOR de elemento de unidad de OneDrive/SharePoint.
fileType Tipo de archivo, como PDF o DOCX.

Ejemplo de uso del SDK de bot Framework

El siguiente ejemplo muestra cómo puede controlar cargas de archivos y enviar solicitudes de consentimiento del archivo al usuario en el cuadro de diálogo del bot. Los fragmentos de código que se muestran a continuación pertenecen a un ejemplo completo ejecutable que puede descargar en esta ubicación: FileUpload.

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    bool messageWithFileDownloadInfo = turnContext.Activity.Attachments?[0].ContentType == FileDownloadInfo.ContentType;
    if (messageWithFileDownloadInfo)
    {
        var file = turnContext.Activity.Attachments[0];
        var fileDownload = JObject.FromObject(file.Content).ToObject<FileDownloadInfo>();

        string filePath = Path.Combine("Files", file.Name);

        var client = _clientFactory.CreateClient();
        var response = await client.GetAsync(fileDownload.DownloadUrl);
        using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
        {
            await response.Content.CopyToAsync(fileStream);
        }

        var reply = ((Activity)turnContext.Activity).CreateReply();
        reply.TextFormat = "xml";
        reply.Text = $"Complete downloading <b>{file.Name}</b>";
        await turnContext.SendActivityAsync(reply, cancellationToken);
    }
    else
    {
        string filename = "teams-logo.png";
        string filePath = Path.Combine("Files", filename);
        long fileSize = new FileInfo(filePath).Length;
        await SendFileCardAsync(turnContext, filename, fileSize, cancellationToken);
    }
}

private async Task SendFileCardAsync(ITurnContext turnContext, string filename, long filesize, CancellationToken cancellationToken)
{
    var consentContext = new Dictionary<string, string>
    {
        { "filename", filename },
    };

    var fileCard = new FileConsentCard
    {
        Description = "This is the file I want to send you",
        SizeInBytes = filesize,
        AcceptContext = consentContext,
        DeclineContext = consentContext,
    };

    var asAttachment = new Attachment
    {
        Content = fileCard,
        ContentType = FileConsentCard.ContentType,
        Name = filename,
    };

    var replyActivity = turnContext.Activity.CreateReply();
    replyActivity.Attachments = new List<Attachment>() { asAttachment };

    await turnContext.SendActivityAsync(replyActivity, cancellationToken);
}

protected override async Task OnTeamsFileConsentAcceptAsync(ITurnContext<IInvokeActivity> turnContext, FileConsentCardResponse fileConsentCardResponse, CancellationToken cancellationToken)
{
    try
    {
        JToken context = JObject.FromObject(fileConsentCardResponse.Context);

        string filePath = Path.Combine("Files", context["filename"].ToString());
        long fileSize = new FileInfo(filePath).Length;
        var client = _clientFactory.CreateClient();
        using (var fileStream = File.OpenRead(filePath))
        {
            var fileContent = new StreamContent(fileStream);
            fileContent.Headers.ContentLength = fileSize;
            fileContent.Headers.ContentRange = new ContentRangeHeaderValue(0, fileSize - 1, fileSize);
            await client.PutAsync(fileConsentCardResponse.UploadInfo.UploadUrl, fileContent, cancellationToken);
        }

        await FileUploadCompletedAsync(turnContext, fileConsentCardResponse, cancellationToken);
    }
    catch (Exception e)
    {
        await FileUploadFailedAsync(turnContext, e.ToString(), cancellationToken);
    }
}

protected override async Task OnTeamsFileConsentDeclineAsync(ITurnContext<IInvokeActivity> turnContext, FileConsentCardResponse fileConsentCardResponse, CancellationToken cancellationToken)
{
    JToken context = JObject.FromObject(fileConsentCardResponse.Context);

    var reply = ((Activity)turnContext.Activity).CreateReply();
    reply.TextFormat = "xml";
    reply.Text = $"Declined. We won't upload file <b>{context["filename"]}</b>.";
    await turnContext.SendActivityAsync(reply, cancellationToken);
}