QwenCloudBRASIL
Tradução de apoio para consulta. Código e identificadores técnicos preservados. Consultar referência original ↗

Reconhecimento de fala em tempo real com o AOQ + fun-asr-realtime

Use o QOA para se conectar fun-asr-realtime para transmitir áudio de microfone e receber resultados de reconhecimento de fala em tempo real. Exemplos de código de cliente usam Android Java; outras plataformas suportadas pelo AOQ compartilham a mesma interface.

Visão geral

fun-asr-realtime transcreve um fluxo de áudio em texto pontuado em tempo real. O SDK do AOQ separa mídia e eventos em faixas distintas: o cliente envia áudio na faixa de áudio e troca de controle/reconhecimento de eventos na faixa de dados. Este modelo usa o protocolo de eventos de inferência em vez do protocolo de eventos em tempo real.

Esta abordagem se adequa a legendas em tempo real, transcrição de reuniões, entrada de voz e assistentes inteligentes. A faixa de áudio evita codificar áudio em mensagens de eventos, enquanto a faixa de dados preserva semântica de tarefas completas, como tarefas de execução, resultados gerados e tarefas de finalização.

  1. O cliente pede credenciais temporárias de conexão do AppServer.
  2. O AppServer usa uma chave API para solicitar um Token de QwenCloud, então retorna os campos de conexão para o cliente.
  3. O cliente estabelece uma conexão AOQ e envia uma tarefa de execução, após receber a tarefa iniciada, começa a transmitir áudio do microfone.
  4. O servidor retorna continuamente eventos gerados por resultados, o cliente envia tarefas finais e espera pelo resultado final e finalizado.

Pré-requisitos

  1. Ativar QwenCloud e obter uma chave API seguindo [Obter e configurar uma chave API] (/api-reference/preparation/api-key). Mantenha a chave API apenas no AppServer de negócios -- nunca incorpore em código de cliente ou compromete-a em um repositório.
  2. Baixe o mais recente cliente do AOQ SDK como descrito em [SDK download] (/api-reference/realtime-api/sdk-download). Este tutorial transporta áudio Opus e requer o plugin Opus.
  3. Configure um AppServer de negócios e implemente a autenticação de proxy do lado do servidor de inferência AOQ, conforme descrito em Autenticação do Token. O cliente deve obter novas credenciais de conexão do AppServer antes de cada nova conexão.

Importar o SDK

Escolha o método de importação para sua plataforma de desenvolvimento. A implementação do cliente seguinte usa o Android Java, outras plataformas compartilham o mesmo design de interface e fluxo de eventos.

Android

1.  Coloque a libPluginOpus.so do plugin Opus em app/src/main/jniLibs/armeabi-v7a/ e app/src/main/jniLibs/arm64-v8a/ para os ABIs correspondentes.  Coloque AoqClientSdk-release.aar no diretório app/libs e configure a dependência e os filtros ABI em app/build.gradle:

```groovy
android {
  defaultConfig {
    minSdk 21
    ndk { abiFilters 'armeabi-v7a', 'arm64-v8a' }
  }
}
dependencies {
  implementation fileTree(dir: 'libs', include: ['*.aar'])
}
```

2. Declare a rede e as permissões de gravação no AndroidManifest.xml:

```xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
```

3.  Peça permissão para gravar antes de começar a gravação.  Reconhecimento de fala sozinho não requer permissão da CÂMERA.

iOS

1. Arraste o AoqClientSdk.framework e o PluginOpus.framework para seu projeto Xcode e selecione Incorporar e Iniciar o Alvo > Geral > Frameworks, Bibliotecas e Conteúdo Incorporado. O SDK suporta dispositivos iOS 13.0+ arm64.
2.  Adicione NSMicrophoneUsageDescription para Info.plist.  Reconhecimento de fala sozinho não requer NSCameraUsageDescription.
3. Para projetos Swift, use `import AoqClientSdk`; para o objetivo-C, use `#import <AoqClientSdk/AoqClientSdk.h>`.

