HarmonyOS Next SDK

更新时间:
复制 MD 格式

本文介绍如何使用 HarmonyOS Next NUI SDK 实现一句话识别,包括 SDK 集成、调用流程、代码示例、接口和回调。

前提条件

重要

由应用服务端获取 NLS Token,再下发到客户端。不要将 AccessKey ID、AccessKey Secret 写入客户端代码或保存在设备端,也不要在日志中输出 Token 或包含 Token 的初始化参数。

下载安装与集成

  1. 下载harmony_neonui_sdk.tar.gz。

  2. 解压 SDK 包,将 entry/libs/neonui.har 导入应用工程。SDK 包同时提供 C++ 动态库和头文件,分别位于 native/libs 和 native/include。

  3. 使用 DevEco Studio 打开示例工程,在 entry/src/main/ets/Utils/UserKey.ets 中填写 Appkey 和 Token,再运行 entry/src/main/ets/pages/OneSentenceAsrPage.ets。

类别

兼容范围

系统及开发环境

HarmonyOS Next 5.0,API level 12;DevEco Studio 5.0.3.403。

架构

arm64-v8a

SDK 包的功能支持情况如下。

功能

是否支持

一句话识别

是

实时语音识别

是

语音合成

是

实时长文本语音合成

是

流式文本语音合成

是

离线语音合成

否

录音文件识别极速版

是

唤醒及命令词

否

听悟实时推流

是

调用流程

  1. 创建 SDK 实例和录音实例,实现 INativeNuiCallback。

  2. 调用 initialize 初始化 SDK,再调用 setParams 设置识别参数。

  3. 调用 startDialog 开始识别,根据 onNuiAudioStateChanged 通知启动录音。

  4. 顺序调用 updateAudio 向 SDK 传入录音数据,通过事件回调获取中间结果。

  5. 调用 stopDialog 结束识别,EVENT_ASR_RESULT 返回最终识别结果。

  6. 不再使用时调用 release 释放 SDK 资源。

重要

SDK 接口为同步调用,不要在 UI 线程调用,以免阻塞界面。不要在 SDK 的事件回调中直接调用 SDK 接口,以免死锁;需要继续调用时,将操作调度到回调之外执行。

代码示例

以下示例展示 SDK 调用片段,不是独立的应用页面。完整页面为 SDK 包中的 OneSentenceAsrPage.ets,业务封装为 entry/src/main/ets/neonui/OnSentenceAsr.ets。资源目录使用应用上下文的 resourceDir + "/resources_cloud",调试目录使用可写的 filesDir。

示例通过构造函数创建实例,也可使用 NativeNui.GetInstance() 获取单例。对同一实例重新初始化前,先释放其资源。

初始化

导入 SDK 类型。createRecognizer 的 callback 为下文的回调实现,其他参数由应用提供。

import { NativeNui, Constants, INativeNuiCallback, KwsResult, AsrResult } from 'neonui';

function createRecognizer(callback: INativeNuiCallback, resourceDir: string,
  filesDir: string, appkey: string, token: string, deviceId: string): NativeNui {
  const nui = new NativeNui(Constants.ModeType.MODE_DIALOG, 'asr');
  const parameters: Record<string, string> = {
    app_key: appkey,
    token: token,
    device_id: deviceId,
    url: 'wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1',
    workspace: resourceDir + '/resources_cloud',
    debug_path: filesDir,
    service_mode: Constants.ModeAsrCloud
  };
  const ret = nui.initialize(callback, JSON.stringify(parameters),
    Constants.LogLevel.LOG_LEVEL_VERBOSE, false);
  if (ret !== Constants.NuiResultCode.SUCCESS) {
    throw new Error('initialize failed: ' + ret);
  }
  return nui;
}

app_key、token、唯一的 device_id 和可读写的 workspace 为必填项。debug_path 用于保存调试文件。仅在需要时开启 save_log;开启后,日志持续写入且没有大小上限,需及时清理。save_wav 可用于保存音频调试数据,需要开启 save_log 并提供有效、可写的调试目录。

设置识别参数

在初始化成功后、开始识别前设置参数。

