先看實現效果:

利用百度UNIT預置的智能問答技能和微信小程序,實現語音問答機器人。這里主要介紹小程序功能開發實現過程,分享主要功能實現的子程序模塊,都是干貨!
想了解UNIT預置技能調用,請參看我之前的帖子:《UNIT搭建機器人助理》
https://ai.baidu.com/forum/topic/show/953021
想了解微信小程序的開發過程,請參看我之前的帖子:《UNIT接入小程序》https://ai.baidu.com/forum/topic/show/953022
1 系統框架
用到的技術主要有:百度語音識別、語音合成、UNIT語義解析和微信小程序。小程序通過語音識別,將用戶的問題提交給百度UNIT,進行語義解析。返回的回答結果通過語音合成,轉化為語音,實現與用戶的語音交互。全部功能都在小程序客戶端完成,不需要服務器,適合個人開發者使用。
2 小程序項目
2.1 程序創建
在根目錄的全局配置文件app.json中增加:"pages/contact/contact" ,會自動創建相關頁面文件,結構如下:
contact.js:功能邏輯模塊
contact.wxss:頁面樣式文件
contact.wxml:頁面布局文件
contact.json:頁面配置文件

2.2 小程序錄音功能實現
采用微信提供的錄音管理器 recorderManager實現錄音,錄音格式aac。需要注意的是,電腦上的微信開發工具和手機上錄音結果文件是不一致的, format設置為 'aac',電腦端的錄音是aac格式,手機端錄音是m4a格式。由於百度語音識別極速版目前支持微信小程序錄音m4a格式,所以上傳語音文件時不用轉格式,方便許多!
// 獲取全局唯一的錄音管理器 recorderManager
const recorderManager = wx.getRecorderManager();
// 錄音時需要的參數, format設置為aac
const voiceOptions = {
duration: 60000,
sampleRate: 16000,
numberOfChannels: 1,
encodeBitRate: 48000,
format: 'aac',
frameSize: 50
}
// 按鈕按下
touchdown: function () {
// 開始錄音
recorderManager.start(voiceOptions);
this.setData({
isSpeaking: true,
})
that.speaking.call();
console.log("[Console log]:Touch down!Start recording!");
},
// 停止錄音,會觸發onStop事件
touchup: function () {
recorderManager.stop(voiceOptions)
console.log("[Console log]:Touch up!Stop recording!");
this.setData({
isSpeaking: false,
speakerUrl: '/res/image/speaker.png',
})
clearInterval(that.speakerInterval);//定時器停止
},
// 添加錄音停止觸發事件,這段代碼可以放到onLoad()里,頁面加載的時候就添加上
recorderManager.onStop((res) => {
const { tempFilePath, fileSize } = res
//錄音完成調用語音識別API
this.sendAsrRequest(res.tempFilePath, res.fileSize);
});
2.3 小程序語音播放功能實現
需要注意的是:小程序自身錄音,用wx.playVoice()函數播放不了,要用到innerAudioContext。
//微信語音播放,
play: function (e) {
const innerAudioContext = wx.createInnerAudioContext()
innerAudioContext.autoplay = true
innerAudioContext.src = filePath
innerAudioContext.onPlay(() => {
console.log('開始播放')
})
innerAudioContext.onError((res) => {
console.log(res.errMsg)
console.log(res.errCode)
})
},
3 調用語音識別極速版API
3.1 首先要在控制台創建應用,調用語音識別極速版API,“獲取API Key/Secret Key”。
接口文檔地址:https://ai.baidu.com/docs#/ASR-API-PRO/top
請求URL: https://vop.baidu.com/pro_api
3.2 語音識別功能實現
//發送語音識別請求,傳入語音文件路徑及長度,len為錄音結束返回的字節長度:res.fileSize。
ASRRequest: function (tempFilePath,len,arg) { // corpus是要發送的對話;arg是回調方法
var that = this;
// appkey
var appkey = that.globalData.NLPAppkey;
// appsecret
var appSecret = that.globalData.NLPAppSecret;
var api = "nli";
var timestamp = new Date().getTime();
var voice0 = fs.readFileSync(tempFilePath, "base64");
console.log("[Console log]voice:" + voice0);
console.log("[Console log]len:" + len);
var rqJson = {
'dev_pid': 80001,
'format': 'm4a',
'rate': 16000,
'token': '填入獲得的token ',
'cuid': '填入cuid ',
'channel': 1,
'len': len,
'speech': voice0
};
var rq = JSON.stringify(rqJson);
console.log(rq);
var ASRUrl = that.globalData.ASRUrl;
// cusid是用來實現上下文的,可以自己隨意定義內容,要夠長夠隨機
var cusid = that.globalData.NLPCusid;
console.log("[Console log]:ASRRequest(),URL:" + ASRUrl);
wx.request({
url: ASRUrl,
data: rq,
header: { 'content-type': 'application/json' },
method: 'POST',
success: function (res) {
var resData = res.data;
console.log("[Console log]:ASTRequest() success...");
console.log("[Console log]:Result:" + resData);
var nli = JSON.stringify(resData);
// 回調函數,解析數據
typeof arg.success == "function" && arg.success(nli);
},
fail: function (res) {
console.log("[Console log]:ASRRequest() failed...");
console.error("[Console log]:Error Message:" + res.errMsg);
typeof arg.fail == "function" && arg.fail();
},
complete: function () {
console.log("[Console log]:ASRRequest() complete...");
typeof arg.complete == "function" && arg.complete();
}
})
},
4 調用UNIT接口,獲得回答
4.1 首先要在控制台創建應用,調用UNIT接口,“獲取API Key/Secret Key”。
接口文檔地址:https://ai.baidu.com/docs#/UNIT-v2-API/top
請求URL: https://aip.baidubce.com/rpc/2.0/unit/bot/chat
4.2 程序實現
NLIRequest: function (corpus, arg) { // corpus是要發送的對話;arg是回調方法
var that = this;
// appkey
var appkey = that.globalData.NLPAppkey;
// appsecret
var appSecret = that.globalData.NLPAppSecret;
var api = "nli";
var timestamp = new Date().getTime();
var rqJson = {
"bot_session": "",
"log_id": "7758521",
"request": {
"bernard_level": 0,
"client_session": "{\"client_results\":\"\", \"candidate_options\":[]}",
"query": corpus,
"query_info": {
"asr_candidates": [],
"source": "KEYBOARD",
"type": "TEXT"
},
"updates": "",
"user_id": "88888"
},
"bot_id": "64053",
"version": "2.0"
};
var rq = JSON.stringify(rqJson);
var nliUrl = that.globalData.NLPUrl;
// cusid是用來實現上下文的,可以自己隨意定義內容,要夠長夠隨機
var cusid = that.globalData.NLPCusid;
console.log("[Console log]:NLIRequest(),URL:" + nliUrl);
wx.request({
url: nliUrl,
data: rq,
header: { 'content-type': 'application/x-www-form-urlencoded' },
method: 'POST',
success: function (res) {
console.log("[Console log]:res:"+ res);
var resData = res.data;
console.log("[Console log]:NLIRequest() success...");
console.log("[Console log]:Result:");
console.log("[Console log]:resData:"+resData);
var nli = JSON.stringify(resData);
console.log("[Console log]:nli:" + nli);
// 回調函數,解析數據
typeof arg.success == "function" && arg.success(nli);
},
fail: function (res) {
console.log("[Console log]:NLIRequest() failed...");
console.error("[Console log]:Error Message:" + res.errMsg);
typeof arg.fail == "function" && arg.fail();
},
complete: function () {
console.log("[Console log]:NLIRequest() complete...");
typeof arg.complete == "function" && arg.complete();
}
})
},
5 調用語音合成API
5.1 首先要在控制台創建應用,調用語音合成API,“獲取API Key/Secret Key”。
接口文檔地址:https://ai.baidu.com/docs#/TTS-API/top
請求URL: https://tsn.baidu.com/text2audio
5.2 程序實現
// 語音合成
tts: function (e) {
console.log("[Console log]tts:" + e);
var tex = encodeURI(e);//轉換編碼url_encode UTF8編碼
var tok = "填入獲得的token";
var cuid = app.globalData.NLPCusid;
var ctp = 1;
var lan = "zh"; // zh表示中文
// 字符編碼
var spd = 5; // 表示朗讀的語速,9代表最快,1是最慢(撩妹請用2,繞口令請用9)
var url = "https://tsn.baidu.com/text2audio?tex=" + tex + "&lan=" + lan + "&cuid=" + cuid + "&ctp=" + ctp + "&tok=" + tok + "&spd=" + spd
wx.downloadFile({
url: url,
success: function (res) {
console.log(res)
filePath = res.tempFilePath;
// 只要服務器有響應數據,就會把響應內容寫入文件並進入 success 回調
if (res.statusCode === 200) {
//小程序自身錄音,用playVoice播放不了,要用innerAudioContext
/* wx.playVoice({
filePath: res.tempFilePath
})*/
var filepath = res.tempFilePath;
console.log(filepath);
const innerAudioContext = wx.createInnerAudioContext();
innerAudioContext.src = filepath;
innerAudioContext.onPlay(() => {
console.log('開始播放')
});
innerAudioContext.onError((res) => {
console.log(res.errMsg)
console.log(res.errCode)
});
innerAudioContext.play();
}
}
})
},
作者:wangwei8638
