Catégories
Plugin et site web

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

A propos de l'auteur

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

Lorsqu'il s'agit de créer un assistant de conversation conversationnel pouvant ê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-il pas? 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 chat qui peut également être utilisé dans nos applications Web intégrées?

Dialogflow est une plate-forme qui simplifie le processus de création et de conception d'un assistant de discussion 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 est prévu que vous ayez une compréhension de Node.js et de Dialogflow. Si vous découvrez Dialogflow pour la première fois, cet article explique clairement ce qu'est Dialogflow et 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 en tant que 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 au fur et à mesure 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 les intentions, l'exécution, la 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 restaurerons un agent qui a été exporté dans un dossier ZIP après avoir été formé, à l'aide de la fonction d'exportation et d'importation de l'agent.

Avant d'effectuer l'importation, nous devons créer un nouvel 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 avec lequel lier l'agent. S'il n'y a pas de projet existant sur le Google Cloud avec lequel établir un lien, un nouveau peut être créé ici.

Un agent a été préalablement 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 situé dans la page Paramètres de l'agent.

Restauration d'un agent précédemment exporté à partir d'un dossier ZIP
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 verrons 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. La get-wine-recommendation intention

Cette intention a un contexte d'entrée unique 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 les contextes se trouvent 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 d'entraînement 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 au sein de nos agents get-wine-recommendation l'intention (comme indiqué ci-dessous) indique le choix du vin et la catégorie de prix:

Liste des phrases de formation disponibles avec une intention de recommandation de vin.
Page d'intention Get-wine-recommendation affichant les phrases d'entraînement 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 surbrillance est appelée annotation sur Dialogflow et est automatiquement effectuée pour extraire les types de données reconnus, connus sous le nom d’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 adressée à 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 l'agent à l'aide de l'émulateur Dialogflow situé dans la section droite de la console Dialogflow. Pour tester, nous commençons la conversation par un "salut»Et faites un suivi 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 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 à l'aide de Ngrok et la réponse de l'agent sur le côté droit montrant un vin dans la fourchette de prix de 20 $ saisie 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, tels que l'envoi de 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 package non pris en charge dans un environnement de navigateur, sauf lorsqu'il est corrigé à l'aide de webpack, la manière recommandée d'utiliser ce package est à partir d'un environnement Node. Nous pouvons le faire en configurant une application back-end Express.js pour utiliser ce package, puis servir les données à l'application Web via ses points de terminaison API et c'est ce que nous ferons ensuite.

Configuration d'une application Node Express

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.

# create a new directory and ( && ) move into directory
mkdir dialogflow-server && cd dialogflow-server

# create a new Node project
yarn init -y

# Install needed packages
yarn add 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(`🔥  server running on port ${PORT}`));

Lorsqu'il est exécuté, le code de l'extrait de code ci-dessus démarre un serveur HTTP qui écoute les connexions sur un PORT Express.js spécifié. Il a également activé le partage de ressources cross-origin (CORS) 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 demande car il n'a pas de route créée, alors créons-le.

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

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 créés POST routes qui pour l'instant, ne répondent qu'avec un 200 code d'état 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 à l'aide de app.use et d'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(`🔥  server running on port ${PORT}`));

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

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

Après la réussite de la demande ci-dessus, nous pouvons nous attendre à voir une réponse contenant des données d'objet en cours d'impression sur la console.

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 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. Parmi les six méthodes disponibles pour se connecter à un projet sur le cloud google, l'utilisation de l'option Comptes de service est la plus pratique lors de la connexion à un service particulier sur le cloud Google via sa 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 tombe entre de mauvaises mains.

Que sont les comptes de service?

Les comptes de service sont un type spécial de compte sur Google Cloud, créé pour une interaction non humaine, principalement via des API externes. 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 un excellent guide pour créer un compte de service. Lors de la création du compte de service, le rôle d'administrateur de l'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 ci-dessous 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 le bouton Ajouter une clé liste déroulante et cliquez sur le Créer une nouvelle clé option 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 aucun système de contrôle de version car il contient des données très sensibles sur un projet sur Google Cloud. Cela peut être fait en ajoutant le fichier au .gitignore fichier.

Avec un compte de service créé et une clé de compte de service disponible dans l'annuaire 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("path")
 
