https://d226lax1qjow5r.cloudfront.net/blog/blogposts/play-the-game-of-telephone-with-the-nexmo-voice-api-ruby-on-rails-and-google-cloud-platform-dr/Game-of-Telephones_1200x675.jpg

Spielen Sie das Spiel Telefon mit der Nexmo Voice API

Zuletzt aktualisiert am May 14, 2021

Lesedauer: 11 Minuten

Erinnern Sie sich noch an das Telefonspiel aus Ihrer Kindheit? Vielleicht haben Sie es in den Pausen auf dem Schulhof oder im Sommer in einem Ferienlager gespielt? Ich erinnere mich, dass eine Lehrerin in der Grundschule dieses Spiel benutzte, um zu zeigen, wie unzuverlässig die Kommunikation sein kann. Falls Sie es nie gespielt haben, hier eine kurze Zusammenfassung:

Das Telefonieren beginnt damit, dass eine Person der Person neben ihr eine Nachricht zuflüstert. Die zweite Person flüstert dieselbe Nachricht der nächsten Person zu, die sie dann an die Person neben sich weitergibt, und so weiter und so fort. Das Spiel geht so lange weiter, bis die Nachricht ihren Weg durch alle Mitspieler beendet hat und zum ursprünglichen Absender zurückkehrt. Oft ist die endgültige Nachricht ganz anders als die ursprüngliche.

Es gibt unzählige wichtige und kritische Aufgaben, die moderne Cloud-Kommunikationsanwendungen erfüllen können. Aber manchmal ist es einfach unterhaltsam, eine Pause einzulegen und etwas Lustiges zu machen. In diesem Walkthrough werden wir das Telefonspiel mit Ruby on Rails, der Nexmo Voice API und den Google Cloud Platform Speech to Text und Translate APIs nachstellen.

Wenn wir fertig sind, werden wir eine Sprachanwendung haben, die einen eingehenden Telefonanruf annimmt, eine Originalnachricht annimmt, sie in Text umwandelt, sie durch mehrere Sprachen übersetzt, bis sie sie schließlich wieder ins Englische zurückübersetzt, und die endgültige Nachricht dem Anrufer vorspielt.

Sie können auch eine Arbeitskopie dieser Anwendung auf Ihren lokalen Rechner klonen, und zwar von GitHub.

Sind Sie bereit? Fangen wir an!

Voraussetzungen

Vonage API-Konto

Um dieses Tutorial durchzuführen, benötigen Sie ein Vonage API-Konto. Wenn Sie noch keines haben, können Sie sich noch heute anmelden und mit einem kostenlosen Guthaben beginnen. Sobald Sie ein Konto haben, finden Sie Ihren API-Schlüssel und Ihr API-Geheimnis oben auf dem Vonage-API-Dashboard.

In diesem Lernprogramm wird auch eine virtuelle Telefonnummer verwendet. Um eine zu erwerben, gehen Sie zu Rufnummern > Rufnummern kaufen und suchen Sie nach einer Nummer, die Ihren Anforderungen entspricht.

Für die ersten Schritte benötigen Sie Folgendes:

Einrichten von ngrok

Es gibt mehrere Möglichkeiten, unseren lokalen Entwicklungsserver von außen zugänglich zu machen, aber eine der einfachsten ist ngrok. Sie können lesen diesen Artikel für eine genauere Erklärung der Funktionsweise von ngrok. Für unsere Zwecke müssen wir es jedoch nur zum Laufen bringen und die URL kopieren, die es uns liefert.

Um ngrok zu starten, öffnen Sie ein neues Terminal-Fenster und führen Sie folgendes in der Kommandozeile aus:

ngrok http 3000

Sie sehen nun eine ngrok-Protokollierungsschnittstelle in Ihrem Terminalfenster. Am oberen Rand der Schnittstelle befindet sich eine Zeile, die mit Forwarding beginnt und zwei URLs enthält. Die erste ist die von außen zugängliche ngrok-URL, die mit ngrok.io gefolgt von http://localhost:3000wobei es sich um Ihren lokalen Entwicklungsserver handelt. Wenn Sie oder Nexmo nun die ngrok.io URL kontaktieren, wird sie an Ihren lokalen Server weitergeleitet.

