Fermer

janvier 14, 2021

Intégration d'un agent Dialogflow dans une application React


À propos de l'auteur

Nwani Victory travaille en tant qu'ingénieur frontend chez Liferithms.inc de Lagos, Nigeria. Après les heures de bureau, il se double d'un ingénieur cloud à la recherche de moyens de faire du cloud…
En savoir plus sur
Nwani

Lorsqu'il s'agit de créer un assistant de conversation conversationnel qui pourrait être utilisé au niveau d'une petite ou d'une entreprise, Dialogflow serait probablement l'une des premières options à apparaître dans votre liste de recherche – et pourquoi ne le ferait pas. t-il? Il offre plusieurs fonctionnalités telles que la possibilité de traiter les entrées audio et textuelles, de fournir des réponses dynamiques à l'aide de webhooks personnalisés, de se connecter à des millions d'appareils compatibles Google à l'aide de l'assistant Google, et bien plus encore. Mais à part sa console qui est fournie pour concevoir et gérer un agent, comment pouvons-nous créer un assistant de discussion qui peut également être utilisé dans nos applications Web intégrées?

Dialogflow est une plate-forme qui simplifie la processus de création et de conception d'un assistant de conversation conversationnel de traitement du langage naturel qui peut traiter la saisie vocale ou de texte lorsqu'il est utilisé à partir de la console Dialogflow ou d'une application Web intégrée.

Bien que l'agent Dialogflow intégré soit brièvement expliqué dans cet article, il doit comprendre Node.js et Dialogflow. Si vous découvrez Dialogflow pour la première fois, cet article donne une explication claire de ce qu'est Dialogflow et de ses concepts.

Cet article est un guide sur la création d'un Agent Dialogflow avec prise en charge de la voix et du chat qui peut être intégré dans une application Web à l'aide d'une application back-end Express.js comme lien entre une application Web React.js et l'agent sur Dialogflow lui-même. À la fin de l'article, vous devriez être en mesure de connecter votre propre agent Dialogflow à votre application Web préférée.

Pour rendre ce guide facile à suivre, vous pouvez passer à la partie du didacticiel qui vous intéresse le plus ou les suivre dans l'ordre suivant tel qu'ils apparaissent:

1. Configuration d'un agent Dialogflow

Comme expliqué dans cet article un assistant de discussion sur Dialogflow est appelé un agent et il comprend des composants plus petits tels que intentions réalisation base de connaissances et bien plus encore. Dialogflow fournit une console permettant aux utilisateurs de créer, former et concevoir le flux de conversation d'un agent. Dans notre cas d'utilisation, nous allons restaurer un agent qui a été exporté dans un dossier ZIP après avoir été formé, à l'aide de la fonction Export and Import .

Avant d'effectuer l'importation, nous devons créer un nouveau agent qui sera fusionné avec l'agent sur le point d'être restauré. Pour créer un nouvel agent à partir de la console, un nom unique est nécessaire ainsi qu'un projet sur le Google Cloud pour lier l'agent. S'il n'y a pas de projet existant sur Google Cloud avec lequel établir un lien, un nouveau peut être créé ici .

Un agent a été précédemment créé et formé pour recommander des produits viticoles à un utilisateur en fonction de son budget . Cet agent a été exporté dans un ZIP; vous pouvez télécharger le dossier ici et le restaurer dans notre agent nouvellement créé à partir de l'onglet Exporter et importer de la page Paramètres de l'agent.

 Restauration d'un agent précédemment exporté à partir d'un ZIP dossier
Restauration d'un agent précédemment exporté à partir d'un dossier ZIP. ( Grand aperçu )

L'agent importé a été préalablement formé pour recommander un produit vinicole à l'utilisateur en fonction du budget de l'utilisateur pour l'achat d'une bouteille de vin.

En passant par l'agent importé, nous verra qu'il a trois intentions créées à partir de la page des intentions. L'une étant une intention de secours, utilisée lorsque l'agent ne reconnaît pas l'entrée d'un utilisateur, l'autre est une intention de bienvenue utilisée lorsqu'une conversation avec l'agent est démarrée, et la dernière intention est utilisée pour recommander un vin à l'utilisateur en fonction de la paramètre de quantité dans la phrase. L'intention get-wine-recommendation

Cette intention a une seule entrée contexte de wine-recommendation provenant de l'intention de bienvenue par défaut pour lier la conversation à cette intention.

«Un Contexte est un système au sein d'un Agent utilisé pour contrôler le flux d'une conversation d'une intention à l'autre.»

Sous le Les contextes sont les Phrases de formation qui sont des phrases utilisées pour former un agent sur le type de déclarations à attendre d'un utilisateur. Grâce à une grande variété de phrases de formation au sein d'un intent, un agent est capable de reconnaître la phrase d'un utilisateur et l'intention dans laquelle elle s'inscrit.

