https://a.storyblok.com/f/270183/28256/39112980de/live-captions_video-api-1.png

Ative as legendas em tempo real no Vonage Video usando o Symbl.ai

Publicado em December 13, 2021

Tempo de leitura: 8 minutos

Nesta postagem do blog, gostaria de mostrar a vocês como é possível adicionar transcrição/legendas ocultas ao seu aplicativo Vonage Video. Vamos utilizar SDK web do Symbl.ai para fazer isso. O áudio será enviado do lado do cliente para o Symbl.ai; portanto, não são necessárias alterações no lado do servidor. O Symbl.ai permite que você adicione facilmente inteligência conversacional aos seus aplicativos de voz e vídeo com seu conjunto de APIs e ferramentas para desenvolvedores.

Por que você precisa de legendas?

A acessibilidade foi um dos principais requisitos quando as comunicações passaram a ocorrer online durante a pandemia. Você tem clientes com sotaques diferentes que às vezes tem dificuldade para entender? Quer saber quais são as preocupações dos seus usuários, o que eles querem e com o que têm dificuldade? Ou está simplesmente procurando armazenar transcrições de uma ligação para poder fazer uma análise posterior? Nós temos a solução para você. Fique por aqui. Se preferir assistir a um vídeo do aplicativo pronto, fique à vontade para conferi-lo.

Nesta postagem do blog, vou mostrar a vocês como adicionar legendas em uma chamada individual. Confira o repositório do GitHub para ver o código-fonte completo, que traz exemplos de gráficos de análise de sentimentos. Ele também oferece insights e um resumo da sua chamada, além das legendas.

Vou desenvolver usando o ReactJS, mas você pode usar JavaScript puro ou qualquer framework/biblioteca de sua preferência.

Requisitos

Para executar este aplicativo de exemplo, você precisará de algumas coisas:

Arquitetura

O diagrama a seguir mostra o que vamos desenvolver hoje. Para simplificar, esta postagem do blog abordará a integração com o Symbl.ai no lado do cliente. Para uma explicação mais detalhada sobre a arquitetura do aplicativo, você pode consultar o arquivo Readme do aplicativo.

O Vonage Client SDK controla nosso aplicativo de vídeo. Como você pode ver no diagrama a seguir, o Client SDK se comunicará com o SDK da Symbl.ai abrindo uma conexão bidirecional por meio de um WebSocket. O áudio dos participantes será enviado ao SDK da Symbl.ai e receberemos a transcrição desse áudio.

Para autenticar a sessão do Vonage e a conexão com o Symbl.ai no lado do cliente, criamos uma API em nosso servidor Node.js para gerar credenciais. Essa API utilizará o SDK do Vonage para Node.js e a API do Symbl.ai.

Diagram of Vonage Video application connecting to Symbl.ai

Criação de nomes de usuário

Para uma chamada individual, o SDK do Symbl.ai estabelecerá uma conexão com a infraestrutura do Symbl.ai, na qual dois usuários enviarão áudio. Assim que recebermos o resultado da transcrição, precisamos saber a qual usuário as legendas pertencem. É por isso que nosso aplicativo terá o conceito de usuários com nomes de usuário. Dessa forma, quando criarmos o connectionConfig no useSymblai hook, podemos informar ao Symbl.ai quem está falando e quando. A saída do Symbl.ai inclui o nome do locutor junto com a transcrição, para que possamos saber a quem a transcrição pertence a todo momento.

Para começar, criei um contexto de preferências para poder acessar o nome de usuário e conversationId em qualquer lugar do nosso aplicativo. O conversationId é um identificador único para uma determinada conversa que ocorre na infraestrutura do Symbl.ai. Ela pode ter um ou mais usuários. Não é necessário habilitar as legendas, mas vamos usar o conversationId para fazer chamadas de API ao Symbl.ai a fim de recuperar informações sobre análise de sentimento e um resumo da conversa. Abordaremos esses tópicos na seção de bônus.

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

Agora, só precisamos envolver nosso aplicativo com o ContextProvider para que possamos acessar as preferências em qualquer lugar do nosso aplicativo.

     <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>

Como você pode ver na estrutura do nosso aplicativo, por padrão, o usuário será redirecionado para o WaitingRoom componente. Lá, pediremos ao usuário que digite seu nome de usuário e o nome de uma sala. Você pode ver a implementação da sala de espera aqui. A Protected rota é um componente que verificará se o usuário definiu um nome de usuário e, caso contrário, o redirecionará para a sala de espera. Você pode ver a implementação dessa rota aqui. Isso serve para impedir que um usuário entre em uma sala sem ter escolhido um nome. Se o usuário já tiver definido um nome de usuário, vamos redirecioná-lo para o Wrapper componente, que contém um Header e o componente principal. Se você estiver curioso, pode dar uma olhada nesse componente aqui.

Esta é a aparência da Sala de Espera:

Waiting Room UI requesting username and room name

Usar o gancho Symblai

Vamos utilizar o SDK web do Symbl.ai para simplificar a complexidade de estabelecer uma conexão WebSocket e transmitir o áudio. Em um aplicativo React, é uma boa prática escrever um hook personalizado do React para tornar nosso aplicativo mais reutilizável e o código mais limpo. Você pode ver a implementação completa do hook personalizado aqui, mas vou explicar cada etapa em detalhes.

Vamos instalar e importar o SDK:

npm i @symblai/symbl-web-sdk

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

Vamos criar um hook personalizado que aceitará o editor da sessão do Vonage Video, bem como um sinalizador booleano que indica se o editor já começou a enviar mídia. O hook personalizado retornará nossas legendas, as legendas da outra parte e o nome do locutor.

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

