https://d226lax1qjow5r.cloudfront.net/blog/blogposts/enable-live-captions-in-vonage-video-using-symbl-ai/live-captions_video-api-1.png

Activation des sous-titres en direct dans les vidéos de Vonage à l'aide de Symbl.ai

Publié le December 13, 2021

Temps de lecture : 9 minutes

Dans cet article de blog, j'aimerais vous montrer comment vous pouvez ajouter la transcription/le sous-titrage à votre application Vonage Video. Nous allons tirer parti de SDK web de Symbl.ai de Symbl.ai pour y parvenir. L'audio sera envoyé du côté client à Symbl.ai, donc il n'y a pas de changements requis du côté serveur. Symbl.ai vous permet d'ajouter facilement de l'intelligence conversationnelle à vos applications Voice Voice et Video grâce à sa suite d'API et d'outils de développement.

Pourquoi avez-vous besoin de légendes ?

L'accessibilité était l'une des principales exigences lorsque les communications ont été transférées en ligne pendant la pandémie. Avez-vous des clients avec des accents différents que vous avez parfois du mal à comprendre ? Voulez-vous savoir ce qui préoccupe vos utilisateurs, ce qu'ils veulent, ce qu'ils ont du mal à faire ? Ou cherchez-vous simplement à stocker les transcriptions d'un appel afin de pouvoir les analyser ultérieurement ? Nous avons ce qu'il vous faut. Restez dans les parages. Si vous préférez regarder une vidéo de l'application terminéen'hésitez pas à y jeter un coup d'œil.

Dans cet article de blog, je vais vous montrer comment ajouter le sous-titrage dans un appel individuel. Consultez le dépôt Dépôt GitHub pour obtenir le code source complet, qui présente des exemples de graphiques d'analyse des sentiments. Il vous fournit également des informations et un résumé de votre appel, en plus des sous-titres.

Je vais construire avec ReactJS, mais vous pouvez utiliser vanilla JS ou n'importe quel framework/bibliothèque de votre choix.

Exigences

Pour exécuter cet exemple d'application, vous aurez besoin de quelques éléments :

Architecture

Le diagramme suivant montre ce que nous allons construire aujourd'hui. Pour des raisons de simplicité, ce billet de blog va couvrir l'intégration avec Symbl.ai du côté client. Pour une explication plus approfondie de l'architecture de l'application, vous pouvez consulter le fichier fichier Readme de l'application.

Le Client SDK de Vonage est le moteur de notre application vidéo. Comme vous pouvez le voir dans le diagramme suivant, le Client SDK communiquera avec le SDK Symbl.ai en ouvrant une connexion bidirectionnelle par le biais d'une WebSocket. L'audio des participants sera transmis au SDK Symbl.ai et nous recevrons la transcription de l'audio.

Afin d'authentifier la session Vonage et la connexion Symbl.ai du côté client, nous avons créé une API dans notre serveur Node.js pour générer des informations d'identification. Cette API s'appuiera sur le SDK Node.js de Vonage et l'API de Symbl.ai.

Diagram of Vonage Video application connecting to Symbl.ai

Création de noms d'utilisateur

Pour un appel one-to-one, le SDK Symbl.ai va ouvrir une connexion avec l'infrastructure Symbl.ai où les deux utilisateurs vont envoyer de l'audio. Une fois que nous recevons le résultat de la transcription, nous avons besoin de savoir à quel utilisateur appartiennent les légendes. C'est pourquoi notre app aura le concept d'utilisateurs avec des noms d'utilisateurs. De cette façon, lorsque nous créons l'élément connectionConfig dans le useSymblai hooknous pouvons informer Symbl.ai qui parle et quand. La sortie de Symbl.ai inclut le nom de l'orateur ainsi que la transcription, ce qui nous permet de savoir à tout moment à qui appartient la transcription.

