Quelle approche pour la réalisation d’un chatbot ?

Nous avons eu l’occasion de travailler sur la mise en place d’un bot conversationnel pour réaliser une commande sur un site e-Commerce, le but était de créer un prototype fonctionnel en testant les différentes options disponibles sur le marché. Dans cet article, nous allons vous exposer notre démarche et nos conclusions.

Avant de commencer, voici quelques abréviations utilisées dans l’article :

  • NLP : Natural Language Processing, capacité d’identifier le type de chaque mot (verbes, noms, adjectifs…) et de structurer le sens d’un texte en langage naturel. Un article plus complet sur le sujet est disponible sur notre blog ;
  • NLU : Natural Language Understanding, capacité de comprendre un langage, par exemple pour déterminer une intention ou une émotion.

Les fonctionnalités désirées de l’application que nous allons construire sont les suivantes :

  • définir un jeu de données à remplir par l’utilisateur (la commande d’un produit) ;
  • pouvoir revenir à une étape précédente pour la corriger ;
  • pouvoir sélectionner des choix prédéfinis pour guider l’utilisateur facilement ;
  • supporter les entrées / sorties audio et textes ;
  • supporter le français.

La première étape a été de lister les outils pouvant nous servir pour accomplir ce POC. Grâce aux dernières avancées en termes d’intelligence artificielle et de language processing et notamment avec la commercialisation des assistants Google Home et Alexa, les géants de l’internet ont mis à disposition certains de leurs outils. Voici une liste, non exhaustive, des services faisant de l’IA et/ou du NLP :

Un autre outil à noter, mais que nous n’avons pas décidé d’utiliser est Sphinx, une librairie en C pour du NLP et qui a été compilée en JS. Elle semble supporter le français, mais lors des tests les résultats étaient très approximatifs.

Lex et Cognitive services

Lex était seulement disponible aux US en preview, il est depuis peu également disponible en Europe, mais seulement avec le support de l’anglais.

Cognitive services semble prometteur, avec de nombreux langages supportés et le streaming du support audio, ce qui n’était pas encore disponible lors de nos recherches. Ces deux services restent payants, nos recherches se sont donc focalisées sur ceux proposés par Google et Facebook.

Dialogflow (précédemment api.ai)

Premier essai avec ce service facile d’accès et gratuit : un compte Google et nous pouvons déjà démarrer avec un agent de test.

De manière générale, un robot de discussion cherche à comprendre ce que dit l’utilisateur. Il y a donc forcément une compréhension du langage qui est nécessaire (NLP), ainsi que de l’interprétation pour répondre correctement à l’utilisateur (NLU). Cette logique est traitée via les « Intents » dans ce service, qui se compose de plusieurs éléments :

  • Le contexte : le contexte permet de garder une liaison entre les différentes étapes du dialogue. Nous pouvons guider la discussion via l’utilisation de contextes d’entrée et de sortie.
  • Les événements permettent de forcer un Intent lors de la discussion, ce qui peut être pratique pour rajouter des interventions manuelles dans la discussion (par exemple, si l’utilisateur clique sur un bouton, l’intelligence lui répond).
  • Phrases d’entraînement : c’est ici qu’il va falloir « entraîner » votre bot en lui soumettant des phrases types. Dialogflow va par la suite gérer les synonymes ou pluriels de ce mot pour améliorer l’interprétation.
  • Les actions et paramètres sont le but principal de l’intent, dans la mesure où elles permettent de récupérer des informations exploitables par notre application. Ces informations sont appelées « Entities » et peuvent être typées dans le système (comme par exemple une date), ou être directement fournies par le développeur (comme par exemple les catégories de produits d’un site marchand). Pour chaque paramètre, nous pouvons spécifier son type, s’il est requis, ainsi que la question qui lui est associée.
  • Les « réponses » sont les réponses que le bot peut donner à l’utilisateur une fois que tous les paramètres ont été récupérés.

Voici une capture d’écran d’une intention permettant de récupérer une adresse et une date avant d’effectuer une livraison

Dialogflow

Une fois que vous avez défini les étapes avec chaque intent, vous pouvez les tester via l’intégration « Web demo ». Un grand nombre d’autres intégrations est disponible (Slack, Messenger, SMS avec Twilio ou encore Cortana / Alexa pour les assistants vocaux).

Web démo

Dans notre cas, nous voulions aussi pouvoir rajouter des choix prédéfinis, par exemple pour les accessoires. Une interface React très simple a été mise en place et nous appelons ainsi juste l’API pour créer notre discussion. Pour attacher des comportements spécifiques à des Intent, nous utilisons le « contexte » présenté plus haut :

const CHOICES = {
  [CONTEXT_SIZE]: [
    {value: 30, label: "30 roses : 26,50 €"},
    {value: 40, label: "40 roses : 29,50 €"},
    {value: 50, label: "50 roses : 34,50 €"},
    {value: 60, label: "60 roses : 39,50 €"},
    {value: 70, label: "70 roses : 44,50 €"}
  ]
};

Choices

Cette première approche s’est avérée très rapide à mettre en place, la principale complexité se trouvant à la création du flux de dialog dans Dialogflow (oui on se répète un peu, le nom est bien choisi).

Wit.ai et implémentation en JavaScript

Nous avons tenté une autre approche pour se passer de l’intelligence conversationnelle de Google et avoir un contrôle total sur l’arbre de discussion. Toutefois, il fallait un service pour comprendre l’utilisateur et Wit est justement fait pour ça.

Dans ces premières versions, le service proposait de construire un arbre logique pour guider la discussion, mais il est désormais dédié uniquement à la NLP. Le support des langages est impressionnant, avec plus de 70 langues et une détection très précise des intentions.

La partie NLP est donc couverte, mais il nous faut gérer toute la discussion de notre côté. Pour cela, nous avons implémenté une « state machine » très simple, qui s’occupe de naviguer et valider les différentes étapes.

export default class StepsManager {
  steps = {
    size: new Step({
      question: "Bienvenue, vous avez sélectionné un bouquet de rose. Quelle taille souhaitez-vous ?",
      choices: [
        {value: 30, label: "30 roses : 26,50 €"},
        {value: 40, label: "40 roses : 29,50 €"},
        {value: 50, label: "50 roses : 34,50 €"},
        {value: 60, label: "60 roses : 39,50 €"},
        {value: 70, label: "70 roses : 44,50 €"}
      ],
      validation: yup.number(),
      expectedNlpEntity: NLP_ENTITIES.NUMBER
    }),
    accessoriesAdd: new Step({
      question: "Souhaitez vous ajouter des accessoires ?",
      choices: [
        {value: "oui", label: "Oui"},
        {value: "non", label: "Non"},
      ],
      validation: yup.boolean()
    }),
    ...

Un simple appel à l’API avec le message de l’utilisateur permet d’identifier sa réponse et de lui proposer la prochaine étape.

const message = "40 roses : 29,50 €";
fetch(`https://api.wit.ai/message?q=${message}`, {
    headers: {
        Authorization: "Bearer SuperSecretToken"
    },
})

/**
{
   "_text": "40 roses : 29,50 \u20ac",
   "entities": {
      "number": [
         {
            "confidence": 1,
            "value": 40,
            "type": "value"
         },
         {
            "confidence": 1,
            "value": 29.5,
            "type": "value"
         }
      ]
   },
   "msg_id": "0yxt1uCPb5z73paiA"
}
**/

C’est un essai concluant, qui nous donne un contrôle total sur le dialogue, mais qui nécessite beaucoup plus de code pour atteindre l’objectif voulu. Si nous disposons de plus d’autonomie de flexibilité, cela se fait toutefois au prix de la simplicité, l’ensemble n’étant pas facilement modifiable par un non-développeur.

Conversational form

Lors de notre veille, ce projet intéressant avait déjà attiré notre attention. Le principe est d’étendre un formulaire déjà existant pour le transformer en dialogue.

Conversational form

L’API est simple, il suffit d’ajouter des attributs sur les éléments du formulaire :

<select cf-questions="Bienvenue, vous avez sélectionné un bouquet de rose. Quelle taille souhaitez-vous ?" name="size">
    <option value="30">30 roses : 26,50 €</option>
    <option value="40">40 roses : 29,50 €</option>
    <option value="50">50 roses : 34,50 €</option>
    <option value="60">60 roses : 39,50 €</option>
    <option value="70">70 roses : 44,50 €</option>
</select>

La conversation va ainsi respecter l’ordre du formulaire dans le DOM. Cette approche est facile à mettre en place, mais ne comprend pas d’intelligence ou d’interprétation des réponses.

Le module JS nous permet toutefois, via son API, d’interagir avec les données reçues. Par exemple, pour un champ de type date, il est intéressant de rajouter du NLP pour que l’utilisateur puisse simplement répondre « demain à 8h ».

ConversationalForm.startTheConversation({
      flowStepCallback: (dto, success, error) => {
        if (dto.tag.name === "date") {
            fetch(`https://api.wit.ai/message?q=${dto.tag.value}`)
            .then(response => response.json())
            .then(json => {
              const value = json.entities.datetime[0].value;
              // Set the value of the input

Interprétation de l’audio et synthèse vocale

Les trois exemples précédents répondent aux problématiques de dialogue, mais un de nos prérequis est de pouvoir supporter une entrée vocale et une sortie vocale.

La reconnaissance automatique du langage n’est hélas disponible que pour Chrome, en utilisant l’API Speech de Google. Nous pouvons toutefois souligner l’effort de Mozilla avec le projet open source Common Voice pour collecter des voix et entrainer le modèle DeepSpeech 👍.

Une première implémentation à l’aide du module annyang nous a permis d’ajouter cette fonctionnalité très rapidement :

annyang.debug(true);
annyang.setLanguage('fr-FR');
annyang.addCallback('result', (phrases) => {
    const message = phrases[0];
    this.dialogFlowClient.textRequest(message)
        .then(this.handleResponse)
        .catch(this.handleError)
    ;
});

Toutefois, cette approche ne supporte que Chrome et nous avons donc expérimenté avec une autre API de Wit.ai pour envoyer directement de l’audio. Cela soulève un autre problème, qui est celui de savoir quand l’utilisateur parle et quand est-ce qu’il s’arrête de parler. Pour cela, nous avons inclus le javascript du plugin Cordova audioinput pour enregistrer le flux audio et l’envoyer à Wit.

const onSpeechCaptured = (blob) => {
    fetch(`https://api.wit.ai/speech`, {
      method: "POST",
      body: blob,
      headers: {
        Authorization: "Bearer SuperSecretToken",
        "Content-Type": "audio/wav"
      }
    })
    .then((response) => {
        // ... handle NLP response
    });
};

speechcapture.start(config, onSpeechCaptured, onSpeechError, onSpeechStatus);

Il nous reste à couvrir la sortie vocale, en utilisant l’API Speech Synthesis qui est, heureusement, déjà bien supportée par les navigateurs.

function synthVoice(text) {
  const synth = window.speechSynthesis;
  const utterance = new SpeechSynthesisUtterance();
  utterance.text = text;
  utterance.lang = "fr-FR"
  synth.speak(utterance);
}

Conclusion

Le défi est terminé et nous avons plusieurs solutions pour répondre au besoin.

  • une première approche avec toute l’intelligence dans le service Dialogflow, que nous pouvons améliorer en ajoutant une interface ou relier très facilement à un système de messages tel que Facebook Messenger ;
  • une approche nous donnant un contrôle total, avec une implémentation d’un workflow maison et le service Wit ;
  • et enfin l’excellent Conversational form, pour créer très rapidement un dialogue avec une interface sur un formulaire existant.

Avez-vous déjà implémenté un bot conversationnel pour vos clients ? N’hésitez pas à partager vos problématiques et les outils choisis dans les commentaires !

blog comments powered by Disqus