Enviar anexos de mídia com o SDK do Bot Framework

APLICA-SE A: SDK v4

A troca de mensagens entre usuário e bot pode conter anexos de mídia como imagens, vídeo, áudio e arquivos. O SDK do Bot Framework oferece suporte à tarefa de envio de mensagens avançadas para o usuário. Para determinar o tipo de mensagens avançadas compatíveis com um canal (Facebook, Slack etc.), consulte a documentação do canal para obter informações sobre as limitações.

Observação

Os SDKs do Bot Framework para JavaScript, C# e Python continuarão a ter suporte, no entanto, o SDK para Java está sendo desativado. Seu suporte final de longo prazo será encerrado em novembro de 2023. Somente correções críticas de segurança e de bugs serão realizadas neste repositório.

Os bots existentes criados com o SDK para Java continuarão a funcionar.

Para a criação de novos bots, considere usar o Power Virtual Agents e leia sobre como escolher a solução de chatbot mais adequada.

Para obter mais informações, confira O futuro da criação de bots.

Pré-requisitos

Enviar anexos

Para enviar o conteúdo do usuário, como uma imagem ou um vídeo, é possível adicionar um anexo ou lista de anexos a uma mensagem.

Confira a Experiência do usuário de design para obter exemplos dos cartões disponíveis.

Confira também Qual é o limite de tamanho de um arquivo transferido usando canais? nas perguntas frequentes.

Todo o código-fonte mostrado nesta seção é baseado no exemplo Manipulação de anexos.

A propriedade Attachments do objeto Activity contém uma matriz de objetos Attachment que representam os anexos de mídia e os cartões avançados na mensagem. Para adicionar um anexo de mídia a uma mensagem, crie um objeto Attachment para a atividade reply e defina as propriedades ContentType, ContentUrl e Name.

Para criar a mensagem de resposta, defina o texto e, em seguida, configure os anexos. A atribuição dos anexos à resposta é a mesma para cada tipo de anexo, no entanto vários anexos são configurados e definidos de forma diferente, como visto nos snippets de código a seguir. O código a seguir é a configuração da resposta para um anexo embutido:

Bots/AttachmentsBot.cs

{
    reply = MessageFactory.Text("This is an inline attachment.");

Em seguida, vamos examinar os tipos de anexos. O primeiro é um anexo embutido:

Bots/AttachmentsBot.cs

{
    var imagePath = Path.Combine(Environment.CurrentDirectory, @"Resources", "architecture-resize.png");
    var imageData = Convert.ToBase64String(File.ReadAllBytes(imagePath));

    return new Attachment
    {
        Name = @"Resources\architecture-resize.png",
        ContentType = "image/png",
        ContentUrl = $"data:image/png;base64,{imageData}",
    };
}

Em seguida, um anexo carregado:

Bots/AttachmentsBot.cs

{
    if (string.IsNullOrWhiteSpace(serviceUrl))
    {
        throw new ArgumentNullException(nameof(serviceUrl));
    }

    if (string.IsNullOrWhiteSpace(conversationId))
    {
        throw new ArgumentNullException(nameof(conversationId));
    }

    var imagePath = Path.Combine(Environment.CurrentDirectory, @"Resources", "architecture-resize.png");

    var connector = turnContext.TurnState.Get<IConnectorClient>() as ConnectorClient;
    var attachments = new Attachments(connector);
    var response = await attachments.Client.Conversations.UploadAttachmentAsync(
        conversationId,
        new AttachmentData
        {
            Name = @"Resources\architecture-resize.png",
            OriginalBase64 = File.ReadAllBytes(imagePath),
            Type = "image/png",
        },
        cancellationToken);

    var attachmentUri = attachments.GetAttachmentUri(response.Id);

    return new Attachment
    {
        Name = @"Resources\architecture-resize.png",
        ContentType = "image/png",
        ContentUrl = attachmentUri,
    };
}

Por fim, um anexo de internet:

Bots/AttachmentsBot.cs

    {
        // ContentUrl must be HTTPS.
        return new Attachment
        {
            Name = @"Resources\architecture-resize.png",
            ContentType = "image/png",
            ContentUrl = "https://docs.microsoft.com/en-us/bot-framework/media/how-it-works/architecture-resize.png",
        };
    }
}