HarmonyOS

1.  Coloque libPluginOpus.so do plugin Opus em entrada/libs/arm64-v8a/.  Coloque AoqClientSdk.har em entrada/libs e declare a dependência em entrada/oh-pacote.json5. O SDK é compatível com API 12 e suporta arm64-v8a:

```json
{
  "dependencies": {
    "@aoq/client-sdk": "file:./libs/AoqClientSdk.har"
  }
}
```

2. Declare permissão de rede e microfone em entrada/src/main/module.json5:

```json
"requestPermissions": [
  { "name": "ohos.permission.INTERNET" },
  {
    "name": "ohos.permission.MICROPHONE",
    "reason": "$string:perm_mic_reason",
    "usedScene": { "abilities": ["EntryAbility"], "when": "inuse" }
  }
]
```

3. Abilidade de chamadaAccessCtrl.createAtManager().PedidoPermissões do Usuário para solicitar permissão do microfone antes de iniciar a gravação.

Linux (Python)

1. Extrair o SDK e manter aoq\_client\_sdk.py, libAoqClientSdk.so, e libonnxruntime.so.1.16.3 no mesmo diretório.
2.  Adicione o diretório SDK aos caminhos de pesquisa de bibliotecas dinâmicas e Python:

```bash
export PYTHONPATH="$PWD/AoqClientSdk:$PYTHONPATH"
export LD_LIBRARY_PATH="$PWD/AoqClientSdk:$LD_LIBRARY_PATH"
```

3.  Importar em seu código Python com `import aoq_client_sdk`. Alternativamente, especifique o caminho absoluto para a variável de ambiente libAoqClientSdk.so via AOQ\_CLIENT\_SDK\_LIB.

Tente a demo.

QwenCloud fornece um aplicativo de demonstração Android para verificar rapidamente conectividade AOQ. Baixe o APK e configure a chave da API e workspaceId para tentar modelos selecionados.

Analise o seguinte código QR para baixar a demonstração:

[Código QR para baixar a demo] (https://g-adoc.alcasset.com/media/maas_docs/sfm/common/images/6a4b3c2d1e0f92cc.png)

Fluxo de implementação

  1. O AppServer usa o ponto final do Token para obter parâmetros de conexão AOQ para fun-asr-realtime.
  2. O cliente converte a resposta Token em uma AoqConnectConfig, publica faixas de áudio e dados, e assina a faixa de dados.
  3. O cliente configura parâmetros de codificação de áudio por requisitos de negócios e especificações de modelos, inicia a captura de microfone sem enviar áudio, e estabelece a conexão AOQ.
  4. Após a conexão, o cliente envia tarefas de execução, ao receber tarefas iniciadas, ele permite o envio de áudio.
  5. O cliente lida com resultados gerados no DataMsg, para terminar a gravação, ele desativa o envio de áudio e então envia tarefas finais.
  6. Após receber a tarefa finalizada, o cliente pode iniciar uma nova rodada de reconhecimento na mesma conexão com uma nova tarefa, ou desconectar e destruir o motor.

[aoq-realtime-asr-sequence-zh] (http://icms-x-dita-hz.oss-cn-hangzhou.aliyuncs.com/zh-CN/images/p1094760.png)

Pedido do AppServer Token

Defina DASHSCOPE_API_KEY no AppServer e envie uma solicitação para o ponto final do AOQ Inference Token. clientIp é o IP público real do terminal; este campo é opcional, mas recomendado para que o serviço possa atribuir um ponto de acesso adequado ao Relay.

curl -X POST \
  "https://maas.qwencloudapi.com/api/v1/webrtc/inference?model=fun-asr-realtime" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${DASHSCOPE_API_KEY}" \
  -H "x-dashscope-rtc-transport: moq" \
  -d "{\"clientIp\": \"${CLIENT_REAL_IP}\"}"

Se o AppServer não puder determinar o IP público real do terminal, remova o campo clienteIp do corpo de solicitação inteiramente -- não passe uma string vazia.

Devolva os seguintes campos de resposta do AppServer ao cliente. Nunca devolva a chave API para o cliente em produção. Para os parâmetros completos de solicitação e campos de resposta, veja Autenticação do Token.

Campo de resposta. Campo SDK
AoqTokenForClient AoqConnectConfig.token
Sid. AoqConnectConfig.sid
CLIENTE RELAYCertFingerprint AoqConnectConfig.certFingerprint
CLIENTE RELAYEndpoints AoqConnectConfig.relayEndpoints
ExtraInfo. Espaço de trabalhoIdHash AoqConnectConfig. Espaço de trabalhoIdHash

Implemente o cliente Android

Os passos seguintes quebram o código do cliente Android Java na ordem de conexão e execução de tarefas. Cada trecho vem do exemplo completo mostrado mais tarde.

1. Crie o motor e ajuste as chamadas.

Crie o motor do cliente do AOQ e registre o status de conexão e os dados de retorno de eventos. Implementar o tratamento de retorno de chamadas de acordo com sua lógica de negócios, iniciar a tarefa de reconhecimento apenas após uma conexão bem sucedida.

AoqClientListener listener = new AoqClientListener() {
  @Override
  public void onConnectionStatusChange(AoqClientEngine.AoqConnectionStatus status) {
    connected = status == AoqClientEngine.AoqConnectionStatus
            .AoqConnectionStatusConnected;
    if (connected) {
      beginRecognition();
    }
  }
  @Override
  public void onDataMsg(AoqClientEngine.AoqDataMsg msg) {
    handleServerEvent(msg);
  }
};
AoqClientEngine.AoqCreateConfig createConfig = new AoqClientEngine.AoqCreateConfig();
createConfig.workDir = context.getFilesDir().getAbsolutePath();
engine = AoqClientEngine.createEngine(context, createConfig, listener);

- Dois. Configurar codificação de áudio

Configure a codificação de áudio enviada para o modelo. Defina o formato, taxa de amostragem e contagem de canais de acordo com seus requisitos de negócios e especificações de modelos. O exemplo a seguir usa o mono Opus de 16 kHz; para intervalos suportados, veja os parâmetros de execução em Eventos do cliente.

AoqClientEngine.AoqAudioCodecConfig encoder =
        new AoqClientEngine.AoqAudioCodecConfig();
encoder.trackType = AoqClientEngine.AoqTrackType.AoqTrackTypeAudio;
encoder.codecType = AoqClientEngine.AoqEncoderType.AoqEncoderTypeAudioOpus;
encoder.sampleRate = 16000;
encoder.channel = 1;
encoder.bitrate = 24000;
engine.setAudioEncoderConfig(encoder);

3. Configure conexões e rotas de transporte.

Configure a conexão do AOQ usando as credenciais devolvidas pelo AppServer, e escolha quais faixas publicar e assinar. O seguinte código publica faixas de áudio e dados e assina a faixa de dados para reconhecimento de fala em tempo real.

addTrack(connectConfig, true,
        AoqClientEngine.AoqTrackType.AoqTrackTypeAudio);
addTrack(connectConfig, true,
        AoqClientEngine.AoqTrackType.AoqTrackTypeData);
addTrack(connectConfig, false,
        AoqClientEngine.AoqTrackType.AoqTrackTypeData);

- Quatro. Comece a captura de áudio e conecte-se.

Configure a captura de áudio e estabeleça a conexão do QAO. Escolha captura integrada ou externa, modo VoIP e contagem de canais para suas necessidades de negócios. Mantenha o áudio desactivado até que a tarefa seja recebida.

AoqClientEngine.AoqAudioCaptureConfig capture =
        new AoqClientEngine.AoqAudioCaptureConfig();
capture.isExternal = false;
capture.isVoipMode = true;
capture.channel = 1;
engine.startAudioCapture(capture);
// Do not send audio until task-started is received.
engine.enableSendMediaStream(
        AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, false);
engine.connect(connectConfig);

- Cinco. Comece a tarefa de reconhecimento.

Depois de se conectar, gere uma tarefa de identificação e envie uma tarefa de execução para começar o reconhecimento. Configure o modelo, formato, amostra e outros parâmetros de tarefa por modelo e entrada de áudio. Para descrições completas dos parâmetros, veja [Eventos do cliente] (/api-reference/qwen-audio-realtime/client-events).

taskId = UUID.randomUUID().toString();
JSONObject header = createHeader("run-task");
JSONObject parameters = new JSONObject()
        .put("format", "pcm")
        .put("sample_rate", 16000);
JSONObject payload = new JSONObject()
        .put("task_group", "audio")
        .put("task", "asr")
        .put("function", "recognition")
        .put("model", "fun-asr-realtime")
        .put("parameters", parameters)
        .put("input", new JSONObject());
send(new JSONObject().put("header", header).put("payload", payload));

Seis. Lidar com eventos de servidores

Lidar com status de tarefa, resultados de reconhecimento e eventos de erro, passando resultados para a camada de negócios. Implemente lógica de retorno de chamadas de acordo com as necessidades de gerenciamento de estado e exibição de sua aplicação; envie áudio somente após receber eventos cardíacos iniciados e filtrar quando exibir resultados. Para estruturas de resposta completa, veja [Eventos de servidor] (/api-reference/qwen-audio-realtime/server-events).

String eventName = header.optString("event", "");
if ("task-started".equals(eventName)) {
  taskStarted = true;
  engine.enableSendMediaStream(
          AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, true);
} else if ("result-generated".equals(eventName)) {
  JSONObject payload = event.optJSONObject("payload");
  JSONObject output = payload == null ? null : payload.optJSONObject("output");
  JSONObject sentence = output == null ? null : output.optJSONObject("sentence");
  if (sentence != null && !sentence.optBoolean("heartbeat", false)) {
    String text = sentence.optString("text", "");
    if (!text.isEmpty()) {
      resultListener.onResult(
              text, sentence.optBoolean("sentence_end", false));
    }
  }
} else if ("task-finished".equals(eventName)) {
  resetTaskState();
  resultListener.onTaskFinished();
} else if ("task-failed".equals(eventName)) {
  String message = header.optString("error_message", "Recognition failed");
  resetTaskState();
  resultListener.onError(message);
}

- 7? - 7? Termine a tarefa de reconhecimento.

Quando o usuário terminar a sessão de gravação atual, pare o link de áudio e envie a tarefa final. Mantenha a conexão aberta até que o resultado final de reconhecimento e finalização da tarefa sejam recebidos, e comece uma nova tarefa ou libere a conexão conforme necessário. Para formatos de eventos, veja [Eventos do cliente] (/api-reference/qwen-audio-realtime/client-events).

engine.enableSendMediaStream(
        AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, false);
JSONObject payload = new JSONObject().put("input", new JSONObject());
send(new JSONObject()
        .put("header", createHeader("finish-task"))
        .put("payload", payload));

Oito. Desligue e destrua o motor.

Quando a página for destruída ou o reconhecimento não for mais necessário, libere a captura de áudio, a conexão com o AOQ e os recursos do motor. Escolha o tempo de lançamento por seu ciclo de vida da aplicação. Não solte imediatamente após enviar a tarefa final.

engine.enableSendMediaStream(
        AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, false);
engine.stopAudioCapture();
engine.disconnect();
AoqClientEngine.destroy();

Exemplo completo.

Esta classe Java do Android converte a resposta JSON do AppServer em uma AoqConnectConfig e combina a lógica de conexão, captura, tarefa e liberação de recursos descrita acima.

AsrClient.java full code

import android.content.Context;
import com.alibaba.aoq.clientsdk.AoqClientEngine;
import com.alibaba.aoq.clientsdk.AoqClientListener;
import org.json.JSONArray;
import org.json.JSONObject;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
public final class AsrClient {
  public interface ResultListener {
    void onResult(String text, boolean sentenceEnd);
    void onTaskFinished();
    void onError(String message);
  }
  private final AoqClientEngine engine;
  private final ResultListener resultListener;
  private String taskId;
  private boolean connected;
  private boolean taskStarted;
  public AsrClient(Context context, AoqClientEngine.AoqConnectConfig connectConfig,
                   ResultListener resultListener) {
    this.resultListener = resultListener;
    AoqClientListener listener = new AoqClientListener() {
      @Override
      public void onConnectionStatusChange(AoqClientEngine.AoqConnectionStatus status) {
        connected = status == AoqClientEngine.AoqConnectionStatus
                .AoqConnectionStatusConnected;
        if (connected) {
          beginRecognition();
        }
      }
      @Override
      public void onDataMsg(AoqClientEngine.AoqDataMsg msg) {
        handleServerEvent(msg);
      }
    };
    AoqClientEngine.AoqCreateConfig createConfig = new AoqClientEngine.AoqCreateConfig();
    createConfig.workDir = context.getFilesDir().getAbsolutePath();
    engine = AoqClientEngine.createEngine(context, createConfig, listener);
    configureAudioEncoder();
    configureTracks(connectConfig);
    startAudioCapture();
    engine.connect(connectConfig);
  }
  private void configureAudioEncoder() {
    AoqClientEngine.AoqAudioCodecConfig encoder = new AoqClientEngine.AoqAudioCodecConfig();
    encoder.trackType = AoqClientEngine.AoqTrackType.AoqTrackTypeAudio;
    encoder.codecType = AoqClientEngine.AoqEncoderType.AoqEncoderTypeAudioOpus;
    encoder.sampleRate = 16000;
    encoder.channel = 1;
    encoder.bitrate = 24000;
    engine.setAudioEncoderConfig(encoder);
  }
  private static void configureTracks(AoqClientEngine.AoqConnectConfig connectConfig) {
    addTrack(connectConfig, true, AoqClientEngine.AoqTrackType.AoqTrackTypeAudio);
    addTrack(connectConfig, true, AoqClientEngine.AoqTrackType.AoqTrackTypeData);
    addTrack(connectConfig, false, AoqClientEngine.AoqTrackType.AoqTrackTypeData);
  }
  private void startAudioCapture() {
    AoqClientEngine.AoqAudioCaptureConfig capture =
            new AoqClientEngine.AoqAudioCaptureConfig();
    capture.isExternal = false;
    capture.isVoipMode = true;
    capture.channel = 1;
    engine.startAudioCapture(capture);
    engine.enableSendMediaStream(AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, false);
  }
  /** Start a new recognition task on the existing AOQ connection. */
  public void beginRecognition() {
    if (!connected || taskStarted || taskId != null) {
      return;
    }
    taskId = UUID.randomUUID().toString();
    JSONObject header = createHeader("run-task");
    JSONObject parameters = new JSONObject()
            .put("format", "pcm")
            .put("sample_rate", 16000);
    JSONObject payload = new JSONObject()
            .put("task_group", "audio")
            .put("task", "asr")
            .put("function", "recognition")
            .put("model", "fun-asr-realtime")
            .put("parameters", parameters)
            .put("input", new JSONObject());
    send(new JSONObject().put("header", header).put("payload", payload));
  }
  /** End the current task. Wait for task-finished before disconnecting. */
  public void finishRecognition() {
    if (taskId == null) {
      return;
    }
    engine.enableSendMediaStream(AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, false);
    JSONObject payload = new JSONObject().put("input", new JSONObject());
    send(new JSONObject()
            .put("header", createHeader("finish-task"))
            .put("payload", payload));
  }
  public void close() {
    engine.enableSendMediaStream(AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, false);
    engine.stopAudioCapture();
    engine.disconnect();
    AoqClientEngine.destroy();
  }
  private void handleServerEvent(AoqClientEngine.AoqDataMsg msg) {
    if (msg == null || msg.data == null) {
      return;
    }
    JSONObject event = new JSONObject(new String(msg.data, StandardCharsets.UTF_8));
    JSONObject header = event.optJSONObject("header");
    if (header == null) {
      return;
    }
    String eventName = header.optString("event", "");
    if ("task-started".equals(eventName)) {
      taskStarted = true;
      engine.enableSendMediaStream(
              AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, true);
    } else if ("result-generated".equals(eventName)) {
      handleRecognitionResult(event);
    } else if ("task-finished".equals(eventName)) {
      resetTaskState();
      resultListener.onTaskFinished();
    } else if ("task-failed".equals(eventName)) {
      String message = header.optString("error_message", "Recognition failed");
      resetTaskState();
      resultListener.onError(message);
    }
  }
  private void handleRecognitionResult(JSONObject event) {
    JSONObject payload = event.optJSONObject("payload");
    JSONObject output = payload == null ? null : payload.optJSONObject("output");
    JSONObject sentence = output == null ? null : output.optJSONObject("sentence");
    if (sentence == null || sentence.optBoolean("heartbeat", false)) {
      return;
    }
    String text = sentence.optString("text", "");
    if (!text.isEmpty()) {
      resultListener.onResult(text, sentence.optBoolean("sentence_end", false));
    }
  }
  private void resetTaskState() {
    engine.enableSendMediaStream(AoqClientEngine.AoqTrackType.AoqTrackTypeAudio, false);
    taskStarted = false;
    taskId = null;
  }
  private JSONObject createHeader(String action) {
    return new JSONObject()
            .put("action", action)
            .put("task_id", taskId)
            .put("streaming", "duplex");
  }
  private void send(JSONObject event) {
    AoqClientEngine.AoqDataMsg msg = new AoqClientEngine.AoqDataMsg();
    msg.data = event.toString().getBytes(StandardCharsets.UTF_8);
    engine.sendDataMsg(msg);
  }
  private static void addTrack(AoqClientEngine.AoqConnectConfig config, boolean publish,
                               AoqClientEngine.AoqTrackType type) {
    AoqClientEngine.AoqTrackParam track = new AoqClientEngine.AoqTrackParam();
    track.trackType = type;
    if (publish) {
      config.publishTracks.add(track);
    } else {
      config.subscribeTracks.add(track);
    }
  }
  /** Convert the AppServer Token response into an SDK connection config. */
  public static AoqClientEngine.AoqConnectConfig parseConnectConfig(String responseText) {
    JSONObject response = new JSONObject(responseText);
    AoqClientEngine.AoqConnectConfig config = new AoqClientEngine.AoqConnectConfig();
    config.token = response.optString("aoqTokenForClient", "");
    config.sid = response.optString("sid", "");
    config.certFingerprint = response.optString("clientRelayCertFingerprint", "");
    JSONArray endpoints = response.optJSONArray("clientRelayEndpoints");
    if (endpoints != null) {
      for (int i = 0; i < endpoints.length(); i++) {
        JSONObject item = endpoints.optJSONObject(i);
        if (item == null) {
          continue;
        }
        AoqClientEngine.AoqRelayEndpoint endpoint =
                new AoqClientEngine.AoqRelayEndpoint();
        endpoint.routeIndex = item.has("route_index")
                ? item.optInt("route_index", i) : i;
        endpoint.endpoint = item.optString("endpoint", "");
        endpoint.port = item.optInt("port", 0);
        config.relayEndpoints.add(endpoint);
      }
    }
    JSONObject extraInfo = response.optJSONObject("extraInfo");
    config.workspaceIdHash = extraInfo == null
            ? "" : extraInfo.optString("workspaceIdHash", "");
    return config;
  }
}

Exemplo de uso

Passe a resposta do AppServer Token para a ParseConnectConfig, e então crie o cliente. Reconhecimento começa automaticamente após a primeira conexão bem sucedida. O botão de parada só termina a tarefa atual; solte a conexão e os recursos locais apenas quando a página é destruída.

private AsrClient client;
void startRecognition(Context context, String tokenResponseText) {
  AoqClientEngine.AoqConnectConfig config =
          AsrClient.parseConnectConfig(tokenResponseText);
  client = new AsrClient(context, config, new AsrClient.ResultListener() {
    @Override
    public void onResult(String text, boolean sentenceEnd) {
      // Update UI with intermediate or final sentence.
    }
    @Override
    public void onTaskFinished() {
      // Enable start button, or call beginRecognition() for a new task.
    }
    @Override
    public void onError(String message) {
      // Display or log the error.
    }
  });
}
void onStopButtonClick() {
  // End the current task while keeping the AOQ connection until task-finished.
  client.finishRecognition();
}
void onPageDestroyed() {
  // Release local resources only when the page closes.
  client.close();
}
  1. Ligue o AppServer. Confirme que a solicitação Token retorna HTTP 200 com sid, aoqTokenForClient, clienteRelayEndpoints, clienteRelayCertFingerprint, e extraInfo.workspaceIdHash.
  2. Instale e execute o aplicativo em um dispositivo Android, conceda permissão ao microfone e fale.
  3. Observe as chamadas. A sequência normal de eventos é:
task-started
result-generated (sentence_end=false)
result-generated (sentence_end=true)
task-finished

Você deve receber o texto de reconhecimento intermediário continuamente enquanto fala. Depois de chamar o fim de reconhecimento, você deve receber o texto final para a sentença atual seguido de tarefa terminada. Não desligue imediatamente após enviar a tarefa final.

Cenários comuns

Múltiplas rodadas de reconhecimento em uma única conexão.

Após receber a tarefa finalizada, comece a chamar a reconhecer para começar a próxima rodada de reconhecimento na mesma conexão do QAO. Cada rodada deve usar uma nova tarefa. Não há necessidade de pedir um novo Token ou reconstruir a conexão, mas se a conexão já foi descartada, você deve obter novas credenciais.

Reconhecimento de fundo Android

No Android 10 ou mais, para continuar capturando áudio do microfone depois que o aplicativo entrar em segundo plano, use um serviço de primeiro plano com primeiro planoServiceType=microfone e comece o serviço enquanto o aplicativo ainda está visível para o usuário.

FAQ

Problema. Solução
A conexão falhou. Confirme se o Token não expirou e verifique se o AppServer está passando o IP público do terminal. Não reutilize um velho Token após a desconexão.
A tarefa começou, mas sem resultados de reconhecimento. Confirmar envio de áudio só é ativado após receber a tarefa iniciada, e verificar o formato de áudio, taxa de amostragem, e outros parâmetros de entrada por o modelo Eventos de clientes.
Nenhum resultado final recebido. Desativar o envio de áudio antes de enviar a tarefa final; esperar pelo resultado final gerado e finalizado -- não desconectar imediatamente.
Android SDK não carrega Confirme que o AAR está incluído como dependência e os pacotes de aplicativos só são ABIs suportados por SDK (armeabi-v7a ou arm64-v8a).
A próxima tarefa na mesma conexão é rejeitada. Confirme a rodada anterior recebida finalizada, e gere uma nova tarefa para a nova tarefa.

Documentação relacionada

Para detalhes de parâmetros completos, campos de eventos e outras interfaces de plataforma, veja: