Como adicionar tradução de voz a seu app para Android

Este tutorial mostra como fornecer um recurso de tradução de fala ao seu app para Android. A amostra neste tutorial usa um microsserviço que recebe uma mensagem de áudio, traduz a mensagem para um conjunto de idiomas predefinidos e armazena as mensagens traduzidas em arquivos de áudio. O aplicativo para Android cliente faz o download e reproduz os arquivos de áudio traduzidos quando solicitado pelo usuário.

Visão geral da solução

A solução inclui os seguintes componentes:

Microsserviço

O microsserviço é implementado no Cloud Functions para Firebase e usa os seguintes produtos do Cloud AI para traduzir as mensagens:

O microsserviço armazena mensagens de áudio traduzidas em um bucket no Cloud Storage para Firebase.

Aplicativo cliente

O componente cliente é um aplicativo para Android que registra mensagens de áudio e faz o download das mensagens traduzidas do bucket do Cloud Storage. A amostra é um aplicativo de bate-papo usado no tutorial Criar um aplicativo para Android usando o Firebase e o ambiente flexível do App Engine. Neste tutorial, você verá como estender o aplicativo de amostra para implementar o recurso de tradução de fala.

O diagrama a seguir mostra a interação entre o microsserviço e o aplicativo cliente:

Arquitetura detalhada da solução

O microsserviço executa as seguintes tarefas:

  1. Recebe a mensagem de áudio no formato de codificação em Base64.
  2. Transcreve a mensagem de áudio usando a API Speech-to-Text.
  3. Traduz a mensagem transcrita usando a API Translation.
  4. Sintetiza a mensagem traduzida usando a API Text-to-Speech.
  5. Armazena a mensagem de áudio traduzida em um bucket do Cloud Storage.
  6. Envia a resposta de volta para o cliente. A resposta inclui o local da mensagem de áudio traduzida.

Arquitetura de microsserviço

O aplicativo cliente executa as seguintes tarefas:

  1. Registra a mensagem de áudio usando as práticas recomendadas da API Speech-to-Text para maior precisão. O aplicativo usa o microfone no dispositivo para capturar o áudio.
  2. Codifica a mensagem de áudio no formato Base64.
  3. Envia uma solicitação HTTP para o microsserviço que inclui a mensagem de áudio codificada.
  4. Recebe a resposta HTTP do microsserviço, que inclui o local da mensagem de áudio traduzida.
  5. Envia uma solicitação para o bucket do Cloud Storage para recuperar o arquivo que inclui a mensagem de áudio traduzida.
  6. Reproduz a mensagem de áudio traduzida.

Objetivos

Neste tutorial, confira como:

  • usar o Cloud Functions para Firebase para criar um microsserviço que contenha a lógica necessária para traduzir mensagens de áudio usando os seguintes produtos do Cloud AI:
    • API Speech-to-Text
    • API Translation
    • API Text-to-Speech
  • Use as APIs do Android Framework para gravar áudio seguindo as recomendações sobre como fornecer dados de áudio para a API Speech-to-Text.
  • usar a biblioteca da Cronet para fazer upload dos dados de fala do aplicativo cliente para o microsserviço e fazer o download das mensagens traduzidas do Cloud Storage. Para mais informações sobre a biblioteca da Cronet, consulte Executar operações de rede usando a Cronet na documentação do desenvolvedor do Android.

Custos

Neste tutorial, o aplicativo de amostra implementado em Criar um aplicativo para Android usando o Firebase e o ambiente flexível do App Engine é estendido. Revise a seção de custos no tutorial mencionado e considere os seguintes custos extras:

  • O Firebase define cotas para o uso de Cloud Functions que especificam limitações de recursos, tempo e taxa. Para mais informações, consulte Cotas e limites na documentação do Firebase.
  • O uso da API Speech-to-Text é cobrado mensalmente com base na duração do áudio processado. Há um limite predeterminado de tempo de processamento que é possível usar gratuitamente todos os meses. Para mais informações, consulte Preços da API Speech-to-Text.
  • O uso da API Translation é cobrado mensalmente com base no número de caracteres enviados à API para processamento. Para mais informações, consulte Preços da API Translation.
  • O uso da API Text-to-Speech é cobrado mensalmente com base no número de caracteres sintetizados em áudio. Há um limite de caracteres que é possível usar gratuitamente a cada mês. Para mais informações, consulte Preços da API Text-to-Speech.
  • As taxas de uso do Firebase Storage são processadas como taxas do Google Cloud Storage. Para mais informações, consulte Preços do Cloud Storage.

Antes de começar

Conclua o tutorial Criar um aplicativo para Android usando o Firebase e o ambiente flexível do App Engine e instale os seguintes softwares:

Teste o recurso de tradução de fala em um dispositivo de hardware com o Android 7.0 (nível de API 24) ou superior.

Como clonar o código de amostra

Use o comando a seguir para clonar o repositório nodejs-docs-samples, que inclui o código do microsserviço:

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

Como ativar o faturamento e as APIs para o projeto do Google Cloud

Neste tutorial, usamos o projeto Playchat criado em "Criar um aplicativo Android usando o Firebase e o ambiente flexível do App Engine". Esse projeto requer a API Admin do App Engine e a API do Compute Engine.

O microsserviço requer as seguintes APIs para processar solicitações de tradução de fala:

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

Para ativar as APIs necessárias:

  1. No Console do Google Cloud, selecione o projeto Playchat.

    Acessar a página "Projetos"

  2. Verifique se o faturamento está ativado para seu projeto na nuvem. Saiba como confirmar se o faturamento está ativado para o projeto.

  3. Ative as APIs App Engine, Speech-to-Text, Translation, and Text-to-Speech.

    Ative as APIs

Como configurar o bucket padrão no Cloud Storage para Firebase

O microsserviço usa o bucket padrão do Cloud Storage no projeto do Firebase para armazenar os arquivos de áudio traduzidos. É preciso ativar o acesso de leitura para as contas de usuário que querem recuperar os arquivos de áudio.

Para fazer isso, você precisa do UID do usuário do Firebase da conta. Para recuperar o UID do usuário, siga estes passos:

  1. No menu à esquerda do Console do Firebase, selecione Autenticação no grupo Desenvolver.
  2. Anote o valor do UID do usuário da conta de usuário que você quer usar para testar o app. O UID do usuário é uma string de 28 caracteres.

Para habilitar o acesso de leitura na conta de usuário, você precisa criar uma regra de segurança de armazenamento. Para fazer isso, siga estas etapas:

  1. No menu à esquerda do Console do Firebase, selecione Armazenamento no grupo Desenvolver.
  2. Anote o URL do bucket padrão, que está no formato gs://[FIREBASE_PROJECT_ID].appspot.com e aparece ao lado de um ícone de link. Você precisa desse valor para implantar o microsserviço.
  3. Na página Armazenamento, acesse a seção Regras e adicione a seguinte regra na seção service firebase.storage:

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

    Substitua ACCOUNT_USER_UID pelo valor do UID do usuário que você nas etapas anteriores.

Para mais informações, consulte Primeiros passos com as regras de segurança do Storage na documentação do Firebase.

Como criar e implantar o microsserviço

Para criar o microsserviço, abra uma janela de terminal e acesse a pasta functions/speech-to-speech/functions no repositório nodejs-docs-samples que você clonou na seção anterior.

O código de microsserviço inclui um arquivo .nvmrc que declara a versão do Node.js que você precisa usar para executar o app. Execute o seguinte comando para configurar o NVM e instalar as dependências de microsserviço:

nvm install && nvm use && npm install

Execute o comando a seguir para fazer login no Firebase usando a interface da linha de comando:

firebase login

O microsserviço requer as seguintes variáveis de ambiente:

  • OUTPUT_BUCKET: o bucket padrão do Cloud Storage no projeto do Firebase.
  • SUPPORTED_LANGUAGE_CODES: uma lista separada por vírgulas de códigos de idioma compatíveis com o microsserviço.

