HarmonyOS 鸿蒙Next AI语音-实时语音识别

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

HarmonyOS 鸿蒙Next AI语音-实时语音识别

三文带你轻松上手鸿蒙的AI语音01-实时语音识别

前言

HarmonyOSNext中集成了强大的AI功能。Core Speech Kit(基础语音服务)是它提供的众多AI功能中的一种。

Core Speech Kit(基础语音服务)集成了语音类基础AI能力,包括文本转语音(TextToSpeech)及语音识别(SpeechRecognizer)能力,便于用户与设备进行互动,实现将实时输入的语音与文本之间相互转换。

简单来讲Core Speech Kit主要提供了两大语音AI功能:

  1. 语音识别
  2. 文本转语音

语音识别介绍

语音识别功能可以将一段音频信息(短语音模式不超过60s,长语音模式不超过8h)转换为文本。

其中语音识别又可以实现:

  1. 实时语音转文本
  2. 声音文件转文本

实时语音转文本

实现流程

先介绍语音识别的流程,后面的文字转语音大同小异

  1. 申请权限
  2. 创建AI语音引擎
  3. 设置监听回调
  4. 开始监听

tips: 完整代码在每一个功能的末尾,可以结合封装后的代码来阅读

申请权限

申请权限分成3个步骤

  1. 声明权限
  2. 检查是否拥有权限
  3. 申请权限

声明权限

  1. entry\src\main\module.json5中添加以下配置代码 requestPermissions
{
  "module": {
    ...
    "requestPermissions": [
      {
        "name": "ohos.permission.MICROPHONE",
        "reason": "$string:voice_reason",
        "usedScene": {
          "abilities": [
            "FormAbility"
          ],
          "when": "always"
        }
      }
    ],
  }
}
  1. entry\src\main\resources\base\element\string.json 添加 申请原因 voice_reason
{
  "string": [
    {
      "name": "module_desc",
      "value": "module description"
    },
    {
      "name": "EntryAbility_desc",
      "value": "description"
    },
    {
      "name": "EntryAbility_label",
      "value": "label"
    },
    {
      "name": "voice_reason",
      "value": "用于获取用户的录音"
    }
  ]
}

检查权限

实际开发中,我们在申请权限之前可以先调用接口checkAccessTokenSync,检查下是否已经拥有权限。如果没有,则主动申请权限

申请权限

当我们需要申请某个功能的权限时,可以通过调用 requestPermissionsFromUser 来实现

封装好的权限代码

因为HarmonyOSNext中关于权限的代码,都是没有经过封装的,难以使用。所以这里提供了封装好的版本。

没有封装过的示例代码:

封装好的代码

// 导入必要的模块,包括权限管理相关的功能
import { abilityAccessCtrl, bundleManager, common, Permissions } from '@kit.AbilityKit';

export class PermissionManager {
  // 静态方法用于检查给定的权限是否已经被授予
  static checkPermission(permissions: Permissions[]): boolean {
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    let tokenID: number = 0;

    const bundleInfo =
      bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);

    tokenID = bundleInfo.appInfo.accessTokenId;

    if (permissions.length === 0) {
      return false;
    } else {
      return permissions.every(permission =>
      abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED ===
      atManager.checkAccessTokenSync(tokenID, permission)
      );
    }
  }

  // 异步静态方法用于请求用户授权指定的权限
  static async requestPermission(permissions: Permissions[]): Promise<boolean> {
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();

    const context: Context = getContext() as common.UIAbilityContext;

    const result = await atManager.requestPermissionsFromUser(context, permissions);

    return !!result.authResults.length && result.authResults.every(authResults => authResults === 0);
  }
}

页面中使用权限代码

import { PermissionManager } from '../utils/permissionMananger'
import { Permissions } from '@kit.AbilityKit'

@Entry
@Component
struct Index {
  @State
  text: string = ""

  fn1 = async () => {
    const permissions: Permissions[] = ["ohos.permission.MICROPHONE"]
    const isPermission = await PermissionManager.checkPermission(permissions)
    if (!isPermission) {
      PermissionManager.requestPermission(permissions)
    }
  }

  fn2 = () => {
    SpeechRecognizerManager.init(res => {
      console.log("实时语音识别", JSON.stringify(res))
      this.text = res.result
    })
  }

  build() {
    Column({ space: 10 }) {
      Text(this.text)

      Button("申请权限")
        .onClick(this.fn1)
      Button("实时语音识别")
        .onClick(this.fn2)
    }
    .width("100%")
    .height("100%")
    .justifyContent(FlexAlign.Center)
  }
}

实时语音识别相关步骤

以下主要实现实时语音识别

创建AI语音引擎

创建AI语音引擎主要有以下几个步骤

  1. 声明AI语音引擎配置参数,主要有语种、区域信息等

  2. 调用开始创建 createEngine 方法开始创建,并且返回 AI语音实例引擎

设置AI语音监听回调

在开始语音识别之前,需要先设置语音识别回调 setListener 。它主要有以下几个分类

  1. 开始识别回调
  2. 事件回调
  3. 识别结果回调
  4. 识别完成回调
  5. 识别错误回调

开始监听实时语音

需要先配置监听的参数,便可以调用startListening实现语音识别了

参数配置 其中,实时语音识别和语音文件识别的主要配置在 recognitionMode 字段, 0 表示实时语音识别

封装好的语音识别代码

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

class SpeechRecognizerManager {
  private static extraParam: Record<string, Object> = { "locate": "CN", "recognizerMode": "long" };
  private static initParamsInfo: speechRecognizer.CreateEngineParams = {
    language: 'zh-CN',
    online: 1,
    extraParams: this.extraParam
  };
  private static asrEngine: speechRecognizer.SpeechRecognitionEngine | null = null
  static speechResult: speechRecognizer.SpeechRecognitionResult | null = null
  private static sessionId: string = "asr" + Date.now()

  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) {
      },
      onError(sessionId: string, errorCode: number, errorMessage: string) {
      },
    }
    SpeechRecognizerManager.asrEngine?.setListener(setListener);
  }

  static startListening() {
    let recognizerParams: speechRecognizer.StartParams = {
      sessionId: SpeechRecognizerManager.sessionId,
      audioInfo: {
        audioType: 'pcm',
        sampleRate: 16000,
        soundChannel: 1,
        sampleBit: 16
      },
      extraParams: {
        "recognitionMode": 0,
        maxAudioDuration: 60000
      }
    }
    SpeechRecognizerManager.asrEngine?.startListening(recognizerParams);
  };

  static cancel() {
    SpeechRecognizerManager.asrEngine?.cancel(SpeechRecognizerManager.sessionId)
  }

  static shutDown() {
    SpeechRecognizerManager.asrEngine?.shutdown()
  }

  static async release() {
    SpeechRecognizerManager.cancel()
    SpeechRecognizerManager.shutDown()
  }

  static async init(callback: (srr: speechRecognizer.SpeechRecognitionResult) => void = () => {
  }) {
    await SpeechRecognizerManager.createEngine()
    SpeechRecognizerManager.setListener(callback)
    SpeechRecognizerManager.startListening()
  }
}

export default SpeechRecognizerManager

页面中调用语音识别代码

import { PermissionManager } from '../utils/permissionMananger'
import { Permissions } from '@kit.AbilityKit'
import SpeechRecognizerManager from '../utils/SpeechRecognizerManager'

@Entry
@Component
struct Index {
  @State
  text: string = ""

  fn1 = async () => {
    const permissions: Permissions[] = ["ohos.permission.MICROPHONE"]
    const isPermission = await PermissionManager.checkPermission(permissions)
    if (!isPermission) {
      PermissionManager.requestPermission(permissions)
    }
  }

  fn2 = () => {
    SpeechRecognizerManager.init(res => {
      console.log("实时语音识别", JSON.stringify(res))
      this.text = res.result
    })
  }

  build() {
    Column({ space: 10 }) {
      Text(this.text)

      Button("申请权限")
        .onClick(this.fn1)
      Button("实时语音识别")
        .onClick(this.fn2)
    }
    .width("100%")
    .height("100%")
    .justifyContent(FlexAlign.Center)
  }
}

语音识别结果分析

语音识别成功后的数据格式如下

实时语音识别 {"isFinal":false,"isLast":false,"result":"是"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":"是否给你"}
I

更多关于HarmonyOS 鸿蒙Next AI语音-实时语音识别的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

23 回复

版本是API14,尝试了但是运行不了,这里尝试了之后发现权限获取可以,引擎创建一直失败并且找不到报错原因

尝试用官方文档的写法之后,点击按钮直接退出软件并报错

更多关于HarmonyOS 鸿蒙Next AI语音-实时语音识别的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


用的是真机吗,模拟器不支持,

用的是真机,不是模拟器,也试过重装系统也不可以,经过定位我能定位创建引擎错误,AI说是创建模型这里出错的,但是代码上没有错误,而且点击也可以找到,

牛的,感谢楼主分享。

谢谢支持,

基本信息

  • 姓名: 张三
  • 年龄: 28
  • 职业: 软件工程师

语音识别,如何不重复,我说“你好”,结果出来很多“你好”

找HarmonyOS工作还需要会Flutter技术的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:BV1S4411E7LY/?p=17

通过合理搭配 isCompletedisFinal 来处理即可,

isCompleted是啥,判断isFinal会导致有一定识别延迟,我对比了下感觉没有安卓的速度快。

cke_3300.png

设置为long,就是报引擎异常

你好,我反复试了好几遍,不管官网的例子,还是你这个代码,都跑着试了,模式设置为short是正常,但是设置成long,创建引擎时就会报错(https://developer.huawei.com/consumer/cn/doc/harmonyos-references/errorcode-corespeech-0000001748511022#section48792273468),你这里有碰到这种情况吗?

官网文档我看在Beta1中创建引擎时是有这项配置的,但DP2中就没有了,但是我目前用的也是Beta1,

cke_3516.png

cke_3898.png

不会,你的运行环境是什么,

IDE用的最新的Beta1-800,手机是Mate60Pro,系统是NEXT.0.0.60(SP12DEVCOOE61R4P9log)Developer Beta5,

和我环境是一样的。你手机重置 出厂设置 试试。

请问第2个例子实时语音识别,需要真机运行吗?试过运行在模拟器时,报错如下。

是的,这个硬件能力需要真机执行。

感谢分享。

感谢评论,

基本信息

  • 姓名: 张三
  • 年龄: 28
  • 职位: 软件工程师

技能

  • Python
  • Java
  • C++

HarmonyOS 鸿蒙Next的AI语音-实时语音识别功能基于鸿蒙系统的分布式能力和AI技术,能够实现高效、低延迟的语音识别。该功能通过鸿蒙的分布式软总线技术,将语音数据在设备间快速传输,结合端侧AI模型进行实时处理,减少对云端依赖,提升响应速度和隐私保护。鸿蒙Next的AI语音识别支持多设备协同,用户可以在不同设备上无缝切换语音交互场景。系统内置的语音识别引擎支持多种语言和方言,并具备噪声抑制、回声消除等优化技术,确保在复杂环境下的识别准确率。开发者可以通过鸿蒙提供的AI Kit接口,集成实时语音识别功能到应用中,支持语音转文字、语音指令识别等场景。

HarmonyOS鸿蒙Next的AI语音实时语音识别功能,依托于先进的神经网络算法和本地化处理,能够在设备端实现高效、低延迟的语音转文字。该技术支持多语种识别,并具备噪声抑制和上下文理解能力,确保在复杂环境下仍能保持高准确率。通过系统级的深度优化,鸿蒙Next的实时语音识别不仅提升了用户体验,还增强了隐私保护,因为所有处理均在设备本地完成,无需上传云端。

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