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

news/2024/12/15 19:16:13/文章来源:https://www.cnblogs.com/aspXiaoBai/p/18608345

三文带你轻松上手鸿蒙的 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: 完整代码在每一个功能的末尾,可以结合封装后的代码来阅读

申请权限

image-20240828222453973

因为在开发功能过程中,需要调用手机的麦克风功能。所以需要主动申请权限。

image-20240828222047223

申请权限分成 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"}}],}
    }
    
  2. \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中关于权限的代码,都是没有经过封装的,难以使用。所以这里提供了封装好的版本。

没有封装过的示例代码:

image-20240828224125035


封装好的代码

entry\src\main\ets\utils\permissionMananger.ets

// 导入必要的模块,包括权限管理相关的功能
import { abilityAccessCtrl, bundleManager, common, Permissions } from '@kit.AbilityKit';export class PermissionManager {// 静态方法用于检查给定的权限是否已经被授予static checkPermission(permissions: Permissions[]): boolean {// 创建一个访问令牌管理器实例let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();// 初始化tokenID为0,稍后将获取真实的tokenIDlet tokenID: number = 0;// 获取本应用的包信息const bundleInfo =bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);// 设置tokenID为应用的访问令牌IDtokenID = bundleInfo.appInfo.accessTokenId;// 如果没有传入任何权限,则返回false表示没有权限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();// 获取上下文(这里假设getContext是一个可以获取到UI能力上下文的方法)let context: Context = getContext() as common.UIAbilityContext;// 请求用户授权指定的权限const result = await atManager.requestPermissionsFromUser(context, permissions);// 检查请求结果是否成功(authResults数组中每个元素都应该是0,表示成功)return !!result.authResults.length && result.authResults.every(authResults => authResults === 0);}
}

页面中使用权限代码

Index.ets

import { PermissionManager } from '../utils/permissionMananger'
import { Permissions } from '@kit.AbilityKit'@Entry
@Component
struct Index {// 1 申请权限fn1 = async () => {// 准备好需要申请的权限 麦克风权限const permissions: Permissions[] = ["ohos.permission.MICROPHONE"]// 检查是否拥有权限const isPermission = await PermissionManager.checkPermission(permissions)if (!isPermission) {//   如果没权限,就主动申请PermissionManager.requestPermission(permissions)}}build() {Column() {Button("申请权限").onClick(this.fn1)}.width("100%").height("100%").justifyContent(FlexAlign.Center)}
}

image-20240828224918956

实时语音识别相关步骤

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

创建 AI 语音引擎

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

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

    image-20240828225611828

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

设置 AI 语音监听回调

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

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

image-20240828225832286

开始监听实时语音

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

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

image-20240828230419298

封装好的语音识别代码

\entry\src\main\ets\utils\SpeechRecognizerManager.ets

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",/*** 离线模式:1*/online: 1,extraParams: this.extraParam,};/*** 引擎*/private static asrEngine: speechRecognizer.SpeechRecognitionEngine | null =null;/*** 录音结果*/static speechResult: speechRecognizer.SpeechRecognitionResult | null = null;/*** 会话ID*/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) {},// 错误回调,错误码通过本方法返回// 如:返回错误码1002200006,识别引擎正忙,引擎正在识别中// 更多错误码请参考错误码参考onError(sessionId: string, errorCode: number, errorMessage: string) {},};// 设置回调SpeechRecognizerManager.asrEngine?.setListener(setListener);}/*** 开始监听* */static startListening() {// 设置开始识别的相关参数let recognizerParams: speechRecognizer.StartParams = {// 会话idsessionId: 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);}/*** 取消识别*/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();}
}export default SpeechRecognizerManager;

页面中调用语音识别代码

import { PermissionManager } from '../utils/permissionMananger'
import { Permissions } from '@kit.AbilityKit'
import SpeechRecognizerManager from '../utils/SpeechRecognizerManager'@Entry
@Component
struct Index {@Statetext: string = ""// 1 申请权限fn1 = async () => {// 准备好需要申请的权限 麦克风权限const permissions: Permissions[] = ["ohos.permission.MICROPHONE"]// 检查是否拥有权限const isPermission = await PermissionManager.checkPermission(permissions)if (!isPermission) {//   如果没权限,就主动申请PermissionManager.requestPermission(permissions)}}// 2 实时语音识别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)}
}

PixPin_2024-08-28_23-19-49


语音识别结果分析

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

实时语音识别 {"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":true,"isLast":false,"result":"是否给你承诺的太多?"}
I     实时语音识别 {"isFinal":false,"isLast":false,"result":""}

其中需要关注的是:

  1. 识别功能是持续触发的,当收集到声音时持续触发

  2. isFinal 表示一个句子是否结束

    image-20240828232352345

  3. isLast 表示这一次语音识别是否结束

总结

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

Core Speech Kit(基础语音服务)集成了语音类基础 AI 能力,包括文本转语音(TextToSpeech)及语音识别(SpeechRecognizer)能