Use os comandos a seguir para declarar os dados do ambiente necessários na interface de linha de comando. Substitua o rótulo FIREBASE_PROJECT_ID pelo valor que você consultou na seção 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"

Como configurar o app para Android

O aplicativo de amostra do Playchat requer o URL do microsserviço para ativar os recursos de tradução de fala. Para recuperar o URL do microsserviço, siga estes passos:

  1. No menu à esquerda do Console do Firebase, selecione Funções no grupo Desenvolver.
  2. O URL do microsserviço é exibido na coluna gatilho, que está no formato https://[REGION_ID]-[FIREBASE_PROJECT_ID].cloudfunctions.net/[FUNCTION_NAME].

Para configurar o app para funcionar com o microsserviço, abra o arquivo app/src/main/res/values/speech_translation.xml no repositório firebase-android-client e atualize o campo speechToSpeechEndpoint com o URL do microsserviço.

Como executar o aplicativo para Android

Para usar o recurso de tradução de fala no aplicativo, você precisa usar um dispositivo compatível com a gravação de áudios com o microfone integrado, como um dispositivo de hardware.

Para usar o recurso de tradução de fala no aplicativo, siga estes passos:

  1. Verifique se o dispositivo de hardware usa um dos idiomas configurados na seção Como criar e implantar o microsserviço. Para alterar o idioma, abra o aplicativo Configurações no dispositivo e acesse Sistema > Idiomas e entrada > Idiomas.
  2. Abra o projeto Playchat no Android Studio e conecte o dispositivo de hardware ao seu computador usando um cabo USB. Para mais informações, consulte Configurar um dispositivo para desenvolvimento.
  3. Clique em Executar no Android Studio para criar e executar o aplicativo no dispositivo.
  4. No aplicativo Playchat, toque no ícone do microfone para iniciar a gravação, grave uma mensagem curta e toque no ícone novamente para interromper a gravação.
  5. Após alguns segundos, o aplicativo Playchat exibe o texto da mensagem gravada na tela. Toque na mensagem para reproduzir a versão do áudio.
  6. Configure o dispositivo para usar outro idioma compatível.
  7. O aplicativo Playchat exibirá a mensagem gravada anteriormente nesse novo idioma. Toque na mensagem para reproduzir essa versão do áudio.

A captura de tela a seguir mostra o aplicativo Playchat exibindo uma mensagem traduzida para o francês:

Recurso de tradução de fala no Android

Explorar o código

O aplicativo cliente executa as seguintes tarefas para dar suporte ao recurso de tradução de fala:

  1. Grava áudio usando os parâmetros recomendados descritos nas práticas recomendadas da API Speech-to-Text.
  2. Codifica o áudio usando o esquema Base64 para representar o áudio em um formato de string que pode ser incorporado em uma solicitação HTTP.
  3. Envia uma solicitação HTTP para o microsserviço. A solicitação inclui a mensagem de áudio codificada junto com os metadados que fornecem informações extras sobre a carga útil. O aplicativo usa a Biblioteca Cronet para gerenciar as solicitações de rede.
  4. Quando o usuário quer ouvir a mensagem traduzida, o aplicativo faz o download do arquivo de áudio correspondente enviando uma solicitação HTTP autenticada ao bucket do Cloud Storage que armazena as mensagens traduzidas.

O exemplo de código a seguir mostra as constantes que a amostra usa para especificar os parâmetros de configuração de gravação:

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 uma fonte de áudio não processada porque a aplicação de algoritmos de processamento de sinal, como redução de ruído ou controle de ganho, diminui a acurácia do reconhecimento.
  • SAMPLE_RATE_IN_HZ: a amostra usa um valor de 16,000 para a taxa de amostragem nativa da fonte de áudio.
  • CHANNEL_CONFIG: AudioFormat.CHANNEL_IN_MONO indica apenas um canal de áudio na gravação. A amostra presume a voz de apenas uma pessoa na gravação.
  • AUDIO_FORMAT: AudioFormat.ENCODING_PCM_16BIT indica o formato de dados de áudio PCM linear com 16 bits por amostra. O PCM linear é um formato sem perdas, ideal para reconhecimento de fala.

O app cliente usa a API AudioRecord para gravar áudio do microfone integrado e armazena um arquivo .WAV no dispositivo. Para mais informações, consulte a classe RecordingHelper da amostra do Playchat.

Para codificar o áudio usando o esquema Base64, a amostra usa a classe Base64 do framework do Android. O áudio codificado não pode incluir terminadores de linha, que são omitidos com a sinalização NO_WRAP. O exemplo a seguir mostra como codificar áudio usando a classe 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 o áudio codificado para o microsserviço, o aplicativo cliente emite uma solicitação HTTP com os seguintes parâmetros:

  • Método: POST
  • Tipo de conteúdo: application/json
  • Corpo: objeto JSON com os seguintes atributos:
    • encoding: a string LINEAR16
    • sampleRateHertz: a taxa de amostragem do áudio gravado. Por exemplo, 16000.
    • languageCode: o código de idioma da mensagem gravada. O aplicativo cliente supõe que a mensagem seja gravada no idioma configurado nas configurações do dispositivo. Por exemplo, pt-BR.
    • audioContent: a mensagem de áudio codificada no esquema Base64.

Veja no exemplo a seguir como construir um objeto JSON que inclui os atributos necessários no corpo da solicitação:

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 mais detalhes sobre como criar a solicitação HTTP, consulte a classe SpeechTranslationHelper do app de amostra Playchat.

Para recuperar os arquivos de áudio do bucket do Cloud Storage, o aplicativo usa um URL de download que inclui um token que pode ser revogado no Console do Firebase, se desejado. Você pode receber o URL de download chamando o método getDownloadUrl(), conforme mostrado no exemplo a seguir:

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

O microsserviço executa a seguinte tarefa para oferecer suporte ao recurso de tradução de fala:

  1. Recebe solicitações de tradução de fala, incluindo o áudio codificado em Base64.
  2. Envia o áudio codificado para a API Speech-to-Text e recebe uma transcrição no idioma de origem.
  3. Para cada um dos idiomas compatíveis, envia a transcrição para a API Translation e recebe o texto traduzido.
  4. Para cada um dos idiomas compatíveis, envia o texto traduzido para a API Text-to-Speech e recebe o áudio traduzido.
  5. Carrega os arquivos de áudio traduzidos no bucket do Cloud Storage.

O microsserviço usa o resultado de uma chamada para uma API Cloud como a entrada da chamada para a próxima API, conforme mostrado no exemplo de código a seguir:

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

Limpeza

Para evitar cobranças dos recursos usados neste tutorial na conta do Google Cloud, siga estas etapas:

Excluir o projeto do Google Cloud e do Firebase

A maneira mais simples de não ser cobrado é excluir o projeto criado neste tutorial. Embora você tenha criado o projeto no Console do Firebase, também é possível excluí-lo no Console do Google Cloud, já que os projetos do Firebase e do Google Cloud são iguais.

  1. No Console do Cloud, acesse a página Gerenciar recursos:

    Acessar "Gerenciar recursos"

  2. Na lista de projetos, selecione o projeto que você quer excluir e clique em Excluir .
  3. Na caixa de diálogo, digite o ID do projeto e clique em Encerrar para excluí-lo.

Excluir as versões não padrão do aplicativo App Engine

Se você não quiser excluir o projeto do Google Cloud e do Firebase, poderá reduzir os custos excluindo as versões não padrão do aplicativo do ambiente flexível do App Engine.

  1. No Console do Cloud, acesse a página Versões do App Engine.

    Acessar "Versões"

  2. Marque a caixa de seleção da versão não padrão do app que você quer excluir.
  3. Para excluir a versão do app, clique em Excluir.