查看: 89|回复: 3

鸿蒙Core Speech Kit实现语音翻页:ASR降级与文本修复实践

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
最近在做一个鸿蒙App上的提词器功能,产品经理提了个需求:让提词器跟着朗读速度自动翻页,不用手动滑。想法很简单——对着提词器念台词,系统实时识别语音,跟剧本逐行比对,读完一行就自动翻到下一行。听起来就是语音识别加字符串匹配的事,但真正做起来才发现坑不少。

ASR出来的文本跟剧本对不上:"1024"被识成"一零二四","A"变成"诶",标点全不一样,还有各种语气词混在里面。折腾了两周才把这个功能从"能跑"调到"好用"。下面分享整个架构和关键实现。

首先把架构理清楚:整个语音翻页分四层。最底层是ASR引擎层,由SpeechFollowManager封装鸿蒙Core Speech Kit的语音识别引擎,只管把麦克风采集的音频流送进ASR引擎,拿到识别文本后回调给上层。第二层是热词增强层,AsrScriptEnhancer在引擎启动前从剧本里提取热词短语塞进引擎的参数里,让ASR往剧本词汇上"靠"。第三层是文本修复层,AsrTextRepair对每次吐出的片段做剧本约束修复,包括全角转半角、汉字数字还原、V+数字纠正、小数点修正。最上层是行匹配层,TextMatchUtil把修复后的文本跟剧本逐行比对,判断当前行是否读完。

ASR引擎层最核心的设计不是怎么调ASR,而是ASR挂了怎么办。鸿蒙Core Speech Kit有四种引擎配置:在线长语音、在线短语音、离线长语音、离线短语音。实测第三方应用在鸿蒙上用离线引擎经常创建失败,官方文档没明说,但看起来对三方应用有限制。所以优先走在线长语音,失败了降级到在线短语音,再失败才走离线。降级逻辑很简单,就是个for循环依次尝试四种配置,但有个关键细节:每次降级前必须调用releaseEngine()释放当前引擎实例,否则下一个引擎创建成功但startListening会报错201(设备忙),原因是上一个引擎还占着麦克风。

引擎启动时的参数配置也需要注意。热词偏置通过extraParams里的subject字段传入,recognitionMode固定传0表示实时流式识别。ASR引擎onResult回调频率很高,一秒能吐十几次,如果每次都触发UI更新会掉帧甚至ANR。项目里做了一层36ms的节流:大约对应28fps,人眼感知已经"实时"了。20ms太激进,50ms体感迟钝,36ms刚好。但首段识别结果必须立即投递,不能等节流——用户开口说第一个字时UI没反应会以为功能没开,所以用firstUiEmitDone标记来处理。

热词增强层从剧本里提取短语塞给ASR引擎当提示词。中文滑窗是关键,把连续中文段切成2~6字的子串,让ASR更容易匹配剧本词汇。孤立的单字母或数字也要加进热词,比如剧本里有个"A"或"5",ASR容易识成中文"诶"或"五"。热词最终拼成一个空格分隔的长串,截断到800字符以内——太长引擎会忽略后面的词,太短覆盖不到足够多的剧本词汇。

文本修复层是"脏活累活"。ASR吐出来的文本跟剧本有各种差异,需要逐个修复。核心函数repairAsrAgainstScript按顺序跑五道修复:第一道全角转半角,把全角数字字母转成半角;第二道汉字数字平铺还原,从剧本里提取至少2位的阿拉伯数字串,检查ASR文本里有没有对应的汉字平铺形式,有就替换回去——比如"二零二四年"替换成"2024年";第三道单行单字修复,维护一张常见误识词表,把"诶"变回"A"、"达布刘"变回"W"等;第四道V+数字纠正,把"V一"改成"V1";第五道小数点修正,把"3点1"改成"3.1"。这些修复都遵循"剧本约束"原则:只做剧本能佐证的修复,不做无依据的猜测。

行匹配层是决策核心。比对前识别文本和剧本行都要做归一化——去空白、小写、全角转半角、汉字数字折叠成阿拉伯数字。判断当前行是否读完有三种方式:优先识别串以该行结尾;次选整行在识别串中出现且最后一次出现贴近串尾(允许10个字符的余量给语气词);兜底用去掉标点的宽松归一化再试一次。支持跳行朗读:每次回调往前最多看6行,如果发现某行已经完整出现就跳转到那一行。会话文本合并时要处理流式重叠——相邻两次回调的文本可能有重叠,通过检测后缀-前缀重叠来去重。合并后的文本上限16000字符,超过后保留前4000加后12000,避免截断导致前面行的匹配上下文丢失。

声纹锁联动:VoiceFollowTrust控制是否允许翻行。声纹验证通过后给12秒信任窗口,窗口内ASR匹配到行切换才真正翻页。如果触发行匹配但声纹未通过,底部提示"非本人声,未翻行"。

最后是两个踩坑记录。第一个坑:ASR引擎创建成功但startListening报错201。排查发现鸿蒙上多个AudioCapturer不能同时占用同一个输入设备——声纹监听和ASR识别用了两个独立的麦克风采集实例,声纹先启动导致ASR冲突。解决方案是在ASR引擎onStart回调之后再启动声纹采集,让ASR先拿到麦克风。第二个坑:汉字数字折叠时单个"五"被当成数字5替换,导致"队伍"变成"队5"。解决办法是只折叠连续2个及以上的汉字数字序列,单个汉字数字不动。

这些经验希望能帮到在鸿蒙上做语音相关功能的开发者。Core Speech Kit的能力足够强大,但细节处理上需要多下功夫。
回复

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: 鸿蒙Core Speech Kit实现语音翻页:ASR降级与文本修复实践

非常详细的实践分享,从架构设计到具体踩坑都讲得很透彻。你提到的ASR引擎降级策略和释放资源的细节确实关键,很多文档没写清楚,实际跑起来才能发现引擎占着麦克风不释放的坑。文本修复层的五道修复逻辑也很实用,尤其是汉字数字平铺还原和V+数字纠正,这种剧本约束的思路比通用文本纠错更可靠。声纹锁联动和跳行匹配的设计也很有启发,感谢分享!
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: 鸿蒙Core Speech Kit实现语音翻页:ASR降级与文本修复实践

感谢楼主的详细分享!这个语音翻页的落地细节非常扎实,尤其是ASR降级循环和文本修复的“剧本约束”原则,很值得学习。想请教一下,热词增强层的中文滑窗切到2~6字,对于剧本里比较长的专业术语(比如超过6字的固定搭配)你们是怎么处理的?是单纯靠多次滑窗重叠来覆盖,还是另外做了长短语的保留逻辑?
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: 鸿蒙Core Speech Kit实现语音翻页:ASR降级与文本修复实践

感谢分享!这个语音翻页方案设计得非常扎实,特别是多层降级和文本修复的细节,解决了很多实际落地会遇到的痛点。 想请教一下,热词增强层做中文滑窗时,单字母或数字加进去后会不会引入误匹配?比如剧本里有个独立的“5”,但ASR在其他地方识别出“五”时,会不会因为热词偏置而强行纠正成数字? 另外,声纹锁的12秒信任窗口在实际连续朗读时,如果翻页间隔超过12秒,岂不是每行都需要重新验证?还是说信任窗口会在每次翻页成功后重置?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-7-22 20:36 , Processed in 0.028894 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部