HarmonyOS APP开发:语音识别ASR技术深度实践
HarmonyOS APP开发:语音识别ASR技术深度实践
核心要点:掌握HarmonyOS语音识别(ASR)能力调用、实时流式识别、离线识别配置,以及识别结果的后处理与业务集成。
一、背景与动机
你有没有这样的体验——开车时想给朋友发条消息,但双手握着方向盘根本腾不出手来打字?或者做菜时想查个食谱,手上全是油渍不方便碰手机?这些场景下,语音输入就成了最自然的交互方式。
语音识别(Automatic Speech Recognition,ASR)就是把人说的话转成文字的技术。听起来简单,但背后涉及声学模型、语言模型、解码器等一整套深度学习管线。好在HarmonyOS已经把这些能力封装成了标准API,我们作为应用开发者,只需要关心"怎么调用"和"怎么用好"。
HarmonyOS的语音识别能力有几个亮点:
- 支持实时流式识别:边说边出字,用户体验丝滑
- 支持离线识别:没网也能用,保护隐私
- 多语言支持:中文、英文、粤语等主流语种全覆盖
- 端云协同:本地轻量模型+云端大模型,灵活切换
今天这篇文章,我们就来深入聊聊HarmonyOS上ASR的完整开发实践。
二、核心原理
2.1 ASR技术架构总览
语音识别的核心流程可以概括为:音频采集 → 预处理 → 特征提取 → 声学解码 → 语言模型修正 → 输出文本。
在HarmonyOS中,这个流程被封装为speechRecognizer模块,开发者通过SpeechRecognizer引擎与系统服务交互。
flowchart TD
A[用户语音输入] --> B[音频采集模块]
B --> C[预处理:降噪/VAD]
C --> D[特征提取:MFCC/Fbank]
D --> E{识别模式选择}
E -->|在线模式| F[云端ASR引擎]
E -->|离线模式| G[端侧ASR引擎]
F --> H[声学模型解码]
G --> H
H --> I[语言模型修正]
I --> J[输出识别文本]
J --> K[业务逻辑处理]
classDef primary fill:#4FC3F7,stroke:#0288D1,color:#000
classDef warning fill:#FFB74D,stroke:#F57C00,color:#000
classDef error fill:#EF5350,stroke:#C62828,color:#FFF
classDef info fill:#81C784,stroke:#388E3C,color:#000
classDef purple fill:#CE93D8,stroke:#7B1FA2,color:#000
class A,B primary
class C,D info
class E warning
class F,G purple
class H,I,J,K primary
2.2 端云协同机制
HarmonyOS的ASR采用端云协同架构:
| 维度 | 端侧识别 | 云端识别 |
|---|---|---|
| 延迟 | 极低(<100ms) | 较高(200-500ms) |
| 准确率 | 中等(92-95%) | 高(97%+) |
| 网络依赖 | 无 | 必须联网 |
| 隐私性 | 高,数据不出设备 | 低,音频上传云端 |
| 适用场景 | 简单指令、隐私敏感 | 长文本、专业术语 |
2.3 流式识别原理
流式识别是ASR体验的关键。传统识别是"说完再出结果",而流式识别是"边说边出",核心区别在于解码策略:
- 全量解码:等整段音频录完,一次性解码,准确率最高但延迟大
- 流式解码:按固定帧长(通常100-200ms)增量解码,实时输出中间结果,最终输出确认结果
HarmonyOS的onResult回调中,isFinal字段标识了当前结果是中间结果还是最终结果。
三、代码实战
3.1 基础语音识别——一次性识别
最简单的用法:点击按钮开始录音,说完后获取识别结果。
// ASR基础识别示例
import { speechRecognizer } from '@kit.AISpeechKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct BasicASRPage {
// 识别结果状态
@State recognizeText: string = '点击按钮开始识别';
@State isListening: boolean = false;
// 语音识别引擎实例
private asrEngine: speechRecognizer.SpeechRecognizer | null = null;
aboutToAppear(): void {
this.initASREngine();
}
// 初始化ASR引擎
private initASREngine(): void {
try {
// 创建语音识别引擎,使用中文普通话
const extraParams: Record<string, Object> = {
'locate': 'CN', // 地区:中国
'language': 'zh-CN', // 语言:中文普通话
};
const initParams: speechRecognizer.CreateEngineParams = {
language: 'zh-CN',
extraParams: extraParams
};
this.asrEngine = speechRecognizer.createEngine(initParams);
console.info('[ASR] 引擎创建成功');
// 设置识别结果回调
this.setupCallbacks();
} catch (error) {
const err = error as BusinessError;
console.error(`[ASR] 引擎创建失败: code=${err.code}, msg=${err.message}`);
}
}
// 设置识别回调监听
private setupCallbacks(): void {
if (!this.asrEngine) return;
// 识别结果回调
this.asrEngine.on('result', (callback: speechRecognizer.Result) => {
if (callback.isFinal) {
// 最终结果
this.recognizeText = callback.result;
this.isListening = false;
console.info(`[ASR] 最终结果: ${callback.result}`);
} else {
// 中间结果(流式识别时使用)
this.recognizeText = callback.result + '...';
console.info(`[ASR] 中间结果: ${callback.result}`);
}
});
// 识别完成回调
this.asrEngine.on('complete', () => {
this.isListening = false;
console.info('[ASR] 识别完成');
});
// 错误回调
this.asrEngine.on('error', (callback: speechRecognizer.Error) => {
this.isListening = false;
console.error(`[ASR] 识别错误: code=${callback.code}, msg=${callback.message}`);
});
}
// 开始识别
private startListening(): void {
if (!this.asrEngine) {
console.error('[ASR] 引擎未初始化');
return;
}
try {
const listenerInfo: speechRecognizer.ListenerInfo = {
sessionId: 'basic_asr_session_001'
};
this.asrEngine.startListening(listenerInfo);
this.isListening = true;
this.recognizeText = '正在聆听...';
console.info('[ASR] 开始监听');
} catch (error) {
const err = error as BusinessError;
console.error(`[ASR] 启动监听失败: code=${err.code}, msg=${err.message}`);
}
}
// 停止识别
private stopListening(): void {
if (!this.asrEngine) return;
try {
this.asrEngine.finish('basic_asr_session_001');
console.info('[ASR] 停止监听');
} catch (error) {
const err = error as BusinessError;
console.error(`[ASR] 停止监听失败: code=${err.code}, msg=${err.message}`);
}
}
build() {
Column({ space: 20 }) {
// 标题
Text('语音识别')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor('#E0E0E0')
// 识别结果展示区
Column() {
Text(this.recognizeText)
.fontSize(20)
.fontColor('#FFFFFF')
.textAlign(TextAlign.Center)
.padding(20)
}
.width('90%')
.minHeight(200)
.borderRadius(16)
.backgroundColor('rgba(255,255,255,0.08)')
.backdropBlur(20)
.justifyContent(FlexAlign.Center)
// 控制按钮
Button(this.isListening ? '停止识别' : '开始识别')
.width('80%')
.height(56)
.fontSize(18)
.fontColor('#FFFFFF')
.backgroundColor(this.isListening ? '#EF5350' : '#4FC3F7')
.borderRadius(28)
.onClick(() => {
if (this.isListening) {
this.stopListening();
} else {
this.startListening();
}
})
}
.width('100%')
.height('100%')
.backgroundColor('#1A1A2E')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
aboutToDisappear(): void {
// 释放引擎资源
if (this.asrEngine) {
this.asrEngine.off('result');
this.asrEngine.off('complete');
this.asrEngine.off('error');
this.asrEngine = null;
}
}
}
3.2 流式识别——实时语音转写
流式识别是语音输入法、会议记录等场景的核心能力。关键在于处理中间结果与最终结果的差异。
// 流式语音识别示例——会议实时转写
import { speechRecognizer } from '@kit.AISpeechKit';
import { BusinessError } from '@kit.BasicServicesKit';
interface TranscriptEntry {
text: string; // 识别文本
isFinal: boolean; // 是否为最终结果
timestamp: number; // 时间戳
}
@Entry
@Component
struct StreamingASRPage {
@State transcriptList: TranscriptEntry[] = [];
@State currentPartial: string = '';
@State isRecording: boolean = false;
@State elapsedTime: string = '00:00';
private asrEngine: speechRecognizer.SpeechRecognizer | null = null;
private startTime: number = 0;
private timerId: number = -1;
aboutToAppear(): void {
this.initStreamingASR();
}
// 初始化流式识别引擎
private initStreamingASR(): void {
try {
const extraParams: Record<string, Object> = {
'locate': 'CN',
'language': 'zh-CN',
'vadBegin': 6000, // 语音起始超时:6秒无语音自动结束
'vadEnd': 2000, // 语音尾端超时:2秒静音自动结束
'maxAudioDuration': 60000, // 最大录音时长60秒
};
const initParams: speechRecognizer.CreateEngineParams = {
language: 'zh-CN',
extraParams: extraParams
};
this.asrEngine = speechRecognizer.createEngine(initParams);
this.setupStreamingCallbacks();
console.info('[StreamingASR] 流式引擎初始化成功');
} catch (error) {
const err = error as BusinessError;
console.error(`[StreamingASR] 初始化失败: ${err.code} - ${err.message}`);
}
}
// 设置流式识别回调
private setupStreamingCallbacks(): void {
if (!this.asrEngine) return;
// 流式结果回调——核心!
this.asrEngine.on('result', (callback: speechRecognizer.Result) => {
if (callback.isFinal) {
// 最终结果:追加到历史记录
this.transcriptList.push({
text: callback.result,
isFinal: true,
timestamp: Date.now()
});
this.currentPartial = '';
console.info(`[StreamingASR] 最终: ${callback.result}`);
} else {
// 中间结果:更新当前行(实时刷新)
this.currentPartial = callback.result;
console.info(`[StreamingASR] 中间: ${callback.result}`);
}
});
// 识别完成——自动重启实现连续识别
this.asrEngine.on('complete', () => {
if (this.isRecording) {
// 如果还在录音状态,自动重新开始下一轮识别
this.restartListening();
}
});
this.asrEngine.on('error', (callback: speechRecognizer.Error) => {
console.error(`[StreamingASR] 错误: ${callback.code} - ${callback.message}`);
if (this.isRecording && callback.code !== 11200002) {
// 非用户主动取消的错误,尝试重启
this.restartListening();
}
});
}
// 重新开始监听(连续识别的关键)
private restartListening(): void {
if (!this.asrEngine) return;
try {
const listenerInfo: speechRecognizer.ListenerInfo = {
sessionId: `stream_session_${Date.now()}`
};
this.asrEngine.startListening(listenerInfo);
} catch (error) {
console.error('[StreamingASR] 重启监听失败');
}
}
// 开始录音
private startRecording(): void {
if (!this.asrEngine) return;
this.isRecording = true;
this.transcriptList = [];
this.currentPartial = '';
this.startTime = Date.now();
// 启动计时器
this.timerId = setInterval(() => {
const elapsed = Math.floor((Date.now() - this.startTime) / 1000);
const min = String(Math.floor(elapsed / 60)).padStart(2, '0');
const sec = String(elapsed % 60).padStart(2, '0');
this.elapsedTime = `${min}:${sec}`;
}, 1000);
const listenerInfo: speechRecognizer.ListenerInfo = {
sessionId: `stream_session_${Date.now()}`
};
this.asrEngine.startListening(listenerInfo);
}
// 停止录音
private stopRecording(): void {
if (!this.asrEngine) return;
this.isRecording = false;
clearInterval(this.timerId);
this.asrEngine.finish(`stream_session_${Date.now()}`);
}
build() {
Column({ space: 16 }) {
// 顶部状态栏
Row({ space: 12 }) {
Text('实时转写')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor('#E0E0E0')
if (this.isRecording) {
// 录音指示灯
Circle({ width: 12, height: 12 })
.fill('#EF5350')
Text(this.elapsedTime)
.fontSize(16)
.fontColor('#EF5350')
.fontFamily('monospace')
}
}
.width('90%')
.justifyContent(FlexAlign.SpaceBetween)
// 转写内容区域
Scroll() {
Column({ space: 8 }) {
ForEach(this.transcriptList, (entry: TranscriptEntry, index: number) => {
Row() {
Text(entry.text)
.fontSize(16)
.fontColor('#E0E0E0')
.width('100%')
}
.width('100%')
.padding(12)
.borderRadius(8)
.backgroundColor('rgba(255,255,255,0.05)')
}, (entry: TranscriptEntry, index: number) => `${index}`)
// 当前正在识别的中间结果
if (this.currentPartial) {
Row() {
Text(this.currentPartial)
.fontSize(16)
.fontColor('#4FC3F7')
.fontStyle(FontStyle.Italic)
.width('100%')
}
.width('100%')
.padding(12)
.borderRadius(8)
.backgroundColor('rgba(79,195,247,0.1)')
.border({ width: 1, color: 'rgba(79,195,247,0.3)' })
}
}
}
.width('90%')
.layoutWeight(1)
.align(Alignment.Top)
// 底部控制区
Row({ space: 20 }) {
Button(this.isRecording ? '停止' : '开始转写')
.width(160)
.height(56)
.fontSize(18)
.fontColor('#FFFFFF')
.backgroundColor(this.isRecording ? '#EF5350' : '#4FC3F7')
.borderRadius(28)
.onClick(() => {
if (this.isRecording) {
this.stopRecording();
} else {
this.startRecording();
}
})
// 导出按钮
Button('导出文本')
.width(120)
.height(56)
.fontSize(16)
.fontColor('#81C784')
.backgroundColor('rgba(129,199,132,0.15)')
.borderRadius(28)
.enabled(this.transcriptList.length > 0)
.onClick(() => {
const fullText = this.transcriptList
.map(e => e.text)
.join('\n');
console.info(`[导出] ${fullText}`);
})
}
}
.width('100%')
.height('100%')
.backgroundColor('#1A1A2E')
.justifyContent(FlexAlign.Start)
.padding({ top: 40 })
}
aboutToDisappear(): void {
clearInterval(this.timerId);
if (this.asrEngine) {
this.asrEngine.off('result');
this.asrEngine.off('complete');
this.asrEngine.off('error');
this.asrEngine = null;
}
}
}
3.3 离线识别——无网络环境下的语音输入
离线识别对于隐私敏感场景(如金融、医疗)和弱网环境至关重要。HarmonyOS支持端侧ASR引擎,需要在创建引擎时指定离线模式。
// 离线语音识别示例
import { speechRecognizer } from '@kit.AISpeechKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct OfflineASRPage {
@State offlineResult: string = '等待离线识别...';
@State isListening: boolean = false;
@State engineMode: string = 'offline'; // offline / online
@State confidence: number = 0;
private asrEngine: speechRecognizer.SpeechRecognizer | null = null;
aboutToAppear(): void {
this.initOfflineEngine();
}
// 初始化离线识别引擎
private initOfflineEngine(): void {
try {
// 关键:通过extraParams指定离线模式
const extraParams: Record<string, Object> = {
'locate': 'CN',
'language': 'zh-CN',
// 指定使用端侧引擎(离线模式)
'recognizerMode': 'offline',
// 离线识别的音频格式
'audioFormat': 'pcm',
'sampleRate': 16000,
};
const initParams: speechRecognizer.CreateEngineParams = {
language: 'zh-CN',
extraParams: extraParams
};
this.asrEngine = speechRecognizer.createEngine(initParams);
this.setupOfflineCallbacks();
console.info('[OfflineASR] 离线引擎初始化成功');
} catch (error) {
const err = error as BusinessError;
console.error(`[OfflineASR] 初始化失败: ${err.code} - ${err.message}`);
// 离线引擎不可用时,降级到在线模式
this.fallbackToOnline();
}
}
// 降级到在线模式
private fallbackToOnline(): void {
try {
const extraParams: Record<string, Object> = {
'locate': 'CN',
'language': 'zh-CN',
'recognizerMode': 'online',
};
const initParams: speechRecognizer.CreateEngineParams = {
language: 'zh-CN',
extraParams: extraParams
};
this.asrEngine = speechRecognizer.createEngine(initParams);
this.setupOfflineCallbacks();
this.engineMode = 'online';
console.info('[OfflineASR] 降级到在线模式');
} catch (error) {
console.error('[OfflineASR] 在线模式也不可用');
}
}
// 设置离线识别回调
private setupOfflineCallbacks(): void {
if (!this.asrEngine) return;
this.asrEngine.on('result', (callback: speechRecognizer.Result) => {
if (callback.isFinal) {
this.offlineResult = callback.result;
this.isListening = false;
// 离线识别通常带有置信度信息
console.info(`[OfflineASR] 离线结果: ${callback.result}`);
}
});
this.asrEngine.on('complete', () => {
this.isListening = false;
});
this.asrEngine.on('error', (callback: speechRecognizer.Error) => {
this.isListening = false;
this.offlineResult = `识别错误: ${callback.message}`;
console.error(`[OfflineASR] 错误: ${callback.code}`);
});
}
// 开始离线识别
private startOfflineListening(): void {
if (!this.asrEngine) return;
this.isListening = true;
this.offlineResult = '正在聆听(离线模式)...';
const listenerInfo: speechRecognizer.ListenerInfo = {
sessionId: `offline_session_${Date.now()}`
};
this.asrEngine.startListening(listenerInfo);
}
build() {
Column({ space: 20 }) {
Text('离线语音识别')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor('#E0E0E0')
// 引擎模式指示
Row({ space: 8 }) {
Circle({ width: 8, height: 8 })
.fill(this.engineMode === 'offline' ? '#81C784' : '#FFB74D')
Text(this.engineMode === 'offline' ? '端侧引擎' : '云端引擎(降级)')
.fontSize(14)
.fontColor(this.engineMode === 'offline' ? '#81C784' : '#FFB74D')
}
// 结果展示
Column() {
Text(this.offlineResult)
.fontSize(20)
.fontColor('#FFFFFF')
.textAlign(TextAlign.Center)
.padding(20)
}
.width('90%')
.minHeight(180)
.borderRadius(16)
.backgroundColor('rgba(255,255,255,0.08)')
.backdropBlur(20)
// 开始按钮
Button(this.isListening ? '停止' : '开始离线识别')
.width('80%')
.height(56)
.fontSize(18)
.fontColor('#FFFFFF')
.backgroundColor(this.isListening ? '#EF5350' : '#81C784')
.borderRadius(28)
.onClick(() => {
if (this.isListening) {
this.asrEngine?.finish(`offline_session_${Date.now()}`);
} else {
this.startOfflineListening();
}
})
// 提示信息
Text('离线识别无需联网,数据不出设备,适合隐私敏感场景')
.fontSize(12)
.fontColor('#9E9E9E')
.width('80%')
.textAlign(TextAlign.Center)
}
.width('100%')
.height('100%')
.backgroundColor('#1A1A2E')
.justifyContent(FlexAlign.Center)
}
aboutToDisappear(): void {
if (this.asrEngine) {
this.asrEngine.off('result');
this.asrEngine.off('complete');
this.asrEngine.off('error');
this.asrEngine = null;
}
}
}
四、踩坑与注意事项
4.1 权限配置
语音识别需要申请麦克风权限,在module.json5中添加:
{
"requestPermissions": [
{
"name": "ohos.permission.MICROPHONE",
"reason": "$string:microphone_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
]
}
⚠️ 注意:麦克风权限是用户授权权限,必须动态申请,不能静默获取。首次使用时务必调用requestPermissionsFromUser()。
4.2 引擎生命周期管理
这是新手最容易踩的坑:
- 引擎只能创建一次:不要在每次识别时都
createEngine(),应该在页面初始化时创建,页面销毁时释放。 - sessionId必须唯一:每次
startListening()时使用不同的sessionId,避免与上一次冲突。 - 回调必须先注册再启动:先调用
on('result')注册回调,再调用startListening(),否则可能丢失结果。 - 页面销毁时必须off:在
aboutToDisappear()中调用off()移除所有回调,否则会内存泄漏。
4.3 VAD参数调优
VAD(Voice Activity Detection)参数直接影响识别体验:
| 参数 | 默认值 | 建议值 | 说明 |
|---|---|---|---|
| vadBegin | 6000ms | 3000-6000ms | 开始后多久没检测到语音就结束 |
| vadEnd | 2000ms | 1500-3000ms | 静音多久后认为说完 |
| maxAudioDuration | 60000ms | 按需设置 | 单次最大录音时长 |
调优建议:
- 会议转写场景:
vadEnd设大一些(3000ms),避免说话停顿被误判为结束 - 语音指令场景:
vadEnd设小一些(1500ms),快速响应 - 长文本输入:
maxAudioDuration设大(300000ms),支持5分钟长录音
4.4 离线模型可用性检查
离线识别依赖设备端预装的语音模型,并非所有设备都支持。务必做好降级处理:
// 检查离线引擎是否可用
private async checkOfflineAvailability(): Promise<boolean> {
try {
const extraParams: Record<string, Object> = {
'recognizerMode': 'offline',
'language': 'zh-CN',
};
const initParams: speechRecognizer.CreateEngineParams = {
language: 'zh-CN',
extraParams: extraParams
};
const testEngine = speechRecognizer.createEngine(initParams);
// 创建成功说明离线可用
return true;
} catch {
// 创建失败,离线不可用
return false;
}
}
4.5 多语言识别切换
切换识别语言时,需要重新创建引擎,不能在运行时切换:
// 错误做法:直接切换语言
// this.asrEngine.startListening({ language: 'en-US' }); // ❌ 不支持
// 正确做法:销毁旧引擎,创建新引擎
private switchLanguage(lang: string): void {
// 先释放旧引擎
if (this.asrEngine) {
this.asrEngine.off('result');
this.asrEngine.off('complete');
this.asrEngine.off('error');
this.asrEngine = null;
}
// 用新语言创建引擎
const initParams: speechRecognizer.CreateEngineParams = {
language: lang,
extraParams: { 'locate': lang === 'zh-CN' ? 'CN' : 'US' }
};
this.asrEngine = speechRecognizer.createEngine(initParams);
this.setupCallbacks();
}
五、HarmonyOS 6适配
5.1 API变更
HarmonyOS 6对语音识别API做了以下调整:
| 变更项 | HarmonyOS 5 | HarmonyOS 6 |
|---|---|---|
| 引擎创建 | createEngine() |
createEngine()不变,但extraParams新增preferOnline字段 |
| 离线模型 | 部分设备不支持 | 全线设备预装端侧模型,准确率提升5% |
| 流式回调 | on('result') |
新增on('partialResult')分离中间结果回调 |
| 错误码 | 11200001-11200010 | 新增11200011(模型加载超时)、11200012(并发限制) |
5.2 迁移指南
// HarmonyOS 6 推荐的引擎创建方式
const extraParams: Record<string, Object> = {
'locate': 'CN',
'language': 'zh-CN',
// HarmonyOS 6新增:优先使用在线引擎
'preferOnline': true,
// HarmonyOS 6新增:自动降级到离线
'autoFallback': true,
};
5.3 新增能力
HarmonyOS 6的ASR新增了以下能力:
- 标点符号预测:自动在识别结果中添加标点,
extraParams中设置'punctuation': true - 逆文本正则化(ITN):将"一百二十三"转为"123",设置
'itn': true - 敏感词过滤:云端识别支持敏感词屏蔽,设置
'filterProfanity': true
六、总结
mindmap
root((HarmonyOS ASR))
引擎管理
创建 createEngine
释放 aboutToDisappear
生命周期管理
识别模式
在线识别 高准确率
离线识别 隐私安全
端云协同 自动降级
核心回调
on result 识别结果
on complete 识别完成
on error 错误处理
参数调优
VAD超时配置
最大录音时长
多语言切换
HarmonyOS 6
preferOnline字段
partialResult回调
标点预测 ITN
踩坑要点
麦克风权限动态申请
sessionId唯一性
回调注册顺序
离线模型可用性检查
classDef primary fill:#4FC3F7,stroke:#0288D1,color:#000
classDef warning fill:#FFB74D,stroke:#F57C00,color:#000
classDef error fill:#EF5350,stroke:#C62828,color:#FFF
classDef info fill:#81C784,stroke:#388E3C,color:#000
classDef purple fill:#CE93D8,stroke:#7B1FA2,color:#000
| 知识点 | 关键内容 |
|---|---|
| 引擎创建 | speechRecognizer.createEngine(),指定language和extraParams |
| 流式识别 | on('result')中通过isFinal区分中间/最终结果 |
| 离线识别 | extraParams设置recognizerMode: 'offline',注意降级处理 |
| VAD调优 | vadBegin/vadEnd/maxAudioDuration按场景调整 |
| 权限管理 | 麦克风权限需动态申请,不能静默获取 |
| 生命周期 | 引擎只创建一次,回调先注册再启动,页面销毁时off |
| HarmonyOS 6 | 新增preferOnline、autoFallback、标点预测、ITN |
语音识别是语音智能的"耳朵",是所有语音交互的起点。掌握了ASR,你就掌握了让应用"听懂"用户的能力。下一篇我们将聊聊"嘴巴"——语音合成TTS,让应用能"说话"。
- 点赞
- 收藏
- 关注作者
评论(0)