const app = express();

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

  // Create a new session
   const sessionClient = new Dialogflow.SessionsClient({
    keyFilename: Path.join(__dirname, "./key.json"),
  });

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

  // The dialogflow request object
  const request = {
    session: sessionPath,
    queryInput: {
      text: {
        // The query to send to the dialogflow agent
        text: message,
      },
    },
  };

  // Sends data from the agent as a response
  try {
    const responses = await sessionClient.detectIntent(request);
    res.status(200).send({ data: responses });
  } catch (e) {
    console.log(e);
    res.status(422).send({ e });
  }
});

module.exports = app;

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

  • Première
    Il s'authentifie auprès du cloud Google puis crée une session avec Dialogflow en utilisant le projectID du projet cloud Google lié à l'agent Dialogflow et également un identifiant 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.
  • Seconde
    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.
  • Troisième
    En utilisant le detectIntent de la session Dialogflow, nous envoyons l'objet de requête de manière asynchrone et attendons la réponse de l'agent à l'aide de la syntaxe async / await ES6 dans un bloc try-catch si le detectIntent retourne une exception, nous pouvons attraper l'erreur et la renvoyer, plutôt que de planter toute l'application. Un exemple de l'objet de réponse renvoyé par l'agent est fourni dans la documentation Dialogflow et peut être inspecté pour savoir comment extraire les données de l'objet.

Nous pouvons utiliser Postman pour tester la connexion Dialogflow implémentée ci-dessus dans le dialogflow-response route. Postman est une plate-forme de collaboration pour le développement d'API avec des fonctionnalités pour 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.

À l'aide du client Web Postman, nous pouvons créer un nouvel espace de travail ou utiliser un espace existant pour créer un POST demande à notre point de terminaison API à http://localhost:5000/api/agent/text-input et ajoutez des données avec une clé de message et la valeur de "Salut»Dans les paramètres de la requête.

Au clic du Envoyer bouton, un POST la demande sera adressée au serveur Express en cours d'exécution – 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 en fonction de l'exemple de définition de réponse fourni dans la documentation Dialogflow Webhook.

Gestion des entrées vocales

Par défaut, tous les agents Dialogflow sont activés pour traiter à la fois le texte et les données audio et également renvoyer 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 texte.

Pour gérer et traiter les entrées vocales, nous commencerons la mise en œuvre du /voice-input endpoint que nous avons précédemment créé afin de recevoir des fichiers audio et de les envoyer à Dialogflow en échange d'une réponse de l'Agent:

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

const app = express();

app.use(
  busboy({
    immediate: true,
  })
);

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()
  );

  // transform into a promise
  const pump = util.promisify(pipeline);

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

  try {
    req.busboy.on("file", (_, file, filename) => {
      pump(
        file,
        new Transform({
          objectMode: true,
          transform: (obj, _, next) => {
            next(null, { inputAudio: obj });
          },
        }),
        detectStream
      );
    });
  } catch (e) {
    console.log(`error  : ${e}`);
  }
});

Avec une vue d'ensemble, le /voice-input route ci-dessus reçoit l'entrée vocale d'un utilisateur sous forme de fichier contenant le message en cours de parole à l'assistant de chat 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ées dans la requête 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.
    Ensuite, en utilisant la méthode promisify du module util intégré Node.js, nous obtenons et enregistrons 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 un objet de requête 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 parole-texte sur le fichier audio envoyé.
  • Ensuite, à l'aide de la session créée et de l'objet de requête, nous détectons l'intention d'un utilisateur à partir du fichier audio à l'aide de detectStreamingIntent méthode qui ouvre un nouveau flux de données de l'agent Dialogflow vers l'application backend. Les données seront renvoyées par petits bits via ce flux et en utilisant les données "un événement"À partir du flux lisible dans lequel nous stockons les données streamData variable pour une utilisation ultérieure. Une fois le flux fermé, le "fin”Est ​​déclenché et nous envoyons la réponse de l'agent Dialogflow stocké dans le streamData variable à l'application Web.
  • Enfin, en utilisant l'événement de flux de fichier 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 le detectStreamingIntent méthode ci-dessus.

Pour tester et confirmer que les étapes ci-dessus fonctionnent comme prévu, nous pouvons faire une demande de test contenant un fichier audio dans le corps de la demande au /voice-input point final à 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 de saisie vocale à l'aide du facteur 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 corps de la demande.

À 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 consommant les API créées ici à partir d'une application Reactjs.

Intégration dans une application Web

