https://a.storyblok.com/f/270183/127734/5c2b44174f/multitrack-call-transcription_1200x675.jpg

Transcrição de chamadas em múltiplas faixas com gravação dividida

Publicado em May 10, 2021

Tempo de leitura: 6 minutos

Em abril, anunciamos que a gravação dividida estava disponível como parte da Voice API. A gravação dividida permite gravar uma conversa em estéreo, com um participante em cada canal. Isso facilita muito o tratamento de casos de uso comuns, como a transcrição.

No entanto, havia uma desvantagem na gravação dividida: se houvesse mais de dois participantes, o primeiro ficaria no canal 0 e todos os demais no canal 1, o que significa que perderíamos a capacidade de transcrever o que cada um disse individualmente.

E se eu lhe dissesse que a Nexmo agora suporta não um, nem dois, mas três (!) canais separados em uma gravação? Isso te deixaria feliz? E se eu dissesse que poderíamos suportar quatro? Cinco? Temos o prazer de anunciar que, a partir de agora, a Nexmo suporta até 32 canais em cada gravação. Você leu certo: podemos oferecer 32 canais de áudio distintos, cada um contendo um único participante, para você processar da maneira que quiser.

Assim como da última vez, vamos analisar juntos um caso de uso simples. Nesse cenário, Alice precisa discutir um projeto de trabalho com Bob e Charlie, e todos concordaram que seria uma boa ideia gravar a ligação. Para isso, Alice criou um pequeno aplicativo em Node.js que usa o Nexmo para conectá-la a Bob e Charlie e gravar a conversa.

Todo o código desta postagem está está disponível no GitHub.

Inicialização do seu aplicativo

A primeira coisa que precisamos fazer é criar um novo aplicativo e instalar todas as nossas dependências. Para isso, vamos usar npm para inicializar um projeto e instalar express e body-parser para lidar com nossas solicitações HTTP, e dotenv para gerenciar a configuração do nosso aplicativo. Também precisaremos instalar o nexmo cliente para que possamos acessar a gravação da chamada assim que recebermos uma notificação de que ela está disponível e @google-cloud/speech para transcrever o áudio.

npm init -y
npm install express body-parser dotenv nexmo @google-cloud/speech --save

Depois de instalar todas as dependências, você precisará criar uma aplicação e alugar um número para o qual as pessoas possam ligar.

A Nexmo envia solicitações HTTP para o seu aplicativo sempre que ocorre um evento dentro dele. Isso pode acontecer quando uma chamada começa a tocar, quando é atendida ou quando uma gravação de chamada fica disponível, apenas para citar alguns exemplos. Para isso, a Nexmo precisa ter acesso ao seu aplicativo, o que é difícil quando o aplicativo está sendo executado localmente no seu laptop. Para expor seu aplicativo local pela internet, você pode usar uma ferramenta chamada ngrok. Para mais informações, leia nossa post no blog .

Exponha seu servidor agora executando ngrok http 3000. Você deverá ver um texto semelhante a http://2afec62c.ngrok.io -> localhost:3000. A primeira seção é a sua URL do ngrok, e é o que você vai precisar para o restante deste post.

Finalmente estamos prontos para criar uma aplicação Nexmo e vincular um número a ela. Você precisará substituir http://2afec62c.ngrok.io pela sua própria URL do ngrok nestes exemplos:

# Create an application
nexmo app:create "MultiTranscription" http://2afec62c.ngrok.io/webhooks/answer http://2afec62c.ngrok.io/webhooks/event --keyfile private.key
# Application created: aaaaaaaa-bbbb-cccc-dddd-0123456789ab <- Make a note of this, you'll need it later

# Purchase a number
nexmo number:buy --country_code GB
# Number purchased: 442079460005 <- You'll need this too

# Link our number to our application
nexmo link:app NUMBER APPLICATION_ID

Se você ligar agora para o número que comprou, a Nexmo enviará uma solicitação para http://[id].ngrok.io/webhooks/answer para saber como lidar com a chamada. Como ainda não criamos esse aplicativo, a chamada falhará.

Como atender uma chamada recebida

Vamos desenvolver nosso aplicativo para atender chamadas recebidas.

Crie o index.js arquivo e insira o código mostrado abaixo. Isso requiresão todas as nossas dependências, configura o cliente Nexmo e cria uma nova express instância:

require("dotenv").config();

const express = require("express");
const bodyParser = require("body-parser");
const Nexmo = require("nexmo");

const nexmo = new Nexmo({
    apiKey: "not_used", // Voice applications don't use the API key or secret
    apiSecret: "not_used", 
    applicationId: process.env.NEXMO_APPLICATION_ID,
    privateKey: process.env.NEXMO_PRIVATE_KEY_PATH
});

const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

Em seguida, precisamos criar nosso /webhooks/answer ponto de extremidade que retornará um NCCO e informar à Nexmo como lidar com nossa chamada. Em nosso NCCO, usamos duas connect ações para discar automaticamente os números de telefone do Bob e do Charlie e adicioná-los à conversa, além de uma record ação que instruirá a Nexmo a gravar a chamada.

É na record ação é onde a mágica acontece. Nós instruímos a Nexmo a dividir o áudio em canais separados, definindo split: conversation e que o áudio deve ser dividido em três canais, definindo channels: 3.

app.get('/webhooks/answer', (req, res) => {
    return res.json([
        {
            action: 'connect',
            endpoint: [{
                type: 'phone',
                number: process.env.BOB_PHONE_NUMBER
            }]
        },
        {
            action: 'connect',
            endpoint: [{
                type: 'phone',
                number: process.env.CHARLIE_PHONE_NUMBER
            }]
        },
        {
            "action": "record",
            "eventUrl": [`${req.protocol}://${req.get('host')}/webhooks/recording`],
            "split": "conversation",
            "channels": 3,
            "format": "wav"
        }
    ]);
});

Precisaremos fornecer os números de telefone do Bob e do Charlie para que isso funcione, mas vamos terminar de criar nossos endpoints antes de configurarmos nosso aplicativo.

Crie o /webhooks/event ponto de extremidade que será notificado quando eventos forem acionados na chamada. Por enquanto, tudo o que faremos é registrar os parâmetros que recebemos e confirmar o recebimento enviando uma 204 resposta.

app.post('/webhooks/event', (req, res) => {
    console.log(req.body);
    return res.status(204).send("");
});

Por fim, precisamos implementar nosso/webhooks/recording ponto de extremidade. Essa URL foi definida em nosso NCCO na record ação e será notificado quando uma gravação estiver disponível. Transcreveremos o áudio automaticamente mais tarde, mas, por enquanto, vamos registrar os parâmetros da solicitação para que possamos ver o que está disponível.

app.post('/webhooks/recording', (req, res) => {
    transcribeRecording(req.body);
    return res.status(204).send("");
});

function transcribeRecording(params) {
    console.log(params);
}

app.listen(3000, () => console.log(`Listening`))

Neste momento, resta apenas uma coisa a fazer: preencher nosso .env arquivo com as informações de que nosso aplicativo precisa. Você precisará do seu application_id, além de alguns números de telefone para o Bob e o Charlie, para ajudar nos testes. Crie um .env arquivo e adicione o seguinte, certificando-se de substituir o ID do aplicativo e os números de telefone pelos seus próprios valores:

NEXMO_APPLICATION_ID="aaaaaaaa-bbbb-cccc-dddd-0123456789ab"
NEXMO_PRIVATE_KEY_PATH="./private.key"

BOB_PHONE_NUMBER="442079460000"
CHARLIE_PHONE_NUMBER="442079460001"

GOOGLE_APPLICATION_CREDENTIALS="./google_creds.json"

Certifique-se de adicionar a linha com as credenciais do Google, mesmo que ainda não tenhamos criado esse arquivo. Vamos criá-lo na próxima seção

Depois de fazer isso, você pode testar seu aplicativo executando node index.js e, em seguida, ligar para o número da Nexmo que você adquiriu. Ele deve ligar automaticamente para os dois números que você adicionou ao .env arquivo e, assim que todos desligarem, seu /webhooks/recording endpoint deverá receber uma URL de gravação.

Conectando-se ao Google

