https://a.storyblok.com/f/270183/1368x665/dea46e8442/customer-voicemail_node-express-socket.png

Crie uma caixa postal personalizada com Node.js, Express e Socket.io

Publicado em May 14, 2024

Tempo de leitura: 9 minutos

Introdução

Neste tutorial, você aprenderá a criar seu correio de voz. Usaremos Express.js e Socket.io.

Você pode encontrar o código completo no GitHub.

Estrutura e pré-requisitos

  • Node.js instalado

  • O Ngrok é instalado para expor seu servidor de desenvolvimento local à internet.

  • Conhecimentos básicos de JavaScript e Node.js

  • Uma conta da API da Vonage para acessar nossa Voice API

Estrutura do projeto

Para sua referência, eis como ficará a estrutura do diretório do projeto:

[node_modules] [public] [voicemails] // Voicemail mp3 files here index.html .env index.js package-lock.json package.json private.key

Inicializar o projeto

  1. Crie um diretório para o seu aplicativo e acesse-o.

  2. Execute npm init -y para inicializar seu projeto.

Configurar o Ngrok

Para tornar os endpoints do nosso servidor local acessíveis pela internet sem precisar implantar nosso aplicativo em um ambiente de produção, vamos expor nossa máquina local usando ngrok.

Abra uma nova janela do terminal ou do prompt de comando e inicie o ngrok na porta 3000 com o seguinte comando: ngrok http 3000.

Crie uma aplicação Vonage e adicione a chave privada

  1. Faça login/Cadastre-se no seu painel da API da Vonage e acesse “Seus aplicativos” na seção “Criar e gerenciar”.

  2. Clique em “+ Criar um novo aplicativo”. Dê um nome ao seu aplicativo e selecione “Gerar chave pública e privada”. Em seguida, baixe a chave privada gerada.

  3. Na seção “Recursos”, ative “Voice” e forneça as URLs do evento e dos endpoints de webhook. Use sua URL do Ngrok: ${NGROK_URL}/event para a URL do evento e ${NGROK_URL}/answer para a URL de resposta.

  4. Salve seu aplicativo. Observe que o ID do aplicativo e a chave da API são fornecidos.

  5. Adicione a chave privada baixada ao diretório do seu projeto.

Confira nosso guia do ngrok para obter ajuda sobre os endpoints de webhook

Adquira um número virtual

Em seguida, vamos adquirir um número virtual para servir como ponto de contato para as chamadas recebidas. Esse número será associado ao nosso aplicativo da Vonage. Veja a seguir o procedimento para obtê-lo:

Instale o CLI da Vonage: npm install @vonage/cli -g Pesquise números disponíveis na região de sua preferência: vonage numbers:search US (substitua “US” pelo código do seu país, se necessário). Compre um número: vonage numbers:buy 12079460000 US.

Lembre-se de que alguns Numbers não podem ser adquiridos pela linha de comando; portanto, você deve comprá-los pelo painel de controle. Para isso, acesse o Painel da Vonage e na página página “Comprar Numbers”. Marque a opção “Voice” no filtro de busca e selecione o país onde deseja comprar um número.

Vincular um número de telefone virtual ao aplicativo

Depois de selecionar nosso número, precisamos vinculá-lo ao nosso aplicativo da Vonage. Isso pode ser feito diretamente pelo Painel de Controle da Vonage ou por meio da CLI. Ao vincular o número, garantimos que as chamadas sejam direcionadas corretamente para o nosso aplicativo.

vonage apps:link --number=12079460000 VONAGE_APPLICATION_ID

Você também pode fazer isso pelo painel. Acesse a página de aplicativos e clique no aplicativo que você criou anteriormente. Clique no botão “Vincular” ao lado do número que deseja vincular na seção “Voice”.

Criar variáveis de ambiente

Crie um .env arquivo na raiz do seu projeto com o seguinte conteúdo, preenchendo com seus dados do Painel da Vonage: Confira esta postagem do blog se você não estiver familiarizado com “Como usar variáveis de ambiente no Node.js”.

