https://d226lax1qjow5r.cloudfront.net/blog/blogposts/aws-transcribe-with-nexmo-voice-using-php-dr/E_Voice-Transcription-PHP_1200x600.png

AWS Transcribe mit Nexmo Voice unter Verwendung von PHP

Zuletzt aktualisiert am April 28, 2021

Lesedauer: 13 Minuten

Anwendungsfälle für die Sprachtranskription werden immer häufiger - von IoT-Geräten, die oft nur über eine Audioschnittstelle verfügen, bis hin zu Sprachnachrichtendiensten, von denen erwartet wird, dass sie eine Echtzeit-Textvorschau des Nachrichteninhalts liefern, werden Sprache-zu-Text-Funktionen für eine Vielzahl von Anwendungen unverzichtbar.

In diesem Tutorial verwenden wir eine Nexmo Voice Nummer, um ein Rückrufskript zu erstellen, das mit einem Anrufer interagiert und ihn zur Eingabe einer Sprachnachricht auffordert. Nachdem wir den Inhalt der Aufnahme abgerufen haben, werden wir eine Sprachtranskription von Amazon Transcribe.

Voraussetzungen

In diesem Beispiel werden die folgenden Angaben benötigt:

  • PHP lokal installiert (Version 7.3+ bevorzugt)

  • Composer installiert global (weitere Einzelheiten später)

  • AWS Konto

  • ngrok lokal installiert (mehr dazu später)

Ein vollständiges Codebeispiel finden Sie unter https://github.com/nexmo-community/voice-aws-speechtotext-php.

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.

AWS-Einrichtung

Sie benötigen ein AWS-Konto, sowie IAM-Anmeldeinformationen die mit einem Benutzer verbunden sind, der Zugriff hat auf Amazon Transcribe und AWS S3.

Ein S3 Bucket erstellen

Erstellen Sie ein S3 Bucket, um die von Nexmo abgerufenen MP3-Dateien der Sprachaufnahmen zu speichern. Dies ermöglicht Amazon Transcribe den einfachen Zugriff auf die Dateien, um sie später zu transkribieren.

Aktivieren Sie nach der Erstellung des Bereichs das Kontrollkästchen neben dem Bereichsnamen. Dadurch wird ein Feld von rechts eingeblendet. Klicken Sie auf die Schaltfläche "Copy Bucket ARN" und speichern Sie sie zur späteren Verwendung.

Erstellen eines IAM-Benutzers

Wählen Sie die IAM-Verwaltungskonsole im Bereich Dienste aus:

Select IAM Management ConsoleSelect IAM Management Console

Fügen Sie in der IAM-Verwaltungskonsole einen neuen IAM-Benutzer hinzu, indem Sie auf die blaue Schaltfläche Benutzer hinzufügen klicken:

AWS new IAM userAdd a new IAM user

Nachfolgend finden Sie ein JSON-Snippet, mit dem Sie dem neuen Benutzer die erforderlichen Berechtigungen für die Nutzung von S3 und der Transcribe-Dienste zuweisen können. Stellen Sie sicher, dass Sie {bucket_name} durch den tatsächlichen Bucket-Namen ersetzen. Die Resource im JSON sollte mit dem ARN übereinstimmen, den Sie nach der Erstellung des Buckets in S3 gespeichert haben:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "transcribe:*",
            "Resource": "*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
            "s3:PutObject",
            "s3:GetObject",
            "s3:DeleteObject"
        ],
            "Resource": "arn:aws:s3:::{bucket_name}/*"
        }
    ]
}

Anwendung Basis

An diesem Punkt müssen wir mit der Organisation der Anwendung selbst beginnen. Wir gehen von einem leeren Verzeichnis aus und beginnen von dort aus mit der Erstellung der Beispiel-Callback-Anwendung. Außerdem gehen wir von einem lokalen System aus, auf dem PHP bereits eingerichtet ist und läuft und über die Befehlszeilenschnittstelle (CLI) verwendet werden kann.

Erstellen Sie in diesem leeren Verzeichnis eine neue PHP-Datei und nennen Sie sie index.php. Im Moment geben Sie einfach das Wort "test" in die Datei ein. Dies wird eine Ausgabe erzeugen und uns ermöglichen, im nächsten Schritt zu testen.

PHP Eingebauter Webserver und ngrok

In diesem Beispiel führen wir eine PHP-Anwendung lokal mit dem PHP eingebauten Webserver. Obwohl der integrierte Webserver nicht in einer Produktionsumgebung verwendet werden sollte, ist er für Beispielskripte wie dieses gut geeignet.

Wechseln Sie mit einem Terminal in das Projektverzeichnis. Geben Sie dort den Befehl zum Starten des integrierten PHP-Webservers wie folgt ein:

php -S localhost:8080

Jetzt sollte die Eingabe von "http://localhost:8080" in einem Browser eine "Test"-Antwort ergeben, wenn Sie dies in der index.php Datei eingegeben haben.

Wir verwenden auch ngrok um die lokale Anwendung im Internet als Callback-Endpunkt für den Nexmo-Voice-Dienst verfügbar zu machen. Werfen Sie einen Blick auf diese Seite wenn Sie Hilfe bei der Einrichtung von ngrok benötigen, aber die Grundlagen sind: Erstellen Sie ein Konto bei ngrok, laden Sie die ausführbare Datei herunter, starten Sie einen Tunnel per CLI und verwenden Sie dann die vom CLI bereitgestellten Weiterleitungs-URLs.

Als Nächstes bringen Sie ngrok zum Laufen, um die Ergebnisse des Webservers über das Internet verfügbar zu machen. Navigieren Sie in einem Terminal zu dem Ort, an dem ngrok zuvor installiert wurde, und geben Sie den folgenden Befehl ein:

./ngrok http 8080

Im Gegenzug stellt uns ngrok einige wichtige Informationen zur Verfügung, wie auf dem folgenden Screenshot zu sehen ist:

ngrok information returnedngrok information returned

Auf diese Weise erhalten wir die Informationen über den Dienst, einschließlich der Tunnel-URLs, mit denen wir unser lokal ausgeführtes Skript aufrufen können. Wir können die bereitgestellten Informationen in einen Webbrowser eingeben und sollten die gleichen Ergebnisse erhalten wie bei der obigen Abfrage über localhost.

Hinweis: Es wird empfohlen, https-URLs zu verwenden, um alle zwischen den Diensten ausgetauschten Anmeldeinformationen zu schützen.

Wir werden die ngrok-Instanz während dieses Beispiels laufen lassen. Wenn Sie bereit sind, es zu beenden, drücken Sie einfach "Strg+c" im Terminal und es wird ngrok geschlossen.

Nexmo-Einrichtung

Mit den von ngrok bereitgestellten URLs können wir eine Anwendung in Nexmo hinzufügen und sie mit einer Nummer verknüpfen. Erweitern Sie im Nexmo Dashboard den Menüpunkt Nummern, um "Ihre Nummern" anzuzeigen (und fügen Sie bei Bedarf eine neue Nummer hinzu):

nexmo_dashboardNexmo Dashboard

Da wir nun sicher sind, dass es eine Nummer gibt, die in einer Anwendung verwendet werden soll, klicken Sie im linken Menü auf "Ihre Anwendungen" und dann auf "Eine neue Anwendung erstellen":

create_applicationCreate Application

Geben Sie der Anwendung einen guten Namen, klicken Sie dann auf die Schaltfläche zum Erzeugen eines öffentlichen und privaten Schlüssels im Bereich Authentifizierung und speichern Sie die private.key in dem oben neu erstellten App-Verzeichnis:

authentication_keysAuthentication Keys

Schalten Sie die Sprachfunktion ein und fügen Sie die von ngrok oben angegebene URL in die Felder ein:

voice_urlsVoice URLs

Dies weist Nexmo an, Rückrufe zu tätigen, wenn bestimmte Ereignisse eintreten, und wir wollen, dass diese Rückrufe auf die neue App verweisen, die wir erstellen werden.

Die Ereignis-URL wird verwendet, wenn ein Ereignis den Status eines Anrufs ändert, während die Antwort-URL für alle eingehenden Anrufe angefordert wird, um ein NCCO-Objekt abzurufen (Nexmo Anrufsteuerungsobjekt).

Klicken Sie abschließend unten auf die Schaltfläche "Neuen Antrag erstellen".

Nur noch ein weiterer Schritt, um sicherzustellen, dass diese neue Anwendung wie erwartet funktioniert. Klicken Sie auf der Seite Ihre Anwendungen auf die neu erstellte Anwendung. Unten auf der Seite finden Sie eine Liste der verfügbaren Nummern im Konto. Klicken Sie auf die Schaltfläche "Verknüpfen", um die Anwendung mit der gewünschten Nummer zu verknüpfen:

link_the_appLink the app

Jetzt sind wir mit der Einrichtung von Nexmo fertig. Zeit, mit der Entwicklung der App zu beginnen!

Komponist

Im Projektordner müssen wir Composer starten, damit wir einige Pakete/Abhängigkeiten einbinden können. Navigieren Sie zum Projektverzeichnis und geben Sie den folgenden Befehl ein:

composer init

Die neuesten Versionen von Composer führen nun einen schrittweisen Prozess durch, um Ihnen bei der Einrichtung eines Projekts zu helfen. Folgen Sie den Eingabeaufforderungen und füllen Sie die Felder wie gewünscht aus. Stellen Sie sicher, dass Sie diese Pakete einschließen:

Erforderliche Abhängigkeiten

Um den Assistenten aus dem vorigen Abschnitt zu vervollständigen oder manuell eine composer.json Datei zu erstellen, schließen Sie die folgenden Abhängigkeiten für dieses Beispiel ein:

  • vlucas/phpdotenv - speichert Anmeldeinformationen in der superglobalen Datei $_ENV

  • schlank/slim - leichtes Microframework, das den Umgang mit HTTP-Aufrufen und Rückrufen erleichtert

  • slim/psr7 - erleichtert die HTTP-Interoperabilität zwischen Bibliotheken

  • nexmo/client - für alles, was mit Nexmo zu tun hat, was auch Guzzle als Abhängigkeit einbringt

  • league/flysystem-aws-s3-v3 - um die Nutzung von S3 zu abstrahieren, was auch das AWS SDK als Abhängigkeit einbringt

Abgeschlossen composer.json Beispiel:

{
    "require": {
        "ext-json":  "used for JSON handling",
        "slim/slim": "4.2.0",
        "slim/psr7": "0.5",
        "vlucas/phpdotenv": "3.5.x-dev",
        "nexmo/client": "2.0.0",
        "league/flysystem-aws-s3-v3": "1.0.23"
    }
}

Composer-Installation

Nachdem alle Abhängigkeiten zu Composer hinzugefügt wurden, können wir sie nun mit dem folgenden Befehl in der CLI installieren:

composer install

Berechtigungsnachweise hinzufügen

Die Zugangsdaten für diese Beispielanwendung werden in einer ENV-Datei gespeichert und von phpdotenv geparst.

ENV-Einrichtung

Das Erstellen einer .env Datei ermöglicht es uns, Anmeldeinformationen zu speichern, die für die Verbindung mit externen Diensten wie Nexmo und AWS benötigt werden. Fügen Sie den folgenden Inhalt in eine neu erstellte .env Datei im Stammverzeichnis des Projekts hinzu:

APP_ID=voice-aws-transcribe-php LANG_CODE=en-US SAMPLE_RATE=8000 AWS_REGION= AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= AWS_S3_BUCKET_NAME= AWS_S3_RECORDING_FOLDER_NAME= NEXMO_APPLICATION_PRIVATE_KEY_PATH='./private.key' NEXMO_APPLICATION_ID=

HINWEIS: Die oben genannten Informationen können sich ändern. Prüfen Sie daher die Einstellungen bei AWS bzw. Nexmo.

PHPDotEnv Verwendung

In der Datei index.php fügen Sie den folgenden Code ein, um den Composer Autoloader zu nutzen und das PHP-Paket phpdotenv zu verwenden, um den Inhalt der Datei .env Datei in die superglobale Datei $_ENV einzufügen:

<?php

require('vendor/autoload.php');

Dotenv\Dotenv::create(__DIR__)->load();

Slim PHP verwenden

Um slim in unserem Beispiel-Callback-Skript einzurichten, importieren wir mit einer use Anweisung importieren, unmittelbar nach dem Composer Autoload require. Dann rufen wir die create() Funktion von Slim auf, um eine Slim-App zu erstellen und einen Funktionsaufruf an app->run am Ende der Datei, um die Dinge in Gang zu setzen:

use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Slim\Factory\AppFactory;

$app = AppFactory::create();

//... call to Dotenv::create() shown earlier

//... we will create additional route-based middleware here

$app->run();

Hinzufügen von Abhängigkeiten

Es sind noch einige weitere Abhängigkeiten erforderlich, um unsere Arbeit zu erleichtern, also fügen wir unserem Skript die folgenden Importe hinzu. Damit stellen wir sicher, dass die benötigten Klassen für den Composer-Autoloader verfügbar sind:

use Nexmo\Client;
use Nexmo\Client\Credentials\Keypair;
use Aws\S3\S3Client;
use League\Flysystem\AwsS3v3\AwsS3Adapter;
use League\Flysystem\Filesystem;
use Aws\TranscribeService\TranscribeServiceClient;

Status-Updates

Wie bereits erwähnt, wird Nexmo bei so gut wie jedem Ereignis Status-Updates senden. Lassen Sie uns also zuerst diese routenbasierte Middleware aufbauen, um sie aus dem Weg zu räumen:

$app->post('/webhooks/event', function (Request $request, Response $response) {

    $params = $request->getParsedBody();

    error_log($params['recording_url']);

    return $response
        ->withStatus(204);
});

Diese routenbasierte Middleware empfängt einfach eine Anfrage an /webhooks/event und protokolliert sie. Mehr wird für dieses Beispiel nicht benötigt.

Antwort auf einen Anruf

Wir möchten die Slim-Funktionalität nutzen, um HTTP-Anfragen an unseren /webhooks/answer Endpunkt unter Verwendung einer routenbasierten Middleware abzufangen, so dass wir, wenn Nexmo einen Anruf an unsere (zuvor konfigurierte) Nummer erhält, eine JSON-Antwort bereitstellen können. Konkret wollen wir Nexmo eine NCCO-Nutzlast zur Verfügung stellen.

So sieht diese Middleware aus:

$app->any('/webhooks/answer', function (Request $request, Response $response) {
    $uri = $request->getUri();

    if ($request->getMethod() != 'GET') {
        return $response->withStatus(403);
    }

    $ncco = [
        [
            'action' => 'talk',
            'text' => 'Please leave a message after the tone, then press #.'
        ],
        [
            'action' => 'record',
            'eventUrl' => [
                $uri->getScheme().'://'.$uri->getHost().'/webhooks/fetch'
            ],
            'endOnSilence' => '3',
            'endOnKey' => '#',
            'beepOnStart' => true
        ],
        [
            'action' => 'talk',
            'text' => 'Thank you for your message. Goodbye.'
        ],
        [
            'action' => 'notify',
            'payload' => ['followup' => true],
            'eventUrl' => [
                $uri->getScheme().'://'.$uri->getHost().'/webhooks/transcribe'
            ],
            'eventMethod' => "POST"
        ],

    ];

    $response->getBody()->write(json_encode($ncco));
    return $response
        ->withHeader('Content-Type', 'application/json');
});

Mit dieser routenbasierten Middleware reagiert die App auf eine GET HTTP-Anfrage an /webhooks/answer mit einem NCCO-Objekt, das Nexmo anweist, den Anruf zu beantworten, indem es nach einer Nachricht fragt und den Anrufer auffordert, die #-Taste zu drücken, um den Anruf zu beenden.

Nach der Aufnahme, die entweder durch eine 3-sekündige Stille oder durch Drücken der #-Taste beendet wird, sollte Nexmo einen Rückruf an den /webhooks/fetch Endpunkt machen, der die MP3-Abfrage der Aufnahme startet und sich beim Anrufer für die Nachricht bedankt.

Und schließlich, sobald der Rückruf in der Aufnahme abgeschlossen ist, wird Nexmo einen Benachrichtigungsrückruf an den /webhooks/transcribe Endpunkt, um Amazon Transcribe zu starten.

Aufnahmen holen

Wenn eine Sprachaufnahme gemacht wird, wird sie bei Nexmo zum Abruf gespeichert. Daher müssen wir eine routenbasierte Middleware erstellen, die von Nexmo aufgerufen wird, um den Download zu initiieren. Sie wird wie folgt aussehen:

$app->post('/webhooks/fetch', function (Request $request, Response $response) {

    $params = json_decode($request->getBody(), true);

    // Create Nexmo Client
    $keypair = new Keypair(
        file_get_contents($_ENV['NEXMO_APPLICATION_PRIVATE_KEY_PATH']),
        $_ENV['NEXMO_APPLICATION_ID']
    );

    $nexmoClient = new Client($keypair);

    $data = $nexmoClient->get($params['recording_url']);

    // Create AWS S3 Client
    $S3Client = new S3Client([
        'region' => $_ENV['AWS_REGION'],
        'version' => 'latest',
    ]);

    $adapter = new AwsS3Adapter($S3Client, $_ENV['AWS_S3_BUCKET_NAME']);

    $filesystem = new Filesystem($adapter);

    $filesystem->put('/' . $_ENV['AWS_S3_RECORDING_FOLDER_NAME'] .'/'.$params['conversation_uuid'].'.mp3', $data->getBody());

    return $response
        ->withStatus(204);
});

Im Beispielcode dekodieren wir das JSON aus dem Request Body, um die URL der Aufzeichnung zu erhalten. Dann erstellen wir einen Client des Nexmo SDK (unter Verwendung eines Schlüsselpaares für die Anmeldedaten) und rufen die Aufnahme ab.

Anschließend leiten wir die Aufzeichnung an AWS S3 weiter, indem wir FlySystemund nutzen das AWS SDK für die Konnektivität.

umschreiben.

Der letzte Schritt besteht darin, die routenbasierte Middleware zu erstellen, um die Transkription durch den Amazon Transcribe Dienst anzufordern. Hier ist, wie man das macht:

$app->post('/webhooks/transcribe', function (Request $request, Response $response) {

    $params = json_decode($request->getBody(), true);

    // Create Amazon Transcribe Client
    $awsTranscribeClient = new TranscribeServiceClient([
        'region' => $_ENV['AWS_REGION'],
        'version' => 'latest',
    ]);

    $transcriptionResult = $awsTranscribeClient->startTranscriptionJob([
            'LanguageCode' => 'en-US',
            'Media' => [
                'MediaFileUri' => 'https://' . $_ENV['AWS_S3_BUCKET_NAME'] . '.s3.amazonaws.com/' . $_ENV['AWS_S3_RECORDING_FOLDER_NAME'] . '/' . $params['conversation_uuid'] . '.mp3',
            ],
            'MediaFormat' => 'mp3',
            'TranscriptionJobName' => 'nexmo_voice_' . $params['conversation_uuid'],
    ]);

    $response->getBody()->write(json_encode($transcriptionResult->toArray()));

    return $response
        ->withHeader('Content-Type', 'application/json')
        ->withStatus(204);
});

Hinweis: Das AWS SDK erhält die Anmeldung und den Schlüssel von der Umgebung.

In dieser Middleware wird die JSON-Nutzlast in der Anfrage geparst, damit wir die conversation_uuid.

Dann wird ein Amazon Transcribe-Client verwendet, um einen Transkriptionsauftrag unter Verwendung der auf S3 gespeicherten MP3-Datei zu erstellen.

Schlussfolgerung

Anhand dieses Beispiels konnten wir einen Anruf an eine Nexmo-Nummer entgegennehmen, den Anrufer auffordern, eine Nachricht zu hinterlassen, die Nachricht im MP3-Format abrufen und auf AWS S3 speichern und dann Amazon Transcribe auffordern, die Sprache in Text umzuwandeln.

Von dort aus kann der Text über die AWS-Konsole von AWS Transcribe abgerufen werden. Vielleicht können wir auch eine Art geplante Aufgabe erstellen, die in regelmäßigen Abständen überprüft, bevor sie für andere Zwecke heruntergeladen wird.

Ein vollständiges Codebeispiel finden Sie unter https://github.com/nexmo-community/voice-aws-speechtotext-php.

Share:

https://a.storyblok.com/f/270183/384x384/b3c7ffaf85/adamculp.png
Adam CulpVonage Ehemalige

Adam ist ein Entwickler und Berater, der gerne Ultraläufe absolviert, bloggt und anderen dabei hilft, Technologien zu zähmen, um erstaunliche Dinge zu erreichen, und der ein unstillbares Verlangen hat, Mentoren zu sein und zu helfen.