Agrega traducción de voz a tu app para Android

Last reviewed 2019-02-08 UTC

En este instructivo, se muestra cómo proporcionar una función de traducción de voz a la app para Android. En la muestra de este instructivo, se usa un microservicio que recibe un mensaje de audio, traduce el mensaje a un conjunto de idiomas predefinidos y almacena los mensajes traducidos en archivos de audio. La app cliente para Android descarga y reproduce los archivos de audio traducidos cuando el usuario lo solicita.

Descripción general de la solución

La solución incluye los siguientes componentes:

Microservicio

El microservicio se implementa en Cloud Functions para Firebase y usa los siguientes productos de IA de Cloud a fin de traducir los mensajes:

El microservicio almacena los mensajes de audio traducidos en un depósito en Cloud Storage para Firebase.

App cliente

El componente de cliente es una app para Android que graba mensajes de audio y descarga los mensajes traducidos del bucket de Cloud Storage. La muestra es una app de chat que se usa en el instructivo Compila una app para Android con Firebase y el entorno flexible de App Engine. En este instructivo, se explica cómo extender la app de muestra para implementar la función de traducción de voz.

En el siguiente diagrama, se muestra la interacción entre el microservicio y la app cliente:

Arquitectura de soluciones de alto nivel

El microservicio realiza las siguientes tareas:

  1. Recibe el mensaje de audio en formato con codificación Base64.
  2. Transcribe el mensaje de audio con la API de Speech-to-Text.
  3. Traduce el mensaje transcrito con la API de Translation.
  4. Sintetiza el mensaje traducido con la API de Text-to-Speech.
  5. Almacena el mensaje de audio traducido en un bucket de Cloud Storage.
  6. Envía la respuesta al cliente. En la respuesta, se incluye la configuración regional del mensaje de audio traducido.

Arquitectura de microservicios

La app cliente realiza las siguientes tareas:

  1. Graba el mensaje de audio con las prácticas recomendadas de la API de Speech-to-Text para lograr una mayor precisión. La app usa el micrófono del dispositivo para capturar el audio.
  2. Codifica el mensaje de audio en formato Base64.
  3. Envía una solicitud HTTP al microservicio que incluye el mensaje de audio codificado.
  4. Recibe la respuesta HTTP del microservicio, que incluye la configuración regional del mensaje de audio traducido.
  5. Envía una solicitud al bucket de Cloud Storage para recuperar el archivo que incluye el mensaje de audio traducido.
  6. Reproduce el mensaje de audio traducido.

Objetivos

En este instructivo, se muestra cómo realizar las siguientes acciones:

  • Usar Cloud Functions para Firebase a fin de compilar un microservicio que encapsule la lógica que se requiere en la traducción de mensajes de audio mediante los siguientes productos de IA de Cloud:
    • API de Speech-to-Text
    • API de Translation
    • API de Text-to-Speech
  • Usa las API de Android Framework para grabar audio mediante las recomendaciones sobre cómo proporcionar datos de audio a la API de Speech-to-Text.
  • Usar la biblioteca Cronet para subir datos de voz desde la app cliente al microservicio y descargar mensajes traducidos desde Cloud Storage. A fin de obtener más información sobre la biblioteca Cronet, consulta Realiza operaciones de red mediante Cronet en la documentación para desarrolladores de Android.

Costos