Pour consommer notre API REST intégrée, nous allons étendre cette application React.js existante qui a déjà une page d'accueil affichant une liste de vins récupérés à partir d'une API et une prise en charge des décorateurs utilisant le plugin babel proposition decorators. Nous allons le refactoriser un peu en introduisant Mobx pour la gestion de l'état et également 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 à l'aide de MobX lorsque nous créons un magasin Mobx avec quelques valeurs observables et des méthodes en tant qu'actions.

// 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
  isChatWindowOpen = false;

  @observable
  isLoadingChatMessages = false;

  @observable
  agentMessages = ();

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

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

     Axios.post(`${ENDPOINT}/dialogflow-response`, {
      message: message || "Hi",
     })
      .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 composant de discussion où 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
    Ce tableau stocke toutes les réponses provenant des requêtes effectuées pour obtenir une réponse de l'agent Dialogflow. Les données du tableau sont affichées ultérieurement dans le composant.
  • handleConversation
    Cette méthode décorée comme une action ajoute des données dans le agentMessages tableau. Tout d'abord, il ajoute le message de l'utilisateur transmis en tant qu'argument, puis effectue une requête à l'aide d'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 agentMessages tableau.

Remarque: En l'absence du décorateurs support dans une application, MobX fournit makeObservable qui peut être utilisé dans le constructeur de la classe de magasin 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 le index.js fichier.

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

import { store } from "./state/";
import Home from "./pages/home";

function App() {
  return (
    
      
); } export default App;

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

Créer 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 discussion affichant les messages répertorié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 } from "react";
import { FiSend, FiX } from "react-icons/fi";
import "../styles/chat-window.css";

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

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

  return (
   
Zara
closeChatwindow()} />
  • Hi there, welcome to our Agent


{}} className="input-container"> setMessage(e.target.value)} value={Message} placeholder="Begin a conversation with our agent" />
{}}>
); }; export default ChatComponent

Le composant ci-dessus contient le balisage HTML de base nécessaire pour une application de chat. Il comporte 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 comportant un onChange gestionnaire d'événements attaché au champ d'entrée pour stocker le texte saisi dans l'état local du composant à l'aide de useState de React.

Un aperçu du composant de chat avec un message codé en dur de l'agent de chat
Un aperçu du composant de chat avec un message codé en dur 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.

// ./components/chatComponent.js

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

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

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

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

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

  const data = toJS(agentMessages);
 
  return (
        
Zara {isLoadingChatMessages && "is typing ..."}
closeChatwindow()} />
    {data.map(({ fulfillmentText, userMessage }) => (
  • {userMessage && (

    .

    {userMessage}

    )} {fulfillmentText && (

    {fulfillmentText}

    .

    )}
  • ))}

{ e.preventDefault(); handleConversation(Message); }} className="input-container" > setMessage(e.target.value)} value={Message} placeholder="Begin a conversation with our agent" />
handleConversation(Message)} >
); }; export default inject("ApplicationStore")(observer(ChatComponent));

À partir des parties en surbrillance du code ci-dessus, nous pouvons voir que l'ensemble du 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 démarrons la conversation avec l'agent immédiatement après l'ouverture du composant de chat en invoquant le handleConversation méthode dans un useEffect hook pour faire une requête immédiatement le composant est rendu.
  • Nous utilisons maintenant le isLoadingMessages valeur 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 le isLoadingMessages valeur à true et mettez à jour l'en-tête en Zara écrit…
  • le agentMessages Le tableau dans le 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 le toJS utilitaire de MobX et stocker 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 à l'aide d'une fonction de carte.

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

Composant de discussion affichant une liste de données renvoyées par la requête HTTP à l'application express.
Composant de discussion affichant une liste de données renvoyées par la requête HTTP à l'application express. (Grand aperçu)

Enregistrement de l'entrée vocale de l'utilisateur

Par défaut, tous les agents Dialogflow peuvent accepter la saisie vocale ou textuelle dans n'importe quelle langue spécifiée d'un utilisateur. Cependant, quelques ajustements d'une application Web sont nécessaires pour accéder au microphone d'un utilisateur et enregistrer une entrée vocale.

Pour ce faire, nous modifions le magasin MobX pour utiliser l'API d'enregistrement HTML MediaStream pour enregistrer la voix d'un utilisateur dans deux nouvelles méthodes du magasin MobX.

// 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}`));
  };
};

