使用微信小程序实现语音识别功能的过程中,爬了很多坑,主要的原因竟然是微信小程序发展太快,网上的资料跟不上,旧的一些资料让自己走了错误的路线,希望后面的小伙伴不要在走弯路,所以分享给大家。

语音识别整体思路

使用微信小程序录音功能,获取录音文件

发送录音文件到后台服务器

后台服务器对录音文件进行转码,推荐转码成pcm格式

调用百度语音识别 API 进行语音识别

后台服务器获取 API 返回的识别结果

返回识别结果给微信小程序

看一个图加深记忆

8fd9b167b83b

image

语音转换

为什么会有语音转换这一步呢?简单说就是微信小程序录音文件的格式,各大语音转换 API 都不支持,不转也用不了啊。

微信小程序从基础库 1.6.0 开始,录音推荐使用 wx.getRecorderManager() 方法,录音文件的格式可以自己指定,有 aac 和 mp3 两种格式。

由于之前没有了解过音频转换这块,所以直接上网搜索微信小程序语音转换的相关资料,此时坑已经挖好,并且跳进去了。

网上大部分资料都是说,微信小程序的录音文件是变种的 silk 文件(可能以前的小程序确实是这样),需要特殊处理,然后使用 silk-v3-decoder 或者 ffmepg 进行转码,经过各种折腾后发现还是不行,在坑里徘徊不前好久。

最后真是一个无意识的操作发现了转机,录音文件我一直用的 mp3 格式,双击后居然可以正常打开,并且播放声音,这是什么鬼?你不是变种得么,好吧,你居然是个正常"人"。

一切都了然了,微信小程序可能对这块做了优化,减少了复杂的处理,就这样一切都通顺了之后,剩下的就简单了。

微信小程序代码

录音开始

/** 录音开始 */

function speechStart(e,that) {

const recorderManager = wx.getRecorderManager();

const options = {

duration: 10000,

sampleRate: 16000,

numberOfChannels: 1,

encodeBitRate: 64000,

format: 'mp3',

frameSize: 50

}

recorderManager.start(options);

}

录音结束后,调用后台服务

/** 语音识别 */

function speechRecognition (that,res) {

console.log("语音识别");

wx.uploadFile({

url: API_URL,

filePath: res.tempFilePath,

name: 'file',

formData: {

'user': 'test'

},

success: function (res) {

console.log(res); console.log(res.data);

},

fail:function(){

console.log("语音识别失败");

}

})

}

后台服务器 Java 实现

添加 mp3plugin.jar

添加百度 API 依赖

com.baidu.aip

java-sdk

4.1.0

测试代码

// 设置APPID/AK/SK,注册百度语音识别API即可获取

public static final String APP_ID = "******";

public static final String API_KEY = "******";

public static final String SECRET_KEY = "******";

/**

* @Description TODO

* @return

* @author liuyang

* @blog http://www.pqsky.me

* @date 2018年1月27日

*/

@RequestMapping(value = "/speechRecognition")

public Object speechReco(HttpServletRequest request) {

MultipartFile file = ((MultipartHttpServletRequest) request).getFile("file");

try {

byte[] pcmBytes = mp3Convertpcm(file.getInputStream());

JSONObject resultJson = speechBdApi(pcmBytes);

System.out.println(resultJson.toString());

if (null != resultJson && resultJson.getInt("err_no") == 0) {

return resultJson.getJSONArray("result").get(0).toString().split(",")[0];

}

} catch (Exception e) {

e.printStackTrace();

}

return "";

}

/**

* @Description MP3转换pcm

* @param mp3Stream

* 原始文件流

* @return 转换后的二进制

* @throws Exception

* @author liuyang

* @blog http://www.pqsky.me

* @date 2018年1月30日

*/

public byte[] mp3Convertpcm(InputStream mp3Stream) throws Exception {

// 原MP3文件转AudioInputStream

AudioInputStream mp3audioStream = AudioSystem.getAudioInputStream(mp3Stream);

// 将AudioInputStream MP3文件 转换为PCM AudioInputStream

AudioInputStream pcmaudioStream = AudioSystem.getAudioInputStream(AudioFormat.Encoding.PCM_SIGNED,

mp3audioStream);

byte[] pcmBytes = IOUtils.toByteArray(pcmaudioStream);

pcmaudioStream.close();

mp3audioStream.close();

return pcmBytes;

}

/**

* @Description 调用百度语音识别API

* @param pcmBytes

* @return

* @author liuyang

* @blog http://www.pqsky.me

* @date 2018年1月30日

*/

public static JSONObject speechBdApi(byte[] pcmBytes) {

// 初始化一个AipSpeech

AipSpeech client = new AipSpeech(APP_ID, API_KEY, SECRET_KEY);

// 可选:设置网络连接参数

client.setConnectionTimeoutInMillis(2000);

client.setSocketTimeoutInMillis(60000);

// 调用接口

JSONObject res = client.asr(pcmBytes, "pcm", 16000, null);

return res;

}

总结

以上代码都是作为测试用例,帮助理清整体思路和实现简单的调用,更详细的设计就需要结合具体的业务了,希望可以帮到看到的人。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