HarmonyOS鸿蒙Next开发者技术支持-语音转文字案例

HarmonyOS鸿蒙Next开发者技术支持-语音转文字案例

鸿蒙语音转文字案例

1.1 问题说明:清晰呈现问题场景与具体表现

在鸿蒙(HarmonyOS)应用开发中,经常遇到需要将用户的语音输入实时、准确地转换为文本的场景,例如:

  • **语音助手:**​ 用户通过语音发送指令。
  • **智能输入:**​ 在聊天、笔记应用中,用户通过语音快速输入长文本。
  • **语音搜索:**​ 在内容平台中,用户通过语音输入搜索关键词。
  • **无障碍服务:**​ 为视觉或操作不便的用户提供语音交互支持

1.2 解决方案:落地解决思路,给出可执行、可复用的具体方案

以下提供一个基于AsrManager核心类的简化示例代码和集成步骤。

步骤一:申请必要权限

module.json5中配置

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.MICROPHONE"
      },
      {
        "name": "ohos.permission.INTERNET" // 如果使用云端引擎
      }
    ]
  }
}

步骤二:创建核心管理类AsrManager.ets(简化版)

// AsrManager.ets
import audio from '@ohos.multimedia.audio';
import { AsrCloudEngine } from './AsrCloudEngine'; // 假设的云端引擎适配器
import { AsrLocalEngine } from './AsrLocalEngine'; // 假设的本地引擎适配器

export enum AsrEngineType {
  LOCAL,
  CLOUD,
  AUTO
}

export interface AsrResult {
  text: string;
  isFinal: boolean; // 是否为最终结果(true),或中间临时结果(false)
}

export class AsrManager {
  private audioCapturer: audio.AudioCapturer | undefined;
  private currentEngine: IAsrEngine | undefined; // IAsrEngine是定义的引擎接口
  private onResultCallback: (result: AsrResult) => void = () => {};

  // 初始化并选择引擎
  async init(engineType: AsrEngineType = AsrEngineType.AUTO, config?: any): Promise<void> {
    // 1. 根据策略选择引擎
    let targetEngineType = engineType;
    if (engineType === AsrEngineType.AUTO) {
      // 简单策略:有网且非隐私模式则用云端,否则用本地
      // 实际策略可以更复杂
      targetEngineType = await this.isNetworkGood() ? AsrEngineType.CLOUD : AsrEngineType.LOCAL;
    }

    // 2. 实例化引擎
    switch (targetEngineType) {
      case AsrEngineType.CLOUD:
        this.currentEngine = new AsrCloudEngine(config?.cloudConfig);
        break;
      case AsrEngineType.LOCAL:
      default:
        this.currentEngine = new AsrLocalEngine(config?.localConfig);
        break;
    }

    // 3. 初始化音频采集器(配置参数需与引擎要求匹配)
    await this.initAudioCapturer();
    console.info(`ASR Manager initialized with engine: ${AsrEngineType[targetEngineType]}`);
  }

  private async initAudioCapturer(): Promise<void> {
    // 配置音频参数:采样率、声道、格式等
    const audioStreamInfo: audio.AudioStreamInfo = {
      samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_16000,
      channels: audio.AudioChannel.MONO,
      sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
      encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW
    };

    const audioCapturerInfo: audio.AudioCapturerInfo = {
      source: audio.SourceType.SOURCE_TYPE_MIC,
      capturerFlags: 0 // 默认标志
    };

    this.audioCapturer = await audio.createAudioCapturer(audioCapturerInfo, audioStreamInfo);
  }

  // 开始识别
  async start(callback: (result: AsrResult) => void): Promise<void> {
    if (!this.currentEngine || !this.audioCapturer) {
      throw new Error('ASR Manager not initialized.');
    }
    this.onResultCallback = callback;

    // 1. 启动引擎
    await this.currentEngine.start((engineResult: AsrResult) => {
      // 接收引擎返回的结果
      this.onResultCallback(engineResult);
    });

    // 2. 开始录音并持续向引擎输送数据
    await this.audioCapturer.start();
    const bufferSize = await this.audioCapturer.getBufferSize();
    const audioBuffer = await this.audioCapturer.read(bufferSize, true);

    // 这里应设置一个循环或使用事件监听,持续读取音频数据
    // 并将audioBuffer.data发送给 this.currentEngine.feedAudioData(audioBuffer.data)
    // 此处为简化示例,实际需要更复杂的异步流处理
    console.info('ASR recording started.');
  }

  // 停止识别
  async stop(): Promise<void> {
    await this.audioCapturer?.stop();
    await this.currentEngine?.stop();
    this.onResultCallback = () => {};
    console.info('ASR stopped.');
  }

  // 释放资源
  async release(): Promise<void> {
    await this.stop();
    await this.audioCapturer?.release();
    this.currentEngine = undefined;
  }

  private async isNetworkGood(): Promise<boolean> {
    // 实现网络状态检查,此处返回true
    return true;
  }
}

步骤三:在UI页面中调用

// Index.ets 页面示例
import { AsrManager, AsrEngineType } from '../utils/AsrManager';
import promptAction from '@ohos.promptAction';

@Entry
@Component
struct Index {
  private asrManager: AsrManager = new AsrManager();
  @State recognizedText: string = '';

  async aboutToAppear() {
    // 初始化,选择云端引擎,并传入自定义热词
    try {
      await this.asrManager.init(AsrEngineType.CLOUD, {
        cloudConfig: {
          apiKey: 'YOUR_CLOUD_API_KEY',
          language: 'zh-CN',
          hotWords: ['鸿蒙', 'HarmonyOS', 'ArkTS']
        }
      });
    } catch (error) {
      promptAction.showToast({ message: `初始化失败: ${error.message}` });
    }
  }

  // 开始录音按钮事件
  async startRecording() {
    this.recognizedText = '正在聆听...';
    try {
      await this.asrManager.start((result) => {
        // 实时更新UI,isFinal为true时可做最终处理(如发送)
        this.recognizedText = result.text;
        if (result.isFinal) {
          promptAction.showToast({ message: '识别完成!' });
          // 这里可以将最终文本发送出去
        }
      });
    } catch (error) {
      promptAction.showToast({ message: `启动失败: ${error.message}` });
    }
  }

  // 停止录音按钮事件
  async stopRecording() {
    try {
      await this.asrManager.stop();
    } catch (error) {
      promptAction.showToast({ message: `停止失败: ${error.message}` });
    }
  }

  aboutToDisappear() {
    this.asrManager.release();
  }

  build() {
    Column() {
      Text(this.recognizedText)
        .fontSize(20)
        .margin(20)
        .height(100)

      Button('开始说话')
        .onClick(() => this.startRecording())
        .margin(10)
      Button('停止')
        .onClick(() => this.stopRecording())
        .margin(10)
    }
    .width('100%')
    .height('100%')
  }
}

1.3 结果展示:开发效率提升以及为后续同类问题提供参考

  1. 开发效率显著提升:
    • **标准化集成:**​ 新功能语音识别需求的集成时间从原来的“天”级别缩短到“小时”级别。开发者只需关注AsrManagerinitstartstop三个核心方法,无需深入音频和网络细节。
    • **降低决策成本:**​ 通过AUTO模式或简单配置,开发者无需纠结于本地与云端的选择,框架内置了合理的降级策略。
    • **代码复用率高:**​ AsrManager及引擎适配器可在全团队乃至全公司范围内复用,形成技术资产。

更多关于HarmonyOS鸿蒙Next开发者技术支持-语音转文字案例的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

学习了

更多关于HarmonyOS鸿蒙Next开发者技术支持-语音转文字案例的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


鸿蒙Next的语音转文字功能基于ArkTS开发,通过@ohos.multimedia.audio和@ohos.multimedia.media等模块实现。主要流程包括:初始化音频录制、配置参数、启动录音,然后利用语音识别服务将音频流转换为文本。开发者需在module.json5中声明ohos.permission.MICROPHONE权限。具体实现可参考官方文档中的语音识别API使用指南。

这是一个非常专业和完整的HarmonyOS Next语音转文字(ASR)实现方案。您提供的案例清晰地展示了从权限申请、核心管理类封装到UI集成的全流程,具有很高的参考价值。

针对您提供的代码,我补充几点关键的技术细节和优化建议:

  1. 音频数据流的持续处理:您在start方法中提到的“需要更复杂的异步流处理”是核心。在实际开发中,应使用audioCapturer.on('readable')事件监听或在一个独立的Worker/任务中循环读取audioBuffer,并持续调用this.currentEngine.feedAudioData(audioBuffer.data),以确保音频数据被实时送入识别引擎。

  2. 引擎接口 IAsrEngine 的定义:为了使架构更清晰,建议明确定义此接口,例如:

    interface IAsrEngine {
      start(onResult: (result: AsrResult) => void): Promise<void>;
      stop(): Promise<void>;
      feedAudioData(data: ArrayBuffer): void; // 用于持续送入音频数据
    }
    

    这样AsrCloudEngineAsrLocalEngine都实现此接口,管理类的职责会更明确。

  3. 本地引擎的实际调用:HarmonyOS Next 提供了@ohos.ai.speech等Kit,用于端侧语音识别。在AsrLocalEngine中,应调用如speech.AudioCapturer或相关的本地ASR API,而不是假设的类。云端引擎则需要对接具体的云服务商SDK。

  4. 权限的动态申请:在module.json5中声明权限后,在首次使用录音功能前(如initAudioCapturer时),需要使用abilityAccessCtrl相关API进行动态授权请求,确保应用在真实环境中的兼容性。

  5. 错误处理与状态管理:示例中的try-catch是很好的实践。在生产环境中,建议为AsrManager增加更细粒度的状态(如IDLE, RECORDING, PROCESSING),并对外提供状态变化事件,便于UI层做出更精准的反馈(如禁用按钮、显示加载动画)。

您这个案例将复杂的音频采集、引擎选择与业务逻辑进行了有效解耦,封装出的AsrManager接口简洁,确实能极大提升团队在类似功能上的开发效率,是符合HarmonyOS应用架构设计模式的优秀实践。

回到顶部