Pour commencer, j'ai créé un contexte de préférences pour pouvoir accéder au nom d'utilisateur et à conversationId n'importe où dans notre application. Le conversationId est un identifiant unique pour une conversation donnée qui a lieu dans l'infrastructure de Symbl.ai. Elle peut avoir un ou plusieurs utilisateurs. Il n'est pas nécessaire d'activer le sous-titrage, mais nous utiliserons l'identifiant conversationId pour effectuer des appels API à Symbl.ai afin de récupérer des informations sur l'analyse du sentiment et un résumé de la conversation. Nous couvrirons ces sujets dans la section section Bonus.

import { createContext } from 'react';
 
export const PreferencesContext = createContext();
const [preferences, setPreferences] = useState({
   userName: null,
   conversationId: null,
 });
 
 const preferencesValue = useMemo(
   () => ({ preferences, setPreferences }),
   [preferences, setPreferences]
 );

Il ne nous reste plus qu'à envelopper notre application avec l'élément ContextProvider afin de pouvoir accéder aux préférences n'importe où dans notre application.

     <Router>
       <PreferencesContext.Provider value={preferencesValue}>
         <Switch>
    <ProtectedRoute exact path="/room/:roomName" component={Wrapper} />
           <Route path="/room/:roomName/:conversationId/end">
             <EndCall />
           </Route>
           <Route path="/">
             <WaitingRoom />
           </Route>
         </Switch>
       </PreferencesContext.Provider>
     </Router>

Comme vous pouvez le voir dans la de notre applicationpar défaut, l'utilisateur sera redirigé vers le composant WaitingRoom (composant). Là, nous demanderons à l'utilisateur de saisir son nom d'utilisateur et un nom de salle. Vous pouvez voir la l'implémentation de la salle d'attente ici. La route Protected est un composant qui vérifie si l'utilisateur a défini un nom d'utilisateur et le redirige vers la salle d'attente si ce n'est pas le cas. Vous pouvez voir l'implémentation de cette route ici. Cela permet d'éviter qu'un utilisateur ne rejoigne une salle sans avoir choisi de nom. Si l'utilisateur a déjà choisi un nom d'utilisateur, nous le redirigerons vers le composant Wrapper qui contient un Header et le composant principal. Si vous êtes curieux, vous pouvez jeter un coup d'œil à ce composant ici.

Voici à quoi ressemble la salle d'attente :

Waiting Room UI requesting username and room name

Crochet UseSymblai

Nous allons utiliser le SDK web de Symbl.ai pour nous abstraire de la complexité de l'ouverture d'une connexion WebSocket et de l'acheminement de l'audio. Dans une application React, c'est une bonne pratique d'écrire un crochet React personnalisé pour rendre notre application plus réutilisable et le code plus propre. Vous pouvez voir l'implémentation complète du hook personnalisé icimais je vais expliquer chaque étape en détail.

Installons et importons le SDK :

npm i @symblai/symbl-web-sdk

import symbl from '@symblai/symbl-web-sdk';

Nous allons créer un crochet personnalisé qui acceptera l'éditeur de la session Vonage Video, ainsi qu'un drapeau booléen indiquant si l'éditeur a commencé à envoyer des médias. Le crochet personnalisé renverra nos sous-titres, les sous-titres de l'autre partie et le nom de l'orateur.

 
//CODE WILL GO HERE
 
return {
   captions,
   myCaptions,
   name,
 };
 
}
let streamRef = useRef(null);
 const { preferences } = useContext(PreferencesContext);
 const [captions, setCaptions] = useState('');
 const [myCaptions, setMyCaptions] = useState('');
 const [name, setName] = useState(null);
 const [symblToken, setSymblToken] = useState(null);
 let { roomName } = useParams();

Nous créons quelques variables d'état pour stocker nos propres légendes, les légendes de l'autre partie, le nom de la personne qui parle et le jeton. Nous allons également créer un ref vers le streamObject renvoyée par Symbl.ai une fois que nous aurons établi une connexion avec eux. Nous consommerons le contexte que nous avons précédemment créé.