Les phrases de formation de nos agents get-wine-recommendation intent (as ci-dessous) indique le choix du vin et la catégorie de prix:

 Liste des phrases de formation disponibles avec l'intention de recommandation de vin.
Page d'intention de recommandation de vin avec les phrases de formation disponibles. ( Grand aperçu )

En regardant l'image ci-dessus, nous pouvons voir les phrases d'entraînement disponibles répertoriées, et le chiffre de la devise est surligné en jaune pour chacun d'eux. Cette mise en évidence est connue sous le nom d'annotation sur Dialogflow et elle est automatiquement effectuée pour extraire les types de données reconnus, appelés entité, de la phrase d'un utilisateur.

Une fois que cette intention a été mise en correspondance dans une conversation avec l'agent, une requête HTTP sera fait à un service externe pour obtenir le vin recommandé en fonction du prix extrait en tant que paramètre de la phrase d'un utilisateur, via l'utilisation du webhook activé trouvé dans la section Fulfillment au bas de cette page d'intention.

Nous pouvons tester le agent à l'aide de l'émulateur Dialogflow situé dans la section droite de la console Dialogflow. Pour tester, nous commençons la conversation avec un message « Bonjour » et suivons avec la quantité de vin désirée. Le webhook sera immédiatement appelé et une réponse riche similaire à celle ci-dessous sera affichée par l'agent.

 Test du webhook d'agent importé.
Test du webhook d'exécution de l'agent importé à l'aide de l'émulateur d'agent dans la console. ( Grand aperçu )

À partir de l'image ci-dessus, nous pouvons voir l'URL du webhook générée avec Ngrok et la réponse de l'agent sur le côté droit montrant un vin dans la fourchette de prix de 20 $ saisi par l'utilisateur.

À ce stade, l'agent Dialogflow a été entièrement configuré. Nous pouvons maintenant commencer à intégrer cet agent dans une application Web pour permettre à d'autres utilisateurs d'accéder et d'interagir avec l'agent sans accéder à notre console Dialogflow .

Intégration d'un agent Dialogflow

Bien qu'il existe d'autres moyens de se connecter à un agent Dialogflow, comme faire des requêtes HTTP à ses points de terminaison REST la méthode recommandée pour se connecter à Dialogflow consiste à utiliser sa bibliothèque client officielle disponible dans plusieurs langages de programmation. Pour JavaScript, le package @ google-cloud / dialogflow peut être installé à partir de NPM .

En interne, le package @ google-cloud / dialogflow utilise gRPC pour ses connexions réseau, ce qui rend le paquet non pris en charge dans un environnement de navigateur sauf lorsqu'il est patché à l'aide de webpack la manière recommandée d'utiliser ce paquet est à partir d'un environnement Node. Nous pouvons le faire en configurant une application back-end Express.js pour utiliser ce package puis servir des données à l'application Web via ses points de terminaison API et voici ce que nous ferons ensuite.

Configuration d'une application Node Express [19659003] Pour configurer une application express, nous créons un nouveau répertoire de projet puis récupérons les dépendances nécessaires en utilisant yarn à partir d'un terminal de ligne de commande ouvert.
 # créer un nouveau répertoire et (&&) déplacer dans le répertoire
mkdir dialogflow-server && cd dialogflow-server

# créer un nouveau projet Node
fil init -y

# Installer les packages nécessaires
fil ajouter express cors dotenv uuid

Une fois les dépendances nécessaires installées, nous pouvons procéder à la configuration d'un serveur Express.js très léger qui gère les connexions sur un port spécifié avec le support CORS activé pour l'application Web.

 // index.js
const express = require ("express")
const dotenv = require ("dotenv")
const cors = require ("cors")

dotenv.config ();

const app = express ();
const PORT = process.env.PORT || 5000;

app.use (cors ());

app.listen (PORT, () => console.log (`🔥 serveur fonctionnant sur le port $ {PORT}`)); 

Lorsqu'il est exécuté, le code de l'extrait ci-dessus démarre un serveur HTTP qui écoute les connexions sur un spécifié PORT Express.js. Il a également Cross-origin resource sharing (CORS) activé sur toutes les demandes utilisant le package cors comme middleware Express . Pour l'instant, ce serveur n'écoute que les connexions, il ne peut pas répondre à une requête car il n'a pas de route créée alors créons ceci.

Nous devons maintenant ajouter deux nouvelles routes: une pour l'envoi de texte données tandis que l'autre pour envoyer une entrée vocale enregistrée. Ils accepteront tous les deux une requête POST et enverront les données contenues dans le corps de la requête à l'agent Dialogflow ultérieurement.

 const express = require ("express")

const app = express ()

app.post ("/ text-input", (req, res) => {
  res.status (200) .send ({data: "TEXT ENDPOINT CONNECTION SUCCESSFUL"})
});

app.post ("/ voice-input", (req, res) => {
  res.status (200) .send ({data: "VOICE ENDPOINT CONNECTION SUCCESSFUL"})
});

module.exports = app 

Ci-dessus, nous avons créé une instance de routeur distincte pour les deux routes POST créées qui pour l'instant, ne répondent qu'avec un code d'état 200 et une réponse factice codée en dur. Lorsque nous avons terminé l'authentification avec Dialogflow, nous pouvons revenir pour implémenter une connexion réelle à Dialogflow au sein de ces points de terminaison.

Pour la dernière étape de la configuration de notre application backend, nous montons l'instance de routeur créée précédemment dans l'application Express en utilisant app.use et un chemin de base pour l'itinéraire.

 // agentRoutes.js

const express = require ("express")
const dotenv = require ("dotenv")
const cors = require ("cors")

const Routes = require ("./ routes")

dotenv.config ();
const app = express ();
const PORT = process.env.PORT || 5000;

app.use (cors ());

app.use ("/ api / agent", Routes);

app.listen (PORT, () => console.log (`🔥 serveur fonctionnant sur le port $ {PORT}`));

Ci-dessus, nous avons ajouté un chemin de base aux deux routes, deux nous pouvons tester n'importe laquelle d'entre elles via une requête POST en utilisant cURL à partir d'une ligne de commande comme ci-dessous avec un corps de la requête vide;

 curl -X http: // localhost: 5000 / api / agent / text-response 

Une fois la requête ci-dessus terminée, nous pouvons nous attendre à voir une réponse contenant des données d'objet imprimées sur

Il ne nous reste plus qu'à établir une connexion réelle avec Dialogflow qui comprend la gestion de l'authentification, l'envoi et la réception des données de l'agent sur Dialogflow à l'aide du package @ google-cloud / dialogflow .

] Authentification avec Dialogflow

Chaque agent Dialogflow créé est lié à un projet sur le Google Cloud . Pour nous connecter en externe à l'agent Dialogflow, nous nous authentifions auprès du projet sur le cloud Google et utilisons Dialogflow comme l'une des ressources du projet. Sur les six méthodes disponibles pour se connecter à un projet sur le cloud Google, l’option Comptes de service est la plus pratique lors de la connexion à un service particulier sur le cloud Google via son bibliothèque cliente.

Remarque : Pour les applications prêtes pour la production, l'utilisation de clés API de courte durée est recommandée par rapport aux clés de compte de service afin de réduire le risque qu'une clé de compte de service pénètre dans

Que sont les comptes de service?

Les comptes de service sont un type spécial de compte sur le Google Cloud créé pour une interaction non humaine, principalement via des Apis. Dans notre application, le compte de service sera accessible via une clé générée par la bibliothèque cliente Dialogflow pour s'authentifier auprès de Google Cloud.

La documentation cloud sur la création et la gestion des comptes de service fournit une excellente guide pour créer un compte de service. Lors de la création du compte de service, le rôle Administrateur d'API Dialogflow doit être attribué au compte de service créé, comme indiqué à la dernière étape. Ce rôle donne au compte de service un contrôle administratif sur l'agent Dialogflow lié.

Pour utiliser le compte de service, nous devons créer une Clé de compte de service . Les étapes suivantes expliquent comment en créer un au format JSON:

  1. Cliquez sur le compte de service nouvellement créé pour accéder à la page du compte de service.
  2. Faites défiler jusqu'à la section Clés et cliquez sur Ajouter une clé menu déroulant et cliquez sur l'option Créer une nouvelle clé qui ouvre un modal.
  3. Sélectionnez un format de fichier JSON et cliquez sur le bouton Créer en bas à droite du modal.

Remarque: Il est recommandé de garder une clé de compte de service privée et de ne pas la valider dans un système de contrôle de version car elle contient des données très sensibles sur un projet sur Google Cloud. Cela peut être fait en ajoutant le fichier au fichier .gitignore .

Avec un compte de service créé et une clé de compte de service disponible dans le répertoire de notre projet, nous pouvons utiliser la bibliothèque cliente Dialogflow pour envoyer et recevoir des données de l'agent Dialogflow.

 // agentRoute.js
require ("dotenv"). config ();

const express = require ("express")
const Dialogflow = require ("@ google-cloud / dialogflow")
const {v4 as uuid} = require ("uuid")
const Path = require ("chemin")
 
const app = express ();

app.post ("/ text-input", async (req, res) => {
  const {message} = req.body;

  // Créer une nouvelle session
   const sessionClient = new Dialogflow.SessionsClient ({
    keyFilename: Path.join (__ dirname, "./key.json"),
  });

  const sessionPath = sessionClient.projectAgentSessionPath (
    process.env.PROJECT_ID,
    uuid ()
  );

  // L'objet de requête de dialogflow
  demande const = {
    session: sessionPath,
    queryInput: {
      texte: {
        // La requête à envoyer à l'agent de dialogue
        message texte,
      },
    },
  };

  // Envoie les données de l'agent en réponse
  essayez {
    réponses const = attendre sessionClient.detectIntent (demande);
    res.status (200) .send ({données: réponses});
  } catch (e) {
    console.log (e);
    res.status (422) .send ({e});
  }
});

module.exports = application;

L'ensemble de l'itinéraire ci-dessus envoie des données à l'agent Dialogflow et reçoit une réponse à travers les étapes suivantes.

  • D'abord
    Il s'authentifie avec le cloud Google puis crée une session avec Dialogflow en utilisant le projectID du projet cloud Google lié à l'agent Dialogflow et également un ID aléatoire pour identifier la session créée. Dans notre application, nous créons un identifiant UUID sur chaque session créée à l'aide du package JavaScript UUID . Ceci est très utile lors de la journalisation ou du suivi de toutes les conversations gérées par un agent Dialogflow.
  • Second
    Nous créons un objet de requête de données suivant le format spécifié dans la documentation Dialogflow. Cet objet de requête contient la session créée et les données de message extraites du corps de la requête qui doivent être transmises à l'agent Dialogflow.
  • Third
    Utilisation de la méthode detectIntent de la session Dialogflow , nous envoyons l'objet de requête de manière asynchrone et attendons la réponse de l'agent en utilisant la syntaxe ES6 async / await dans un bloc try-catch si la méthode detectIntent renvoie une exception, nous pouvons intercepter l'erreur et renvoyez-le, plutôt que de planter l'application entière. Un échantillon de l'objet de réponse renvoyé par l'agent est fourni dans la documentation de Dialogflow et peut être inspecté pour savoir comment extraire les données de l'objet.

Nous pouvons utiliser Postman pour tester le Dialogflow connexion implémentée ci-dessus dans la route dialogflow-response . Postman est une plate-forme de collaboration pour le développement d'API avec des fonctionnalités permettant de tester les API intégrées aux étapes de développement ou de production.

Remarque: Si elle n'est pas déjà installée, l'application de bureau Postman n'est pas nécessaire pour tester une API. À partir de septembre 2020, le client Web de Postman est passé à un état généralement disponible (GA) et peut être utilisé directement à partir d'un navigateur.

En utilisant le client Web Postman, nous pouvons soit créer un nouvel espace de travail, soit utiliser un espace existant pour créer une requête POST à notre point de terminaison API à http: // localhost: 5000 / api / agent / text-input et ajouter des données avec une clé de message ] et la valeur de « Bonjour » dans les paramètres de la requête.

En cliquant sur le bouton Envoyer une demande POST sera adressée au exécutant le serveur Express – avec une réponse similaire à celle illustrée dans l'image ci-dessous:

 Test du point de terminaison de l'API de saisie de texte à l'aide de Postman.
Test du point de terminaison de l'API de saisie de texte à l'aide de Postman. ( Grand aperçu )

Dans l'image ci-dessus, nous pouvons voir les données de réponse jolies de l'agent Dialogflow via le serveur Express. Les données renvoyées sont formatées selon la définition de l'exemple de réponse donnée dans la documentation Dialogflow Webhook .

Gestion des entrées vocales

Par défaut, tous les agents Dialogflow sont activés pour traiter les deux texte et audio et renvoie également une réponse au format texte ou audio. Cependant, travailler avec des données d'entrée ou de sortie audio peut être un peu plus complexe que des données textuelles.

Pour gérer et traiter les entrées vocales, nous commencerons l'implémentation du point de terminaison / voice-input que nous avons précédemment créés pour recevoir des fichiers audio et les envoyer à Dialogflow en échange d'une réponse de l'agent:

 // agentRoutes.js
import {pipeline, Transform} depuis "stream";
importer busboy depuis "connect-busboy";
importation util de "promisfy"
importer Dialogflow depuis "@ google-cloud / dialogflow"

const app = express ();

app.use (
  busboy ({
    immédiat: vrai,
  })
);

app.post ("/ voice-input", (req, res) => {
  const sessionClient = new Dialogflow.SessionsClient ({
    keyFilename: Path.join (__ dirname, "./recommender-key.json"),
  });
  const sessionPath = sessionClient.projectAgentSessionPath (
    process.env.PROJECT_ID,
    uuid ()
  );

  // se transforme en promesse
  pompe const = util.promisify (pipeline);

  const audioRequest = {
    session: sessionPath,
    queryInput: {
      audioConfig: {
        audioEncoding: "AUDIO_ENCODING_OGG_OPUS",
        sampleRateHertz: "16000",
        languageCode: "en-US",
      },
      singleUtterance: vrai,
    },
  };
  
  const streamData = null;
  const detectStream = sessionClient
    .streamingDetectIntent ()
    .on ("erreur", (erreur) => console.log (erreur))
    .on ("données", (données) => {
      streamData = data.queryResult
    })
    .on ("fin", (données) => {
      res.status (200) .send ({données: streamData.fulfillmentText}}
    })
  
  detectStream.write (audioRequest);

  essayez {
    req.busboy.on ("fichier", (_, fichier, nom de fichier) => {
      pompe(
        fichier,
        nouvelle transformation ({
          objectMode: vrai,
          transformer: (obj, _, suivant) => {
            suivant (nul, {inputAudio: obj});
          },
        }),
        detectStream
      );
    });
  } catch (e) {
    console.log (`erreur: $ {e}`);
  }
});

Avec une vue d'ensemble élevée, la route / entrée vocale ci-dessus reçoit l'entrée vocale d'un utilisateur sous la forme d'un fichier contenant le message en cours de parole à l'assistant de discussion et l'envoie à l'agent Dialogflow. Pour mieux comprendre ce processus, nous pouvons le décomposer en étapes plus petites suivantes:

  • Tout d'abord, nous ajoutons et utilisons connect-busboy comme middleware Express pour analyser les données de formulaire. envoyé dans la demande depuis l'application Web. Après quoi nous nous authentifions avec Dialogflow à l'aide de la clé de service et créons une session, de la même manière que nous l'avons fait dans l'itinéraire précédent.
    Puis en utilisant la méthode promisify de la Node.js intégrée module util nous obtenons et sauvegardons un équivalent promis de la méthode de pipeline Stream à utiliser plus tard pour canaliser plusieurs flux et également effectuer un nettoyage une fois les flux terminés.
  • Ensuite, nous créons une requête objet contenant la session d'authentification Dialogflow et une configuration pour le fichier audio sur le point d'être envoyé à Dialogflow. L'objet de configuration audio imbriqué permet à l'agent Dialogflow d'effectuer une conversion Speech-To-Text sur le fichier audio envoyé.
  • Ensuite, en utilisant la session créée et l'objet de requête, nous détectons l'intention d'un utilisateur à partir de le fichier audio utilisant la méthode detectStreamingIntent qui ouvre un nouveau flux de données de l'agent Dialogflow vers l'application principale. Les données seront renvoyées par petits bits à travers ce flux et en utilisant les données « event » du flux lisible, nous stockons les données dans la variable streamData pour une utilisation ultérieure. Une fois le flux fermé, l'événement « end » est déclenché et nous envoyons la réponse de l'agent Dialogflow stockée dans la variable streamData à l'application Web.
  • Enfin, utilisation du fichier stream de connect-busboy nous recevons le flux du fichier audio envoyé dans le corps de la requête et nous le passons ensuite dans l'équivalent promis de Pipeline que nous avons créé précédemment. La fonction de ceci est de diriger le flux de fichier audio provenant de la requête vers le flux Dialogflow, nous dirigeons le flux de fichier audio vers le flux ouvert par la méthode detectStreamingIntent ci-dessus.

Pour tester et confirmer que les étapes ci-dessus fonctionnent comme prévu, nous pouvons faire une requête de test contenant un fichier audio dans le corps de la requête au point de terminaison / voice-input à l'aide de Postman.

 Test du point de terminaison de l'API d'entrée vocale à l'aide de Postman.
Test du point de terminaison de l'API d'entrée vocale en utilisant Postman avec un fichier vocal enregistré. ( Grand aperçu )

Le résultat Postman ci-dessus montre la réponse obtenue après avoir fait une demande POST avec les données de formulaire d'un message vocal enregistré disant " Salut " inclus dans le

À ce stade, nous avons maintenant une application Express.js fonctionnelle qui envoie et reçoit des données de Dialogflow, les deux parties de cet article sont terminées. Où en est-il maintenant de l'intégration de cet agent dans une application Web en utilisant les API créées ici à partir d'une application Reactjs .

Intégration dans une application Web

