Nouvelles Chroniques d'Amethyste

Penser au Sens, pas au Verbe

Une expérience utilisateur plus riche pour vos bots

Poster un commentaire

Les conversations avec les bots ne sont pas limitées à du simple affichage de texte. On peut les améliorer de diverses manières. On a déjà rencontré plusieurs techniques pour améliorer l’apparence visuelle des dialogues: FormFlow, PromptDialog

D’autres outils sont à notre disposition et permettront d’ajouter des images, des pièces jointes, des liens, des boutons… On pourra également formater le texte avec le langage Markdown.

Je vais essayer de faire quelques démonstrations dans cet article qui exposera pas mal de copies d’écran comme vous le verrez!

 

Je ne peux bien entendu pas montrer comment se passe le rendu dans tous les canaux supportés par Microsoft, mais un outil peut vous y aider: le Chanel Inspector:

https://docs.botframework.com/en-us/channel-inspector/channels/Skype/

L’outil est purement statique, mais tout de même utile.

Préparation

Le bot par défaut devrait nous suffire. Je l’ai juste le réécrit pour utiliser une classe IDialog personnalisée. Je vais reprendre le code montré dans ce précédent article:

https://amethyste16.wordpress.com/2017/01/26/un-vrai-dialogue-avec-un-bot

Markdown

J’ai déjà fait quelques démonstration de l’utilisation du langage Markdown dans les dialogues de bots. Et notre code de démonstration en fait même déjà un usage limité:

botm1

 

Voici un exemple plus démonstratif:

string message = "# Démonstration de Markdown\n";
message += "**Un texte en gras**\n\n";
message += "*Un autre en italique*\n\n";
message += "[Un lien vers Google](http://google.fr)\n\n";
message += "![Une image](https://image.freepik.com/free-vector/coloured-robot-design_1148-9.jpg)\n";

await context.PostAsync(message);
context.Wait(MessageReceivedAsync);

Visuellement:

2017-02-27_22-09-02

C’est le rendu dans l’émulateur. Jetons tout de même un coup d’œil pour d’autres canaux. Par exemple WebChat:

2017-02-27_22-14-58

 

Skype for Windows par contre:

2017-02-27_22-16-38

Cette fois c’est moins convainquant.

Conclusion: toujours tester!!!!

Ajouter une pièce-jointe

Une pièce-jointe (un attachement) sera une image, un fichier, une vidéo, bref tout ce qui peut servir à accompagner un texte.

 

private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
   await context.PostAsync("Voici des PJ");
 
   IMessageActivity message = context.MakeMessage();
 
   Attachment attachement = new Attachment();
   attachement.ContentUrl = "https://image.freepik.com/free-vector/coloured-robot-design_1148-9.jpg";
   attachement.ContentType = "image/jpg";
   attachement.Name = "Robot";
   message.Attachments.Add(attachement);
 
   attachement = new Attachment();
   attachement.ContentUrl = "https://jack35.files.wordpress.com/2016/09/133.jpg";
   attachement.ContentType = "image/jpg";
   attachement.Name = "Robot";
   message.Attachments.Add(attachement);
 
   await context.PostAsync(message);
   context.Wait(MessageReceivedAsync);
}

 

Les 3 propriétés importantes d’un attachement sont:

  1. ContentUrl
    Lien vers la ressource
  2. ContentType
    Type mime du contenu de l’url
  3. Name
    Nom de l’attachement

 

On découvre également une deuxième surcharge de PostAsync() qui attend un IMessage plutôt qu’une String.

Dans notre exemple nous passons en PJ deux images, rien de particulier à noter dans le code. Visuellement:

2017-02-27_22-39-52

Et Skype:

2017-02-27_22-45-54

Les cartes

Les cartes sont des dialogues spécialisés pour des affichages complexes comprenant des images, des textes ou des boutons.

Pour l’instant il existe 4 types de cartes:

  1. Hero Card
    Une carte qui affiche une grande image
  2. Thumbnail Card
    Une carte qui affiche une petite image
  3. Receipt card
    Carte qui permet à l’utilisateur d’envoyer ou recevoir une facture
  4. Signing card
    Carte qui permet à l’utilisateur de lancer une opération de signature

 

Hero card

Première démo, on va monter un carousel. Pour vous allécher il ressemblera à ceci:

2017-02-28_23-40-19

 

private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
   // première carte
   HeroCard heroCard1 = new HeroCard()
      {
         Title = "Super Robot 2000",
         Subtitle = "Pour seulement 45 800€"
      };
 
   heroCard1.Images = new List<CardImage>();
   CardImage cardImage;
 
   cardImage = new CardImage()
   {
      Url = "https://jack35.files.wordpress.com/2016/09/133.jpg",
      Alt = "Super Robot 2000"
   };
   heroCard1.Images.Add(cardImage);
 
   // deuxième carte
   HeroCard heroCard2 = new HeroCard()
   {
      Title = "Maxi Robot",
      Subtitle = "Le robot qu'il vous faut"
   };
 
   heroCard2.Images = new List<CardImage>();
 
   cardImage = new CardImage()
   {
      Url = "https://image.freepik.com/free-vector/coloured-robot-design_1148-9.jpg",
      Alt = "Maxi Robot"
   };
   heroCard2.Images.Add(cardImage);
 
 
   IMessageActivity message = context.MakeMessage();
   message.AttachmentLayout = AttachmentLayoutTypes.Carousel;
 
   message.Attachments.Add(heroCard1.ToAttachment());
   message.Attachments.Add(heroCard2.ToAttachment());
 
   await context.PostAsync(message);
   context.Wait(MessageReceivedAsync);
}

On commence par obtenir deux instances de HeroCard. Un HeroCard ne peut afficher qu’au maximum une image, c’est la raison pour laquelle il nous faut deux cartes.

On créé ensuite une instance d’Activity comme on a vu dans le chapitre qui précède. La nouveauté est que l’on précise une valeur pour la propriété AttachmentLayout.

La valeur ‘carousel’ affiche les images à l’horizontale tandis que la valeur ‘list’ (par défaut) les affichent verticalement.

On n’a plus qu’à transformer les cartes en Attachement avec la méthode ToAttachment() et on les ajoute à la collection des attachements.

Je vous laisse lancer le bot et vérifier que l’affichage est conforme à ce qui a été annoncé.

 

 

Une hero carte peut aussi afficher un ou plusieurs boutons d’action. On dispose pour cela de la collection Buttons attachée à chaque carte.

Voici le principe. On ajoute un code de ce style sur chaque carte:

heroCard1.Buttons = new List<CardAction>();
heroCard1.Buttons = new List<CardAction>();
CardAction button = new CardAction()
{
   Value = "https://www.google.fr",
   Type = ActionTypes.OpenUrl,
   Title = "Acheter"
};
heroCard1.Buttons.Add(button);
 
button = new CardAction()
{
   Value = "https://www.bing.fr",
   Type = ActionTypes.OpenUrl,
   Title = "Produits similaires"
};
heroCard1.Buttons.Add(button);

Visuellement:

2017-03-01_00-05-40

L’apparence est plus ou moins fignolée selon le canal. Tester donc.

ActionTypes

Remarquez la propriété Type que nous avons alimenté avec une valeur de ActionTypes. Il s’agit simplement d’un paramètre que l’on va passer à l’action pour préciser ce qu’elle devra faire. On peut utiliser une des valeurs de ActionTypes.

2017-03-01_00-20-02

Par exemple avec la valeur ImBack, le client (le canal) va poster un message public alors que postBack poste un message privé.

Modifiez maintenant la valeur Type des boutons avec PostBack et ImgBack respectivement:

CardAction button = new CardAction()
{
   Value = "https://www.google.fr",
   Type = ActionTypes.PostBack,
   Title = "Acheter"
};
 
button = new CardAction()
{
   Value = "https://www.bing.fr",
   Type = ActionTypes.ImBack,
   Title = "Produits similaires"
};

 

Essayez ensuite d’ouvrir une session Skype sur deux environnements différents. Par exemple le Desktop et votre smartphone.

Cette fois un clic sur Google ne donnera une action visible (réaffichage de la carte) que sur l’environnement utilisé, tandis que le clic sur Bing sera visible partout.

Ces deux types sont intéressants pour simplement poster le contenu de Value vers le bot. C’est ce que nous allons faire dès le chapitre qui suit.

Lier une action à un dialogue

Pour l’instant les boutons se contentent de nous renvoyer vers Google ou Bing. Ce qui serait vraiment intéressant est de lancer un nouveau dialogue du bot. Allons y voir!

L’idée est de modifier la déclaration des boutons de la façon qui suit:

heroCard1.Buttons = new List<CardAction>();
CardAction button = new CardAction()
{
   Value = "id=12345",
   Type = ActionTypes.PostBack,
   Title = "Acheter"
};
heroCard1.Buttons.Add(button);
 
button = new CardAction()
{
   Value = "alter=12345",
   Type = ActionTypes.ImBack,
   Title = "Produits similaires"
};
heroCard1.Buttons.Add(button);

 

On passe ImBack dans Type. Puisque l’on va récupérer la valeur de Value, on organise ensuite un encodage. Le préfixe Id signifie que l’on achète le produit et on passe 12345, son Id.

Le préfixe alter demande de rechercher des produits similaires à 12345.

 

Côté dialogue on récupère facilement la valeur.

La ligne d’attente est celle-ci:


context.Wait(MessageReceivedAsync);

On va donc passer la réponse client à MessageReceivedAsync. On pourra donc écrire quelque chose du style:


IMessageActivity message = await argument;
string[] splitted = message.Text.Split('=');
if (splitted[0] == "Id")
{
   // on achète le produit
}
else
{
   // on cherche des produits similaires
}

 

Il ne reste plus qu’à remplir les vides.

Receipt card

On vient de créer une carte qui sert à faire un achat. Il existe justement une carte spécialisée, c’est la Receipt Card. Un bon exemple d’utilisation serait l’affichage d’un panier, c’est ce que nous allons faire:

ReceiptCard receiptCard1 = new ReceiptCard()
{
   Title = "Votre panier",
   Total = "40.0€",
   Tax = "4.0€",
   Vat = "10%"
};
 
#region Faits
Fact fact = new Fact("Bravo pour vos achats chez", "Bot's shop online");
receiptCard1.Facts = new List<Fact> { fact };
#endregion
 
#region Fiche produit
receiptCard1.Items = new List<ReceiptItem>();
var item = new ReceiptItem
{
   Title = "Super robot 2000",
   Image = new CardImage("https://jack35.files.wordpress.com/2016/09/133.jpg"),
   Price = "45 000€",
   Quantity = "1",
   Subtitle = "Le robot des clients exigeants",
   Text = ""
};
   receiptCard1.Items.Add(item);
 
item = new ReceiptItem
{
   Title = "Maxi Robot",
   Image = new CardImage("https://image.freepik.com/free-vector/coloured-robot-design_1148-9.jpg"),
   Price = "450€",
   Quantity = "1",
   Subtitle = "Le robot qu'il vous faut",
   Text = ""
};
receiptCard1.Items.Add(item);
#endregion
 
 
#region Boutons
receiptCard1.Buttons = new List<CardAction>();
CardAction button = new CardAction()
{
   Value = "https://www.google.fr",
   Type = ActionTypes.OpenUrl,
   Title = "Acheter"
};
receiptCard1.Buttons.Add(button);
 
button = new CardAction()
{
   Value = "https://www.bing.fr",
   Type = ActionTypes.OpenUrl,
   Title = "Continuer ses achats"
};
receiptCard1.Buttons.Add(button);
#endregion
 
IMessageActivity message = context.MakeMessage();
 
message.Attachments.Add(receiptCard1.ToAttachment());
 
await context.PostAsync(message);
context.Wait(MessageReceivedAsync);

Encore une fois le code est très simple, si j’avais un reproche à formuler, c’est que l’usage des Facts n’est pas très clair.

La classe importante est ReceiptItem qui permet d’alimenter la liste des produits du panier.

Visuellement:

2017-03-01_22-39-25

Les valeurs de prix sont très fantaisistes, mais vous voyez le principe.

 

Il existe d’autres sortes de cartes, je ne vais pas les inventorier ici, mais l’idée générale est toujours la même.

 

Bibliographie

 

Chanel inspector

 

Publicités

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s