Nous allons créer un useEffect qui ne s'exécutera que lors du premier rendu. Le but de ce hook est d'obtenir les identifiants de la session Video et un token pour la connexion à Symbl.ai. Les éléments getToken et getSymblToken sont implémentées ici. Elles communiqueront avec une API sur notre serveur qui s'occupera de la génération des informations d'identification. Nous obtiendrons les roomName à partir des paramètres de l'URL.

 useEffect(() => {
   getToken()
     .then((response) => {
       setSymblToken(response.data.accessToken);
       symbl.init({
         accessToken: response.data.accessToken, 
       });
     })
     .catch((e) => console.log(e));
 }, []);

Nous allons aller de l'avant et définir un autre useEffect qui s'exécutera une fois que nous aurons publié dans la session et démarré la connexion avec Symbl.ai. Nous obtiendrons un mediaStreamTrack de l'éditeur une fois que nous aurons publié dans la session. Nous utiliserons alors l Web Audio API pour créer un MediaStreamSource qui sera utilisée comme source dans le fichier connectionConfig pour Symbl.ai.

Si vous ne voulez pas obtenir le mediaStream de l'éditeur Vonage, et obtenir uniquement l'audio du microphone, vous pouvez le faire en ne spécifiant aucune source dans la directive connectionConfig. Par défaut, le SDK Web de Symbl.ai va gérer le contexte audio et les nœuds de source de son propre chef.

Dans notre application, pour des raisons de simplicité, nous attribuons la valeur de id la valeur de roomNamequi est un identifiant unique utilisé par les clients pour se connecter à la conversation et envoyer de l'audio à Symbl.ai. Dans une application du monde réel, vous devez vous assurer que cette valeur de . id est unique et qu'il n'est pas réutilisé après la fin de la conversation.

Vous pouvez voir qu'il y a une userId dans l'objet speaker de l'objet connectionConfig. Si vous y indiquez une adresse électronique valide, vous recevrez un courrier électronique contenant des informations sur la conversation. Si vous laissez l'adresse vide, vous ne recevrez pas d'e-mail. Cependant, nous voulons configurer le nom du locuteur pour que nous sachions de quel discours il s'agit lorsque nous recevons la sortie de Symbl.ai. Comme vous pouvez le voir, nous écoutons la commande onSpeechDetected callback :