力,便于用户与设备进行互动,实现将实时输入的语音与文本之间相互转换。

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

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

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

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

本文主要实现了 实时语音转文本声音文件转文本 将会在下文讲解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/853436.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【原创】ARM64 实时linux操作系xenomai4(EVL)构建安装简述

本文简要记录在瑞芯微RK3588(ARM64)构建安装实时linux操作系统xenomai4的过程,以及实时性测试,希望对你有所帮助!目录0 环境说明1 内核构建2 库编译方式1 交叉编译方式2 本地编译3 测试单元测试hectic:EVL 上下文切换latmus:latency测试4 RK3588 xenomai4实时性能5 总结 本…

最新版chrome如何下载和安装?附安装包

前言 大家好,我是小徐啊。我们在Java开发应用的时候,经常是需要用到浏览器来帮助我们开发的。而浏览器中,谷歌浏览器chrome当属功能最强大的浏览器。今天小徐就来介绍下如何安装chrome。文末附获取方式。 如何安装chrome 首先,双击chrome的安装包,开始安装。然后,可以看到…

[笔记]均分纸牌问题

Index链形均分纸牌每次仅可交换\(1\)张 每次可交换多张环形均分纸牌每次仅可交换\(1\)张 每次可交换多张拓展性很强的贪心问题。或许能推广到树之类的结构上,或者拓展到方案计数问题之类,不过目前还没想好啦。 链形均分纸牌 每次仅可交换\(1\)张 最基础的例题是这样的:有\(n…

掌握PageRank算法核心!你离Google优化高手只差一步!

0 前言 98年前的搜索引擎体验不好:返回结果质量不高:搜索结果不考虑网页质量,而通过时间顺序检索易被钻空:搜索引擎基于检索词检索,页面中检索词出现的频次越高,匹配度越高,这样就会出现网页作弊的情况。有些网页为了增加搜索引擎的排名,故意增加某个检索词频率当时Goo…

ApacheDirectoryStudio如何安装和使用?附安装包

前言 大家好,我是小徐啊。ldap数据库是我们Java开发中,经常会用到的一种数据库。这种数据库是树形结构的,和平常的mysql等数据库还不太一样。但目前对应连接ldap数据库的连接工具比较少,且功能也不强大。今天,小徐就来介绍下一款比较好的连接ldap数据库的连接功能,那就是…

服务器 数据库被攻击如何处理

最近系统有点卡,查看了一下系统事件,发现有人攻击服务器数据库。 以下是我的解决方案 1、修改密码位复杂的密码 2、修改默认数据库默认端口目前已解决下面的腾讯的小哥给的建议,总体差不多一个意思 1、服务器设置大写、小写、特殊字符、数字组成的12-16位的复杂随机密码 ,…

字符数组及应用

这两个等价 长度都为10。这两个等价 长度都为11。如果有:则:注意: 作者QQ4577105

PyQt5 使用 QPlainTextEdit/QTextBrowser 与 Logging 结合后显示日志信息

PyQt5 使用 QPlainTextEdit/QTextBrowser 与 Logging 结合后显示日志信息 本文演示 PyQt5 如何与 Python 的标准库 Logging结合,然后输出日志信息到如:QPlainTextEdit QTextBrowser上 代码结构 本文中全部代码全在test_QPlainTextEdit_Log.py这一个文件中编码,步骤中有变动的…

2024-2025-1 20241314 《计算机基础与程序设计》第十二周学习总结

2024-2025-1 20241314 《计算机基础与程序设计》第十二周学习总结 作业信息这个作业属于哪个课程 2024-2025-1-计算机基础与程序设计这个作业要求在哪里 2024-2025-1计算机基础与程序设计第十二周作业这个作业的目标 复习作业正文 正文教材学习内容总结引言与文件概述在《C语…

PyQt5 使用结合Logging 在 QPlainTextEdit/QTextBrowser 上显示日志信息

PyQt5 使用结合Logging 在 QPlainTextEdit/QTextBrowser 上显示日志信息 本文演示 PyQt5 如何与 Python 的标准库 Logging结合,然后输出日志信息到如:QPlainTextEdit QTextBrowser上 代码结构 本文中全部代码全在test_QPlainTextEdit_Log.py这一个文件中编码,步骤中有变动的…

uniapp+vue3+uViewPlus

1、uniapp创建项目2、 HuilderX菜单栏 工具->插件安装 -》前往插件市场安下载安装到对应的项目 导入的时候需要看广告 耐心看完 3、uview-plus在main.js中配置代码 import uviewPlus from @/uni_modules/uview-plusapp.use(uviewPlus) 4、在uni.scss中配置样式: @import…

NAS部署quark-auto-save,实现网盘资源自由

安装拉取镜像docker pull cp0204/quark-auto-save:latest一键运行容器docker run -d--name quark-auto-save-p 5005:5005-e TZ=Asia/Shanghai-v /volume1/docker/quark-auto-save:/app/config # 配置文件路径--restart unless-stoppedcp0204/quark-auto-save:latest系统配置首次…