URL=YOUR_NGROK_URL API_KEY=Your Vonage API key is used to authenticate API requests. API_SECRET=Your Vonage API secret VONAGE_APPLICATION_ID= The ID of your Vonage application. Vonage applications allow you to manage your communication services and define how they interact with your web application. PRIVATE_KEY=private.key

Instalar dependências

Vamos utilizar as seguintes dependências em nosso projeto: Express Socket.io @vonage/server-client) body-parser dotenv

Você pode instalá-los executando o seguinte comando:

npm install express socket.io @vonage/server-sdk body-parser dotenv

Configuração do servidor

Crie o index.js arquivo e inicialize seu servidor com os pacotes necessários. Configure um cliente Vonage usando variáveis de .env e descreva o /answer, /event, e /voicemail rotas.

require("dotenv").config();

const express = require("express");
const app = express();
const http = require("http").Server(app);
const io = require("socket.io")(http);

const bodyParser = require("body-parser");
const { FileClient } = require("@vonage/server-client");

// Ensure these environment variables are correctly set in your .env file
const fileClient = new FileClient({
  applicationId: process.env.VONAGE_APPLICATION_ID,
  privateKey: process.env.PRIVATE_KEY,
});

app.use(express.static("public"));
app.use(bodyParser.json());

app.get('/answer', (req, res) => {});

app.post('/event', (req, res) => {});

app.post('/voicemail', (req, res) => {});

http.listen(3000, () => console.log("Server is running on port 3000"));

Definir a lógica de tratamento de chamadas

Na /answer rota, configuramos um fluxo de chamadas usando um NCCO (Objeto de Controle de Chamadas) para interagir com os chamadores. Esse script cumprimenta o chamador, solicita que ele deixe uma mensagem após um bipe e encerra a gravação quando a tecla “#” é pressionada, seguida por uma mensagem de despedida. A res.send(ncco); linha envia esse conjunto de instruções de volta para a Vonage, que o executa durante a chamada.

app.get("/answer", (req, res) => {
  const ncco = [
    {
      action: "talk",
      voiceName: "Ivy",
      text: "Please record your message for me after the beep. Press # to end.",
    },
    {
      action: "record",
      eventUrl: [`${process.env.URL}/voicemail`],
      endOnKey: "#",
      beepStart: true,
    },
    {
      action: "talk",
      voiceName: "Ivy",
      text: "Message recorded. Bye!"
    }
  ];
  res.send(ncco);
});

Personalize a saudação para tornar a ligação mais pessoal. Muitas opções de Voice permitem que você ajuste o tom, a altura e o estilo da voz de acordo com suas preferências ou com a identidade da sua marca. Explore diferentes estilos de voz para encontrar a combinação perfeita para sua aplicação. Observe que alguns estilos de voz podem não ser compatíveis com SSML (Speech Synthesis Markup Language), por isso vale a pena verificar a lista de idiomas e estilos compatíveis.

Gerenciar eventos e mensagens de voz

O /event endpoint processa diversos eventos enviados pela API da Vonage. Quando ocorre um evento, como uma chamada atendida ou uma mensagem de voz gravada, a API da Vonage envia dados relacionados a esse evento para este endpoint. Nosso servidor registra esses dados de evento no console para fins de visibilidade e retorna um 204 (resposta “Sem Conteúdo”) para confirmar o recebimento. Esse tratamento mínimo é suficiente para muitas Applications, embora seja possível ampliá-lo para realizar ações específicas com base nos tipos de evento.

Implemente a lógica para /event para processar eventos.

app.post("/event", (req, res) => {
  console.log("Event received:", req.body);
  res.sendStatus(204);
});

Quando alguém deixa uma mensagem de voz, a API da Vonage envia uma solicitação POST para o nosso /voicemail ponto de extremidade com detalhes sobre a gravação, incluindo uma URL onde o arquivo de áudio gravado pode ser acessado.

Nosso servidor simula o salvamento dessa gravação criando um nome de arquivo com base no carimbo de data/hora atual e fingindo salvar o arquivo em um caminho especificado. Essa simplificação tem fins meramente demonstrativos; em uma aplicação real, você provavelmente faria o download da gravação a partir da URL fornecida e a armazenaria de forma mais segura.