useEffect(() => {
   if (isPublishing && publisher) {
     const audioTrack = publisher.getAudioSource();
     const stream = new MediaStream();
     stream.addTrack(audioTrack);
     const AudioContext = window.AudioContext;
     const context = new AudioContext();
     const source = context.createMediaStreamSource(stream);
     const id = roomName;
 
     const connectionConfig = {
       id,
       insightTypes: ['action_item', 'question'],
       source: source,
       config: {
         meetingTitle: 'My Test Meeting ' + id,
         confidenceThreshold: 0.5, // Offset in minutes from UTC
         encoding: 'LINEAR16',
         languageCode: 'en-US',
       speaker: {
         // Optional, if not specified, will simply not send an email in the end.
         userId: '', // Update with valid email
         name: preferences.userName || uuidv4(),
       },
       handlers: {
         /**
          * This will return live speech-to-text transcription of the call.
          */
         onSpeechDetected: (data) => {
           if (data) {
             if (data.user.name !== preferences.userName) {
               setCaptions(data.punctuated.transcript);
               setName(data.user.name);
             } else {
               setMyCaptions(data.punctuated.transcript);
             }
           }
         },
        
       },
     };
 
     const start = async () => {
       try {
         const stream = await symbl.createStream(connectionConfig);
         streamRef.current = stream;
         await stream.start();
         conversationId.current = await stream.conversationId;
         preferences.conversationId = conversationId.current;
       } catch (e) {
         console.log(e);
       }
     };
     start();
   }
 }, [
   isPublishing,
   roomName,
   preferences,
   publisher,
 ]);

Nous avons défini une fonction asynchrone à la fin de notre hook qui sera appelée pour créer une connexion avec Symbl.ai. Ceci est nécessaire car le WebSocket est démarré dans un état de non-traitement, donc nous devons indiquer à Symbl.ai quand nous voulons démarrer la connexion.

À ce stade, nous pouvons utiliser notre crochet personnalisé dans le composant de notre choix. Dans cette application, il sera utilisé dans le composant Composant principal. Nous devons d'abord l'importer :

import { useSymblai } from '../../hooks/useSymblai';

Ensuite, nous pouvons déstructurer les données en appelant le crochet personnalisé, en lui transmettant l'éditeur et la variable isPublishing la variable booléenne :

const { captions, name, myCaptions} =
   useSymblai({
     publisher,
     isPublishing,
   });

À ce stade, vous pouvez simplement afficher les légendes dans votre interface utilisateur ou exécuter la logique que vous souhaitez. Vous pouvez jeter un coup d'œil à l'implémentation du composant vidéo principal ici. l'implémentation du composant Video principal ici. Pour résumer, captions sont les sous-titres de l'autre partie, myCaptions sont vos propres légendes, et name est simplement le nom de l'autre personne.

Bonus

Symbl.ai vous offre non seulement des fonctions de sous-titrage, mais aussi l'analyse des sentiments, l'extraction d'informations, un résumé de l'appel, des analyses, et bien plus encore. J'ai construit un exemple d'application plus complet mettant en valeur ces fonctionnalités..

Vous trouverez plus d'informations sur les fonctionnalités de l'application dans la référence de l'API :

La Video suivante vous montre à quoi ressemble l'application. Deux utilisateurs participent à l'appel, Javier et Binoy. Comme vous pouvez le voir en haut à gauche, un graphique indique le score de l'analyse du sentiment pour le discours de l'autre partie (allant de -1 à 1, 1 étant très positif et -1 étant très négatif). Dans ce cas, nous pouvons voir que Binoy a été très positif lorsque je lui ai parlé des fonctionnalités intéressantes offertes par Symbl.ai.

En bas à gauche, vous pouvez voir quelques action_items qui sont repris par l'API de Symbl.ai. Elles contiennent le nom de l'assigné lorsqu'il est disponible. Dans ce cas, nous pouvons voir quelques questions, comme Binoy demandant à Javier si Symbl.ai était facile à intégrer avec nos Video APIs, et une action qui est Binoy ayant besoin de "les vérifier" (en se référant à Symbl.ai).

Lorsque vous cliquez sur "Terminer l'appel", l'application vous redirige vers la page d'analyse où vous pouvez voir les statistiques de chaque intervenant (temps de parole et temps de silence) et les statistiques de l'ensemble de la réunion. Dans ce cas, nous pouvons voir les statistiques pour Javier et Binoy. Une autre fonctionnalité très intéressante de Symbl.ai est la possibilité de résumer l'appel à l'aide du traitement du langage naturel. Cela vous permet d'obtenir quelques phrases avec un résumé de l'appel. De cette façon, vous pouvez vous faire une idée du contenu de l'appel en lisant quelques extraits.

C'est très utile, car cela permet d'éviter de longs e-mails de suivi avec un récapitulatif et des actions à entreprendre après un appel. Reconnaître les noms de marque est toujours un défi, mais nous pouvons voir comment, dans ce cas, Javier a déjà réalisé une intégration avec une société d'IA qui vous permet d'activer le sous-titrage en direct, l'analyse des sentiments, et plus encore. Gardez à l'esprit qu'il s'agissait d'une réunion très courte, mais plus la réunion est longue, plus le résumé sera précis.

Quelle est la prochaine étape ?

Nous espérons que vous savez maintenant comment activer le sous-titrage en direct dans votre application Vonage Video et obtenir des informations supplémentaires sur vos appels vidéo. Le projet terminé est disponible sur GitHub,

Faites-nous savoir sur Twitter des projets que vous réalisez à l'aide de l'API Video de Vonage !

En outre, n'oubliez pas de rejoindre notre communauté sur Slack.

Partager:

https://a.storyblok.com/f/270183/384x384/6007824739/javier-molina-sanz.png
Javier Molina Sanz

Javier studied Industrial Engineering back in Madrid where he's from. He is now one of our Solution Engineers, so if you get into trouble using our APIs he may be the one that gives you a hand. Out of work he loves playing football and travelling as much as he can.