Au clic de l'icône d'enregistrement du composant de chat, le startAudioConversation méthode dans le magasin MobX ci-dessus est appelée pour définir la méthode l'observable isRecording est à true, pour que le composant de discussion fournisse un retour visuel pour montrer qu'un enregistrement est en cours.

À l’aide de l’interface de navigateur du navigateur, l’objet Périphérique multimédia est accessible pour demander le microphone de l’appareil de l’utilisateur. Une fois l'autorisation accordée au getUserMedia demande, il résout sa promesse avec des données MediaStream que nous transmettons ensuite au constructeur MediaRecorder pour créer un enregistreur en utilisant les pistes multimédias dans le flux renvoyé par le microphone de l'appareil de l'utilisateur. Nous stockons ensuite l'instance de Media Recorder dans le magasin recorder propriété car nous y accèderons à partir d'une autre méthode plus tard.

Ensuite, nous appelons la méthode start sur l'instance de l'enregistreur, et une fois la session d'enregistrement terminée, le ondataavailable est déclenchée avec un argument d'événement contenant le flux enregistré dans un Blob que nous stockons dans le recordedBits propriété array.

Déconnexion des données dans l'argument d'événement passé dans le déclenché ondataavailable événement, nous pouvons voir le Blob et ses propriétés dans la console du navigateur.

Navigateur Devtools console montrant le Blob déconnecté créé par l'enregistreur multimédia après la fin d'un enregistrement.
Navigateur Devtools console montrant le Blob déconnecté créé par l'enregistreur multimédia après la fin d'un enregistrement. (Grand aperçu)

Maintenant que nous pouvons démarrer un flux MediaRecorder, nous devons être en mesure d'arrêter le flux MediaRecorder lorsqu'un utilisateur a terminé d'enregistrer son entrée vocale et d'envoyer le fichier audio généré à l'application Express.js.

La nouvelle méthode ajoutée au magasin ci-dessous arrête le flux et fait un POST demande contenant l'entrée vocale enregistrée.

//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();

La méthode ci-dessus exécute la méthode d'arrêt de MediaRecorder pour arrêter un flux actif. Dans le onstop événement déclenché après l'arrêt du MediaRecorder, nous créons un nouveau Blob avec un type de musique et l'ajoutons dans un FormData créé.

Comme dernière étape, nous faisons POST requête avec l'objet blob créé ajouté au corps de la requête et un Content-Type: multipart/formdata ajouté aux en-têtes de la requête afin que le fichier puisse être analysé par le middleware connect-busboy à partir de l'application de service de backend.

L'enregistrement étant effectué à partir du magasin MobX, tout ce que nous devons ajouter au composant de chat est un bouton pour exécuter les actions MobX pour démarrer et arrêter l'enregistrement de la voix de l'utilisateur et également un texte à afficher lorsqu'une session d'enregistrement est 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

À partir de la partie en surbrillance dans l'en-tête du composant de chat ci-dessus, nous utilisons les opérateurs ternaires ES6 pour basculer le texte en "Zara écoute….”Chaque fois qu'une entrée vocale est enregistrée et envoyée à l'application backend. Cela donne à l'utilisateur des commentaires sur ce qui est fait.

De plus, en plus de la saisie de texte, nous avons ajouté une icône de microphone pour informer l'utilisateur des options de saisie de texte et de voix disponibles lors de l'utilisation de l'assistant de chat. Si un utilisateur décide d'utiliser la saisie de texte, nous basculons le bouton du microphone sur un bouton d'envoi en comptant la longueur du texte stocké et en utilisant un opérateur ternaire pour effectuer le changement.

Nous pouvons tester l'assistant de discussion nouvellement connecté plusieurs fois en utilisant à la fois les entrées vocales et textuelles et le regarder répondre exactement comme il le ferait lors de l'utilisation de la console Dialogflow!

Conclusion

Dans les années à venir, l'utilisation d'assistants de traitement de la langue dans les services publics sera devenue courante. Cet article a fourni un guide de base sur la façon dont l'un de ces assistants de discussion créés avec Dialogflow peut être intégré dans votre propre application Web via l'utilisation d'une application backend.

L'application construite a été déployée à l'aide de Netlify et peut être trouvée ici. N'hésitez pas à explorer le référentiel Github de l'application backend express ici et l'application web React.js ici. Ils contiennent tous deux un README détaillé pour vous guider sur les fichiers des deux projets.

Références

Éditorial fracassant(ks, vf, yk, il)

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *