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

AWS Transcribe Con Nexmo Voice Usando PHP

Publicado el April 28, 2021

Tiempo de lectura: 14 minutos

Los casos de uso de la transcripción de voz son cada vez más frecuentes: desde los dispositivos IoT, que a menudo sólo tienen una interfaz de audio, hasta los servicios de mensajería de voz, que se espera que proporcionen previsualizaciones de texto en tiempo real del contenido de los mensajes, las capacidades de voz a texto se están convirtiendo en esenciales para una amplia variedad de aplicaciones.

En este tutorial, utilizaremos un Nexmo Voice para crear un script de devolución de llamada que interactúe con la persona que llama para solicitar un mensaje de voz. A continuación, tras recuperar el contenido de la grabación, solicitaremos una transcripción de voz a Amazon Transcribe.

Requisitos previos

En este ejemplo se necesita lo siguiente:

  • PHP instalado localmente (preferiblemente la versión 7.3+)

  • Composer instalado globalmente (más detalles más adelante)

  • AWS Account

  • ngrok instalado localmente (más detalles más adelante)

Para ver un ejemplo de código completo, visite https://github.com/nexmo-community/voice-aws-speechtotext-php.

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.

Configuración de AWS

Necesitará una Account de AWS, así como credenciales de IAM asociadas a un usuario que tenga acceso a Amazon Transcribe y AWS S3.

Crear un bucket S3

Cree un bucket de S3 para almacenar los archivos MP3 de grabación de voz recuperados de Nexmo. Esto permitirá a Amazon Transcribe acceder fácilmente a los archivos para transcribirlos más tarde.

Después de crearlo, asegúrese de marcar la casilla junto al nombre del cubo. Esto hará que se desplace un panel desde la derecha. Haga clic en el botón "Copiar ARN de cubo" y guárdelo para su uso posterior.

Creación de un usuario IAM

Seleccione la consola de gestión de IAM en el panel Servicios:

Select IAM Management ConsoleSelect IAM Management Console

En la consola de gestión de IAM, añada un nuevo usuario de IAM haciendo clic en el botón azul Añadir usuario:

AWS new IAM userAdd a new IAM user

A continuación se muestra un fragmento JSON para asignar los permisos necesarios para que el nuevo usuario utilice S3 y los servicios Transcribe. Asegúrese de sustituir {bucket_name} por el nombre real del bucket. El Resource en el JSON debe coincidir con el ARN que guardó de S3 después de crear el bucket:

{
    "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}/*"
        }
    ]
}

Base de aplicaciones

Llegados a este punto, necesitamos empezar a organizar la propia aplicación. Asumiremos un directorio vacío, y comenzaremos a construir la aplicación de callback de ejemplo desde allí. También asumiremos un sistema local con PHP ya configurado y corriendo, y capaz de ser usado vía CLI (Command Line Interface).

En este directorio vacío, cree un nuevo archivo PHP y nómbrelo index.php. Por el momento, simplemente escriba la palabra "test" en el archivo. Esto creará alguna salida y nos permitirá probar en el siguiente paso.

Servidor web incorporado en PHP y ngrok

En este ejemplo, ejecutaremos una aplicación PHP localmente con el PHP incorporado en el servidor web. Aunque el servidor web incorporado no debería usarse en un entorno de producción, está bien para scripts de ejemplo como este.

Utilizando un terminal, navegue hasta el directorio del proyecto. Una vez allí, ejecute el comando para iniciar el servidor web PHP incorporado, así:

php -S localhost:8080

Llegados a este punto, si introduce "http://localhost:8080" en un navegador, debería obtener una respuesta de "prueba", si eso es lo que ha introducido en el archivo index.php archivo.

También utilizaremos ngrok para que la aplicación local esté disponible en Internet como punto final de devolución de llamada para el servicio Nexmo Voice. Echa un vistazo a esta página si necesitas ayuda para configurar ngrok, pero lo básico es: crear una Account en ngrok, descargar el ejecutable, iniciar un túnel vía CLI, y luego usar las URLs de reenvío provistas por el CLI.

A continuación, ejecute ngrok para que los resultados del servidor web estén disponibles en Internet. En un terminal, navega a la ubicación donde ngrok fue instalado previamente, e introduce el siguiente comando:

./ngrok http 8080

A cambio, ngrok nos proporcionará información importante, como en la siguiente captura de pantalla:

ngrok information returnedngrok information returned

Esto nos permite conocer la información del servicio, incluyendo las URL del túnel que debemos utilizar para acceder a nuestro script que se ejecuta localmente. Podemos introducir la información proporcionada en un navegador web y obtener los mismos resultados que cuando se solicita a través de localhost anteriormente.

Nota: Se recomienda utilizar URLs https para proteger las credenciales que se comparten entre los servicios.

Dejaremos que la instancia de ngrok se ejecute a lo largo de este ejemplo. Cuando estés listo para apagarlo, simplemente pulsa "Ctrl+c" en el terminal y se cerrará ngrok.

Configuración de Nexmo

Con las URLs proporcionadas por ngrok, podemos añadir una Application en Nexmo y vincularla a un número. En el Panel de control de Nexmo, despliega el elemento de menú Numbers para exponer "Tus números" (y añade uno nuevo si es necesario):

nexmo_dashboardNexmo Dashboard

Ahora que estamos seguros de que hay un número para utilizar en una aplicación, en el menú de la izquierda, haga clic en "Sus aplicaciones" y después en "Crear una nueva aplicación":

create_applicationCreate Application

Dé un buen nombre a la aplicación y, a continuación, haga clic en el botón para generar una clave pública y privada en el área Autenticación, guardando el archivo private.key en el directorio de aplicaciones recién creado anteriormente:

authentication_keysAuthentication Keys

Active la función Voice y añada en los campos la URL indicada anteriormente por ngrok:

voice_urlsVoice URLs

Esto instruye a Nexmo para hacer callbacks cuando ocurran eventos específicos, y queremos que esos callbacks apunten a la nueva aplicación que vamos a crear.

La URL de evento se utilizará cuando cualquier evento cambie el estado de una llamada, mientras que la URL de respuesta se solicita para cualquier llamada entrante para recuperar un objeto NCCO (Objeto de Control de Llamada Nexmo).

Por último, haga clic en el botón de la parte inferior para "Generar nueva solicitud".

Sólo un paso más para asegurar que esta nueva aplicación funciona como se espera. Desde el tablón de Sus Aplicaciones, haga clic en la aplicación recién creada. Hacia la parte inferior de la página, habrá una lista de Numbers disponibles en la Account. Haga clic en el botón para "Vincular" la aplicación con el número deseado:

link_the_appLink the app

Ahora hemos terminado con la configuración de Nexmo. ¡Es hora de empezar a construir la aplicación!

Compositor

En la carpeta del proyecto, tenemos que init Composer, lo que nos permite incluir algunos paquetes / dependencias. Navegue hasta el directorio del proyecto y ejecute el siguiente comando.:

composer init

Las últimas versiones de Composer ahora realizan un proceso paso a paso para ayudar a configurar un proyecto. Siga las indicaciones y rellene lo que desee. Asegúrese de incluir estos paquetes:

Dependencias necesarias

Para completar el asistente de la sección anterior, o para configurar manualmente un archivo composer.json incluya las siguientes dependencias para este ejemplo:

  • vlucas/phpdotenv - almacena las credenciales en el superglobal $_ENV

  • slim/slim - microframework ligero que facilita el manejo de llamadas HTTP y callbacks

  • slim/psr7 - facilita la interoperabilidad HTTP entre bibliotecas

  • nexmo/cliente - para todas las cosas Nexmo, que también traerá en Guzzle como una dependencia

  • league/flysystem-aws-s3-v3 - para abstraer el uso de S3, que también traerá el SDK de AWS como una dependencia

Completado composer.json ejemplo:

{
    "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"
    }
}

Instalación de Composer

Con todas las dependencias añadidas a Composer, ahora estamos listos para instalarlas utilizando el siguiente comando en la CLI:

composer install

Añadir credenciales

Las credenciales para esta aplicación de ejemplo se alojarán en un archivo ENV y serán analizadas por phpdotenv.

Configuración ENV

La creación de un .env nos permite almacenar las credenciales necesarias para conectarnos a servicios externos, como Nexmo y AWS. Añade el siguiente contenido a un archivo .env en la raíz del proyecto:

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=

NOTA: La información anterior puede cambiar, así que asegúrese de comprobar la configuración en AWS y Nexmo respectivamente.

Uso de PHPDotEnv

En el archivo index.php creado anteriormente, añada el siguiente código para aprovechar el autocargador de Composer y utilizar el paquete phpdotenv de PHP para inyectar el contenido del archivo .env en el superglobal $_ENV:

<?php

require('vendor/autoload.php');

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

Uso de Slim PHP

Para configurar slim en nuestro script callback de ejemplo, importaremos con una sentencia use inmediatamente después de la carga automática de Composer require. Luego llamaremos a la función create() de Slim para crear una aplicación Slim y una llamada a la función app->run al final del archivo para poner las cosas en marcha:

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();

Añadir dependencias

Hay algunas dependencias más necesarias para hacer nuestro trabajo más fácil, así que vamos a añadir las siguientes importaciones a nuestro script. Esto asegurará que tenemos las clases que necesitamos disponibles para el Composer autoloader:

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;

Actualizaciones

Como hemos dicho antes, Nexmo enviará actualizaciones de estado en prácticamente todos los eventos. Por lo tanto, vamos a construir ese middleware basado en rutas primero para sacarlo de nuestro camino:

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

    $params = $request->getParsedBody();

    error_log($params['recording_url']);

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

Este middleware basado en rutas simplemente recibe una petición a /webhooks/event y la registra. No se necesita nada más para este ejemplo.

Responder a una llamada

Queremos usar la funcionalidad Slim para capturar peticiones HTTP a nuestro /webhooks/answer utilizando un middleware basado en rutas, de modo que cuando Nexmo reciba una llamada a nuestro número (configurado anteriormente) podamos proporcionar una respuesta JSON. En concreto, queremos proporcionar a Nexmo una carga útil NCCO.

Este es el aspecto del middleware:

$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');
});

Con este middleware basado en rutas, la aplicación responderá a una solicitud GET HTTP a /webhooks/answer con un objeto NCCO indicando a Nexmo que responda a la llamada pidiendo un mensaje y solicitando a la persona que llama que pulse la tecla # para finalizar la llamada.

Tras la grabación, que finaliza con un silencio de 3 segundos o cuando la persona que llama pulsa la tecla #, Nexmo debe realizar una devolución de llamada al punto final, que inicia la recuperación en MP3 de la grabación y agradece a la persona que llama el mensaje. /webhooks/fetch que inicia la recuperación en MP3 de la grabación y da las gracias a la persona que llama por el mensaje.

Y por último, una vez completada la devolución de llamada en la grabación, Nexmo realizará una devolución de llamada de notificación al /webhooks/transcribe endpoint para poner en marcha Amazon Transcribe.

Grabaciones Fetch

Cuando se realiza una grabación de voz, se almacena en Nexmo para su recuperación. Por lo tanto, necesitamos crear un middleware basado en rutas para ser llamado por Nexmo para iniciar la descarga. Tendrá el siguiente aspecto:

$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);
});

En el código de ejemplo, decodificamos el JSON del cuerpo de la solicitud para obtener la URL de la grabación. A continuación, creamos un cliente del Nexmo SDK (utilizando un par de claves para las credenciales) y recuperamos la grabación.

A continuación, reenviamos la grabación a AWS S3 utilizando FlySystemaprovechando el AWS SDK para la conectividad.

Transcriba

El último paso es crear el middleware basado en rutas para solicitar la transcripción por parte de servicio Amazon Transcribe de Amazon. He aquí cómo hacerlo:

$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);
});

Nota: El SDK de AWS obtiene el nombre de usuario y la clave del entorno.

En este middleware, analizamos la carga útil JSON de la solicitud para obtener la información conversation_uuid.

A continuación, se utiliza un cliente de Amazon Transcribe para crear un trabajo de transcripción utilizando el archivo MP3 almacenado en S3.

Conclusión

Con este ejemplo, hemos podido recibir una llamada a un número de Nexmo, pedir a la persona que llama que deje un mensaje, recuperar el mensaje en formato MP3 y almacenarlo en AWS S3 y, a continuación, solicitar a Amazon Transcribe que convierta la voz en texto.

A partir de ahí, el texto se puede recuperar de AWS Transcribe a través de la consola de AWS, o tal vez podríamos crear algún tipo de tarea programada para comprobar periódicamente antes de descargar para otros usos.

Para ver un ejemplo de código completo, visite https://github.com/nexmo-community/voice-aws-speechtotext-php.

Compartir:

https://a.storyblok.com/f/270183/384x384/b3c7ffaf85/adamculp.png
Adam CulpAntiguos alumnos de Vonage

Adam es un desarrollador y consultor al que le gusta correr a toda velocidad, bloguear y ayudar a otros a domar la tecnología para conseguir cosas increíbles, con un deseo insaciable de servir de mentor y ayudar.