
Compartir:
Ben es un desarrollador de segunda carrera que anteriormente pasó una década en los campos de la educación de adultos, la organización comunitaria y la gestión de organizaciones sin ánimo de lucro. Trabajó como defensor de los desarrolladores para Vonage. Escribe regularmente sobre la intersección entre el desarrollo comunitario y la tecnología. Originario del sur de California y residente durante mucho tiempo en Nueva York, Ben reside ahora cerca de Tel Aviv (Israel).
Juega al teléfono con la Voice API de Nexmo
Tiempo de lectura: 12 minutos
¿Recuerdas el juego del teléfono de cuando eras niño? ¿Quizá lo jugabas en el patio del colegio durante el recreo o en un campamento de verano? Recuerdo a un profesor de primaria que utilizaba el juego para ilustrar lo poco fiables que podían ser las comunicaciones. Si nunca has jugado, aquí tienes un breve resumen:
El teléfono comienza cuando una persona susurra un mensaje a la de al lado. La segunda persona susurra el mismo mensaje a la siguiente, que a su vez lo comparte con la persona de al lado, y así sucesivamente. El juego continúa hasta que el mensaje completa su recorrido a través de todas las personas que juegan y vuelve al remitente original. A menudo, el mensaje final es bastante diferente del original.
Hay innumerables tareas esenciales y críticas que las modernas aplicaciones de comunicaciones en la nube pueden llevar a cabo. Sin embargo, a veces resulta entretenido tomarse un respiro y hacer algo divertido. Así que, en este tutorial, vamos a recrear el juego del teléfono utilizando Ruby on Rails, la Voice API de Nexmo y las API de voz a texto y traducción de Google Cloud Platform.
Cuando hayamos terminado, tendremos una aplicación de voz que aceptará una llamada entrante, tomará un mensaje original, lo convertirá en texto, lo traducirá a varios idiomas hasta que por fin lo vuelva a traducir al inglés y reproducirá el mensaje final a la persona que llama.
También puedes clonar en tu máquina local una copia de trabajo de esta aplicación desde GitHub.
¿Preparados? ¡Comencemos!
Requisitos previos
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.
Para empezar necesitas lo siguiente:
Configuración de ngrok
Hay varias formas de hacer que nuestro servidor de desarrollo local sea accesible externamente, pero una de las formas más sencillas es con ngrok. Puedes leer este artículo para una explicación más detallada de cómo funciona ngrok. Sin embargo, para nuestros propósitos, sólo necesitamos ponerlo en marcha y copiar la URL que nos proporciona.
Para iniciar ngrok, abra una nueva ventana de terminal y ejecute lo siguiente desde la línea de comandos:
Ahora verá una interfaz de registro ngrok en su ventana de terminal. Cerca de la parte superior de la interfaz hay una línea que comienza con Forwarding y contiene dos URLs. La primera es la URL ngrok accesible externamente, que termina con ngrok.io seguido de http://localhost:3000que es tu servidor de desarrollo local. Ahora, cuando tú o Nexmo contacte con la URL ngrok.io URL, lo reenviará a tu servidor local.
Asegúrese de copiar la ngrok.io URL en un lugar seguro. La utilizaremos en el siguiente paso de configuración de nuestra cuenta Nexmo, número de teléfono y aplicación Voice.
Crear una Nexmo Account
Para que nuestra aplicación de voz funcione, necesitamos una cuenta Nexmo, un número de teléfono provisto por Nexmo, una aplicación Nexmo y, por último, necesitamos vincular nuestra aplicación a nuestro número de teléfono.
En el menú de la izquierda, haga clic en el Voice menu . Verá las cuatro opciones siguientes bajo APPLICATIONS:

Haga clic en la opción Create an application y accederá a una página en la que podrá configurar una nueva aplicación Nexmo.
Rellene el formulario con lo siguiente:
Application nameintroducir campo de textorails-telephone-gameEvent URLintroduzca su URL ngrok:https://[ngrok url here]/eventAnswer URLintroduzca de nuevo su URL ngrok:https://[ngrok url here]/webhooks/answer
Cuando haya terminado, haga clic en el botón azul Create Application azul.
Ya ha creado una aplicación Nexmo Voice. Nuestro siguiente paso es comprar un número de teléfono Nexmo y vincularlo a esta aplicación.
En el Panel de control de Nexmo, haga clic en el elemento de menú Numbers en el menú de la izquierda. Verá que aparecen tres opciones:

Haga clic en la opción Buy numbers y accederá a una página en la que podrá elegir el país, las características, el tipo y los cuatro dígitos que desea que tenga el número.

