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/FileTranscriberPage.ets。

调用流程

  1. 创建 SDK 实例,实现 INativeFileTransCallback。

  2. 调用 initializeFileTrans 初始化 SDK,再按需调用 setParams 设置参数。

  3. 准备音频文件路径和编码格式,调用 startFileTranscriber。

  4. 在 EVENT_FILE_TRANS_RESULT 回调中获取最终识别结果。

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

重要

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

代码示例

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

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

初始化

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

import { NativeNui, Constants, INativeFileTransCallback, AsrResult } from 'neonui';

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

app_key、token、唯一的 device_id 和可读写的 workspace 为必填项。debug_path 用于保存调试文件。需要保存调试音频时,可配置 save_wav,同时开启 save_log 并保证调试目录有效、可写。

设置参数

function configureFileRecognizer(nui: NativeNui): number {
  const nlsConfig: Record<string, boolean> = { enable_intermediate_result: true };
  const parameters: Record<string, Object> = { nls_config: nlsConfig };
  return nui.setParams(JSON.stringify(parameters));
}

开始识别

示例使用工程中的 entry/src/main/resources/resfile/2.wav。将应用上下文中的 resourceDir 传入函数,format 必须与文件的实际编码一致。任务 ID 缓冲区至少需要 33 字节。

function startFileRecognition(nui: NativeNui, resourceDir: string): ArrayBuffer {
  const nlsConfig: Record<string, string> = { format: 'wav' };
  const parameters: Record<string, Object> = {
    file_path: resourceDir + '/2.wav',
    nls_config: nlsConfig
  };
  const taskId = new ArrayBuffer(33);
  const ret = nui.startFileTranscriber(JSON.stringify(parameters), taskId);
  if (ret !== Constants.NuiResultCode.SUCCESS) {
    throw new Error('startFileTranscriber failed: ' + ret);
  }
  return taskId;
}

需要在运行时切换项目时,可在任务参数中设置 app_key。

处理回调

识别结果位于 flash_result.sentences,每个句子的文本位于 text。以下示例按任务 ID 缓存多个文件的结果。

interface RecognizedSentence {
  text: string;
}

interface FlashResult {
  sentences: RecognizedSentence[];
}

interface FileRecognitionResponse {
  flash_result: FlashResult;
}

class FileCallbackHandle implements INativeFileTransCallback {
  taskResults: Map<string, string> = new Map();
  combinedResults: string = '';

  onFileTransEventCallback(event: Constants.NuiEvent, resultCode: number,
    finish: number, asrResult: AsrResult, taskId: string): void {
    if (event === Constants.NuiEvent.EVENT_FILE_TRANS_UPLOADED) {
      console.info('file uploaded: ' + taskId);
    } else if (event === Constants.NuiEvent.EVENT_ASR_ERROR) {
      console.error('recognition error: ' + resultCode + ', task: ' + taskId);
    } else if (event === Constants.NuiEvent.EVENT_FILE_TRANS_RESULT &&
      asrResult && asrResult.asrResult) {
      const response = JSON.parse(asrResult.asrResult) as FileRecognitionResponse;
      if (response.flash_result) {
        let text = '';
        response.flash_result.sentences.forEach((sentence: RecognizedSentence) => {
          text += sentence.text;
        });
        this.taskResults.set(taskId, text);
        this.combinedResults = '';
        this.taskResults.forEach((value: string, key: string) => {
          this.combinedResults += key + ': ' + value + '\n';
        });
      }
    }
  }
}

释放资源

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

关键接口与参数

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

初始化与参数设置

initializeFileTrans(callback: INativeFileTransCallback, parameters: string,
  level: number, save_log: boolean = false): number
setParams(params: string): number

parameters 和 params 为 JSON 字符串。level 为日志级别,值越小输出越多。save_log 默认关闭。初始化成功后、开始任务前调用 setParams。

识别与资源管理

startFileTranscriber(params: string, task_id: ArrayBuffer): number
cancelFileTranscriber(task_id: string): number
release(): number

startFileTranscriber 的 params 包含音频路径等参数。task_id 用于接收 SDK 生成的任务 ID,缓冲区至少分配 33 字节。cancelFileTranscriber 接收要取消的任务 ID 字符串。release 释放 SDK 资源。

回调和事件

onFileTransEventCallback(event: Constants.NuiEvent, resultCode: number,
  finish: number, asrResult: AsrResult, taskId: string): void

event 为任务事件,resultCode 在 EVENT_ASR_ERROR 时提供错误码。第三个参数为保留参数;asrResult 为识别结果,taskId 为任务 ID。

事件

说明

EVENT_FILE_TRANS_CONNECTED

连接识别服务成功。

EVENT_FILE_TRANS_UPLOADED

文件上传成功。

EVENT_FILE_TRANS_RESULT

返回最终识别结果。

EVENT_ASR_ERROR

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

常见问题

如何通过任务 ID 查询状态?

本 SDK 不提供按任务 ID 查询状态的 API。通过 onFileTransEventCallback 接收对应任务的连接、上传、识别结果和错误事件。

是否支持 OPUS 音频?

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

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

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