
Compartir:
Antiguo defensor de los desarrolladores de Vonage, donde su función era apoyar a la comunidad tecnológica local de Londres. Es un experimentado organizador de eventos, jugador de mesa y padre de un precioso perrito llamado Moo. También es el principal organizador de You Got This, una red de eventos sobre las habilidades básicas necesarias para una vida laboral feliz y saludable.
Crear una línea de incidencias del código de conducta con Node.js
Tiempo de lectura: 5 minutos
Disponer de un Código de Conducta como organizador comunitario es sólo una parte de la historia: también es vital contar con formas bien pensadas de denunciar y responder a los malos comportamientos. En los eventos que he organizado en el pasado, se ha facilitado un número de teléfono a los asistentes: pueden llamar o enviar un mensaje de texto al número y este se reenvía a varios organizadores que tienen la responsabilidad de estar disponibles para resolver cualquier problema.
Hoy te mostraré cómo crear el tuyo propio con Vonage Voice y mensajes con un panel simple para descargar grabaciones de llamadas y registrar los mensajes entrantes.
Puede encontrar el código final del proyecto en https://github.com/nexmo-community/node-code-of-conduct-conference-call
Requisitos previos
Node.js instalado en su máquina
node-clique puede instalar ejecutandonpm install nexmo-cli@beta -g
Crea un nuevo directorio y ábrelo en un terminal. Ejecute npm init -y para crear un archivo package.json e instala las dependencias con npm install express body-parser nunjucks uuid nedb-promises nexmo@beta.
Vonage API Account
To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.
This tutorial also uses a virtual phone number. To purchase one, go to Numbers > Buy Numbers and search for one that meets your needs.
Establecer dependencias
Cree un index.js y configure las dependencias:
index.js
const uuid = require('uuid')
const app = require('express')()
const bodyParser = require('body-parser')
const nedb = require('nedb-promises')
const Nexmo = require('nexmo')
const nunjucks = require('nunjucks')
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))
// Future code goes here
app.listen(3000)Una vez hecho esto, ejecuta npx ngrok http 3000 en un nuevo terminal, y toma nota de la URL temporal de ngrok. Esto se utiliza para hacer localhost:3000 disponible para la web pública.
Comprar un número virtual y configurar el cliente Nexmo
Abra otro terminal en el directorio de su proyecto y cree una nueva aplicación con la interfaz de línea de comandos (CLI):
nexmo app:create
-> Select Capabilities: voice, messages
-> Use the default HTTP methods? Y
-> Voice Answer URL: https://NGROK_URL/answer
-> Voice Event URL: https://NGROK_URL/event
-> Messages Inbound URL: https://NGROK_URL/inbound
-> Messages Status URL: https://NGROK_URL/event
-> Private Key path: private.key
Tome nota del ID de la aplicación que aparece en su terminal y, a continuación, busque un número (puede sustituir GB por el prefijo de su país):
nexmo number:search GB --sms --voiceCopie uno de los números en el portapapeles, cómprelo y vincúlelo a su aplicación:
nexmo number:buy NUMBER
nexmo link:app NUMBER APP_ID
nexmo numbers:update NUMBER --mo_http_url https://NGROK_URL/smsEn index.jsinicialice el cliente Nexmo:
const nexmo = new Nexmo({
apiKey: 'API_KEY',
apiSecret: 'API_SECRET',
applicationId: 'APPLICATION_ID',
privateKey: './private.key'
}) Responder a una llamada entrante con voz
Crea el GET /answer endpoint y devuelve un Objeto de control de llamada Nexmo (NCCO) con una única talk acción:
app.get('/answer', async (req, res) => {
res.json([
{ action: 'talk', voiceName: 'Amy', text: 'This is the Code of Conduct Incident Response Line' }
])
})
app.post('/event', (req, res) => {
res.status(200).end()
})
El punto final POST /event endpoint tendrá más tarde datos de llamada enviados a él, y por ahora, sólo debe responder con un HTTP 200 OK estado.
Punto de control: Inicie su servidor ejecutando node index.js y, a continuación, llame al número que compró con la CLI: debería leerse el mensaje en voz alta y, a continuación, la llamada debería colgar. Si hay problemas, siempre se puede comprobar el número y la configuración de la aplicación en el dashboard.
Responder a una llamada entrante marcando Organizadores
En lugar de limitarse a leer el mensaje, añada a la persona que llama a una nueva conversación. Podemos controlar las conversaciones con código, incluyendo la adición de múltiples participantes en la llamada - sólo necesita saber el nombre de la conversación para hacer esto. Sustituye el contenido del /answer por:
const conferenceId = uuid.v4()
res.json([
{ action: 'talk', voiceName: 'Amy', text: 'This is the Code of Conduct Incident Response Line' },
{ action: 'conversation', name: conferenceId, record: true }
])Este código genera un nuevo identificador único y luego añade a la persona que llama a una conversación que utiliza un nombre como identificador (las conversaciones son llamadas con uno o más participantes en este contexto). Sin embargo, las conferencias telefónicas unipersonales son tristes. Antes de res.json()llama a cada organizador y añádelo a la multiconferencia:
for(let organizerNumber of ['NUMBER ONE', 'NUMBER TWO']) {
nexmo.calls.create({
to: [{ type: 'phone', number: organizerNumber }],
from: { type: 'phone', number: 'NEXMO NUMBER' },
ncco: [
{ action: 'conversation', name: conferenceId }
]
})
}Cada número debe estar en formato E.164y debe sustituir NEXMO NUMBER por el número vinculado a su aplicación. Mientras realizas las pruebas, asegúrate de que los números de la matriz no son los mismos que los que utilizarás para llamar.
Punto de control: Reinicie su servidor y llame a su número Nexmo. La aplicación debería llamar a cualquier número proporcionado en la matriz del bucle for().
Grabar la llamada
Al añadir la persona que llama a la multiconferencia, record: true se pasó como opción y, como resultado, se grabó toda la llamada. Una vez finalizada la llamada, el POST /event se envía una carga útil que contiene el ID de la conversación y una URL de grabación.
Antes de los puntos finales existentes crear una nueva base de datos nedb:
const recordingsDb = nedb.create({ filename: 'data/recordings.db', autoload: true })Una vez que reinicie su servidor, se creará un archivo dentro de un data directorio. Actualiza el endpoint del evento para que se vea así:
app.post('/event', async (req, res) => {
if(req.body.recording_url) {
await recordingsDb.insert(req.body)
}
res.status(200).end()
})
Punto de control: Reinicie su servidor y llame a su número Nexmo. Una vez que todos los participantes cuelguen, debería ver una nueva entrada en el archivo datos/grabaciones.db archivo.
Crear un panel de grabaciones
Ahora los datos de grabación se guardan en una base de datos; es hora de crear un cuadro de mandos. Configure nunjucks antes del primer endpoint:
nunjucks.configure('views', { express: app })Esto configura nunjucks para renderizar cualquier archivo en el directorio views y enlaza con la aplicación express almacenada en la variable app variable. Crear un views y un archivo index.html dentro de él:
<h1>Recordings</h1>
{% for recording in recordings %}
<p>
<a href="/details/{{recording.conversation_uuid}}">{{recording.start_time}}</a>
</p>
{% endfor %}Cree también un details.html en el directorio views directorio:
<ul>
<li>{{caller}}</li>
<li>{{recording.timestamp}}</li>
<li><a href="/details/{{recording.conversation_uuid}}/download">Download</a></li>
</ul>Se necesitan tres puntos finales en index.js para que estas vistas funcionen. El primero carga todas las grabaciones de la base de datos y muestra la página de índice:
app.get('/', async (req, res) => {
const recordings = await recordingsDb.find().sort({ timestamp: -1 })
res.render('index.html', { recordings })
})
La página tiene ahora este aspecto, con las últimas grabaciones en primer lugar:
Web page showing one recording timestamp with a blue underline
El siguiente punto final carga la página de detalles después de obtener los detalles de la API de Conversaciones, incluido el número de teléfono de la persona que llama:
app.get('/details/:conversation', (req, res) => {
nexmo.conversations.get(req.params.conversation, async (error, result) => {
const caller = result.members.find(member => member.channel.from != process.env.NEXMO_NUMBER)
const number = caller.channel.from.number
const recording = await recordingsDb.findOne({ conversation_uuid: req.params.conversation })
res.render('detail.html', { caller: number, recording })
})
})
Por último, un endpoint que obtiene el archivo de audio en bruto de la API y lo envía como un MP3 descargable:
app.get('/details/:conversation/download', async (req, res) => {
const recording = await recordingsDb.findOne({ conversation_uuid: req.params.conversation })
nexmo.files.get(recording.recording_url, (error, result) => {
res.writeHead(200, {
'Content-Disposition': 'attachment; filename="recording.mp3"',
'Content-Type': 'audio/mpeg',
})
res.end(Buffer.from(result, 'base64'))
})
})
A page showing a phone number, timestamp, and download link
Punto de control: Reinicie su servidor y llame a su número Nexmo. Una vez finalizada la llamada, debería ver la nueva entrada en el panel de control. Vaya a la página de detalles y descárguela.
Aceptar y guardar SMS
Al tratarse de un número de teléfono, algunas personas que utilicen este servicio también podrán enviarle un mensaje SMS. Utilizando un patrón similar, estos mensajes se almacenarán y se mostrarán en el panel de control. Debajo de la creación de la base de datos existente, añade una nueva para los mensajes:
const messagesDb = nedb.create({ filename: 'data/messages.db', autoload: true })Guarde los mensajes nuevos a medida que los reciba creando un endpoint al que ya hemos apuntado al configurar nuestro número virtual:
app.post('/sms', async (req, res) => {
await messagesDb.insert(req.body)
res.status(200).end()
})
Actualice el punto final del cuadro de mandos para que también recupere y muestre mensajes:
app.get('/', async (req, res) => {
const recordings = await recordingsDb.find().sort({ timestamp: -1 })
const messages = await messagesDb.find().sort({ 'message-timestamp': -1 })
res.render('index.html', { recordings, messages })
})
Añada esta sección al final de index.html:
{% for message in messages %}
<p>{{message.msisdn}} ({{message['message-timestamp']}}): {{message.text}}</p>
{% endfor %}
Web page showing both recordings and two example messages
Punto de control: Reinicia tu servidor y envía un SMS a tu número Nexmo. Deberías verlo aparecer en tu panel de control una vez que lo actualices.
Reenviar SMS y enviar una respuesta
Por último, actualice el punto final de SMS tanto para reenviar el mensaje a los organizadores como para responder al remitente:
app.post('/sms', async (req, res) => {
await messagesDb.insert(req.body)
for(let organizerNumber of ['NUMBER ONE', 'NUMBER TWO']) {
nexmo.channel.send(
{ type: 'sms', number: organizerNumber },
{ type: 'sms', number: 'NEXMO NUMBER' },
{ content: { type: 'text', text: `From ${req.body.msisdn}\n\n${req.body.text}` } }
)
}
nexmo.channel.send(
{ type: 'sms', number: req.body.msisdn },
{ type: 'sms', number: 'NEXMO NUMBER' },
{ content: { type: 'text', text: 'Thank you for sending us a message. Organizers have been made aware and may be in touch for more information.' } }
)
res.status(200).end()
})
Punto de control: Reinicia tu servidor y envía un SMS a tu número Nexmo. Deberías recibir una respuesta, y todos los organizadores de la lista también deberían recibir el mensaje.
Próximos pasos
¡Enhorabuena! Ya dispone de una línea de respuesta a incidentes relacionados con el Código de Conducta que funciona tanto para llamadas telefónicas como para mensajes SMS. Si dispone de más tiempo, puede explorar:
Tratamiento de errores
Utilizando nuestro nuevo reconocimiento de voz para transcribir llamadas
Puede encontrar el código final del proyecto en https://github.com/nexmo-community/node-code-of-conduct-conference-call
Como siempre, si necesitas ayuda, no dudes en ponerte en contacto con nosotros en la Slack de la comunidad de desarrolladores de Vonage. Esperamos verte allí.
Compartir:
Antiguo defensor de los desarrolladores de Vonage, donde su función era apoyar a la comunidad tecnológica local de Londres. Es un experimentado organizador de eventos, jugador de mesa y padre de un precioso perrito llamado Moo. También es el principal organizador de You Got This, una red de eventos sobre las habilidades básicas necesarias para una vida laboral feliz y saludable.
