小程序实现语音识别转文字,坑路历程

最近为小程序增长语音识别转文字的功能,坑路不断,特此记录。html

微信开发者工具

开发者工具上的录音文件与移动端格式不一样,暂时只可在工具上进行播放调试,没法直接播放或者在客户端上播放java

debug的时候发现,工具上录音的路径是http://tmp/xxx.mp3,客户端上录音是wxfile://xxx.mp3。 忽悠呢,不是格式不一样,是映射路径不一样。
其实作个兼容也不难,每次提示一行文字,很丑。git

采样率与编码码率限制

每种采样率有对应的编码码率范围有效值,设置不合法的采样率或编码码率会致使录音失败。详细看这个
https://developers.weixin.qq.com/miniprogram/dev/api/media/recorder/RecorderManager.start.htmlgithub

一开始没有留意,致使录音不成功。
试过几回后,采用这样的配置,感受录音识别率和体积之间比较好平衡:json

1
2
3
sampleRate: 16000, //采样率
numberOfChannels: 1, //录音通道数
encodeBitRate: 96000, //编码码率

单通道基本是必选的。由于asr只支持单通道。frameSize也是能够的,可是要考虑截断对识别的影响。暂时没有用上。小程序

录音优化

由于可能误按,因而对小于500ms的录音直接忽略。
另外,松开录音按键后,再延迟一点时间才真正stop录音。api

录音文件格式

微信录音文件支持mp3和aac。这2种格式文件都比较小,aac文件体积更小。这对上传来讲是件好事情,速度更快。
可是对语音识别转文字就不友好了。由于百度、阿里云ASR、讯飞的语音转文字接口都不支持aac和mp3,一般要求是pcm或者wav格式。
若是微信录音能提供wav格式,那么就不用服务器作格式转换了,可是wav格式体积是mp三、aac的5到10倍,至少短时间是没戏了,这也是不少人吐槽的地方。数组

服务器转换录音文件格式

能够用java第三方库转换,也能够用Process调用ffmpeg转换。要注意的是,根据识别API的要求来作转换。好比阿里云asr的要求是:缓存

支持音频编码格式:pcm(无压缩的pcm文件或wav文件)、opus,16bit采样位数的单声道(mono);
支持音频采样率:8000Hz、16000Hz;服务器

java ProcessBuilder要使用数组传参

转换音视频,习惯用ffmpeg。安装完ffmpeg以后,用java新建进程调用。

1
Process = new ProcessBuilder("ffmpeg -i in.mp3 out.wav").start();

一直提示CreateProcess error。 后来看文档才发现,要以数组的形式传入参数。

1
Process = new ProcessBuilder("ffmpeg", "-y", "-i", "in.mp3", "out.wav").start();

这样就启动成功了。
关于java启动进程,不是本文重点,之后再写篇文章总结。

阿里云asr sdk使用问题

这个问题困扰了一天时间,回想起来真是吐血。
问题表现是微信录制的语音不少都识别不了。
最初是直接把录音mp3文件转换为pcm文件,本地能播放,可是用阿里云asr sdk却识别不了。 一开始觉得是文件编码问题。特地查了asr支持的文件格式,用ffprobe检查,potplayer看属性,都没有看出问题。
甚至把启动ffmpeg进程转换也改了,用了java的库去作,仍是不行。
后来为了方便测试问题,用asr的restful接口测试录音文件,都能识别! 彷佛是sdk的问题。因而打开官方文档例子对比。发现用的是sdk 2.x,老铁啊你复制粘贴过来的代码居然少了!欲哭无泪。

1
2
3
4
// TODO 重要提示:这里是用读取本地文件的形式模拟实时获取语音流并发送的,由于read很快,因此这里须要sleep
// TODO 若是是真正的实时获取语音,则无需sleep, 若是是8k采样率语音,第二个参数改成8000
int deltaSleep = getSleepDelta(len, sampleRate);
Thread.sleep(deltaSleep);

也少了对sampleRate的设置。

阿里云asr token过时

由于用的是免费版asr,没有给福报厂充值,所以token一天失效,致使联调的时候忽然报错。
最后实在受不了,写了个定时任务每小时更新token。
这,就是beggar VIP😎

wx.uploadFile返回值

封装了一个接口parseResponse,统一解析查询结果(文本、语音)。发现奇怪的问题:

  • 用文本查询的,能够正常解析结果
  • 用语音查询的,明明已经返回告终果,却解析不了!

只能console.log()打印出来对比

第一行是wx.request()发起文本查询。
第二行是wx.uploadFile()上传语音文件后直接语音转文字,而且查询。

wx.request返回值是json对象。
wx.uploadFile返回值是“字符串”!
wx.uploadFile返回值是“字符串”!
wx.uploadFile返回值是“字符串”!
重要的事情要说3遍。尽管Content-Type: "application/json; charset=utf8",可是微信根本不作转换!很是坑爹!

解决:对wx.uploadFile返回值进行JSON.parse(res.data),获得json对象。

更换appid和secret

由于正式小程序项目帐号一直拖着没有申请,因此这段时间用的是我我的的appid和secret进行开发。
等正式帐号准备好了,更新了小程序项目的appid,而且发出内部体验包。

此时已经深夜1点半,头脑有点发懵。只更新了小程序appid,居然忘了更新服务器的appid和secret。。。
因而乎反复报错登陆失败。
过了一会才反映过来,更新服务器的appi的secret,可是仍是用户。才想起忘了还有storage缓存没有清除😂,里面放着自定义的session。这下真机体验没问题了。
可是微信开发者工具又是登陆失败。反复摸索后发现:更换小程序appid后,清除全部数据,关闭开发者工具,从新打开,这就正常了。应该是微信开发者工具的bug。

结论:深夜不宜加班写bug😭。

 

https://ycwu314.github.io/p/miniapp-speech-to-text-experience/