Pour utiliser notre API REST intégrée, nous allons développer cette application React.js existante qui a déjà une page d'accueil montrant une liste de vins récupérés à partir d'une API et le support pour les décorateurs utilisant le plugin de décorateurs de proposition babel . Nous allons le refactoriser un peu en introduisant Mobx pour la gestion de l'état et aussi une nouvelle fonctionnalité pour recommander un vin à partir d'un composant de chat en utilisant les points de terminaison API REST ajoutés de l'application Express.js.

Pour commencer , nous commençons à gérer l'état de l'application en utilisant MobX alors que nous créons un magasin Mobx avec quelques valeurs observables et des méthodes comme actions .

 // store.js

importer Axios depuis "axios";
import {action, observable, makeObservable, configure} depuis "mobx";

const ENDPOINT = process.env.REACT_APP_DATA_API_URL;

class ApplicationStore {
  constructeur () {
    makeObservable (this);
  }

  @observable
  isChatWindowOpen = false;

  @observable
  isLoadingChatMessages = false;

  @observable
  agentMessages = [];

  @action
  setChatWindow = (état) => {
    this.isChatWindowOpen = état;
  };

  @action
  handleConversation = (message) => {
     this.isLoadingChatMessages = true;
     this.agentMessages.push ({userMessage: message});

     Axios.post (`$ {ENDPOINT} / dialogflow-response`, {
      message: message || "Salut",
     })
      .then ((res) => {
        this.agentMessages.push (res.data.data [0] .queryResult);
        this.isLoadingChatMessages = false;
      })
      .catch ((e) => {
        this.isLoadingChatMessages = false;
        console.log (e);
      });
  };
}

export const store = new ApplicationStore (); 

Ci-dessus, nous avons créé un magasin pour la fonctionnalité de composant de chat dans l'application avec les valeurs suivantes:

  • isChatWindowOpen
    La valeur stockée ici contrôle la visibilité du chat composant dans lequel les messages de Dialogflow sont affichés.
  • isLoadingChatMessages
    Ceci est utilisé pour afficher un indicateur de chargement lorsqu'une demande de récupération d'une réponse de l'agent Dialogflow est effectuée.
  • agentMessages [19659100] Ce tableau stocke toutes les réponses provenant des requêtes faites pour obtenir une réponse de l'agent Dialogflow. Les données du tableau sont ensuite affichées dans le composant.
  • handleConversation
    Cette méthode décorée comme une action ajoute des données dans le tableau agentMessages . Tout d'abord, il ajoute le message de l'utilisateur transmis en tant qu'argument, puis fait une requête à l'aide de Axios à l'application backend pour obtenir une réponse de Dialogflow. Une fois la demande résolue, il ajoute la réponse de la demande dans le tableau agentMessages .

Remarque: En l'absence du support decorators dans un Application, MobX fournit makeObservable qui peut être utilisé dans le constructeur de la classe de stockage cible. Voir un exemple ici .

Avec la configuration du magasin, nous devons envelopper l'ensemble de l'arborescence des applications avec le composant d'ordre supérieur du fournisseur MobX à partir du composant racine dans index.js ] fichier.

 import React de "react";
import {Provider} de "mobx-react";

import {store} de "./state/";
importer la page d'accueil de "./pages/home";

function App () {
  revenir (
    
      
); } exporter l'application par défaut;

Ci-dessus, nous enveloppons le composant d'application racine avec MobX Provider et nous transmettons le magasin précédemment créé comme l'une des valeurs du fournisseur. Nous pouvons maintenant procéder à la lecture depuis le magasin dans les composants connectés au magasin.

Création d'une interface de chat

Pour afficher les messages envoyés ou reçus à partir des requêtes API, nous avons besoin d'un nouveau composant avec une interface de chat affichant les messages énumérés. Pour ce faire, nous créons un nouveau composant pour afficher d'abord certains messages codés en dur, puis plus tard, nous affichons les messages dans une liste ordonnée.

 // ./chatComponent.js

import React, {useState} de "react";
importer {FiSend, FiX} depuis "react-icons / fi";
import "../styles/chat-window.css";

centre const = {
  affichage: "flex",
  jusitfyContent: "centre",
  alignItems: "center",
};

const ChatComponent = (accessoires) => {
  const {closeChatwindow, isOpen} = accessoires;
  const [Message, setMessage] = useState ("");

  revenir (
   
Zara
closeChatwindow ()} />
  • Bonjour, bienvenue dans notre agent


{}} className = "input-container"> setMessage (e.target.value)} valeur = {Message} placeholder = "Commencer une conversation avec notre agent" />
{}}>
); }; export default ChatComponent