En este instructivo, se extiende la app de muestra implementada en Compila una app para Android con Firebase y el entorno flexible de App Engine. Revisa la sección Costos del instructivo mencionado y considera los siguientes costos adicionales:

  • Firebase define cuotas para el uso de Cloud Functions que especifican límites en recursos, tiempo y frecuencia. Para obtener más información, consulta Cuotas y límites en la documentación de Firebase.
  • El uso de la API de Speech-to-Text tiene un precio mensual en función de la duración de los audios procesados de forma correcta. Hay una cantidad predeterminada de tiempo de procesamiento que puedes usar de forma gratuita cada mes. Para obtener más información, consulta Precios.
  • El uso de la API de Translation tiene un precio mensual en función de la cantidad de caracteres enviados a la API para su procesamiento. Para obtener más información, consulta la página sobre precios de la API de Translation.
  • El uso de la API de Text-to-Speech tiene un precio mensual en función de la cantidad de caracteres que se vayan a sintetizar en audio. Hay una cantidad de caracteres que puedes usar de forma mensual sin cargo. Para obtener más información, consulta Precios.
  • Las tarifas por uso de Firebase Storage se procesan como tarifas de Google Cloud Storage. Para obtener más información, consulta Precios de Cloud Storage.

Antes de comenzar

Completa el instructivo Compila una app para Android con Firebase y el entorno flexible de App Engine y, luego, instala el siguiente software:

Obtén un dispositivo de hardware que ejecute Android 7.0 (nivel de API 24) o superior para probar la función de traducción de voz.

Clona el código de muestra

Usa el siguiente comando para clonar el repositorio nodejs-docs-samples, que incluye el siguiente código de microservicio:

git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

Habilita la facturación y las API para el proyecto de Google Cloud

En este instructivo, se usa el proyecto de Playchat que se creó en “Compila una app para Android con Firebase y el entorno flexible de App Engine”, que requiere la API de Administrador de App Engine y la API de Compute Engine.

El microservicio requiere las siguientes API para procesar solicitudes de traducción de voz:

  • API de Text-to-Speech
  • API de Cloud Translation
  • API de Speech-to-Text

Para habilitar las API requeridas, sigue estos pasos:

  1. En Google Cloud Console, selecciona el proyecto de Playchat.

    Ir a la página Proyectos

  2. Asegúrate de que la facturación esté habilitada para tu proyecto de Google Cloud.

  3. Habilita las API de App Engine, Speech-to-Text, Translation, and Text-to-Speech.

    Habilita las API

Configura el bucket predeterminado en Cloud Storage para Firebase

El microservicio usa el bucket predeterminado de Cloud Storage en el proyecto de Firebase para almacenar los archivos de audio traducidos. Debes habilitar el acceso de lectura a las cuentas de usuario que deseen recuperar los archivos de audio.

Para habilitar el acceso de lectura, necesitas el UID de usuario de Firebase de la cuenta. Para obtener el UID de usuario, haz lo siguiente:

  1. En el menú de la izquierda de Firebase Console, selecciona Autenticación en el grupo Desarrollar.
  2. Toma nota del valor del UID de usuario de la cuenta de usuario que deseas usar para probar la app. El UID de usuario es una string de 28 caracteres.

Para habilitar el acceso de lectura a la cuenta de usuario, debes crear una regla de seguridad de almacenamiento. Para crear una regla de seguridad, haz lo siguiente:

  1. En el menú de la izquierda de Firebase Console, selecciona Almacenamiento en el grupo Desarrollar.
  2. Toma nota de la URL predeterminada del depósito, que tiene el formato gs://[FIREBASE_PROJECT_ID].appspot.com y aparece junto al ícono de un vínculo. Necesitas este valor para implementar el microservicio.
  3. En la página Almacenamiento, ve a la sección Reglas y agrega la siguiente regla dentro de la sección service firebase.storage:

     match /b/{bucket}/o {
       match /{allPaths=**} {
         allow read: if request.auth.uid == "[ACCOUNT_USER_UID]";
       }
     }
    

    Reemplaza ACCOUNT_USER_UID por el valor de UID de usuario que obtuviste en los pasos anteriores.

Para obtener más información, consulta Primeros pasos con las reglas de seguridad de Storage en la documentación de Firebase.

Compila y, luego, implementa el microservicio

Para compilar el microservicio, abre una ventana de la terminal y ve a la carpeta functions/speech-to-speech/functions en el repositorio nodejs-docs-samples que clonaste en la sección anterior.