Stellen Sie sicher, dass Sie die ngrok.io URL an einem sicheren Ort speichern. Wir werden sie im nächsten Schritt verwenden, um unser Nexmo-Konto, unsere Telefonnummer und unsere Voice-Anwendung einzurichten.

Einrichten eines Nexmo-Accounts

Damit unsere Voice-Applikation funktioniert, benötigen wir einen Nexmo Account, eine von Nexmo bereitgestellte Telefonnummer, eine Nexmo Applikation und schließlich müssen wir unsere Applikation mit unserer Telefonnummer verknüpfen.

Klicken Sie im Menü auf der linken Seite auf den Voice menu Eintrag. Sie sehen dann die folgenden vier Optionen unter APPLICATIONS:

Create voice app

Klicken Sie auf die Option Create an application und Sie werden auf eine Seite weitergeleitet, auf der Sie eine neue Nexmo-Anwendung einrichten können.

Füllen Sie das Formular mit den folgenden Angaben aus:

  • Application name Textfeld eingeben rails-telephone-game

  • Event URL Textfeld Ihre ngrok-URL ein: https://[ngrok url here]/event

  • Answer URL Textfeld erneut Ihre ngrok-URL ein: https://[ngrok url here]/webhooks/answer

Wenn Sie fertig sind, klicken Sie auf die blaue Create Application Schaltfläche.

Sie haben nun eine Nexmo Voice Anwendung erstellt. Der nächste Schritt besteht darin, eine Nexmo-Telefonnummer zu erwerben und sie mit dieser Anwendung zu verknüpfen.

Klicken Sie auf dem Nexmo Dashboard auf den Menüpunkt Numbers Menüpunkt im linken Menü. Es werden drei Optionen angezeigt:

Numbers

Klicken Sie auf die Option Buy numbers und Sie werden auf eine Seite weitergeleitet, auf der Sie das Land, die Merkmale, den Typ und die vier Ziffern, die die Nummer haben soll, auswählen können.

Buy numbers

Für unsere Zwecke: Wählen Sie das Land, in dem Sie sich gerade befinden, so dass der Anruf für Sie ein Ortsgespräch ist; wählen Sie Voice für die Merkmale und entweder Handy oder Festnetz für den Typ. Für das Textfeld brauchen Sie nichts einzugeben. Number Textfeld eingeben. Wenn Sie auf Searchklicken, wird eine Liste der verfügbaren Telefonnummern angezeigt. Wählen Sie eine aus, indem Sie auf die orangefarbene Buy klicken und in der Bestätigungsaufforderung erneut auf die orangefarbene Buy bei der Bestätigungsaufforderung noch einmal.

Sobald Sie die Nummer besitzen, können Sie sie mit Ihrer rails-telephone-game Voice-Anwendung verknüpfen. Klicken Sie dazu auf das Zahnrad-Symbol neben der Telefonnummer und Sie sehen das folgende Menü:

Edit numbers conference call

Wählen Sie die voice-proxy-forwarding-demo Anwendung aus der Dropdown-Liste und klicken Sie auf die blaue Ok Schaltfläche. Ihre Nexmo-Telefonnummer ist nun mit Ihrer Voice-Anwendung verknüpft und bereit, eingehende Anrufe über Voice-Proxy anzunehmen und weiterzuleiten.

Einrichten eines Google Cloud Platform-Kontos

Die Google Cloud Platform-Dokumentation bietet eine hervorragende Dokumentation über die Einrichtung eines neuen Accounts.