Estamos criando algumas variáveis de estado para armazenar nossas próprias legendas, as legendas da outra parte, o nome da pessoa que está falando e o token. Também criaremos uma referência ao streamObject retornado pelo Symbl.ai assim que estabelecermos uma conexão com ele. Vamos utilizar o contexto que criamos anteriormente.

Vamos criar um useEffect hook que será executado apenas na primeira renderização. O objetivo desse hook é obter as credenciais para a sessão de Video e um token para a conexão com o Symbl.ai. O getToken e getSymblToken funções estão implementadas aqui. Elas se comunicarão com uma API no nosso lado do servidor que cuidará da geração das credenciais. Obteremos o roomName a partir dos parâmetros da URL.

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

Vamos definir outro useEffect hook que será executado assim que publicarmos na sessão e iniciarmos a conexão com o Symbl.ai. Receberemos um mediaStreamTrack do publisher assim que estivermos publicando na sessão. Em seguida, vamos utilizar a API Web Audio para criar um MediaStreamSource que será usado como fonte no connectionConfig para o Symbl.ai.

Se você não quiser obter o mediaStream do editor da Vonage e apenas obter o áudio do microfone, você pode fazer isso sem especificar nenhuma fonte no connectionConfig. Por padrão, o Symbl.ai Web SDK lida com os nós de contexto e fonte de áudio por conta própria.

Em nosso aplicativo, por uma questão de simplicidade, estamos atribuindo id o valor de roomName, que é um identificador único usado pelos clientes para se conectarem à conversa e enviarem áudio para o Symbl.ai. Em uma aplicação real, você precisa garantir que esse id seja único e não seja reutilizado após o término da conversa.

Você pode ver que há uma userId string no speaker objeto do connectionConfig. Se você configurar um endereço de e-mail válido nesse campo, receberá um e-mail com algumas informações sobre a conversa. Se deixar em branco, nenhum e-mail será enviado. No entanto, queremos configurar o nome do palestrante para sabermos de quem é a palestra quando recebermos a saída do Symbl.ai. Como você pode ver, estamos escutando o 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,
 ]);

Definimos uma função assíncrona no final do nosso hook que será chamada para estabelecer uma conexão com o Symbl.ai. Isso é necessário porque o WebSocket é iniciado em um estado de não processamento; portanto, precisamos informar ao Symbl.ai quando desejamos iniciar a conexão.

Neste momento, podemos usar nosso hook personalizado no componente de nossa escolha. Neste aplicativo, ele será usado no componente Main. Primeiro, precisamos importá-lo:

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

E então podemos desestruturar os dados chamando o hook personalizado, passando a ele o publisher e a isPublishing variável booleana:

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

Nesse ponto, você pode simplesmente exibir as legendas na sua interface de usuário ou executar qualquer lógica que desejar. Você pode conferir a implementação do componente principal de Video aqui. Para recapitular, captions estas são as legendas da outra parte, myCaptions são suas próprias legendas, e name é apenas o nome da outra pessoa.

Bônus

O Symbl.ai não só oferece recursos de legenda, mas também análise de sentimento, extração de insights, resumo da chamada, análises e muito mais. Eu criei um aplicativo de exemplo mais completo que demonstra esses recursos.

Você pode encontrar mais informações sobre os recursos do aplicativo na referência da API:

O vídeo a seguir mostra como é a interface do aplicativo. Há dois usuários na chamada: Javier e Binoy. Como você pode ver no canto superior esquerdo, há um gráfico que mostra a pontuação da análise de sentimento do discurso do interlocutor (variando de -1 a 1, sendo que 1 é muito positivo e -1 é muito negativo). Nesse caso, podemos ver que Binoy estava bastante positivo enquanto eu falava com ele sobre os recursos legais que o Symbl.ai oferece.

No canto inferior esquerdo, você pode ver alguns action_items que são captados pela API do Symbl.ai. Ela contém o nome do responsável, quando disponível. Assim, neste caso, podemos ver algumas perguntas, como a de Binoy perguntando a Javier se o Symbl.ai foi fácil de integrar às nossas Video APIs, e uma ação pendente, que é a necessidade de Binoy “dar uma olhada nelas” (referindo-se ao Symbl.ai).

Ao clicar em “encerrar a chamada”, o aplicativo o redirecionará para a página de análises, onde você poderá ver métricas detalhadas de cada participante (tempo de fala e de silêncio) e métricas gerais da reunião. Neste caso, podemos ver as estatísticas de Javier e Binoy. Outro recurso muito legal que o Symbl.ai oferece é a capacidade de resumir a chamada usando processamento de linguagem natural. Isso fornece algumas frases com um resumo da chamada. Dessa forma, você pode ter uma ideia do que foi discutido na chamada lendo alguns destaques.

Isso é muito útil, pois ajuda a evitar longos e-mails de acompanhamento com um resumo e itens de ação após uma ligação. Reconhecer nomes de marcas é sempre um desafio, mas podemos ver como, neste caso, Javier já fez uma integração com uma empresa de IA que permite ativar legendas em tempo real, análise de sentimentos e muito mais. Lembre-se de que essa foi uma reunião muito curta, mas quanto mais longa for a reunião, mais preciso será o resumo.

E agora?

Esperamos que agora você saiba como ativar as legendas em tempo real no aplicativo Vonage Video e obtenha mais informações sobre suas videochamadas. O projeto concluído está disponível no GitHub,

Conte para a gente no Twitter quais projetos você desenvolve usando a Video API da Vonage!

Além disso, não deixe de participar da nossa comunidade no Slack.

Compartilhar:

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.