Envoyer des pièces jointes multimédias avec le kit de développement logiciel (SDK) Bot Framework
Article
S'APPLIQUE À : SDK v4
Les messages échangés entre l’utilisateur et le bot peuvent contenir des pièces jointes multimédia, comme des images, des vidéos, des pistes audio et des fichiers. Le kit SDK Bot Framework prend en charge l’envoi de messages enrichis à l’utilisateur. Pour déterminer le type de messages enrichis pris en charge par un canal (Facebook, Slack, etc.), consultez la documentation du canal pour obtenir des informations sur les limitations.
Remarque
Les kits SDK JavaScript, C# et Python Bot Framework continueront d’être pris en charge. Toutefois, le kit de développement logiciel (SDK) Java est mis hors service avec une prise en charge finale à long terme se terminant en novembre 2023.
Les bots existants créés avec le kit de développement logiciel (SDK) Java continueront de fonctionner.
Pour envoyer le contenu de l’utilisateur comme une image ou une vidéo, vous pouvez ajouter une pièce jointe ou une liste de pièces jointes à un message.
L'ensemble du code source présenté dans cette section est basé sur l'exemple Gestion des pièces jointes.
La propriété Attachments de l’objet Activity contient un tableau d’objets Attachment qui représentent les pièces jointes multimédias et cartes enrichies attachées au message. Pour ajouter une pièce jointe multimédia à un message, créez un objet Attachment pour l’activité reply et définissez les propriétés ContentType, ContentUrl et Name.
Pour créer le message de réponse, définissez le texte, puis configurez les pièces jointes. L’affectation des pièces jointes à la réponse est identique pour chaque type de pièce jointe, cependant les pièces jointes diverses sont configurées et définies différemment, comme illustré dans les extraits de code suivants. Le code ci-dessous configure la réponse pour une pièce jointe insérée :
Bots/AttachmentsBot.cs
{
reply = MessageFactory.Text("This is an inline attachment.");
Il nous faut ensuite regarder les types de pièces jointes. Tout d’abord, la pièce jointe insérée :
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}",
};
}
Ensuite, en pièce jointe chargée :
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,
};
}
Enfin, la pièce jointe 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",
};
}
}
Pour créer le message de réponse, définissez le texte, puis configurez les pièces jointes. L’affectation des pièces jointes à la réponse est identique pour chaque type de pièce jointe, cependant les pièces jointes diverses sont configurées et définies différemment, comme illustré dans les extraits de code suivants. Le code ci-dessous configure la réponse pour une pièce jointe insérée :
bots/attachmentsBot.js
*/
const firstChar = turnContext.activity.text[0];
if (firstChar === '1') {
Pour envoyer à l’utilisateur un seul élément de contenu, comme une image ou une vidéo, vous pouvez envoyer des actifs multimédias de différentes façons. Tout d’abord, en pièce jointe insérée :
Enfin, en pièce jointe internet contenue dans une 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',
contentUrl: 'https://docs.microsoft.com/en-us/bot-framework/media/how-it-works/architecture-resize.png'
La méthode getAttachments() de l'objet Activity contient un tableau d'objets Attachment qui représentent les pièces jointes multimédias et cartes enrichies attachées au message. Pour ajouter une pièce jointe multimédia à un message, créez un objet Attachment pour l’activité reply et définissez les propriétés ContentType, ContentUrl et Name.
Pour créer le message de réponse, définissez le texte, puis configurez les pièces jointes. L’affectation des pièces jointes à la réponse est identique pour chaque type de pièce jointe, cependant les pièces jointes diverses sont configurées et définies différemment, comme illustré dans les extraits de code suivants. Le code ci-dessous configure la réponse pour une pièce jointe insérée :
AttachmentsBot.java
result = getInlineAttachment()
.thenApply(attachment -> {
Activity reply = MessageFactory.text("This is an inline attachment.");
reply.setAttachment(attachment);
return reply;
});
Il nous faut ensuite regarder les types de pièces jointes. Tout d’abord, la pièce jointe insérée :
AttachmentsBot.java
// 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.
private CompletableFuture<Attachment> getInlineAttachment() {
return getEncodedFileData("architecture-resize.png")
.thenApply(encodedFileData -> {
Attachment attachment = new Attachment();
attachment.setName("architecture-resize.png");
attachment.setContentType("image/png");
attachment.setContentUrl("data:image/png;base64," + encodedFileData);
return attachment;
});
}
// Creates an Attachment to be sent from the bot to the user from a HTTP URL.
private static Attachment getInternetAttachment() {
// ContentUrl must be HTTPS.
Attachment attachment = new Attachment();
attachment.setName("architecture-resize.png");
attachment.setContentType("image/png");
attachment.setContentUrl("https://docs.microsoft.com/en-us/bot-framework/media/how-it-works/architecture-resize.png");
return attachment;
}
Pour créer le message de réponse, définissez le texte, puis configurez les pièces jointes. L’affectation des pièces jointes à la réponse est identique pour chaque type de pièce jointe, cependant les pièces jointes diverses sont configurées et définies différemment, comme illustré dans les extraits de code suivants.
Le code ci-dessous configure la réponse pour une pièce jointe insérée :
bots/attachments_bot.py
reply.text = "This is an inline attachment."
reply.attachments = [self._get_inline_attachment()]
Pour envoyer à l’utilisateur un seul élément de contenu, comme une image ou une vidéo, vous pouvez envoyer des actifs multimédias de différentes façons. Tout d’abord, en pièce jointe insérée :
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}",
)
Ensuite, en pièce jointe chargée :
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,
)
Enfin, en pièce jointe internet contenue dans une 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",
)
Si la pièce jointe est une image, un contenu audio ou une vidéo, le service Connector communique les données de pièce jointe au canal de manière à permettre au canal d’afficher cette pièce jointe dans la conversation. Si la pièce jointe est un fichier, l’URL du fichier s’affiche sous la forme d’un lien hypertexte dans la conversation.
Envoyer une carte de héros
Outre les simples pièces jointes image ou vidéo, vous pouvez attacher une carte de héros, qui vous permet de combiner des images et des boutons dans un seul objet à envoyer à l’utilisateur. Markdown est pris en charge pour la plupart des champs de texte, mais sa prise en charge varie selon le canal.
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);
Pour composer un message avec un bouton et une carte de héros, vous pouvez joindre un objet HeroCard à un message.
* @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];
Pour composer un message avec un bouton et une carte de héros, vous pouvez joindre un objet HeroCard à un message.
private static CompletableFuture<Void> displayOptions(TurnContext turnContext) {
// Create a HeroCard with options for the user to interact with the bot.
HeroCard card = new HeroCard();
card.setText("You can upload an image or select one of the following choices");
// 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.setButtons(
new CardAction(ActionTypes.IM_BACK, "1. Inline Attachment", "1"),
new CardAction(ActionTypes.IM_BACK, "2. Internet Attachment", "2"),
new CardAction(ActionTypes.IM_BACK, "3. Uploaded Attachment", "3")
);
Activity reply = MessageFactory.attachment(card.toAttachment());
return turnContext.sendActivity(reply).thenApply(resourceResponse -> null);
}
Pour composer un message avec un bouton et une carte de héros, vous pouvez joindre un objet HeroCard à un message.
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"
),
],
)
Traiter des événements dans les cartes enrichies
Pour traiter les événements dans les cartes enrichies, utilisez les objets d'action de carte pour spécifier ce qui doit se produire quand l'utilisateur sélectionne un bouton ou appuie sur une section de la carte. Chaque action de carte possède une propriété de type et de valeur.
Pour bien fonctionner, il faut attribuer un type d'action à chaque élément interactif sur une carte de héros. Ce tableau liste et décrit les types d’actions disponibles, et ce qui doit se trouver dans la propriété de valeur associée.
L'action de carte messageBack a une signification plus généralisée que les autres. Consultez la section Action de carte du schéma d'activité pour plus d'informations sur le messageBack et les autres types d'action de carte.
Type
Description
active
call
Procède à un appel téléphonique.
Destination d’un appel téléphonique au format suivant : tel:123123123123.
downloadFile
Télécharge un fichier.
URL du fichier à télécharger.
imBack
Envoie un message au bot et publie une réponse visible dans la conversation.
Texte du message à envoyer.
messageBack
Représente une réponse textuelle à envoyer par le biais du système de conversation.
Valeur programmatique facultative à inclure dans les messages générés.
openUrl
Ouvre une URL dans le navigateur intégré.
URL à ouvrir.
playAudio
Lit le contenu audio.
URL du contenu audio à lire.
playVideo
Lit une vidéo.
URL de la vidéo à lire.
postBack
Envoie un message au bot et ne publie pas une réponse visible dans la conversation.
Texte du message à envoyer.
showImage
Affiche une image.
URL de l’image à afficher.
signin
Lance un processus de connexion OAuth.
URL du flux OAuth à lancer.
Carte de héros utilisant différents types d’événements
Le code suivant montre des exemples d’utilisation de différents événements de carte enrichie.
Pour des exemples de toutes les cartes disponibles, consultez l'exemple Utilisation des cartes.
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;
}
Pour des exemples de toutes les cartes disponibles, consultez l'exemple Utilisation des cartes.
createOAuthCard() {
return CardFactory.oauthCard(
'OAuth connection', // Replace with the name of your Azure AD connection
'Sign In',
'BotFramework OAuth Card'
);
}
Pour des exemples de toutes les cartes disponibles, consultez l'exemple Utilisation des cartes.
Cards.java
public static HeroCard getHeroCard() {
HeroCard heroCard = new HeroCard();
heroCard.setTitle("BotFramework Hero Card");
heroCard.setSubtitle("Microsoft Bot Framework");
heroCard.setText("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.");
heroCard.setImages(new CardImage("https://sec.ch9.ms/ch9/7ff5/e07cfef0-aa3b-40bb-9baa-7c9ef8ff7ff5/buildreactionbotframework_960.jpg"));
heroCard.setButtons(new CardAction(ActionTypes.OPEN_URL, "Get Started", "https://docs.microsoft.com/bot-framework"));
return heroCard;
}
Cards.java
public static SigninCard getSigninCard() {
SigninCard signinCard = new SigninCard();
signinCard.setText("BotFramework Sign-in Card");
signinCard.setButtons(new CardAction(ActionTypes.SIGNIN, "Sign-in", "https://login.microsoftonline.com/"));
return signinCard;
}
Pour des exemples de toutes les cartes disponibles, consultez l'exemple Utilisation des cartes.
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)
Envoyer une carte adaptative
Bien que vous puissiez utiliser la fabrique de messages pour créer un message qui contient une pièce jointe (de n'importe quel type), une carte adaptative est un type spécifique de pièce jointe. Tous les canaux ne prennent pas en charge les cartes adaptatives, et certains canaux ne le font que partiellement. Par exemple, si vous envoyez une carte adaptative dans Facebook, les boutons sont inopérants, alors que les textes et images fonctionnent parfaitement. La fabrique de messages est une classe d'aide du Kit de développement logiciel (SDK) Bot Framework utilisée pour automatiser les étapes de création.
Les cartes adaptatives sont un format d’échange de cartes ouvert permettant aux développeurs d’échanger du contenu d’interface utilisateur de manière commune et cohérente. Cependant, les canaux ne prennent pas tous en charge les cartes adaptatives.
Le concepteur de cartes adaptatives offre une expérience de conception riche et interactive pour la création de cartes adaptatives.
Remarque
Vous devez tester cette fonctionnalité avec les canaux que votre bot utilise pour déterminer s’ils prennent en charge les cartes adaptatives.
Les messages peuvent également inclure plusieurs pièces jointes dans une disposition carrousel, qui place les pièces jointes côte à côte et permet à l’utilisateur de faire défiler latéralement.
En premier lieu, créez la réponse et définissez les pièces jointes sous forme de liste.
// 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);
Ajoutez ensuite les pièces jointes et définissez le type de disposition sur carrousel.
Nous les ajoutons une à une ici, mais n’hésitez pas à arranger la liste pour ajouter les cartes à votre convenance.
// 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());
Une fois les pièces jointes ajoutées, vous pouvez envoyer la réponse comme n’importe quelle autre réponse.
// Send the card(s) to the user as an attachment to the activity
await stepContext.Context.SendActivityAsync(reply, cancellationToken);
Ajoutez les pièces jointes et définissez le type de disposition sur carrousel.
Une fois les pièces jointes ajoutées, vous pouvez envoyer la réponse comme n’importe quelle autre réponse.
En premier lieu, créez la réponse et définissez les pièces jointes sous forme de liste.
// Cards are sent as Attachments in the Bot Framework.
// So we need to create a list of attachments for the reply activity.
List<Attachment> attachments = new ArrayList<>();
// Reply to the activity we received with an activity.
Activity reply = MessageFactory.attachment(attachments);
Ajoutez ensuite les pièces jointes et définissez le type de disposition sur carrousel.
Nous les ajoutons une à une ici, mais n’hésitez pas à arranger la liste pour ajouter les cartes à votre convenance.
// Display a carousel of all the rich card types.
reply.setAttachmentLayout(AttachmentLayoutTypes.CAROUSEL);
reply.getAttachments().add(Cards.createAdaptiveCardAttachment());
reply.getAttachments().add(Cards.getAnimationCard().toAttachment());
reply.getAttachments().add(Cards.getAudioCard().toAttachment());
reply.getAttachments().add(Cards.getHeroCard().toAttachment());
reply.getAttachments().add(Cards.getOAuthCard().toAttachment());
reply.getAttachments().add(Cards.getReceiptCard().toAttachment());
reply.getAttachments().add(Cards.getSigninCard().toAttachment());
reply.getAttachments().add(Cards.getThumbnailCard().toAttachment());
reply.getAttachments().add(Cards.getVideoCard().toAttachment());
Une fois les pièces jointes ajoutées, vous pouvez envoyer la réponse comme n’importe quelle autre réponse.
// Send the card(s) to the user as an attachment to the activity
return stepContext.getContext().sendActivity(reply)
En premier lieu, créez la réponse et définissez les pièces jointes sous forme de liste.
reply = MessageFactory.list([])
Ajoutez ensuite les pièces jointes et définissez le type de disposition sur carrousel.
Nous les ajoutons une à une ici, mais n’hésitez pas à arranger la liste pour ajouter les cartes à votre convenance.
Une fois les pièces jointes ajoutées, vous pouvez envoyer la réponse comme n’importe quelle autre réponse.
# Send the card(s) to the user as an attachment to the activity
await step_context.context.send_activity(reply)
Exemple de code pour le traitement d’une entrée de carte adaptative
L'exemple suivant illustre une façon d'utiliser les entrées de la carte adaptative dans une classe de dialogue de bot.
Il élargit l'exemple des cartes de héros en validant l'entrée reçue dans le champ de texte du client qui répond.
Vous devez d'abord ajouter la fonctionnalité de saisie de texte et de bouton à la carte adaptative existante en ajoutant le code suivant juste avant le crochet final de adaptiveCard.json, qui se trouve dans le dossier des ressources :
L'ID du champ d'entrée de texte est défini sur « texte ». Lorsque l'utilisateur sélectionne OK, le message généré par la carte adaptative a une propriété de valeur nommée text qui contient les informations entrées par l'utilisateur dans le champ d'entrée de texte de la carte.
Notre validateur utilise Newtonsoft.json pour le convertir en JObject, puis pour créer une chaîne de texte tronquée à des fins de comparaison. Par conséquent, ajoutez :
using System;
using System.Linq;
using Newtonsoft.Json.Linq;
à MainDialog.cs et installez le dernier package NuGet stable de Newtonsoft.Json.
Dans le code du validateur, nous avons ajouté le flux logique dans les commentaires du code.
Cette méthode ChoiceValidator est placée dans l'exemple Utilisation de cartes juste après l'accolade fermée publique pour la déclaration 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;
}
À présent, ci-dessus, dans la déclaration MainDialog, changez :
// Define the main dialog and its related components.
AddDialog(new ChoicePrompt(nameof(ChoicePrompt)));
to:
// Define the main dialog and its related components.
AddDialog(new ChoicePrompt(nameof(ChoicePrompt), ChoiceValidator));
le validateur recherchera ainsi les données de la carte adaptative chaque fois qu'une nouvelle invite de choix sera créée.
Ouvrez mainDialog.js et recherchez la méthode d'exécution async run(turnContext, accessor). Elle gère l'activité entrante.
Juste après l'appel dialogSet.add(this);, ajouter ce qui suit :
// 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;
}
Si cette vérification détecte une entrée de texte inexistante à partir du client, elle vérifie s'il existe des entrées à partir d'une carte adaptative.
Si une entrée de carte adaptative existe à _activity.value.text, elle copie cette valeur dans le champ d'entrée de texte normal.
Notre validateur utilise l'aide à la sérialisation de com.microsoft.bot.schema pour convertir le texte en JsonNode, puis pour créer une chaîne de texte tronquée à des fins de comparaison. Nous aurons également besoin de quelques autres importations pour compléter le tout, alors ajoutez :
à MainDialog.java.
Dans le code du validateur, nous avons ajouté le flux logique dans les commentaires du code.
Cette expression PromptValidator est placée dans l'exemple Utilisation de cartes juste après l'accolade fermée publique pour la déclaration 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());
};
À présent, ci-dessus, dans la déclaration MainDialog, changez :
// Define the main dialog and its related components.
addDialog(new ChoicePrompt("ChoicePrompt"));
to:
// Define the main dialog and its related components.
addDialog(new ChoicePrompt("ChoicePrompt", validator, null));
le validateur recherchera ainsi les données de la carte adaptative chaque fois qu'une nouvelle invite de choix sera créée.
Créez et envoyez une activité avec des actions suggérées à l'utilisateur.
Cette méthode choice_validator est placée dans l'exemple Utilisation de cartes juste après l'accolade fermée publique pour la déclaration 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
À présent, ci-dessus, dans la déclaration MainDialog, changez :