El código de microservicio incluye un archivo .nvmrc que muestra la versión de Node.js que debes usar para ejecutar la app. Ejecuta el siguiente comando a fin de configurar NVM y, también, instalar las dependencias de microservicios:

nvm install && nvm use && npm install

Para acceder a Firebase mediante la interfaz de línea de comandos, ejecuta el siguiente comando:

firebase login

El microservicio requiere las siguientes variables de entorno:

  • OUTPUT_BUCKET: El depósito predeterminado de Cloud Storage en el proyecto de Firebase.
  • SUPPORTED_LANGUAGE_CODES: Una lista de códigos de idioma separados por comas que son compatibles con el microservicio.

Usa los siguientes comandos para declarar los datos de entorno requeridos en la interfaz de línea de comandos. Reemplaza el marcador de posición FIREBASE_PROJECT_ID por el valor que buscaste en la sección anterior.

firebase functions:config:set playchat.output_bucket="gs://[FIREBASE_PROJECT_ID].appspot.com"
firebase functions:config:set playchat.supported_language_codes="en,es,fr"

Configura la app para Android

La app de muestra de Playchat requiere la URL del microservicio para habilitar las funciones de traducción de voz. Para recuperar la URL del microservicio, haz lo siguiente:

  1. En el menú de la izquierda de Firebase Console, selecciona Funciones en el grupo Desarrollar.
  2. La URL de microservicio se muestra en la columna Activador, que tiene el formato https://[REGION_ID]-[FIREBASE_PROJECT_ID].cloudfunctions.net/[FUNCTION_NAME].

A fin de configurar la app para que funcione con el microservicio, abre el archivo app/src/main/res/values/speech_translation.xml en el repositorio firebase-android-client y actualiza el campo speechToSpeechEndpoint con la URL del microservicio.

Ejecuta la app para Android

Para usar la función de traducción de voz en la app, debes usar un dispositivo que admita la grabación de audio con un micrófono integrado, como un dispositivo de hardware.

Para usar la función de traducción de voz en la app, haz lo siguiente:

  1. Asegúrate de que el dispositivo de hardware usa alguno de los idiomas configurados en la sección Compila y, luego, implementa el microservicio. Para cambiar el idioma, abre la app de Configuración en el dispositivo y ve a Sistema > Idiomas y entrada > Idiomas.
  2. Abre el proyecto de Playchat en Android Studio y conecta el dispositivo de hardware a tu computadora con un cable USB. Para obtener más información, consulta Cómo configurar un dispositivo para desarrollo.
  3. Haz clic en Ejecutar en Android Studio para compilar y ejecutar la app en el dispositivo.
  4. En la app de Playchat, presiona el ícono del micrófono y comienza a grabar; graba un mensaje breve y vuelve a presionar el ícono del micrófono para detener la grabación.
  5. Después de unos segundos, la app de Playchat muestra el texto del mensaje grabado en la pantalla. Presiona el mensaje para reproducir la versión de audio.
  6. Configura el dispositivo para usar un idioma admitido diferente.
  7. La app de Playchat muestra el mensaje grabado con anterioridad en el nuevo idioma admitido. Presiona el mensaje para reproducir la versión de audio en el nuevo idioma.

En la siguiente captura de pantalla, se ve la app de Playchat que muestra un mensaje traducido al francés:

Función de traducción de voz en Android

Explora el código

La app cliente realiza las siguientes tareas para admitir la función de traducción de voz:

  1. Graba audio con los parámetros recomendados descritos en las prácticas recomendadas de la API de Speech-to-Text.
  2. Codifica el audio con el esquema Base64 para representarlo en un formato de string que se pueda incorporar en una solicitud HTTP.
  3. Envía una solicitud HTTP al microservicio. La solicitud incluye el mensaje de audio codificado junto con los metadatos que proporcionan información adicional sobre la carga útil. La app usa la biblioteca Cronet para administrar las solicitudes de red.
  4. Cuando el usuario quiere escuchar el mensaje traducido, la app emite una solicitud HTTP autenticada al bucket de Cloud Storage que almacena los mensajes traducidos para descargar el archivo de audio correspondiente.

En el siguiente ejemplo de código, se muestran las constantes que se usan en la muestra para especificar los parámetros de configuración de grabación:

private static final int AUDIO_SOURCE = MediaRecorder.AudioSource.UNPROCESSED;
private static final int SAMPLE_RATE_IN_HZ = 16000;
private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;
private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
  • AUDIO_SOURCE: MediaRecorder.AudioSource.UNPROCESSED indica una fuente de audio no procesada porque la aplicación de algoritmos de procesamiento de señal, como reducción de ruido o control de ganancia, reduce la precisión de reconocimiento.
  • SAMPLE_RATE_IN_HZ: la muestra usa un valor de 16,000 para la tasa de muestreo nativa de la fuente de audio.
  • CHANNEL_CONFIG: AudioFormat.CHANNEL_IN_MONO indica solo un canal de audio en la grabación. En la muestra, solo se toma la voz de una persona en la grabación.
  • AUDIO_FORMAT: AudioFormat.ENCODING_PCM_16BIT indica el formato de datos de audio PCM lineal con 16 bits por cada muestra. PCM lineal es un formato sin pérdidas, que se prefiere para el reconocimiento de voz.

La app cliente usa la API de AudioRecord para grabar audio desde el micrófono integrado y almacena un archivo .WAV en el dispositivo. Para obtener más información, consulta la clase RecordingHelper de la muestra de Playchat.

Para codificar el audio con el esquema Base64, en la muestra, se usa la clase Base64 de Android Framework. El audio codificado no debe incluir terminadores de línea, que se omiten mediante la marca NO_WRAP. En el siguiente ejemplo, se muestra cómo codificar audio con la clase Base64:

public static String encode(File inputFile) throws IOException {
    byte[] data = new byte[(int) inputFile.length()];
    DataInputStream input = new DataInputStream(new FileInputStream(inputFile));
    int readBytes = input.read(data);
    Log.i(TAG, readBytes + " read from input file.");
    input.close();
    return Base64.encodeToString(data, Base64.NO_WRAP);
}

Para enviar el audio codificado al microservicio, la app cliente emite una solicitud HTTP con los siguientes parámetros:

  • Método: POST
  • Tipo de contenido: application/json
  • Cuerpo: objeto JSON con los siguientes atributos:
    • encoding: la string LINEAR16.
    • sampleRateHertz: la tasa de muestreo del audio grabado. Por ejemplo, 16000.
    • languageCode: el código de idioma del mensaje grabado. La app cliente supone que el mensaje está grabado en el idioma configurado en la configuración del dispositivo. Por ejemplo, en-US.
    • audioContent: El mensaje de audio codificado en el esquema Base64.

En el siguiente ejemplo, se muestra cómo compilar un objeto JSON que incluye los atributos requeridos en el cuerpo de la solicitud:

JSONObject requestBody = new JSONObject();
try {
    requestBody.put("encoding", SPEECH_TRANSLATE_ENCODING);
    requestBody.put("sampleRateHertz", sampleRateInHertz);
    requestBody.put("languageCode", context.getResources().getConfiguration().getLocales().get(0));
    requestBody.put("audioContent", base64EncodedAudioMessage);
} catch(JSONException e) {
    Log.e(TAG, e.getLocalizedMessage());
    translationListener.onTranslationFailed(e);
}

Para obtener más detalles sobre cómo crear la solicitud HTTP, consulta la clase SpeechTranslationHelper de la app de muestra de Playchat.

Para recuperar los archivos de audio del bucket de Cloud Storage, la app usa una URL de descarga que incluye un token que puedes revocar desde Firebase Console, si lo deseas. Para obtener la URL de descarga, realiza una llamada al método getDownloadUrl(), como se muestra en el siguiente ejemplo:

FirebaseStorage storage = FirebaseStorage.getInstance();
StorageReference gsReference = storage.getReferenceFromUrl(gcsUrl);
gsReference.getDownloadUrl().addOnCompleteListener(getDownloadUriListener);

El microservicio realiza la siguiente tarea para admitir la función de traducción de voz:

  1. Recibe solicitudes de traducción de voz, que incluyen el audio codificado en Base64.
  2. Envía el audio codificado a la API de Speech-to-Text y recibe una transcripción en el idioma de origen.
  3. Para cada uno de los idiomas compatibles, envía la transcripción a la API de Translation y recibe el texto traducido.
  4. Para cada uno de los idiomas compatibles, envía el texto traducido a la API Text-to-Speech y recibe el audio traducido.
  5. Sube los archivos de audio traducidos al bucket de Cloud Storage.

El microservicio usa la salida de una llamada a una API de Cloud como la entrada de la llamada a la siguiente API, como se muestra en el siguiente ejemplo de código:

const [sttResponse] = await callSpeechToText(
  inputAudioContent,
  inputEncoding,
  inputSampleRateHertz,
  inputLanguageCode
);

// The data object contains one or more recognition
// alternatives ordered by accuracy.
const transcription = sttResponse.results
  .map(result => result.alternatives[0].transcript)
  .join('\n');
responseBody.transcription = transcription;
responseBody.gcsBucket = outputBucket;

const translations = [];
supportedLanguageCodes.forEach(async languageCode => {
  const translation = {languageCode: languageCode};
  const outputFilename =
    request.body.outputFilename ||
    `${uuid.v4()}.${outputAudioEncoding.toLowerCase()}`;

  try {
    const [textTranslation] = await callTextTranslation(
      languageCode,
      transcription
    );
    translation.text = textTranslation;

    const [{audioContent}] = await callTextToSpeech(
      languageCode,
      textTranslation
    );
    const path = `${languageCode}/${outputFilename}`;

    console.log('zzx', audioContent);

    await uploadToCloudStorage(path, audioContent);

    console.log(`Successfully translated input to ${languageCode}.`);
    translation.gcsPath = path;
    translations.push(translation);
    if (translations.length === supportedLanguageCodes.length) {
      responseBody.translations = translations;
      console.log(`Response: ${JSON.stringify(responseBody)}`);
      response.status(200).send(responseBody);
    }
  } catch (error) {
    console.error(
      `Partial error in translation to ${languageCode}: ${error}`
    );
    translation.error = error.message;
    translations.push(translation);
    if (translations.length === supportedLanguageCodes.length) {
      responseBody.translations = translations;
      console.log(`Response: ${JSON.stringify(responseBody)}`);
      response.status(200).send(responseBody);
    }
  }
});

Limpia

Para evitar que se generen costos en tu cuenta de Google Cloud por los recursos que se usaron en este instructivo, sigue estos pasos:

Borra el proyecto de Google Cloud y Firebase

La forma más sencilla de detener los cargos de facturación es borrar el proyecto que creaste para este instructivo. Aunque creaste el proyecto en Firebase Console, también puedes borrarlo desde Google Cloud Console, ya que los proyectos de Firebase y de Google Cloud son el mismo.

  1. En la consola de Google Cloud, ve a la página Administrar recursos.

    Ir a Administrar recursos

  2. En la lista de proyectos, elige el proyecto que quieres borrar y haz clic en Borrar.
  3. En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrar el proyecto.

Borra las versiones no predeterminadas de tu app de App Engine

Si no quieres borrar tu proyecto de Google Cloud y Firebase, puedes borrar las versiones no predeterminadas de tu app de entorno flexible de App Engine para reducir los costos.

  1. En la consola de Google Cloud, ve a la página Versiones de App Engine.

    Ir a Versiones

  2. Selecciona la casilla de verificación de la versión no predeterminada de la app que deseas borrar.
  3. Para borrar la versión de la app, haz clic en Borrar.