Para nuestros propósitos: elija el país en el que se encuentra actualmente, para que la llamada sea una llamada local para usted; elija Voice para las características y móvil o fijo para el tipo. No necesita introducir nada en el campo Number campo de texto. Cuando pulse Searchverás una lista de números de teléfono disponibles. Elija uno haciendo clic en el botón naranja Buy y vuelva a pulsar el botón naranja Buy una vez más en el mensaje de confirmación.
Una vez que posea el número, podrá vincularlo a su aplicación de rails-telephone-game aplicación Voice. Para ello, haz clic en el icono de engranaje situado junto al número de teléfono y verás el siguiente menú:

Seleccione la voice-proxy-forwarding-demo Applications de la lista desplegable y haga clic en el botón azul Ok azul. Su número de teléfono Nexmo está ahora vinculado a su aplicación Voice y listo para aceptar y reenviar llamadas telefónicas entrantes a través de proxy de voz.
Configuración de una cuenta de Google Cloud Platform
La documentación de Google Cloud Platform contiene una excelente documentación sobre cómo poner en marcha una nueva Account.
En resumen, una vez que haya creado una Account, deberá crear una nueva aplicación. Después de crear tu nueva aplicación, tendrás que asegurarte de descargar tus credenciales, que estarán en un archivo que contiene JSON. Guarda el archivo en algún lugar que recuerdes, lo usaremos en breve. Vamos a discutir la adición, junto con sus credenciales de la API Nexmo, como variables de entorno en un momento.
Por último, en el panel de control de Google Cloud Platform, asegúrate de haber habilitado tanto la API de voz como la API de traducción. Utilizaremos ambas en nuestro juego telefónico.
Configuración de una aplicación Rails
Ya estamos listos para configurar nuestra aplicación Rails para jugar al teléfono. Haremos lo siguiente:
Inicializar una nueva aplicación
Añadir nuestras credenciales API
Definición de acciones y rutas del controlador
Inicialización de una nueva aplicación
Para inicializar una nueva aplicación ejecute lo siguiente desde la línea de comandos:
Esto creará una nueva aplicación Rails con PostgreSQL como base de datos por defecto.
Una vez que el comando haya terminado, siga adelante y abra la aplicación en su editor de código favorito y edite el archivo Gemfile en la carpeta raíz de la aplicación. Vamos a añadir las gemas Nexmo Ruby, dotenv-rails, Google Cloud Platform Translate API y Google Cloud Platform Speech API:
# Gemfile
gem 'nexmo'
gem 'dotenv-rails'
gem 'google-cloud-translate'
gem 'google-cloud-speech'Una vez guardado el archivo Gemfilepuedes instalar las gemas ejecutando bundle install desde la línea de comandos.
También querrá ejecutar rake db:migrate en esta etapa para inicializar el esquema de la base de datos. Para los propósitos de este tutorial, no estamos persistiendo los datos, pero usted puede hacerlo por su cuenta.
Añadir credenciales API
Necesitamos proporcionar las credenciales de la API tanto para Nexmo como para Google Cloud Platform en nuestra aplicación. Para gestionar de forma segura nuestras variables de entorno, utilizaremos la funcionalidad de la gema dotenv-rails que hemos instalado. En primer lugar, crea un nuevo archivo llamado .env en la carpeta raíz de tu proyecto y añade la ruta a ese archivo a tu archivo .gitignore archivo. Abre el archivo .env y añade lo siguiente:
# .env
GOOGLE_APPLICATION_CREDENTIALS=
GOOGLE_PROJECT_ID=
NEXMO_API_KEY=
NEXMO_API_SECRET=
NEXMO_NUMBER=
NEXMO_APPLICATION_ID=
NEXMO_PRIVATE_KEY=
BASE_URL=La primera variable de entorno, GOOGLE_APPLICATION_CREDENTIALSindica la ruta del archivo JSON que contiene tus credenciales de API para Google. Mueve el archivo que descargaste al configurar tu cuenta anteriormente a la carpeta raíz de tu aplicación y añade la ruta a la derecha del signo = (es decir GOOGLE_APPLICATION_CREDENTIALS=./my-google-cloud-platform-credentials.json).
La segunda variable de entorno, GOOGLE_PROJECT_IDes el ID del proyecto de Google Cloud Platform que creaste cuando te registraste (por ejemplo GOOGLE_PROJECT_ID=rails-telephone-game).
Las siguientes cinco variables de entorno están relacionadas con tu cuenta de Nexmo. Puede encontrar sus NEXMO_API_KEY y NEXMO_API_SECRET en la página principal de tu Panel de control de Nexmo.
El valor de la variable NEXMO_NUMBER es el número de teléfono que ha proporcionado Nexmo.
La dirección NEXMO_APPLICATION_ID se encuentra en la lista de sus aplicaciones en el panel de control de Nexmo. La dirección NEXMO_PRIVATE_KEY es, al igual que las credenciales de Google, la ruta a las credenciales de la clave privada de tu Account. Cuando creaste tu aplicación de voz Nexmo generaste un par de claves pública/privada, que descargó automáticamente la clave privada en tu ordenador. Mueve la clave privada a la carpeta raíz de tu aplicación y añade la ruta como valor de esta variable, exactamente como hiciste para GOOGLE_APPLICATION_CREDENTIALS.
La última variable de entorno, es su URL ngrok externa, por ejemplo: http://my-sample-url.ngrok.io.
Ahora que sus credenciales están agregadas a su aplicación, estamos listos para crear nuestro Controlador y nuestras Rutas.
Definición de acciones del controlador
En primer lugar, cree un nuevo archivo en /app/controllers/ llamado telephone_controller.rb. El trabajo inicial que haremos dentro de él es definir instancias con credenciales del cliente Nexmo y del cliente Google Cloud Platform:
# telephone_controller.rb
class TelephoneController < ApplicationController
Translator = Google::Cloud::Translate.new(project: ENV['GOOGLE_PROJECT_ID'])
NexmoClient = Nexmo::Client.new(
application_id: ENV['NEXMO_APPLICATION_ID'],
private_key: File.read(ENV['NEXMO_PRIVATE_KEY'])
)
Converter = Google::Cloud::Speech.new
También nos tomaremos un momento ahora y definiremos la lista de idiomas que queremos que la API de Google Cloud Platform Translate ejecute en el juego:
# telephone_controller.rb
class TelephoneController < ApplicationController
....
LANGUAGES = [
'ar',
'he',
'hi',
'ku',
'ru',
'tr',
'yi'
]
Para este tutorial, he elegido árabe, hebreo, hindi, kurdo, ruso, turco y yiddish. Por supuesto, puedes sustituir o añadir el idioma que desees.
Necesitamos dos acciones definidas en nuestro Controlador: #answer y #event. El método #answer se encarga de contestar la llamada, escuchar y grabar el mensaje del usuario, y mantener la llamada abierta mientras se procesa. El método #event se encarga de transcribir la grabación a texto, pasarlo por el traductor y devolver el mensaje recién traducido a la persona que llama.
El método #answer método:
def answer
puts "Starting Call"
@@uuid = params[:uuid]
render json:
[
{
:action => 'talk',
:text => 'Welcome to the Nexmo Telephone Game. To begin say your message at the beep. To end the recording press the pound key.'
},
{
:action => 'record',
:eventUrl => ["#{ENV['BASE_URL']}/event"],
:beepStart => true,
:format => "wav",
:endOnKey => "#",
:timeOut => 30
},
{
:action => 'talk',
:text => 'Please wait a moment as your message runs through our sophisticated top secret linguistic algorithm...'
},
{
:action => 'conversation',
:name => 'telephone-game-conversation'
}
].to_json
end
El método #answer se compone de instrucciones Nexmo Call Control Object (NCCO) en formato JSON. La primera instrucción envía un mensaje de bienvenida a la persona que llama, la segunda registra la respuesta de la persona que llama e indica a Nexmo que la URL de devolución de llamada es /event en la URL ngrok de su aplicación. La tercera permite a la persona que llama saber que el mensaje está siendo procesado, mientras que la cuarta instrucción utiliza la función de Nexmo conversation para mantener la llamada abierta mientras se procesa.
El método #event está envuelto dentro de una comprobación condicional para ver si hay una grabación de audio. Nexmo accede varias veces a /event es accedido varias veces por Nexmo con diferentes actualizaciones de estado, pero sólo nos interesa la que contiene una grabación:
def event
if params['recording_url']
# Save Recording
puts "Saving Audio File"
NexmoClient.files.save(params['recording_url'], 'recording.wav')
# Transcribe Recording
transcribed_text = ''
file_name = './recording.wav'
audio_content = File.binread(file_name)
bytes_total = audio_content.size
bytes_sent = 0
chunk_size = 32000
streaming_config = {
config: {
encoding: :LINEAR16,
sample_rate_hertz: 16000,
language_code: "en-US",
enable_word_time_offsets: true
},
interim_results: true
}
puts "Converting Speech to Text with GCP Speech API"
stream = Converter.streaming_recognize(streaming_config)
# Simulated streaming from a microphone
# Stream bytes...
while bytes_sent < bytes_total do
stream.send audio_content[bytes_sent, chunk_size]
bytes_sent += chunk_size
sleep 1
end
puts "Stopped passing audio to be transcribed"
stream.stop
# Wait until processing is complete...
stream.wait_until_complete!
puts "Transcription processing complete"
results = stream.results
results.first.alternatives.each do |alternatives|
transcribed_text = alternatives.transcript
end
# Run Transcription Through Translations
puts "Translating Message"
translated_text = transcribed_text
LANGUAGES.each do |language|
translated_text = (translated_text == transcribed_text) ?
Translator.translate(translated_text, to: language) : Translator.translate(translated_text.text, to: language)
end
final_translation = Translator.translate(translated_text.text, to: 'en')
# Play Final Text Back To Call
puts "Playing Translated Audio to Call"
puts "Transcribed Original Message: #{transcribed_text}"
puts "Final Message: #{final_translation.text}"
closing_msg = "Your message was translated through Arabic, Hebrew, Hindi, Kurdish, Russian, Turkish and Yiddish and is returned to you as: #{final_translation.text}"
NexmoClient.calls.talk.start(@@uuid, text: closing_msg, voice_name: "Kimberly") if transcribed_text != ''
end
end
En el método #event método; vamos a desglosarlo.
Inicialmente, una vez que los parámetros con un recording_url es verdadero, guardamos la grabación localmente. A continuación, utilizamos la API de conversión de voz a texto de GCP para convertir la grabación de audio en texto transcrito.
Para ello, definimos varias variables que contienen la configuración de audio. Optamos por simular transmisión de texto a la API de GCP para su conversión, en lugar de enviar directamente el archivo de audio guardado.
Con este planteamiento se observa una notable diferencia positiva en la velocidad de ejecución. El resultado es una matriz que contiene las transcripciones posibles. Sólo queremos la primera, que es lo que estamos haciendo aquí:
results.first.alternatives.each do |alternatives|
transcribed_text = alternatives.transcript
endLa variable transcribed_text contiene ahora el texto del mensaje de audio de la persona que llama. Nuestro siguiente paso en el método es ejecutarlo a través de los idiomas que hemos definido para la traducción. Queremos que el texto que se traduzca cada vez que se ejecute a través del método Translator sea la siguiente iteración del mensaje traducido. Esto es lo que hará que nuestro mensaje final sea aún más diferente que el mensaje original y, por lo tanto, ¡más divertido!
Para ello, creamos una nueva variable llamada translated_textdefinida inicialmente por el contenido de transcribed_text. Después de cada iteración, el valor de translated_textcambia a la traducción de la iteración actual, que se utiliza como texto a traducir en la siguiente iteración. Finalmente, la última traducción se ejecuta una última vez a través del traductor y se devuelve al inglés. Esto es lo que se reproducirá a la persona que llama:
# Run Transcription Through Translations
puts "Translating Message"
translated_text = transcribed_text
LANGUAGES.each do |language|
translated_text = (translated_text == transcribed_text) ?
Translator.translate(translated_text, to: language) : Translator.translate(translated_text.text, to: language)
end
final_translation = Translator.translate(translated_text.text, to: 'en')Un elemento a tener en cuenta en el código anterior es que empleamos un operador ternario para comprobar si el valor de translated_text es igual al de transcribed_text. Lo hacemos porque necesitamos acceder al texto de forma diferente si se trata de un objeto Speech to Text de Google Cloud Platform (es decir, con notación de puntos) o no.
Lo último que hay que hacer dentro del método es reproducirlo para la persona que lo llama. Para ello utilizamos la variable @@uuid que contiene el ID de la conversación e inyectando el texto como texto a voz en la llamada actual:
# Play Final Text Back To Call
puts "Playing Translated Audio to Call"
puts "Transcribed Original Message: #{transcribed_text}"
puts "Final Message: #{final_translation.text}"
closing_msg = "Your message was translated through Arabic, Hebrew, Hindi, Kurdish, Russian, Turkish and Yiddish and is returned to you as: #{final_translation.text}"
NexmoClient.calls.talk.instance_variable_set(:@host, 'api-us-1.nexmo.com')
NexmoClient.calls.talk.start(@@uuid, text: closing_msg, voice_name: "Kimberly") if transcribed_text != ''Una vez definidas las acciones de nuestro Controlador, el último paso que tenemos que hacer para estar listos es crear las Rutas de nuestra aplicación.
Definición de las rutas
Abra el routes.rb en la carpeta /config carpeta. Vamos a añadir uno GET y una POST solicitud:
# routes.rb
get '/answer', to: 'telephone#answer'
post '/event', to: 'telephone#event'Ya está. Hemos creado con éxito nuestra aplicación. Ahora estamos listos para ejecutarla. Asegúrate de que ngrok se está ejecutando en segundo plano e inicia tu servidor Rails desde la terminal ejecutando : rails s. Ahora puedes llamar a tu número de teléfono Nexmo y jugar al teléfono. Diviértete.
Compartir:
Ben es un desarrollador de segunda carrera que anteriormente pasó una década en los campos de la educación de adultos, la organización comunitaria y la gestión de organizaciones sin ánimo de lucro. Trabajó como defensor de los desarrolladores para Vonage. Escribe regularmente sobre la intersección entre el desarrollo comunitario y la tecnología. Originario del sur de California y residente durante mucho tiempo en Nueva York, Ben reside ahora cerca de Tel Aviv (Israel).
