APLICA-SE A: SDK v4
As mensagens trocadas entre o usuário e o bot podem conter anexos de mídia, como imagens, vídeo, áudio e arquivos. O SDK do Bot Framework suporta a tarefa de enviar mensagens avançadas para o usuário. Para determinar o tipo de mensagens avançadas que um canal (Facebook, Slack e assim por diante) suporta, consulte a documentação do canal para obter informações sobre limitações.
Nota
Para criar agentes com sua escolha de serviços, orquestração e conhecimento de IA, considere usar o SDK de agentes do Microsoft 365. O SDK de agentes tem suporte para C#, JavaScript ou Python. Você pode saber mais sobre o SDK de agentes em aka.ms/agents. Se você estiver procurando por uma plataforma de agente baseada em SaaS, considere o Microsoft Copilot Studio. Se você tiver um bot existente criado com o SDK do Bot Framework, poderá atualizar seu bot para o SDK de agentes. Você pode revisar as principais alterações e atualizações nas diretrizes de migração do SDK do Bot Framework para o SDK de agentes. Os tíquetes de suporte para o SDK do Bot Framework não serão mais atendidos a partir de 31 de dezembro de 2025.
Pré-requisitos
Enviar anexos
Para enviar o conteúdo do usuário, como uma imagem ou um vídeo, você pode adicionar um anexo ou uma lista de anexos a uma mensagem.
Consulte Projetar a experiência do usuário para obter exemplos de cartões disponíveis.
Consulte 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 Manipulando anexos .
A propriedade do objeto Attachments
contém uma matriz de objetos Activity
que representam anexos multimédia e cartões ricos ligados à mensagem. Para adicionar um anexo de mídia a uma mensagem, crie um Attachment
objeto para a reply
atividade e defina as ContentType
propriedades , 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, os vários anexos são configurados e definidos de forma diferente, como visto nos trechos a seguir. O código abaixo está a configurar a resposta a um anexo em linha.
Bots/AttachmentsBot.cs
{
reply = MessageFactory.Text("This is an inline attachment.");
Em seguida, examinamos os tipos de anexos. O primeiro é um anexo em linha:
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 último, um anexo 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",
};
}
}
O código-fonte a seguir é do exemplo de Manipulação de Anexos.
Para usar anexos, inclua as seguintes bibliotecas no bot:
bots/attachmentsBot.js
// @ts-check
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, os vários anexos são configurados e definidos de forma diferente, como visto nos trechos a seguir. O código abaixo está a configurar a resposta a um anexo em linha.
bots/attachmentsBot.js
* @param {Object} turnContext
// possible options.
const firstChar = turnContext.activity.text[0];
Para enviar ao usuário um único conteúdo, como uma imagem ou um vídeo, você pode enviar mídia de algumas maneiras diferentes. Primeiro, como um anexo embutido:
bots/attachmentsBot.js
/**
* Returns an inline attachment.
*/
getInlineAttachment() {
const imageData = fs.readFileSync(path.join(__dirname, '../resources/architecture-resize.png'));
const base64Image = Buffer.from(imageData).toString('base64');
return {
name: 'architecture-resize.png',
contentType: 'image/png',
Em seguida, um anexo carregado:
bots/attachmentsBot.js
* Returns an attachment that has been uploaded to the channel's blob storage.
* @param {Object} turnContext
*/
async getUploadedAttachment(turnContext) {
const imageData = fs.readFileSync(path.join(__dirname, '../resources/architecture-resize.png'));
const connectorFactory = turnContext.turnState.get(turnContext.adapter.ConnectorFactoryKey);
const connector = await connectorFactory.create(turnContext.activity.serviceUrl);
const conversationId = turnContext.activity.conversation.id;
const response = await connector.conversations.uploadAttachment(conversationId, {
name: 'architecture-resize.png',
originalBase64: imageData,
type: 'image/png'
});
// Retrieve baseUri from ConnectorClient for... something.
const baseUri = connector.baseUri;
const attachmentUri = baseUri + (baseUri.endsWith('/') ? '' : '/') + `v3/attachments/${ encodeURI(response.id) }/views/original`;
return {
name: 'architecture-resize.png',
Por último, um anexo da Internet contido num URL:
bots/attachmentsBot.js
/**
* Returns an attachment to be sent to the user from a HTTPS URL.
*/
getInternetAttachment() {
// NOTE: The contentUrl must be HTTPS.
return {
name: 'architecture-resize.png',
contentType: 'image/png',
O código-fonte mostrado nesta seção é baseado no exemplo Manipulando anexos .
O método getAttachments()
do objeto Activity
contém uma matriz de objetos Attachment
que representam os anexos de mídia e os cartões enriquecidos anexados à mensagem. Para adicionar um anexo de mídia a uma mensagem, crie um Attachment
objeto para a reply
atividade e defina as ContentType
propriedades , 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, os vários anexos são configurados e definidos de forma diferente, como visto nos trechos a seguir. O código abaixo está a configurar a resposta a um anexo em linha.
AttachmentsBot.java
Advertência
Parece que a amostra que você está procurando se moveu! Podem ter a certeza de que estamos a trabalhar para resolver este problema.
Em seguida, examinamos os tipos de anexos. O primeiro é um anexo em linha:
AttachmentsBot.java
Advertência
Parece que a amostra que você está procurando se moveu! Podem ter a certeza de que estamos a trabalhar para resolver este problema.
Em seguida, um anexo carregado:
AttachmentsBot.java
Advertência
Parece que a amostra que você está procurando se moveu! Podem ter a certeza de que estamos a trabalhar para resolver este problema.
Por último, um anexo Internet:
AttachmentsBot.java
Advertência
Parece que a amostra que você está procurando se moveu! Podem ter a certeza de que estamos a trabalhar para resolver este problema.
O código-fonte a seguir é do exemplo de Manipulação de Anexos.
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, os vários anexos são configurados e definidos de forma diferente, como visto nos trechos a seguir.
O código abaixo está a configurar a resposta a um anexo em linha.
bots/attachments_bot.py
reply.text = "This is an inline attachment."
reply.attachments = [self._get_inline_attachment()]
Para enviar ao usuário um único conteúdo, como uma imagem ou um vídeo, você pode enviar mídia de algumas maneiras diferentes. Primeiro, como um anexo embutido:
bots/attachments_bot.py
def _get_inline_attachment(self) -> Attachment:
"""
Creates an inline attachment sent from the bot to the user using a base64 string.
Using a base64 string to send an attachment will not work on all channels.
Additionally, some channels will only allow certain file types to be sent this way.
For example a .png file may work but a .pdf file may not on some channels.
Please consult the channel documentation for specifics.
:return: Attachment
"""
file_path = os.path.join(os.getcwd(), "resources/architecture-resize.png")
with open(file_path, "rb") as in_file:
base64_image = base64.b64encode(in_file.read()).decode()
return Attachment(
name="architecture-resize.png",
content_type="image/png",
content_url=f"data:image/png;base64,{base64_image}",
)
Em seguida, um anexo carregado:
bots/attachments_bot.py
async def _get_upload_attachment(self, turn_context: TurnContext) -> Attachment:
"""
Creates an "Attachment" to be sent from the bot to the user from an uploaded file.
:param turn_context:
:return: Attachment
"""
with open(
os.path.join(os.getcwd(), "resources/architecture-resize.png"), "rb"
) as in_file:
image_data = in_file.read()
connector = await turn_context.adapter.create_connector_client(
turn_context.activity.service_url
)
conversation_id = turn_context.activity.conversation.id
response = await connector.conversations.upload_attachment(
conversation_id,
AttachmentData(
name="architecture-resize.png",
original_base64=image_data,
type="image/png",
),
)
base_uri: str = connector.config.base_url
attachment_uri = (
base_uri
+ ("" if base_uri.endswith("/") else "/")
+ f"v3/attachments/{response.id}/views/original"
)
return Attachment(
name="architecture-resize.png",
content_type="image/png",
content_url=attachment_uri,
)
Por último, um anexo da Internet contido num URL:
bots/attachments_bot.py
def _get_internet_attachment(self) -> Attachment:
"""
Creates an Attachment to be sent from the bot to the user from a HTTP URL.
:return: Attachment
"""
return Attachment(
name="architecture-resize.png",
content_type="image/png",
content_url="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 Connector comunicará os dados do anexo ao canal de uma forma que permita que o canal processe esse anexo dentro da conversa. Se o anexo for um arquivo, a URL do arquivo será processada como um hiperlink dentro da conversa.
Enviar um cartão de herói
Além de simples anexos de imagem ou vídeo, você pode anexar um cartão herói, que permite combinar imagens e botões em um objeto, e enviá-los para o usuário. Markdown é suportado para a maioria dos campos de texto, mas o suporte pode variar de acordo com o canal.
Para compor uma mensagem com um cartão herói e um botão, você pode anexar um HeroCard
objeto a uma mensagem.
O código-fonte a seguir é do exemplo de 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);
Para compor uma mensagem com um cartão herói e um botão, você pode anexar um HeroCard
objeto a uma mensagem.
O código-fonte a seguir é do exemplo de Manipulação de Anexos.
bots/attachmentsBot.js
* Sends a HeroCard with choices of attachments.
* @param {Object} turnContext
*/
async displayOptions(turnContext) {
const reply = { type: ActivityTypes.Message };
// 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'.
const buttons = [
{ type: ActionTypes.ImBack, title: '1. Inline Attachment', value: '1' },
{ type: ActionTypes.ImBack, title: '2. Internet Attachment', value: '2' },
{ type: ActionTypes.ImBack, title: '3. Uploaded Attachment', value: '3' }
];
const card = CardFactory.heroCard('', undefined,
buttons, { text: 'You can upload an image or select one of the following choices.' });
reply.attachments = [card];
Para compor uma mensagem com um cartão herói e um botão, você pode anexar um HeroCard
objeto a uma mensagem.
O código-fonte a seguir é do exemplo de Manipulação de Anexos.
AttachmentsBot.java
Advertência
Parece que a amostra que você está procurando se moveu! Podem ter a certeza de que estamos a trabalhar para resolver este problema.
Para compor uma mensagem com um cartão herói e um botão, você pode anexar um HeroCard
objeto a uma mensagem.
O código-fonte a seguir é do exemplo de Manipulação de Anexos.
bots/attachments_bot.py
async def _display_options(self, turn_context: TurnContext):
"""
Create a HeroCard with options for the user to interact with the bot.
:param turn_context:
:return:
"""
# 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'.
card = HeroCard(
text="You can upload an image or select one of the following choices",
buttons=[
CardAction(
type=ActionTypes.im_back, title="1. Inline Attachment", value="1"
),
CardAction(
type=ActionTypes.im_back, title="2. Internet Attachment", value="2"
),
CardAction(
type=ActionTypes.im_back, title="3. Uploaded Attachment", value="3"
),
],
)
Processar eventos em cartões interativos
Para processar eventos em cartões ricos, use objetos de ação do cartão para especificar o que deve acontecer quando o usuário seleciona um botão ou toca em uma seção do cartão. Cada ação de cartão tem uma propriedade tipo e valor.
Para funcionar corretamente, atribua um tipo de ação a cada item clicável em um cartão de herói. Esta tabela lista e descreve os tipos de ação disponíveis e o que deve estar na propriedade value associada.
A messageBack
ação do cartão tem um significado mais generalizado do que as outras ações do cartão. Consulte a secção Ação do cartão do esquema de atividade para obter mais informações sobre o messageBack
e outros tipos de ação do cartão.
Tipo |
Descrição |
valor |
chamar |
Inicia uma chamada telefónica. |
Destino da chamada telefónica neste formato: tel:123123123123 . |
descarregar ficheiro |
Transfere um ficheiro. |
O URL do ficheiro a transferir. |
voltar |
Envia uma mensagem para o bot e publica uma resposta visível no chat. |
Texto da mensagem a enviar. |
MensagemDeVolta |
Representa uma resposta de texto a ser enviada através do sistema de chat. |
Um valor programático opcional para incluir nas mensagens geradas. |
openUrl |
Abre um URL no navegador integrado. |
O URL a abrir. |
reproduzir áudio |
Reproduz áudio. |
O URL do áudio para reproduzir. |
Reproduzir vídeo |
Reproduz um vídeo. |
O URL do vídeo a ser reproduzido. |
postVoltar |
Envia uma mensagem para o bot e pode não publicar uma resposta visível no chat. |
Texto da mensagem a enviar. |
mostrarImagem |
Exibe uma imagem. |
O URL da imagem a ser exibida. |
iniciar sessão |
Inicia um processo de entrada OAuth. |
A URL do fluxo OAuth para iniciar. |
Cartão de herói usando vários tipos de evento
O seguinte código mostra exemplos usando vários eventos de cartões enriquecidos.
Para obter exemplos de todos os cartões disponíveis, consulte o Exemplo de 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;
}
Para obter exemplos de todos os cartões disponíveis, consulte o Exemplo de uso de cartões .
diálogos/mainDialog.js
image: 'https://upload.wikimedia.org/wikipedia/en/3/3c/SW_-_Empire_Strikes_Back.jpg'
}
);
}
createHeroCard() {
return CardFactory.heroCard(
'BotFramework Hero Card',
CardFactory.images(['https://sec.ch9.ms/ch9/7ff5/e07cfef0-aa3b-40bb-9baa-7c9ef8ff7ff5/buildreactionbotframework_960.jpg']),
CardFactory.actions([
{
type: 'openUrl',
title: 'Get started',
diálogos/mainDialog.js
}
])
);
}
createOAuthCard() {
return CardFactory.oauthCard(
Para obter exemplos de todos os cartões disponíveis, consulte o Exemplo de uso de cartões .
Cards.java
Advertência
Parece que a amostra que você está procurando se moveu! Podem ter a certeza de que estamos a trabalhar para resolver este problema.
Cards.java
Advertência
Parece que a amostra que você está procurando se moveu! Podem ter a certeza de que estamos a trabalhar para resolver este problema.
Para obter exemplos de todos os cartões disponíveis, consulte o Exemplo de uso de cartões .
diálogos/main_dialog.py
def create_hero_card(self) -> Attachment:
card = HeroCard(
title="",
images=[
CardImage(
url="https://sec.ch9.ms/ch9/7ff5/e07cfef0-aa3b-40bb-9baa-7c9ef8ff7ff5/buildreactionbotframework_960.jpg"
)
],
buttons=[
CardAction(
type=ActionTypes.open_url,
title="Get Started",
value="https://docs.microsoft.com/en-us/azure/bot-service/",
)
],
)
return CardFactory.hero_card(card)
diálogos/main_dialog.py
def create_oauth_card(self) -> Attachment:
card = OAuthCard(
text="BotFramework OAuth Card",
connection_name="OAuth connection", # Replace it with the name of your Azure AD connection.
buttons=[
CardAction(
type=ActionTypes.signin,
title="Sign in",
value="https://example.org/signin",
)
],
)
return CardFactory.oauth_card(card)
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 suportam Adaptive Cards, e alguns canais podem suportar apenas parcialmente Adaptive Cards. Por exemplo, se você enviar um cartão adaptável no Facebook, os botões não funcionarão enquanto os textos e as 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 Adaptive Cards são um formato aberto de troca de cartões que permite aos desenvolvedores trocar conteúdo da interface do usuário de forma comum e consistente. No entanto, nem todos os canais suportam Adaptive Cards.
O Adaptive Cards Designer oferece uma experiência de design rica e interativa para a criação de cartões adaptáveis.
Nota
Você deve testar esse recurso com os canais que seu bot usará para determinar se esses canais suportam 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 Usando cartões.
Cards.cs
Este exemplo lê o JSON do Adaptive Card 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;
}
Para usar Adaptive Cards, certifique-se de adicionar o adaptivecards
pacote npm.
O código-fonte a seguir é do exemplo Usando cartões.
diálogos/mainDialog.js
Este exemplo lê o JSON do Adaptive Card de um arquivo e cria uma atividade de mensagem com o cartão anexado.
const { AttachmentLayoutTypes, CardFactory } = require('botbuilder');
// ======================================
// Helper functions used to create cards.
// ======================================
O código-fonte a seguir é do exemplo Usando cartões.
Cards.java
Este exemplo lê o JSON do Adaptive Card de um arquivo e o adiciona como um anexo.
Advertência
Parece que a amostra que você está procurando se moveu! Podem ter a certeza de que estamos a trabalhar para resolver este problema.
O código-fonte a seguir é do exemplo Usando cartões.
bots/main_dialog.py
Este exemplo lê o JSON do Adaptive Card de um arquivo e cria uma atividade de mensagem com o cartão anexado.
from .resources.adaptive_card_example import ADAPTIVE_CARD_CONTENT
def create_adaptive_card(self) -> Attachment:
return CardFactory.adaptive_card(ADAPTIVE_CARD_CONTENT)
Envie um carrossel de cartões
As mensagens também podem incluir vários anexos em um layout de carrossel, que coloca os anexos lado a lado e permite que o usuário role para frente.
O código-fonte a seguir é do exemplo Usando cartões.
Diálogos/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 a adicioná-los um de cada vez, mas sinta-se à vontade para manipular a lista para 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());
Uma vez que os anexos são adicionados, você pode enviar a resposta como qualquer outro.
// Send the card(s) to the user as an attachment to the activity
await stepContext.Context.SendActivityAsync(reply, cancellationToken);
O código-fonte a seguir é do exemplo Usando cartões.
diálogos/mainDialog.js
Adicione os anexos e defina o tipo de layout como carrossel.
Uma vez que os anexos são adicionados, você pode enviar a resposta como qualquer outro.
case 'Video Card':
await stepContext.context.sendActivity({ attachments: [this.createVideoCard()] });
break;
default:
await stepContext.context.sendActivity({
attachments: [
this.createAdaptiveCard(),
this.createAnimationCard(),
this.createAudioCard(),
this.createHeroCard(),
this.createOAuthCard(),
this.createReceiptCard(),
this.createSignInCard(),
this.createThumbnailCard(),
O código-fonte a seguir é do exemplo Usando cartões.
MainDialog.java
Primeiro, crie a resposta e defina os anexos como uma lista.
Advertência
Parece que a amostra que você está procurando se moveu! Podem ter a certeza de que estamos a trabalhar para resolver este problema.
Em seguida, adicione os anexos e defina o tipo de layout como carrossel.
Aqui estamos a adicioná-los um de cada vez, mas sinta-se à vontade para manipular a lista para adicionar os cartões como preferir.
Advertência
Parece que a amostra que você está procurando se moveu! Podem ter a certeza de que estamos a trabalhar para resolver este problema.
Uma vez que os anexos são adicionados, você pode enviar a resposta como qualquer outro.
Advertência
Parece que a amostra que você está procurando se moveu! Podem ter a certeza de que estamos a trabalhar para resolver este problema.
O código-fonte mostrado aqui é baseado no exemplo Usando cartões .
diálogos/main_dialog.py
Primeiro, crie a resposta e defina os anexos como uma lista.
reply = MessageFactory.list([])
Em seguida, adicione os anexos e defina o tipo de layout como carrossel.
Aqui estamos a adicioná-los um de cada vez, mas sinta-se à vontade para manipular a lista para adicionar os cartões como preferir.
reply.attachment_layout = AttachmentLayoutTypes.carousel
reply.attachments.append(self.create_adaptive_card())
reply.attachments.append(self.create_animation_card())
reply.attachments.append(self.create_audio_card())
reply.attachments.append(self.create_hero_card())
reply.attachments.append(self.create_oauth_card())
reply.attachments.append(self.create_receipt_card())
reply.attachments.append(self.create_signin_card())
reply.attachments.append(self.create_thumbnail_card())
reply.attachments.append(self.create_video_card())
Uma vez que os anexos são adicionados, você pode enviar a resposta como qualquer outro.
# Send the card(s) to the user as an attachment to the activity
await step_context.context.send_activity(reply)
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 a amostra de cartões de heróis validando a entrada recebida no campo de texto do cliente que responde.
Primeiro, é necessário adicionar a funcionalidade de entrada de texto e botão ao cartão adaptável existente, adicionando o seguinte código imediatamente 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"
}
]
}
}
]
O ID do campo de entrada de texto é definido como "texto". Quando o usuário seleciona OK, a mensagem que o Adaptive Card gera terá uma propriedade value que tem uma propriedade nomeada text
que contém as 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 caracteres de texto cortada para comparação. Então adicione:
using System;
using System.Linq;
using Newtonsoft.Json.Linq;
ao MainDialog.cs e instalar o pacote NuGet estável mais recente do Newtonsoft.Json.
No código do validador, adicionamos o fluxo lógico nos comentários do código.
Este ChoiceValidator
método é colocado no exemplo Usando cartões depois da chave fechada 'public' 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
acima, 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á o seu validador para procurar dados de entrada do Adaptive Card sempre que uma nova solicitação de escolha for criada.
Abra mainDialog.js e localize o método async run(turnContext, accessor)
run Este método lida com a atividade de entrada.
Logo após a chamada dialogSet.add(this);
, adicione o seguinte:
// The following check looks for a non-existent text input
// plus Adaptive Card input in _activity.value.text
// If both conditions exist, the Activity Card text
// is copied into the text input field.
if(turnContext._activity.text == null
&& turnContext._activity.value.text != null) {
this.logger.log('replacing null text with Activity Card text input');
turnContext._activity.text = turnContext._activity.value.text;
}
Se essa verificação encontrar uma entrada de texto inexistente do cliente, ela verificará se há entrada de um Adaptive Card.
Se existir uma entrada do Adaptive Card no _activity.value.text
, ele copiará isso para o campo de entrada de texto normal.
Nosso validador usa o auxiliar de serialização de com.microsoft.bot.schema para primeiro converter isso em um JsonNode
e, em seguida, criar uma cadeia de caracteres de texto cortada para comparação. Também precisaremos de algumas outras importações para concluir isso, então adicione:
import com.fasterxml.jackson.databind.JsonNode;
import com.microsoft.bot.dialogs.prompts.PromptValidator;
import com.microsoft.bot.schema.Serialization;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
para MainDialog.java.
No código do validador, adicionamos o fluxo lógico nos comentários do código.
Esta PromptValidator
expressão é colocada no exemplo Usando cartões logo após a chave 'public' fechada para a declaração de MainDialog:
PromptValidator<FoundChoice> validator = (promptContext) -> {
// Retrieves Adaptive Card comment text as JObject.
// looks for JObject field "text" and converts that input into a trimmed text
// string.
JsonNode jsonNode = Serialization.getAs(promptContext.getContext().getActivity().getValue(), JsonNode.class);
JsonNode textNode = jsonNode != null ? jsonNode.get("text") : null;
String text = textNode != null ? textNode.textValue() : "";
// 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.getRecognized().getSucceeded() && text != null) {
Optional<Choice> choice = promptContext.getOptions()
.getChoices()
.stream()
.filter(c -> StringUtils.compareIgnoreCase(c.getValue(), text) == 0)
.findFirst();
if (choice.isPresent()) {
promptContext.getRecognized().setValue(new FoundChoice() {
{
setValue(choice.get().getValue());
}
});
return CompletableFuture.completedFuture(true);
}
}
return CompletableFuture.completedFuture(promptContext.getRecognized().getSucceeded());
};
Agora, na declaração MainDialog
acima, altere:
// Define the main dialog and its related components.
addDialog(new ChoicePrompt("ChoicePrompt"));
para:
// Define the main dialog and its related components.
addDialog(new ChoicePrompt("ChoicePrompt", validator, null));
Isso invocará o seu validador para procurar dados de entrada do Adaptive Card sempre que uma nova solicitação de escolha for criada.
Crie e envie uma atividade com ações sugeridas para o usuário.
Este choice_validator
método é inserido no exemplo Usando cartões logo após a chave fechada da declaração public de MainDialog
:
@staticmethod
async def choice_validator(prompt_context: PromptValidatorContext) -> bool:
if prompt_context.context.activity.value:
text = prompt_context.context.activity.value["text"].lower()
if not prompt_context.recognized.succeeded and text:
matching_choices = [choice for choice in prompt_context.options.choices if choice.value.lower() == text]
if matching_choices:
choice = matching_choices[0]
prompt_context.recognized.value = FoundChoice(
value=choice.value,
index=0,
score=1.0
)
return True
return prompt_context.recognized.succeeded
Agora, na declaração MainDialog
acima, altere:
self.add_dialog(ChoicePrompt(CARD_PROMPT))
para:
self.add_dialog(ChoicePrompt(CARD_PROMPT, MainDialog.choice_validator))
Isso invocará o seu validador para procurar dados de entrada do Adaptive Card sempre que uma nova solicitação de escolha for criada.
Testar o bot Usando cartões
- Execute o exemplo Usando cartões localmente e abra o bot no Emulador do Bot Framework.
- Siga as instruções no bot para exibir um tipo de cartão, como um Adaptive Card.
Próximos passos