Le composant ci-dessus contient le balisage HTML de base nécessaire pour une application de chat. Il a un en-tête indiquant le nom de l'agent et une icône pour fermer la fenêtre de discussion, une bulle de message contenant un texte codé en dur dans une balise de liste, et enfin un champ de saisie ayant un gestionnaire d'événements onChange attaché au champ de saisie pour stocker le texte saisi dans l'état local du composant à l'aide de React useState .

 Un aperçu du composant Chat avec un message codé en dur de l'agent de chat
Un aperçu du composant Chat avec un disque message codé de l'agent de chat. ( Grand aperçu )

À partir de l'image ci-dessus, le composant de discussion fonctionne comme il se doit, affichant une fenêtre de discussion stylée comportant un seul message de discussion et le champ de saisie en bas. Nous voulons cependant que le message affiché soit des réponses réelles obtenues à partir de la requête API et non du texte codé en dur.

Nous allons de l'avant pour refactoriser le composant Chat, cette fois en connectant et en utilisant les valeurs du magasin MobX au sein du composant. [19659037] // ./components/chatComponent.js

import React, {useState, useEffect} de "react";
importer {FiSend, FiX} depuis "react-icons / fi";
import {observer, injecter} de "mobx-react";
import {toJS} de "mobx";
import "../styles/chat-window.css";

centre const = {
affichage: "flex",
jusitfyContent: "centre",
alignItems: "center",
};

const ChatComponent = (accessoires) => {
const {closeChatwindow, isOpen} = accessoires;
const [Message, setMessage] = useState ("");

const {
handleConversation,
agentMessages,
isLoadingChatMessages,
} = props.ApplicationStore;

useEffect (() => {
handleConversation ();
return () => handleConversation ()
}, []);

const data = toJS (agentMessages);

revenir (

Zara {isLoadingChatMessages && "est en train de taper ..."}
closeChatwindow ()} />
    {data.map (({fillmentText, userMessage}) => (
  • {userMessage && (

    .

    {userMessage}

    )}
    {FillmentText && (

    {FillmentText}

    .

    )}

  • ))}


{
e.preventDefault ();
handleConversation (Message);
}}
className = "conteneur d'entrée"
>
setMessage (e.target.value)}
valeur = {Message}
placeholder = "Commencer une conversation avec notre agent"
/>
handleConversation (Message)}
>

);
};

export par défaut inject ("ApplicationStore") (observer (ChatComponent));

À partir des parties en surbrillance du code ci-dessus, nous pouvons voir que tout le composant de chat a maintenant été modifié pour effectuer les nouvelles opérations suivantes:

  • Il a accès aux valeurs du magasin MobX après avoir injecté le ApplicationStore valeur. Le composant a également été rendu un observateur de ces valeurs de stockage afin qu'il effectue un nouveau rendu lorsque l'une des valeurs change.
  • Nous commençons la conversation avec l'agent immédiatement après l'ouverture du composant de chat en invoquant le handleConversation ] dans un hook useEffect pour faire une requête immédiatement le composant est rendu.
  • Nous utilisons maintenant la valeur isLoadingMessages dans l'en-tête du composant Chat. Lorsqu'une demande pour obtenir une réponse de l'agent est en cours, nous définissons la valeur isLoadingMessages sur true et mettons à jour l'en-tête sur Zara tape…
  • ] Le tableau agentMessages du magasin est mis à jour vers un proxy par MobX une fois ses valeurs définies. À partir de ce composant, nous reconvertissons ce proxy en un tableau en utilisant l'utilitaire toJS de MobX et stockons les valeurs dans une variable au sein du composant. Ce tableau est ensuite itéré pour remplir les bulles de discussion avec les valeurs du tableau en utilisant une fonction de carte.

En utilisant maintenant le composant de discussion, nous pouvons taper une phrase et attendre qu'une réponse soit affichée dans l'agent.

 ]Chat component showing a list data returned from the HTTP request to the express application.
Chat component showing a list data returned from the HTTP request to the express application. (Large preview)

Recording User Voice Input

By default, all Dialogflow agents can accept either voice or text-based input in any specified language from a user. However, it requires a few adjustments from a web application to gain access to a user’s microphone and record a voice input.

To achieve this, we modify the MobX store to use the HTML MediaStream Recording API to record a user’s voice within two new methods in the MobX store.

// store.js

import Axios from "axios";
import { action, observable, makeObservable } from "mobx";

class ApplicationStore {
  constructor() {
    makeObservable(this);
  }

  @observable
  isRecording = false;

  recorder = null;
  recordedBits = [];

  @action
  startAudioConversation = () => {
    navigator.mediaDevices
      .getUserMedia({
        audio: true,
      })
      .then((stream) => {
        this.isRecording = true;
        this.recorder = new MediaRecorder(stream);
        this.recorder.start(50);

        this.recorder.ondataavailable = (e) => {
           this.recordedBits.push(e.data);
        };
      })
      .catch((e) => console.log(`error recording : ${e}`));
  };
};

At the click of the record icon from the chat component, the startAudioConversation method in the MobX store above is invoked to set the method the observable isRecording property is to true , for the chat component to provide visual feedback to show a recording is in progress.

Using the browser’s navigator interface, the Media Device object is accessed to request the user’s device microphone. After permission is granted to the getUserMedia request, it resolves its promise with a MediaStream data which we further pass to the MediaRecorder constructor to create a recorder using the media tracks in the stream returned from the user’s device microphone. We then store the Media recorder instance in the store’s recorder property as we will access it from another method later on.

Next, we call the start method on the recorder instance, and after the recording session is ended, the ondataavailable function is fired with an event argument containing the recorded stream in a Blob which we store in the recordedBits array property.

Logging out the data in the event argument passed into the fired ondataavailable event, we can see the Blob and its properties in the browser console.

Browser Devtools console showing logged out Blob created by the Media Recorder after a recording is ended.Pull Quotes
Browser Devtools console showing logged out Blob created by the Media Recorder after a recording is ended. (Large preview)

Now that we can start a MediaRecorder stream, we need to be able to stop the MediaRecorder stream when a user is done recording their voice input and send the generated audio file to the Express.js application.

The new method added to the store below stops the stream and makes a POST request containing the recorded voice input.

//store.js

import Axios from "axios";
import { action, observable, makeObservable, configure } from "mobx";

const ENDPOINT = process.env.REACT_APP_DATA_API_URL;

class ApplicationStore {
  constructor() {
    makeObservable(this);
  }

  @observable
  isRecording = false;

  recorder = null;
  recordedBits = []; 

  @action
  closeStream = () => {
    this.isRecording = false;
    this.recorder.stop();
    
    this.recorder.onstop = () => {
      if (this.recorder.state === "inactive") {
        const recordBlob = new Blob(this.recordedBits, {
          type: "audio/mp3",
        });

        const inputFile = new File([recordBlob]"input.mp3", {
          type: "audio/mp3",
        });
        const formData = new FormData();
        formData.append("voiceInput", inputFile);

        Axios.post(`${ENDPOINT}/api/agent/voice-input`, formData, {
          headers: {
            "Content-Type": "multipart/formdata",
          },
        })
          .then((data) => {})
          .catch((e) => console.log(`error uploading audio file : ${e}`));
      }
    };
  };
}

export const store = new ApplicationStore();

The method above executes the MediaRecorder’s stop method to stop an active stream. Within the onstop event fired after the MediaRecorder is stopped, we create a new Blob with a music type and append it into a created FormData.

As the last step., we make POST request with the created Blob added to the request body and a Content-Type: multipart/formdata added to the request’s headers so the file can be parsed by the connect-busboy middleware from the backend-service application.

With the recording being performed from the MobX store, all we need to add to the chat-component is a button to execute the MobX actions to start and stop the recording of the user’s voice and also a text to show when a recording session is active.

import React from 'react'

const ChatComponent = ({ ApplicationStore }) => {
  const {
     startAudiConversation,
     isRecording,
     handleConversation,
     endAudioConversation,
     isLoadingChatMessages
    } = ApplicationStore

  const [ Message, setMessage ] = useState("") 

    return (
        
Zara {} {isRecording && "is listening ..."}
closeChatwindow()} />
{ e.preventDefault(); handleConversation(Message); }} className="input-container" > setMessage(e.target.value)} value={Message} placeholder="Begin a conversation with our agent" />
{Message.length > 0 ? (
handleConversation(Message)} >
) : (
handleAudioInput()} >
)}
) } export default ChatComponent

From the highlighted part in the chat component header above, we use the ES6 ternary operators to switch the text to “Zara is listening ….” whenever a voice input is being recorded and sent to the backend application. This gives the user feedback on what is being done.

Also, besides the text input, we added a microphone icon to inform the user of the text and voice input options available when using the chat assistant. If a user decides to use the text input, we switch the microphone button to a Send button by counting the length of the text stored and using a ternary operator to make the switch.

We can test the newly connected chat assistant a couple of times by using both voice and text inputs and watch it respond exactly like it would when using the Dialogflow console!

Conclusion

In the coming years, the use of language processing chat assistants in public services will have become mainstream. This article has provided a basic guide on how one of these chat assistants built with Dialogflow can be integrated into your own web application through the use of a backend application.

The built application has been deployed using Netlify and can be found here. Feel free to explore the Github repository of the backend express application here and the React.js web application here. They both contain a detailed README to guide you on the files within the two projects.

References

Smashing Editorial(ks, vf, yk, il)




Source link