function configureRecognizer(nui: NativeNui, vadMode: boolean): number {
  const nlsConfig: Record<string, Object> = {
    enable_intermediate_result: true,
    enable_punctuation_prediction: true,
    enable_inverse_text_normalization: true,
    enable_voice_detection: vadMode
  };
  if (vadMode) {
    nlsConfig['max_start_silence'] = 10000;
    nlsConfig['max_end_silence'] = 800;
  }
  const parameters: Record<string, Object> = {
    nls_config: nlsConfig,
    service_type: Constants.kServiceTypeASR
  };
  return nui.setParams(JSON.stringify(parameters));
}

可按需在 nls_config 中配置customization_id、vocabulary_id、sample_rate(如 16000)和 sr_format(如 opus)。参数适用条件见接口说明,音频编码限制见下文常见问题。

开始识别

function startRecognizer(nui: NativeNui, token: string): number {
  const dialogParams: Record<string, string> = { token: token };
  return nui.startDialog(Constants.VadMode.TYPE_P2T, JSON.stringify(dialogParams));
}

使用 Constants.VadMode.TYPE_P2T。需要在开始一轮识别时更新 Token 或 Appkey,可在 dialog_params 中传入 token 或 app_key;某轮未传入临时参数时,继续使用初始化参数。

当前在线 SDK 不包含本地 VAD 模块。需要自动检测语音起止时,使用上例的 enable_voice_detection 开启云端 VAD,不使用仅适用于带离线功能 SDK 的 TYPE_VAD。

推送录音数据

在录音模块的 readData 回调中调用以下函数,按采集顺序传入音频。SDK 包中的录音封装为 AudioRecorder。

function pushAudio(nui: NativeNui, buffer: ArrayBuffer): number {
  return nui.updateAudio(buffer, false);
}

处理回调

以下 RecordingController 表示应用的录音控制接口,需连接到实际录音模块:start 启动录音,stop 停止录音。通过 onNuiAudioStateChanged 控制采集,将录音数据送给同一个 SDK 实例。

interface RecordingController {
  start(): void;
  stop(): void;
}

interface RecognitionPayload {
  result: string;
}

interface RecognitionResponse {
  payload: RecognitionPayload;
}

class NativeNuiCallbackHandle implements INativeNuiCallback {
  private recorder: RecordingController;
  constructor(recorder: RecordingController) {
    this.recorder = recorder;
  }

  onNuiAudioStateChanged(state: Constants.AudioState): void {
    if (state === Constants.AudioState.STATE_OPEN) {
      this.recorder.start();
    } else if (state === Constants.AudioState.STATE_CLOSE ||
      state === Constants.AudioState.STATE_PAUSE) {
      this.recorder.stop();
    }
  }

  onNuiNeedAudioData(buffer: ArrayBuffer): number {
    return 0;
  }

  onNuiEventCallback(event: Constants.NuiEvent, resultCode: number, arg2: number,
    kwsResult: KwsResult, asrResult: AsrResult): void {
    if (event === Constants.NuiEvent.EVENT_ASR_PARTIAL_RESULT ||
      event === Constants.NuiEvent.EVENT_ASR_RESULT) {
      if (asrResult && asrResult.asrResult) {
        try {
          const response = JSON.parse(asrResult.asrResult) as RecognitionResponse;
          if (response.payload) {
            console.info(response.payload.result);
          }
        } catch (e) {
          console.error('Invalid recognition response');
        }
      }
    } else if (event === Constants.NuiEvent.EVENT_ASR_ERROR ||
      event === Constants.NuiEvent.EVENT_MIC_ERROR) {
      console.error('recognition error: ' + resultCode);
    }
  }

  onNuiAudioRMSChanged(val: number): number {
    return 0;
  }

  onNuiLogTrackCallback(level: Constants.LogLevel, log: string): void {
  }
}

示例采用主动推送音频的方式,因此 onNuiNeedAudioData 返回 0。asrResult 可包含 task_id,可记录用于排查问题;allResponse 非空时包含完整 JSON 响应。出现 EVENT_ASR_ERROR 时,结合 resultCode、错误信息和任务 ID 排查;出现 EVENT_MIC_ERROR 时,检查录音权限、录音代码及录音模块是否被其他应用占用。EVENT_DIALOG_EX 无需处理。

说明

在 DevEco Studio 5.0.3.403 之前的开发环境中,使用 AudioCapturer.on("readData", ...) 读取录音时,stop 后直接 start 可能不再触发回调。遇到该问题时,按 stop、release、createAudioCapturer、start 的顺序重新创建录音实例。DevEco Studio 5.0.3.403 已解决该问题。

结束识别

function stopRecognizer(nui: NativeNui): number {
  return nui.stopDialog();
}

需要立即取消、不等待最终结果时,改为调用 cancelDialog()。

释放资源

function releaseRecognizer(nui: NativeNui): number {
  return nui.release();
}

关键接口与参数

参数含义和使用条件请参见接口说明。接口返回码及错误处理请参见错误码查询。

初始化与参数设置

initialize(callback: INativeNuiCallback, parameters: string,
  level: number, save_log: boolean = false): number
setParams(params: string): number
GetVersion(): string

parameters 和 params 为 JSON 字符串。level 为日志级别,值越小输出越多。save_log 默认关闭;开启时,日志目录由 debug_path 指定。GetVersion 返回 SDK 版本字符串。

识别与资源管理

startDialog(vad_mode: Constants.VadMode, dialog_params: string): number
updateAudio(data: ArrayBuffer, first_pack: boolean): number
stopDialog(): number
cancelDialog(): number
release(): number

startDialog 启动识别,使用 TYPE_P2T,dialog_params 为本轮临时参数。updateAudio 向 SDK 送入音频。stopDialog 通知服务端结束识别并返回最终结果;cancelDialog 不等待最终结果,立即结束任务。release 释放 SDK 资源。

回调和事件

实现 INativeNuiCallback 的以下五个回调。

onNuiEventCallback(event: Constants.NuiEvent, resultCode: number, arg2: number,
  kwsResult: KwsResult, asrResult: AsrResult): void
onNuiAudioStateChanged(state: Constants.AudioState): void
onNuiNeedAudioData(buffer: ArrayBuffer): number
onNuiAudioRMSChanged(val: number): number
onNuiLogTrackCallback(level: Constants.LogLevel, log: string): void

resultCode 在 EVENT_ASR_ERROR 时提供错误码。arg2 为保留参数;kwsResult 用于暂不支持的唤醒功能;asrResult 为识别结果。onNuiAudioStateChanged 通知打开、停止或关闭录音。回调供数模式下,onNuiNeedAudioData 填充 buffer 并返回实际字节数;由于 ArkTS 异步调用较频繁,建议默认使用 updateAudio 主动顺序推送。onNuiAudioRMSChanged 的能量值范围为 -160~0,可用于录音动效。onNuiLogTrackCallback 用于日志回调。

事件

说明

EVENT_VAD_START

检测到人声起点。

EVENT_VAD_END

检测到人声尾点。

EVENT_ASR_PARTIAL_RESULT

识别中间结果。

EVENT_ASR_RESULT

识别最终结果。

EVENT_ASR_ERROR

识别错误,根据错误码排查。

EVENT_MIC_ERROR

连续 2 秒未收到音频,检查录音系统。

常见问题

是否支持 OPUS 音频?

本 SDK 的一句话识别和录音文件识别极速版支持 OPUS 数据;实时语音识别仅支持 PCM 编码、16 bit 采样位数和单声道。详情请参见接口说明。

是否可以通过回调提供录音数据?

可以。若已通过共享数据和加锁保证录音数据生产、消费有序,可将资源文件 nui.json 中 nui_config.enable_callback_recording 设为 true,在 onNuiNeedAudioData 中填充录音数据,而不使用主动 updateAudio 推送。

实时语音识别与一句话识别的调用有何区别?

配置项

一句话识别

实时语音识别

service_mode

Constants.ModeAsrCloud

Constants.ModeFullCloud

service_type

Constants.kServiceTypeASR

Constants.kServiceTypeSpeechTranscriber

云端 VAD

按需配置是否启用及相关参数。

保持默认。

结果事件

EVENT_ASR_PARTIAL_RESULT、EVENT_ASR_RESULT

EVENT_ASR_PARTIAL_RESULT、EVENT_SENTENCE_END、EVENT_TRANSCRIBER_COMPLETE

接口调用超时导致应用无响应,如何处理?

避免在 UI 线程执行同步 SDK 调用。线程调度方式可参考 SDK 包中的 OneSentenceAsrWorker.ets。