HarmonyOS 鸿蒙Next AI语音02-声音文件转文本

发布于 1周前 作者 caililin 来自 鸿蒙OS

HarmonyOS 鸿蒙Next AI语音02-声音文件转文本

三文带你轻松上手鸿蒙的AI语音02-声音文件转文本

接上一文

前言

本文主要实现 使用鸿蒙的AI语音功能将声音文件识别并转换成文本

实现流程

  1. 利用 AudioCapturer 录制声音,生成录音文件
  2. 利用AI语音功能,实现识别

两个录音库介绍

HarmonyOS NEXT 应用开中,实现录音的两个核心库分别为

  1. AudioCapturer
  2. AVRecorder

AVRecorder录制出来的声音封装格式只能是aac,这个文件格式我们的AI语音引擎不支持,AI语音引擎只支持pcm格式,而 AudioCapturer录制的声音封装格式则是pcm。因此我们选择使用 AudioCapturer 来录制声音

AudioCapturer 介绍

AudioCapturer是音频采集器,用于录制PCM(Pulse Code Modulation)音频数据,适合有音频开发经验的开发者实现更灵活的录制功

能。

主要流程

  1. 创建 AudioCapturer 实例
  2. 调用 start 方法开始录音
  3. 调用 stop 方法停止录音
  4. 调用 release 方法释放实例

创建 AudioCapturer 实例

文末会提供封装好,可以直接使用的代码 下面的代码示例都是基于封装好的代码进行的

我们通过调用 createAudioCapturer 方法实现创建 AudioCapturer 实例,其中该方法需要传递相关参数。

调用 start 方法开始录音

开始调用 start 方法时,需要准备相关数据。如

  1. 提供录音的文件名,可以自定义
  2. 写入录音数据的回调函数(在录制声音的过程中持续触发)
  3. 调用 start 方法

调用 stop 方法停止录音

调用 stop 方法则相对简单,直接调用即可

调用 release 方法释放实例

同理

封装好的录音代码

entry/src/main/ets/utils/AudioCapturerManager.ets 下面是这个类的属性和方法的总结:

属性

  • static audioCapturer: 类型是 audio.AudioCapturer | null,是一个静态属性,用于存储当前的音频捕获器实例。
  • private static recordFilePath: 类型是 string,是一个静态私有属性,用于存储录音文件的路径。

方法

  • static async createAudioCapturer(): 如果 audioCapturer 已经存在,则直接返回该实例;否则创建一个新的音频捕获器实例,并设置其音频流信息和音频捕获信息,然后创建并返回新的实例。
  • static async startRecord(fileName: string): 异步静态方法,用于启动录音过程。首先调用 createAudioCapturer() 方法确保有一个音频捕获器实例。之后初始化缓冲区大小,并打开或创建一个指定名称的 .wav 录音文件。定义一个读取数据的回调函数,用于将捕获到的数据写入文件中。最后开始录音,并记录下录音文件的路径。
  • static async stopRecord(): 异步静态方法,用于停止录音过程。停止音频捕获器的工作,释放其资源,并清除 audioCapturer 实例。

页面中开始录音

可以通过以下路径查看录音文件是否真实生成

/data/app/el2/100/base/你的项目的boundle名称/haps/entry/files

使用AI语音功能 实现声音文件转文本

该流程其实和和上一章的实时识别声音功能类似,只是多了一个步骤

  1. 创建AI语音引擎
  2. 注册语音监听事件
  3. 开始监听
  4. 读取录音文件

创建AI语音引擎

/**
 * 创建引擎
 */
private static async createEngine() {
  // 设置创建引擎参数
  SpeechRecognizerManager.asrEngine = await speechRecognizer.createEngine(SpeechRecognizerManager.initParamsInfo)
}

注册语音监听事件

/**
 * 设置回调
 */
private static setListener(callback: (srr: speechRecognizer.SpeechRecognitionResult) => void = () => {
}) {
  // 创建回调对象
  let setListener: speechRecognizer.RecognitionListener = {
    // 开始识别成功回调
    onStart(sessionId: string, eventMessage: string) {
    },
    // 事件回调
    onEvent(sessionId: string, eventCode: number, eventMessage: string) {
    },
    // 识别结果回调,包括中间结果和最终结果
    onResult(sessionId: string, result: speechRecognizer.SpeechRecognitionResult) {
      SpeechRecognizerManager.speechResult = result
      callback && callback(result)
    },
    // 识别完成回调
    onComplete(sessionId: string, eventMessage: string) {
    },
    // 错误回调,错误码通过本方法返回
    // 如:返回错误码1002200006,识别引擎正忙,引擎正在识别中
    // 更多错误码请参考错误码参考
    onError(sessionId: string, errorCode: number, errorMessage: string) {
      console.log("errorMessage", errorMessage)
    },
  }
  // 设置回调
  SpeechRecognizerManager.asrEngine?.setListener(setListener);
}

开始监听

需要设置 recognitionMode 为 1 表示识别语音文件

/**
 * 开始监听
 */
static startListening2() {
  try { // 设置开始识别的相关参数
    let recognizerParams: speechRecognizer.StartParams = {
      // 会话id
      sessionId: SpeechRecognizerManager.sessionId,
      // 音频配置信息。
      audioInfo: {
        // 音频类型。 当前仅支持“pcm”
        audioType: 'pcm',
        // 音频的采样率。 当前仅支持16000采样率
        sampleRate: 16000,
        // 音频返回的通道数信息。 当前仅支持通道1。
        soundChannel: 1,
        // 音频返回的采样位数。 当前仅支持16位
        sampleBit: 16
      },
      //   录音识别
      extraParams: {
        // 0:实时录音识别  会自动打开麦克风 录制实时语音
        // 1 识别语音文件
        "recognitionMode": 1,
        //   最大支持音频时长
        maxAudioDuration: 60000
      }
    }
    // 调用开始识别方法
    SpeechRecognizerManager.asrEngine?.startListening(recognizerParams);
  } catch (e) {
    console.log("e", e.code, e.message)
  }
};

读取录音文件

需要调用 SpeechRecognizerManager.asrEngine?.writeAudio 来监听语音文件

/**
 *
 * @param fileName {string} 语音文件名称
 */
private static async writeAudio(fileName: string) {
  let ctx = getContext();
  let filePath: string = `${ctx.filesDir}/${fileName}.wav`;
  let file = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE);
  let buf: ArrayBuffer = new ArrayBuffer(1280);
  let offset: number = 0;
  while (1280 == fileIo.readSync(file.fd, buf, {
    offset: offset
  })) {
    let uint8Array: Uint8Array = new Uint8Array(buf);
    // 调用AI语音引擎识别
    SpeechRecognizerManager.asrEngine?.writeAudio(SpeechRecognizerManager.sessionId, uint8Array);
    // 延迟40ms
    await SpeechRecognizerManager.sleep(40)
    offset = offset + 1280;
  }
  fileIo.closeSync(file);

}

/**
 * 加入延迟 否则录音文件识别会出错
 * @param time
 * @returns
 */
static sleep(time: number) {
  const promise = new Promise<void>((resolve: Function) => {
    setTimeout(() => {
      resolve()
    }, time)
  })
  return promise
}

一步调用

/**
 * 初始化ai语音转文字引擎
 */
static async init2(callback: (srr: speechRecognizer.SpeechRecognitionResult) => void = () => {
}, fileName: string) {
  try {
    await SpeechRecognizerManager.createEngine()
    SpeechRecognizerManager.setListener(callback)
    SpeechRecognizerManager.startListening2()
    SpeechRecognizerManager.writeAudio(fileName)
  } catch (e) {
    console.log("e", e.message)
  }
}

完整代码

import { speechRecognizer } from '@kit.CoreSpeechKit';
import { fileIo } from '@kit.CoreFileKit';

class SpeechRecognizerManager {
  static speechResult: speechRecognizer.SpeechRecognitionResult | null = null
  private static extraParam: Record<string, Object> = { "locate": "CN", "recognizerMode": "short" };
  private static initParamsInfo: speechRecognizer.CreateEngineParams = {
    /**
     * 地区信息
     */
    language: 'zh-CN',
    /**
     * 离线模式:1
     */
    online: 1,
    extraParams: this.extraParam
  };
  private static asrEngine: speechRecognizer.SpeechRecognitionEngine | null = null
  private static sessionId: string = "asr" + Date.now()

  /**
   * 开始监听
   */
  static startListening() {
    try { // 设置开始识别的相关参数
      let recognizerParams: speechRecognizer.StartParams = {
        // 会话id
        sessionId: SpeechRecognizerManager.sessionId,
        // 音频配置信息。
        audioInfo: {
          // 音频类型。 当前仅支持“pcm”
          audioType: 'pcm',
          // 音频的采样率。 当前仅支持16000采样率
          sampleRate: 16000,
          // 音频返回的通道数信息。 当前仅支持通道1。
          soundChannel: 1,
          // 音频返回的采样位数。 当前仅支持16位
          sampleBit: 16
        },
        //   录音识别
        extraParams: {
          // 0:实时录音识别  会自动打开麦克风 录制实时语音
          "recognitionMode": 0,
          //   最大支持音频时长
          maxAudioDuration: 60000
        }
      }
      // 调用开始识别方法
      SpeechRecognizerManager.asrEngine?.startListening(recognizerParams);
    } catch (e) {
      console.log("e", e.code, e.message)
    }
  };

  /**
   * 开始监听
   */
  static startListening2() {
    try { // 设置开始识别的相关参数
      let recognizerParams: speechRecognizer.StartParams = {
        // 会话id
        sessionId: SpeechRecognizerManager.sessionId,
        // 音频配置信息。
        audioInfo: {
          // 音频类型。 当前仅支持“pcm”
          audioType: 'pcm',
          // 音频的采样率。 当前仅支持16000采样率
          sampleRate: 16000,
          // 音频返回的通道数信息。 当前仅支持通道1。
          soundChannel: 1,
          // 音频返回的采样位数。 当前仅支持16位
          sampleBit: 16
        },
        //   录音识别
        extraParams:
        {
          // 0:实时录音识别  会自动打开麦克风 录制实时语音
          // 1 识别语音文件
          "recognitionMode": 1,
          //   最大支持音频时长
          maxAudioDuration: 60000
        },
      }
      // 调用开始识别方法
      SpeechRecognizerManager.asrEngine?.startListening(recognizerParams);
    } catch (e) {
      console.log("e", e.code, e.message)
    }
  };

  /**
   * 取消识别
   */
  static cancel() {
    SpeechRecognizerManager.asrEngine?.cancel(SpeechRecognizerManager.sessionId)
  }

  /**
   * 释放ai语音转文字引擎
   */
  static shutDown() {
    SpeechRecognizerManager.asrEngine?.shutdown()
  }

  /**
   * 停止并且释放资源
   */
  static async release() {
    SpeechRecognizerManager.cancel()
    SpeechRecognizerManager.shutDown()

  }

  /**
   * 初始化ai语音转文字引擎
   */
  static async init(callback: (srr: speechRecognizer.SpeechRecognitionResult) => void = () => {
  }) {
    await SpeechRecognizerManager.createEngine()
    SpeechRecognizerManager.setListener(callback)
    SpeechRecognizerManager.startListening()
  }

  /**
   * 初始化ai语音转文字引擎
   */
  static async init2(callback: (srr: speechRecognizer.SpeechRecognitionResult) => void = () => {
  }, fileName: string) {
    try {
      await SpeechRecognizerManager.createEngine()
      SpeechRecognizerManager.setListener(callback)
      SpeechRecognizerManager.startListening2()
      SpeechRecognizerManager.writeAudio(fileName)
    } catch (e) {
      console.log("e", e.message)
    }
  }

  /**
   * 创建引擎
   */
  private static async createEngine() {
    // 设置创建引擎参数
    SpeechRecognizerManager.asrEngine = await speechRecognizer.createEngine(SpeechRecognizerManager.initParamsInfo)
  }

  /**
   * 设置回调
   */
  private static setListener(callback: (srr: speechRecognizer.SpeechRecognitionResult) => void = () => {
  }) {
    // 创建回调对象
    let setListener: speechRecognizer.RecognitionListener = {
      // 开始识别成功回调
      onStart(sessionId: string, eventMessage: string) {
      },
      // 事件回调
      onEvent(sessionId: string, eventCode: number, eventMessage: string) {
      },
      // 识别结果回调,包括中间结果和最终结果
      onResult(sessionId: string, result: speechRecognizer.SpeechRecognitionResult) {
        SpeechRecognizerManager.speechResult = result
        callback && callback(result)
      },
      // 识别完成回调
      onComplete(sessionId: string, eventMessage: string) {
      },
      // 错误回调,错误码通过本方法返回
      // 如:返回错误码1002200006,识别引擎正忙,引擎正在识别中
      // 更多错误码请参考错误码参考
      onError(sessionId: string, errorCode: number, errorMessage: string) {
        console.log("errorMessage", errorMessage)
      },
    }
    // 设置回调
    SpeechRecognizerManager.asrEngine?.setListener(setListener);
  }

  /**
   *
   * @param fileName {string} 语音文件名称
   */
  private static async writeAudio(fileName: string) {
    let ctx = getContext();
    let filePath: string = `${ctx.filesDir}/${fileName}.wav`;
    let file = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE);
    let buf: ArrayBuffer = new ArrayBuffer(1280);
    let offset: number = 0;
    while (1280 == fileIo.readSync(file.fd, buf, {
      offset: offset
    })) {
      let uint8Array: Uint8Array = new Uint8Array(buf);
      // 调用AI语音引擎识别
      SpeechRecognizerManager.asrEngine?.writeAudio(SpeechRecognizerManager.sessionId, uint8Array);
      // 延迟40ms
      await SpeechRecognizerManager.sleep(40)
      offset = offset + 1280;
    }
    fileIo.closeSync(file);

  }

  /**
   * 加入延迟 否则录音文件识别会出错
   * @param time
   * @returns
   */
  static sleep(time: number) {
    const promise = new Promise<void>((resolve: Function) => {
      setTimeout(() => {
        resolve()
      }, time)
    })
    return promise
  }
}

export default SpeechRecognizerManager

更多关于HarmonyOS 鸿蒙Next AI语音02-声音文件转文本的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

在HarmonyOS(鸿蒙Next)中,AI语音功能支持将声音文件转换为文本。该功能通过调用鸿蒙的AI语音识别API实现。开发者可以使用AudioCapturer类捕捉音频数据,并将其传递给AI语音识别引擎进行处理。识别结果以文本形式返回。具体流程包括初始化语音识别引擎、配置音频参数、启动录音、获取音频数据、调用识别API、处理识别结果等步骤。鸿蒙的AI语音识别引擎支持多种音频格式和语言模型,能够在设备端或云端进行识别,具体实现方式取决于开发者的需求和设备性能。

更多关于HarmonyOS 鸿蒙Next AI语音02-声音文件转文本的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,AI语音功能支持将声音文件转换为文本。你可以使用AudioRecorder录制音频,并通过SpeechRecognition服务将音频文件转换为文本。首先,确保设备具备麦克风权限,然后初始化SpeechRecognition实例,调用其startListening方法开始识别。识别完成后,系统会返回文本结果。此功能适用于语音笔记、语音输入等场景,提升交互效率。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!