Kurz gesagt, sobald Sie einen Account erstellt haben, müssen Sie eine neue Anwendung erstellen. Nachdem Sie Ihre neue Anwendung erstellt haben, müssen Sie sicherstellen, dass Sie Ihre Anmeldedaten herunterladen, die in einer Datei mit JSON enthalten sind. Speichern Sie die Datei an einem Ort, den Sie sich merken können, denn wir werden sie in Kürze verwenden. Wir werden gleich besprechen, wie Sie diese Datei zusammen mit Ihren Nexmo-API-Anmeldedaten als Umgebungsvariablen hinzufügen.

Vergewissern Sie sich schließlich in Ihrem Google Cloud Platform-Dashboard, dass Sie sowohl die Speech API als auch die Translate API aktiviert haben. Wir werden beide in unserem Telefonspiel verwenden.

Einrichten einer Rails-Anwendung

Wir sind nun bereit, unsere Rails-Anwendung zum Telefonieren einzurichten. Wir werden das Folgende tun:

  1. Initialisierung einer neuen Anwendung

  2. Hinzufügen unserer API-Anmeldeinformationen

  3. Definieren von Controller-Aktionen und -Routen

Initialisierung einer neuen Anwendung

Um eine neue Anwendung zu initialisieren, führen Sie Folgendes über die Befehlszeile aus:

rails new rails-telephone-game --database=postgresql

Dadurch wird eine neue Rails-Anwendung mit PostgreSQL als Standarddatenbank erstellt.

Sobald dieser Befehl beendet ist, öffnen Sie die Anwendung in Ihrem bevorzugten Code-Editor und bearbeiten Sie die Gemfile im Stammordner der Anwendung. Wir werden die Edelsteine Nexmo Ruby, dotenv-rails, Google Cloud Platform Translate API und Google Cloud Platform Speech API hinzufügen:

# Gemfile

gem 'nexmo'
gem 'dotenv-rails'
gem 'google-cloud-translate'
gem 'google-cloud-speech'

Nachdem Sie die Gemfilegespeichert haben, können Sie die Gems installieren, indem Sie bundle install von der Kommandozeile aus aufrufen.

Sie sollten auch die Funktion rake db:migrate ausführen, um das Datenbankschema zu initialisieren. Für die Zwecke dieser exemplarischen Vorgehensweise werden die Daten nicht persistent gemacht, aber Sie können dies auch selbst tun.

API-Anmeldeinformationen hinzufügen

Wir müssen die API-Anmeldeinformationen sowohl für Nexmo als auch für Google Cloud Platform in unserer Anwendung bereitstellen. Um unsere Umgebungsvariablen sicher zu verwalten, werden wir die Funktionalität des dotenv-rails Gem, das wir installiert haben. Erstellen Sie zunächst eine neue Datei namens .env im Stammverzeichnis Ihres Projekts und fügen Sie den Pfad zu dieser Datei in Ihre .gitignore Datei hinzu. Öffnen Sie die .env Datei und fügen Sie Folgendes hinzu:

# .env

GOOGLE_APPLICATION_CREDENTIALS=
GOOGLE_PROJECT_ID=
NEXMO_API_KEY=
NEXMO_API_SECRET=
NEXMO_NUMBER=
NEXMO_APPLICATION_ID=
NEXMO_PRIVATE_KEY=
BASE_URL=

Die erste Umgebungsvariable, GOOGLE_APPLICATION_CREDENTIALSverweist auf den Pfad der JSON-Datei, die Ihre API-Anmeldeinformationen für Google enthält. Verschieben Sie die Datei, die Sie bei der Einrichtung Ihres Accounts heruntergeladen haben, in das Stammverzeichnis Ihrer Anwendung und fügen Sie den Pfad auf der rechten Seite des = Zeichens (d.h. GOOGLE_APPLICATION_CREDENTIALS=./my-google-cloud-platform-credentials.json).

Die zweite Umgebungsvariable, GOOGLE_PROJECT_IDist die ID des Google Cloud Platform-Projekts, das Sie bei der Anmeldung erstellt haben (d. h. GOOGLE_PROJECT_ID=rails-telephone-game).

Die nächsten fünf Umgebungsvariablen beziehen sich auf Ihren Nexmo Account. Sie finden Ihre NEXMO_API_KEY und NEXMO_API_SECRET auf der Hauptseite deines Nexmo Dashboard.

Der NEXMO_NUMBER ist der Wert der Telefonnummer, die Sie von Nexmo erhalten haben.

Die NEXMO_APPLICATION_ID finden Sie in der Liste Ihrer Applications im Nexmo Dashboard. Die NEXMO_PRIVATE_KEY ist, wie die Google-Anmeldedaten, der Pfad zu den Anmeldedaten des privaten Schlüssels für Ihren Account. Als Sie Ihre Nexmo-Sprachapplikation erstellt haben, haben Sie ein öffentliches/privates Schlüsselpaar generiert, wodurch der private Schlüssel automatisch auf Ihren Computer heruntergeladen wurde. Verschieben Sie den privaten Schlüssel in den Stammordner Ihrer Anwendung und fügen Sie den Pfad als Wert dieser Variable hinzu, genauso wie Sie es für GOOGLE_APPLICATION_CREDENTIALS.

Die letzte Umgebungsvariable ist Ihre externe ngrok-URL, zum Beispiel: http://my-sample-url.ngrok.io.

Nachdem nun alle Anmeldeinformationen zu Ihrer Anwendung hinzugefügt wurden, können wir nun unseren Controller und unsere Routes erstellen.

Definieren von Controller-Aktionen

Erstellen Sie zunächst eine neue Datei in /app/controllers/ mit dem Namen telephone_controller.rb. Die erste Arbeit, die wir darin verrichten werden, ist die Definition von Instanzen des Nexmo-Clients und des Google Cloud Platform-Clients mit Anmeldeinformationen:

# 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

Wir werden uns jetzt auch einen Moment Zeit nehmen und die Liste der Sprachen definieren, die die Google Cloud Platform Translate API im Spiel durchlaufen soll:

# telephone_controller.rb

class TelephoneController < ApplicationController

....

LANGUAGES = [
    'ar',
    'he',
    'hi',
    'ku',
    'ru',
    'tr',
    'yi'
]

Für diese Komplettlösung habe ich Arabisch, Hebräisch, Hindi, Kurdisch, Russisch, Türkisch und Jiddisch gewählt. Sie können natürlich jede Sprache ersetzen oder hinzufügen, die Sie möchten.

Wir müssen zwei Aktionen in unserem Controller definieren: #answer und #event. Die #answer Methode ist für die Annahme des Anrufs, das Abhören und Aufzeichnen der Nachricht des Benutzers und das Offenhalten des Anrufs während der Bearbeitung verantwortlich. Die #event Methode ist für die Transkription der Aufnahme in Text zuständig, lässt sie durch den Übersetzer laufen und gibt die neu übersetzte Nachricht an den Anrufer zurück.

Die #answer Methode:

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

Die #answer Methode besteht aus Nexmo Call Control Object (NCCO) Anweisungen im JSON-Format. Die erste Anweisung sendet eine Willkommensnachricht an den Anrufer, die zweite zeichnet die Antwort des Anrufers auf und teilt Nexmo mit, dass die Callback-URL /event auf die ngrok-URL Ihrer Anwendung. Die dritte Anweisung teilt dem Anrufer mit, dass die Nachricht bearbeitet wird, während die vierte Anweisung Nexmo's conversation Funktion, um den Anruf offen zu halten, während die Verarbeitung stattfindet.

Die Methode #event Methode ist in eine bedingte Prüfung eingeschlossen, um festzustellen, ob es eine Audioaufnahme gibt. Der /event Endpunkt wird von Nexmo mehrmals mit verschiedenen Statusaktualisierungen aufgerufen, aber wir interessieren uns nur für diejenige, die eine Aufnahme enthält:

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

Es gibt eine Menge, was in der #event Methode passiert; lassen Sie es uns aufschlüsseln.

Sobald die Parameter mit einem recording_url zurückkommt, speichern wir die Aufnahme lokal. Dann nutzen wir die GCP Speech to Text API, um die Audioaufnahme in transkribierten Text zu konvertieren.

Zu diesem Zweck definieren wir mehrere Variablen, die die Audiokonfiguration enthalten. Wir haben uns für die Simulation von Streaming von Text an die GCP-API zur Konvertierung zu simulieren, anstatt die gespeicherte Audiodatei direkt zu senden.

Bei diesem Ansatz ist ein deutlicher positiver Unterschied in der Leistungsgeschwindigkeit festzustellen. Das Ergebnis ist ein Array mit den möglichen Transkriptionen. Wir wollen nur die erste, und das ist es, was wir hier tun:

results.first.alternatives.each do |alternatives|
    transcribed_text = alternatives.transcript
end

Die Variable transcribed_text enthält nun den Text der Audionachricht des Anrufers. Unser nächster Schritt in der Methode besteht darin, sie durch die Sprachen laufen zu lassen, die wir für die Übersetzung definiert haben. Wir wollen, dass der Text, der jedes Mal übersetzt wird, wenn er durch die Translator die nächste Iteration der übersetzten Nachricht sein. Dadurch unterscheidet sich die endgültige Nachricht noch mehr von der ursprünglichen Nachricht und macht somit mehr Spaß!

Zu diesem Zweck wird eine neue Variable namens translated_textan, die zunächst durch den Inhalt von transcribed_text. Nach jeder Iteration, translated_textauf die Übersetzung der aktuellen Iteration, die dann als zu übersetzender Text für die nächste Iteration verwendet wird. Schließlich wird die letzte Übersetzung ein letztes Mal durch den Übersetzer laufen gelassen und ins Englische zurückgegeben. Dieser Text wird dem Aufrufer wiedergegeben:

# 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')

Im obigen Code ist zu beachten, dass wir einen ternären Operator verwenden, um zu prüfen, ob der Wert von translated_text gleich ist mit dem transcribed_text. Wir tun dies, weil wir auf den Text anders zugreifen müssen, wenn es sich um ein Google Cloud Platform Speech to Text-Objekt (d. h. mit Punktnotation) handelt oder nicht.

Die letzte Aufgabe innerhalb der Methode besteht darin, sie an den Aufrufer zurückzugeben. Dazu verwenden wir die Variable @@uuid Variable, die die Gesprächs-ID enthält und den Text als Text-to-Speech in den aktuellen Anruf einfügt:

# 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 != ''

Sobald unsere Controller-Aktionen definiert sind, müssen wir als letzten Schritt die Routes für unsere Anwendung erstellen.

Festlegen der Routen

Öffnen Sie die routes.rb Datei im Ordner /config Ordner. Wir fügen eine GET und eine POST Anfrage:

# routes.rb

get '/answer', to: 'telephone#answer'
post '/event', to: 'telephone#event'

Das war's! Wir haben unsere Anwendung erfolgreich erstellt. Wir sind nun bereit, sie zu starten. Vergewissern Sie sich, dass ngrok im Hintergrund läuft, und starten Sie Ihren Rails-Server vom Terminal aus, indem Sie : rails s. Sie können nun Ihre Nexmo-Telefonnummer anrufen und Telefon spielen. Viel Spaß dabei!

Teilen Sie:

https://a.storyblok.com/f/270183/384x384/e5480d2945/ben-greenberg.png
Ben GreenbergVonage Ehemalige

Ben ist ein Entwickler im zweiten Beruf, der zuvor ein Jahrzehnt in den Bereichen Erwachsenenbildung, Community-Organisation und Non-Profit-Management tätig war. Er arbeitete als Anwalt für Entwickler bei Vonage. Er schreibt regelmäßig über die Überschneidung von Gemeindeentwicklung und Technologie. Ursprünglich aus Südkalifornien stammend und lange Zeit in New York City ansässig, wohnt Ben jetzt in der Nähe von Tel Aviv, Israel.