Depois de “salvar” o arquivo, o servidor envia um evento de mensagem de voz a todos os clientes conectados por meio do Socket.io, transmitindo o nome do arquivo e a data e hora atuais.

No /voicemail, simule o armazenamento de mensagens de voz e emita um voicemail evento para o cliente.

app.post("/voicemail", (req, res) => {
  const filename = `voicemail-${Date.now()}.mp3`;
  const path = `${__dirname}/public/voicemails/${filename}`;

  fileClient
    .downloadFile(req.body.recording_url, path)
    .then(() => {
      io.emit("voicemail", {
        date: new Date().toISOString(),
        file: filename,
      });
      res.sendStatus(200);
    })
    .catch((err) => {
      console.error("Error saving file:", err);
      res.status(500).send(err);
    });
});

http.listen(3000, () => console.log("Server is running on port 3000"));

A interface do usuário

Nesta public/index.html, vamos adicionar um <audio> elemento para reproduzir mensagens de correio de voz e um contêiner para listar as mensagens, permitindo que o usuário reproduza ou exclua as mensagens recebidas.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Voicemail</title>
</head>
<body>
    <audio>Sorry, your browser does not support this audio.</audio>
    <div id="voicemails" class="voicemails">
        <h2>New Voicemails</h2>
        <!-- Voicemails will be dynamically added here -->
    </div>
</body>
</html>

Exibir as mensagens de correio de voz recebidas

Nosso JavaScript aprimora a interface do usuário ao se conectar ao servidor via Socket.io para atualizações em tempo real, como quando chegam novas mensagens de voz. Ele adiciona automaticamente essas mensagens a uma lista, exibindo a data e oferecendo botões para reproduzi-las ou excluí-las. Enquanto o botão de reprodução usa um <audio> elemento para a reprodução, o botão de exclusão apenas remove a mensagem de voz da tela, não do servidor. Aprimorar o aplicativo para excluir mensagens de voz do servidor também seria uma melhoria valiosa, exigindo lógica adicional no lado do servidor para lidar com as exclusões de arquivos de forma segura.

Adicione o código a seguir ao seu arquivo index.html:

  <script src="/socket.io/socket.io.js"></script>
  <script>
    const voicemailsDiv = document.getElementById("voicemails");
    const audio = document.querySelector("audio");

    document.addEventListener("click", function (e) {
      let el = e.target;
      if (el.classList.contains("play_btn")) {
        audio.src = el.getAttribute("data-src");
        audio.play();
        console.log("Playing audio from:", audio.src);
      }
      if (el.classList.contains("del_btn")) {
        el.closest(".voicemail-item").remove();
        console.log("Voicemail deleted");
      }
    });

    const socket = io();
    socket.on("connect", () => {
      console.log("Connected to server via Socket.io");
    });
    socket.on("voicemail", (vm) => {
      console.log("Received voicemail event:", vm);
      const voicemailElement = document.createElement("div");
      voicemailElement.classList.add("voicemail-item");
      voicemailElement.innerHTML = `
            <div>Date: ${vm.date}</div>
            <button class="play_btn" data-src="/${vm.file}">Play</button>
            <button class="del_btn">Delete</button>
        `;
      voicemailsDiv.appendChild(voicemailElement);
    });
  </script>
</html>

Experimente

Para colocar seu servidor em funcionamento, execute node index.js no seu terminal a partir da raiz do diretório e certifique-se de que o ngrok esteja em execução.

Se você ligar para o número de telefone associado ao seu aplicativo Vonage, ouvirá a saudação que você configurou nos NCCOs. Depois de gravar sua mensagem, ela deverá aparecer na sua página HTML em localhost:3000.

Conclusão

Você acabou de criar um sistema de correio de voz, permitindo que quem liga deixe mensagens exibidas em uma página da web. Embora a funcionalidade atual não inclua a exclusão de arquivos no lado do servidor, resolver essa questão seria uma melhoria valiosa.

Converse conosco no nosso Slack da Comunidade de Desenvolvedores da Vonage ou envie-nos uma mensagem no X.

Compartilhar:

https://a.storyblok.com/f/270183/400x400/3f6b0c045f/amanda-cavallaro.png
Amanda CavallaroRepresentante de Desenvolvedores