Se um anexo for uma imagem, áudio ou vídeo, o serviço do Connector comunicará os dados do anexo ao canal de modo a permitir que o canal renderize esse anexo na conversa. Se o anexo for um arquivo, a URL do arquivo será renderizada como um hiperlink na conversa.

Enviar um cartão hero

Além de anexos de vídeo ou imagem simples, é possível anexar um cartão hero, o que permite a você combinar imagens e botões em um objeto e depois enviá-los ao usuário. O markdown tem suporte na maioria dos campos de texto, mas o suporte pode variar por canal.

Para redigir uma mensagem com um cartão de destaque e um botão, você pode anexar um objeto HeroCard a uma mensagem.

O código-fonte a seguir é do exemplo Manipulação de anexos.

Bots/AttachmentsBot.cs


      private static async Task DisplayOptionsAsync(ITurnContext turnContext, CancellationToken cancellationToken)
      {
          // Create a HeroCard with options for the user to interact with the bot.
          var card = new HeroCard
          {
              Text = "You can upload an image or select one of the following choices",
              Buttons = new List<CardAction>
              {
                  // Note that some channels require different values to be used in order to get buttons to display text.
                  // In this code the emulator is accounted for with the 'title' parameter, but in other channels you may
                  // need to provide a value for other parameters like 'text' or 'displayText'.
                  new CardAction(ActionTypes.ImBack, title: "1. Inline Attachment", value: "1"),
                  new CardAction(ActionTypes.ImBack, title: "2. Internet Attachment", value: "2"),
                  new CardAction(ActionTypes.ImBack, title: "3. Uploaded Attachment", value: "3"),
              },
          };

          var reply = MessageFactory.Attachment(card.ToAttachment());
          await turnContext.SendActivityAsync(reply, cancellationToken);

Processar eventos em cartões avançados

Para processar eventos em cartões avançados, use objetos ação do cartão para especificar o que deverá acontecer quando o usuário selecionar um botão ou tocar em uma seção do cartão. Cada ação de cartão tem uma propriedade de tipo e valor.

Para funcionar corretamente, atribua um tipo de ação para cada item clicável em um cartão de destaque. Esta tabela lista e descreve os tipos de ação disponíveis e quais devem estar na propriedade de valor associada. A ação do cartão messageBack tem um significado mais generalizado do que as outras ações do cartão. Confira a seção Ação de cartão do Esquema de atividade para obter mais informações sobre o messageBack e outros tipos de ação de cartão.

Tipo Descrição Valor
call Inicia uma chamada telefônica. Destino de uma chamada telefônica nesse formato: tel:123123123123.
downloadFile Baixa um arquivo. A URL do arquivo para download.
imBack Envia uma mensagem para o bot e posta uma resposta visível no bate-papo. Texto da mensagem a ser enviada.
messageBack Representa uma resposta de texto a ser enviado por meio do sistema de chat. Um valor programático opcional a ser incluído nas mensagens geradas.
openUrl Abre uma URL no navegador interno. A URL para abrir.
playAudio Reproduz áudio. A URL do áudio para reproduzir.
playVideo Reproduz um vídeo. A URL do vídeo para reproduzir.
postBack Envia uma mensagem para o bot e não pode postar uma resposta visível no bate-papo. Texto da mensagem a ser enviada.
showImage Exibe uma imagem. A URL da imagem para exibir.
signin Inicia um processo de entrada do OAuth. A URL do fluxo de OAuth para iniciar.

Cartão hero usando vários tipos de evento

O código a seguir mostra exemplos que usam diversos eventos de cartão avançados.

Para obter exemplos de todos os cartões disponíveis, confira o exemplo Uso de cartões.

Cards.cs

public static HeroCard GetHeroCard()
{
    var heroCard = new HeroCard
    {
        Title = "BotFramework Hero Card",
        Subtitle = "Microsoft Bot Framework",
        Text = "Build and connect intelligent bots to interact with your users naturally wherever they are," +
               " from text/sms to Skype, Slack, Office 365 mail and other popular services.",
        Images = new List<CardImage> { new CardImage("https://sec.ch9.ms/ch9/7ff5/e07cfef0-aa3b-40bb-9baa-7c9ef8ff7ff5/buildreactionbotframework_960.jpg") },
        Buttons = new List<CardAction> { new CardAction(ActionTypes.OpenUrl, "Get Started", value: "https://docs.microsoft.com/bot-framework") },
    };

    return heroCard;
}

Cards.cs

public static SigninCard GetSigninCard()
{
    var signinCard = new SigninCard
    {
        Text = "BotFramework Sign-in Card",
        Buttons = new List<CardAction> { new CardAction(ActionTypes.Signin, "Sign-in", value: "https://login.microsoftonline.com/") },
    };

    return signinCard;
}

Enviar um cartão adaptável

Embora você possa usar a fábrica de mensagens para criar uma mensagem que contenha um anexo (de qualquer tipo), um Cartão Adaptável é um tipo específico de anexo. Nem todos os canais oferecem suporte a Cartões Adaptáveis, e alguns canais podem oferecer suporte apenas parcial a Cartões Adaptáveis. Por exemplo, se você enviar um Cartão Adaptável no Facebook, os botões não funcionarão se textos e imagens funcionarem bem. A fábrica de mensagens é uma classe auxiliar do SDK do Bot Framework usada para automatizar as etapas de criação para você.

Os Cartões Adaptáveis são formatos de troca de cartões aberto que permitem aos desenvolvedores trocar o conteúdo da interface do usuário de maneira comum e consistente. Entretanto, nem todos os canais dão suporte a cartões adaptáveis.

O Designer de Cartões Adaptáveis proporciona uma experiência rica e interativa em tempo de design para a criação de cartões adaptáveis.

Observação

Você deve testar esse recurso com os canais de que bot será usado para determinar se esses canais dão suporte a cartões adaptáveis.

Para usar Cartões Adaptáveis, certifique-se de adicionar o pacote NuGet AdaptiveCards.

O código-fonte a seguir é do exemplo Uso de cartões.

Cards.cs

Esse exemplo lê o JSON do Cartão Adaptável de um arquivo e o adiciona como um anexo.

public static Attachment CreateAdaptiveCardAttachment()
{
    // combine path for cross platform support
    var paths = new[] { ".", "Resources", "adaptiveCard.json" };
    var adaptiveCardJson = File.ReadAllText(Path.Combine(paths));

    var adaptiveCardAttachment = new Attachment()
    {
        ContentType = "application/vnd.microsoft.card.adaptive",
        Content = JsonConvert.DeserializeObject(adaptiveCardJson),
    };

    return adaptiveCardAttachment;
}

As mensagens também podem incluir vários anexos em um layout de carrossel, que coloca os anexos lado a lado e permite ao usuário rolar para deslocar.

O código-fonte a seguir é do exemplo Uso de cartões.

Dialogs/MainDialog.cs

Primeiro, crie a resposta e defina os anexos como uma lista.

// Cards are sent as Attachments in the Bot Framework.
// So we need to create a list of attachments for the reply activity.
var attachments = new List<Attachment>();

// Reply to the activity we received with an activity.
var reply = MessageFactory.Attachment(attachments);

Em seguida, adicione os anexos e defina o tipo de layout como carrossel. Aqui estamos adicionando-os um de cada vez, mas sinta-se à vontade para manipular a lista e adicionar os cartões como preferir.

// Display a carousel of all the rich card types.
reply.AttachmentLayout = AttachmentLayoutTypes.Carousel;
reply.Attachments.Add(Cards.CreateAdaptiveCardAttachment());
reply.Attachments.Add(Cards.GetAnimationCard().ToAttachment());
reply.Attachments.Add(Cards.GetAudioCard().ToAttachment());
reply.Attachments.Add(Cards.GetHeroCard().ToAttachment());
reply.Attachments.Add(Cards.GetOAuthCard().ToAttachment());
reply.Attachments.Add(Cards.GetReceiptCard().ToAttachment());
reply.Attachments.Add(Cards.GetSigninCard().ToAttachment());
reply.Attachments.Add(Cards.GetThumbnailCard().ToAttachment());
reply.Attachments.Add(Cards.GetVideoCard().ToAttachment());

Depois que os anexos forem adicionados, você poderá enviar a resposta como faria com qualquer outra.

// Send the card(s) to the user as an attachment to the activity
await stepContext.Context.SendActivityAsync(reply, cancellationToken);

Exemplo de código para processar entrada do Cartão Adaptável

O exemplo a seguir mostra uma maneira de usar entradas de cartão adaptável em uma classe de diálogo de bot. Ele estende o exemplo dos cartões de destaque validando a entrada recebida no campo de texto do cliente respondente. Primeiro, você precisa adicionar a entrada de texto e a funcionalidade de botão ao cartão adaptável existente, adicionando o seguinte código antes do colchete final de adaptiveCard.json, localizado na pasta de recursos:

"actions": [
  {
    "type": "Action.ShowCard",
    "title": "Text",
    "card": {
      "type": "AdaptiveCard",
      "body": [
        {
          "type": "Input.Text",
          "id": "text",
          "isMultiline": true,
          "placeholder": "Enter your comment"
        }
      ],
      "actions": [
        {
          "type": "Action.Submit",
          "title": "OK"
        }
      ]
    }
  }
]

A ID do campo de entrada de texto é definida como "texto". Quando o usuário seleciona OK, a mensagem gerada pelo cartão adaptável terá uma propriedade de valor que contém uma propriedade denominada text com informações que o usuário inseriu no campo de entrada de texto do cartão.

Nosso validador usa Newtonsoft.json para, primeiro, converter isso em um JObject e, em seguida, criar uma cadeia de texto aparada para comparação. Portanto, adicione:

using System;
using System.Linq;
using Newtonsoft.Json.Linq;

ao MainDialog.cs e instale o pacote NuGet estável mais recente de Newtonsoft.Json. No código do validador, adicionamos o fluxo de lógica aos comentários do código. Esse método ChoiceValidator é colocado no exemplo Uso de cartões logo após o colchete público para declaração de MainDialog:

private async Task ChoiceValidator(
    PromptValidatorContext promptContext,
    CancellationToken cancellationToken)
{
    // Retrieves Adaptive Card comment text as JObject.
    // looks for JObject field "text" and converts that input into a trimmed text string.
    var jobject = promptContext.Context.Activity.Value as JObject;
    var jtoken = jobject?["text"];
    var text = jtoken?.Value().Trim();

    // Logic: 1. if succeeded = true, just return promptContext
    //        2. if false, see if JObject contained Adaptive Card input.
    //               No = (bad input) return promptContext
    //               Yes = update Value field with JObject text string, return "true".
    if (!promptContext.Recognized.Succeeded && text != null)
    {
        var choice = promptContext.Options.Choices.FirstOrDefault(
        c => c.Value.Equals(text, StringComparison.InvariantCultureIgnoreCase));
        if (choice != null)
        {
            promptContext.Recognized.Value = new FoundChoice
            {
                Value = choice.Value,
            };
            return true;
        }
    }
    return promptContext.Recognized.Succeeded;
}

Agora, na declaração MainDialog, altere:

// Define the main dialog and its related components.
AddDialog(new ChoicePrompt(nameof(ChoicePrompt)));

para:

// Define the main dialog and its related components.
AddDialog(new ChoicePrompt(nameof(ChoicePrompt), ChoiceValidator));

Isso invocará seu validador para procurar pela entrada do Cartão Adaptável sempre que uma nova solicitação de escolha for criada.

Testar o bot Uso de Cartões

  1. Execute o exemplo Uso de cartões localmente e abra o bot no Bot Framework Emulator.
  2. Siga as instruções no bot para exibir um tipo de cartão, como um Cartão Adaptável.

Próximas etapas