Vamos usar o serviço Speech-To-Text do Google para transcrever a gravação da nossa ligação. Para começar, você precisará gerar credenciais do Google Cloud no Console do Google. Baixe o arquivo JSON fornecido, renomeie-o para google_creds.json e salve-o ao lado de index.js. Esse é o arquivo que o SDK do Google tentará ler para obter suas credenciais de autenticação.

Para transcrever nossos dados de áudio, vamos nos conectar à API de Reconhecimento de Fala do Google, passando o idioma esperado, o número de canais da gravação e o próprio fluxo de áudio. Atualize seu transcribeRecording método para incluir o seguinte código:

function transcribeRecording(params) {
    const client = new speech.SpeechClient();

    const config = {
        encoding: `LINEAR16`,
        languageCode: params.language,
        audioChannelCount: params.channelCount,
        enableSeparateRecognitionPerChannel: true,
    };

    const request = {
        config: config,
        audio: {
            content: params.audio.toString('base64'),
        }
    };

    return client.recognize(request);
}

Isso retorna um promise do SDK de reconhecimento de fala do Google Cloud, que será resolvido quando a transcrição estiver disponível. Antes de podermos usar o SDK de reconhecimento de fala, precisamos importá-lo; portanto, adicione o seguinte à sua require seção no início do seu arquivo:

const speech = require('@google-cloud/speech').v1p1beta1;

Neste momento, estamos prontos para transcrever nosso áudio. A etapa final consiste em buscar a gravação no Nexmo assim que recebermos uma solicitação para /webhooks/recording e enviar o áudio para o serviço de transcrição do Google. Para isso, usamos o nexmo.files.get método e passamos o áudio retornado para o nosso transcribeRecording método:

app.post('/webhooks/recording', (req, res) => {
    nexmo.files.get(req.body.recording_url, (err, audio) => {
        if (err) { console.log(err); return; }

        transcribeRecording({
            "language": "en-US",
            "channelCount": 3,
            "audio": audio,
        }).then((data) => {
            const response = data[0];
            const transcription = response.results
                .map(
                    result =>
                    ` Channel Tag: ` +
                    result.channelTag +
                    ` ` +
                    result.alternatives[0].transcript
                )
                .join('n');
            console.log(`Transcription: n${transcription}`);
        });
    });
    return res.status(204).send("");
});

Além de passar o áudio como parâmetro, informamos ao nosso transcribeRecording método que há 3 canais no áudio e que queremos transcrever usando o en-US modelo de linguagem. Assim que a promessa for resolvida pelo SDK de reconhecimento de fala do Google, lemos os resultados e geramos uma transcrição da conversa, incluindo de qual canal o áudio veio.

Se você ligar agora para o seu número da Nexmo, será conectado tanto ao Bob quanto ao Charlie. Assim que a ligação terminar, desligue e aguarde até que a Nexmo envie um webhook com a gravação. Assim que ele chegar, enviamos esse áudio para o Google, e a transcrição aparecerá no console. É assim que fica para mim:

Transcription:
Channel Tag: 1 this is channel one
Channel Tag: 2 and this is channel two
Channel Tag: 3 and a test from channel three
Channel Tag: 1 great

Conclusão

Acabamos de criar um sistema de teleconferência com transcrição automática usando apenas 76 linhas de código. Além de transcrever automaticamente a chamada, ele transcreve cada canal separadamente, permitindo que você saiba quem disse o quê durante a chamada. Para obter mais informações sobre as opções disponíveis ao gravar uma chamada, você pode consultar o record action em nossa referência do NCCOou conferir um exemplo de implementação do NCCO necessário em várias linguagens.

Compartilhar:

https://a.storyblok.com/f/270183/384x384/1c8825919c/mheap.png
Michael HeapEx-funcionários da Vonage

Michael é um engenheiro de software poliglota, empenhado em reduzir a complexidade dos sistemas e torná-los mais previsíveis. Trabalhando com diversas linguagens e ferramentas, ele compartilha seus conhecimentos técnicos com públicos de todo o mundo em grupos de usuários e conferências. No dia a dia, Michael é ex-representante de desenvolvedores da Vonage, onde dedicava seu tempo a aprender, ensinar e escrever sobre todos os tipos de tecnologia.