實現功能
實現一個智能生活信息查詢的小秘書功能,支持查天氣、新聞、日歷、匯率、笑話、故事、百科、詩詞、郵編、區(qū)號、菜譜、股票、節(jié)目預告,還支持閑聊、算24點、數學計算、單位換算、購物、搜索等功能。
使用方式:
新版上線支持語音識別,按下說話,松開發(fā)送。
老版本上支持搖一搖、點界面按鈕、手動輸入、下拉刷新這四種方式。
掃碼試用(左右皆可)
界面展示
開發(fā)資源
-
免費開放語義接口平臺 olami.ai
-
微信小程序平臺
-
js, css
-
我自己搭建的https的語音識別API
接口
源碼分析
這里主要介紹新版本首頁相關的代碼,其它部分代碼在 微信小程序——智能小秘“遙知之”源碼分享(語義理解基于olami)(注:這個是原來不支持語音識別的版本) 的基礎上,變化不怎么大,具體可參考那篇文章。
asr.js源碼:
-
/**
-
* 作者:happycxz
-
* 時間:2017.09.19
-
* 源碼分享鏈接:http://blog.csdn.net/happycxz/article/details/78024986
-
*
-
* https的silk語音識別API(專供微信小程序調用):https://api.happycxz.com/test/silk2asr/olami/asr
-
* 該API服務搭建全過程解析及源碼分享貼:http://blog.csdn.net/happycxz/article/details/78016299
-
* 需要使用此API請聯(lián)系作者QQ:404499164
-
*
-
* 遵循開放、分享、自由、免費的精神,把開源堅持到底
-
*/
-
-
//獲取應用實例
-
var app = getApp()
-
-
var UTIL = require('../../utils/util.js');
-
var GUID = require('../../utils/GUID.js');
-
var NLI = require('../../utils/NLI.js');
-
-
const appkey = require('../../config').appkey
-
const appsecret = require('../../config').appsecret
-
-
//彈幕定時器
-
var timer;
-
-
var pageSelf = undefined;
-
-
var doommList = [];
-
class Doomm {
-
constructor() {
-
this.text = UTIL.getRandomItem(app.globalData.corpus);
-
this.top = Math.ceil(Math.random() * 40);
-
this.time = Math.ceil(Math.random() * 8 + 6);
-
this.color = getRandomColor();
-
this.display = true;
-
let that = this;
-
setTimeout(function () {
-
doommList.splice(doommList.indexOf(that), 1);
-
doommList.push(new Doomm());
-
-
pageSelf.setData({
-
doommData: doommList
-
})
-
}, this.time * 1000)
-
}
-
}
-
function getRandomColor() {
-
let rgb = []
-
for (let i = 0; i < 3; ++i) {
-
let color = Math.floor(Math.random() * 256).toString(16)
-
color = color.length == 1 ? '0' + color : color
-
rgb.push(color)
-
}
-
return '#' + rgb.join('')
-
}
-
-
Page({
-
data: {
-
j: 1,//幀動畫初始圖片
-
isSpeaking: false,//是否正在說話
-
outputTxt : "", //輸出識別結果
-
-
doommData: []
-
},
-
-
initDoomm: function () {
-
doommList.push(new Doomm());
-
doommList.push(new Doomm());
-
doommList.push(new Doomm());
-
this.setData({
-
doommData: doommList
-
})
-
},
-
-
onLoad: function () {
-
pageSelf = this;
-
this.initDoomm();
-
},
-
-
//手指按下
-
touchdown: function () {
-
UTIL.log("手指按下了... new date : " + new Date)
-
var _this = this;
-
speaking.call(this);
-
this.setData({
-
isSpeaking: true
-
})
-
//開始錄音
-
wx.startRecord({
-
success: function (res) {
-
//臨時路徑,下次進入小程序時無法正常使用
-
var tempFilePath = res.tempFilePath;
-
UTIL.log('record SUCCESS file path:' + tempFilePath)
-
_this.setData({
-
recordPath: tempFilePath
-
});
-
},
-
fail: function (res) {
-
//錄音失敗
-
wx.showModal({
-
title: '提示',
-
content: '錄音的姿勢不對!',
-
showCancel: false,
-
success: function (res) {
-
if (res.confirm) {
-
UTIL.log('用戶點擊確定')
-
return
-
}
-
}
-
})
-
}
-
})
-
},
-
//手指抬起
-
touchup: function () {
-
UTIL.log("手指抬起了...")
-
this.setData({
-
isSpeaking: false,
-
})
-
clearInterval(this.timer)
-
wx.stopRecord()
-
-
var _this = this
-
setTimeout(function () {
-
var urls = "https://api.happycxz.com/test/silk2asr/olami/asr";
-
UTIL.log(_this.data.recordPath);
-
wx.uploadFile({
-
url: urls,
-
filePath: _this.data.recordPath,
-
name: 'file',
-
formData: { "appKey": appkey, "appSecret": appsecret, "userId": UTIL.getUserUnique() },
-
header: { 'content-type': 'multipart/form-data' },
-
success: function (res) {
-
UTIL.log('res.data:' + res.data);
-
-
var nliResult = getNliFromResult(res.data);
-
UTIL.log('nliResult:' + nliResult);
-
var stt = getSttFromResult(res.data);
-
UTIL.log('stt:' + stt);
-
-
var sentenceResult;
-
try {
-
sentenceResult = NLI.getSentenceFromNliResult(nliResult);
-
} catch (e) {
-
UTIL.log('touchup() 錯誤' + e.message + '發(fā)生在' + e.lineNumber + '行');
-
sentenceResult = '沒明白你說的,換個話題?'
-
}
-
-
var lastOutput = "==>語音識別結果:\n" + stt + "\n\n==>語義處理結果:\n" + sentenceResult;
-
_this.setData({
-
outputTxt: lastOutput,
-
});
-
wx.hideToast();
-
},
-
fail: function (res) {
-
UTIL.log(res);
-
wx.showModal({
-
title: '提示',
-
content: "網絡請求失敗,請確保網絡是否正常",
-
showCancel: false,
-
success: function (res) {
-
}
-
});
-
wx.hideToast();
-
}
-
});
-
}, 1000)
-
},
-
-
//切換到老版本
-
turnToOld: function() {
-
wx.navigateTo({
-
url: '../index/index',
-
})
-
},
-
-
})
-
-
function getNliFromResult(res_data) {
-
var res_data_json = JSON.parse(res_data);
-
var res_data_result_json = JSON.parse(res_data_json.result);
-
return res_data_result_json.nli;
-
}
-
-
function getSttFromResult(res_data) {
-
var res_data_json = JSON.parse(res_data);
-
var res_data_result_json = JSON.parse(res_data_json.result);
-
return res_data_result_json.asr.result;
-
}
-
-
//麥克風幀動畫
-
function speaking() {
-
var _this = this;
-
//話筒幀動畫
-
var i = 1;
-
this.timer = setInterval(function () {
-
i++;
-
i = i % 5;
-
_this.setData({
-
j: i
-
})
-
}, 200);
-
}
復制代碼
這部分主要實現錄音按鈕被按下和松開觸發(fā)話筒錄音及結束錄音,當按鈕被按下后,觸發(fā)調用話筒動畫特效(其實是四五個圖片輪流顯示的效果),同時調用wx.startRecord開始錄音。
當按鈕松開時停止錄音,然后將錄音臨時文件往 https://api.happycxz.com/test/silk2asr/olami/asr
上發(fā)送,同時發(fā)olami上注冊申請的appKey和appSecret,以及用戶唯一識別號。
從語音識別接口返回的結果是原封不動的olami官方輸出結果,我們只需要取一下語音識別結果以及語義理解結果即可。 語義理解結果在原來 微信小程序——智能小秘“遙知之”源碼分享(語義理解基于olami)(注:這個是原來不支持語音識別的版本) 中已經有方法解析,為了代碼復用性強些,把解析nli結果的方法簡單改了下,即適用新版語音識別的,也適用以前老版本的手動輸入的。
代碼邏輯很簡單,看看就明白了,這里不再多述。
asr.json源碼:
-
{
-
"window": {
-
"enablePullDownRefresh": false
-
}
-
}
復制代碼
因為老版項目中我開啟了下拉刷新,新界面上不需要了,所以在asr頁面的.json這里特意關閉了此功能。
asr.wxml源碼:
-
<view class="container">
-
<view class="page-section">
-
<view class="text-box" scroll-y="true">
-
<text style="max-width:200px;overflow-y:auto;height:200px;" selectable="true">{{outputTxt}}</text>
-
</view>
-
</view>
-
-
<view class="page-section">
-
<text selectable="true" class="text-head">語義理解基于olami.ai,作者QQ:404499164</text>
-
</view>
-
-
<view class="little-gap-top button-selection2 button-show bottom-button">
-
<button size="mini" type="default" open-type="contact">聯(lián)系作者</button>
-
<button size="mini" type="default" bindtap="turnToOld">切老版本</button>
-
<button size="mini" type="default" open-type="share">幫忙分享</button>
-
</view>
-
-
<view class="page-section">
-
<view class="doommview">
-
<block wx:for="{{doommData}}" wx:key="id">
-
<text wx:if="{{item.display}}" class="aon" style="animation: first {{item.time}}s linear infinite;top:{{item.top}}%;color:{{item.color}};">
-
{{item.text}}
-
</text>
-
</block>
-
</view>
-
</view>
-
-
<view wx:if="{{isSpeaking}}" class="speak-style">
-
<image class="sound-style" src="../../pics/voice_icon_speech_sound_1.png" ></image>
-
<image wx:if="{{j==2}}" class="sound-style" src="../../pics/voice_icon_speech_sound_2.png" ></image>
-
<image wx:if="{{j==3}}" class="sound-style" src="../../pics/voice_icon_speech_sound_3.png" ></image>
-
<image wx:if="{{j==4}}" class="sound-style" src="../../pics/voice_icon_speech_sound_4.png" ></image>
-
<image wx:if="{{j==5}}"class="sound-style" src="../../pics/voice_icon_speech_sound_5.png" ></image>
-
</view>
-
-
</view>
-
-
-
<view class="record-style">
-
<button type="primary" class="btn-style" bindtouchstart="touchdown" bindtouchend="touchup">按下錄音,松開結束</button>
-
</view>
復制代碼
布局調了半天,還是沒有達到我想要的效果,前端布局我沒系統(tǒng)學習過,基本就是湊湊拼拼,望有基本審美觀的各位看官理解……
asr.wxss源碼:
彈幕部分原先是硬代碼實現的,后來在小程序聯(lián)盟里請教后才得知,css里有可以實現動畫特效的功能,就順便修改了一下。還是有點顯示方面BUG的,不折騰了。
其它代碼還是參照我原來的那個文章里介紹的吧:微信小程序——智能小秘“遙知之”源碼分享(語義理解基于olami)(注:這個是原來不支持語音識別的版本) ,基本變動比較少。
“遙知之”微信小程序完整源碼下載:
碼云:http://git.oschina.net/happycxz/ ... chat_littleapp_demo
github: https://github.com/happycxz/nlp_ ... chat_littleapp_demo
寫在最后
這次小程序的版本更新,還是上一次的延續(xù),上次老版本未能支持上語音識別,用起來很不方便,網上也找不到相應的免費的接口,于是索性湊了點時間專門自己搭個HTTPS服務出來,方便同樣想在微信小程序上DEBUG語音識別功能的伙伴們和興趣開發(fā)者們調試和做些小玩意,好在,總算是一路走過來了,特別感謝kn007大神提供的silk decoder源碼以及ffmpeg轉碼腳本,關于此議題(解碼轉換QQ微信的SILK v3編碼音頻為MP3或其他格式)在他本人的博客中火熱地討論了一年多了,感興趣的也可以去膜拜一下這位大神。