>>>>>>>>>>>>>>>>>>>>>>>> 歡迎轉載 <<<<<<<<<<<<<<<<<<<<<<<<css
本文原地址:http://www.cnblogs.com/happycxz/p/7562702.htmlhtml
「遙知之」微信小程序完整源碼下載:前端
碼雲:http://git.oschina.net/happycxz/nlp_olami_yaozhizhi_wechat_littleapp_demogit
github: https://github.com/happycxz/nlp_olami_yaozhizhi_wechat_littleapp_demogithub
與本小程序密切相關的幾個文章:json
====本文中提到的silk轉wav服務端https的API搭建過程詳解見====
微信小程序語音識別服務搭建全過程解析(內附免費的供小程序語音識別的https服務)小程序
微信小程序——智能小祕「遙知之」源碼分享(語義理解基於olami)(注:這個是原來不支持語音識別的版本)微信小程序
此次的改動是基於原來的「遙知之」版本v0.2基礎之上的。加上了語音識別,界面變化較大 。下面主要介紹一下新版本首頁面的功能和代碼實現。api
實現一個智能生活信息查詢的小祕書功能,支持查天氣、新聞、日曆、匯率、笑話、故事、百科、詩詞、郵編、區號、菜譜、股票、節目預告,還支持閒聊、算24點、數學計算、單位換算、購物、搜索等功能。微信
使用方式:
新版上線支持語音識別,按下說話,鬆開發送。
老版本上支持搖一搖、點界面按鈕、手動輸入、下拉刷新這四種方式。
這裏主要介紹新版本首頁相關的代碼,其它部分代碼在 微信小程序——智能小祕「遙知之」源碼分享(語義理解基於olami)(注:這個是原來不支持語音識別的版本) 的基礎上,變化不怎麼大,具體可參考那篇文章。
/** * 做者: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請聯繫做者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 + '發生在' + 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); }
這部分主要實現錄音按鈕被按下和鬆開觸發話筒錄音及結束錄音,當按鈕被按下後,觸發調用話筒動畫特效(實際上是四五個圖片輪流顯示的效果),同時調用wx.startRecord開始錄音。
當按鈕鬆開時中止錄音,而後將錄音臨時文件往 https://api.happycxz.com/test/silk2asr/olami/asr 上發送,同時發olami上註冊申請的appKey和appSecret,以及用戶惟一識別號。
從語音識別接口返回的結果是原封不動的olami官方輸出結果,咱們只須要取一下語音識別結果以及語義理解結果便可。 語義理解結果在原來 微信小程序——智能小祕「遙知之」源碼分享(語義理解基於olami)(注:這個是原來不支持語音識別的版本) 中已經有方法解析,爲了代碼複用性強些,把解析nli結果的方法簡單改了下,即適用新版語音識別的,也適用之前老版本的手動輸入的。
代碼邏輯很簡單,看看就明白了,這裏再也不多述。:)
{ "window": { "enablePullDownRefresh": false } }
由於老版項目中我開啓了下拉刷新,新界面上不須要了,因此在asr頁面的.json這裏特地關閉了此功能。
<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">聯繫做者</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>
佈局調了半天,仍是沒有達到我想要的效果,前端佈局我沒系統學習過,基本就是湊湊拼拼,望有基本審美觀的各位看官理解……
/* pages/asr/asr.wxss */ page{ background-color:beige; background-image: url(http://img.blog.csdn.net/20170720105808995?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGFwcHljeHo=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast); background-size: cover; } .page-section{ display: flex; flex-direction: column; margin-bottom: 10rpx; } .text-head{ color: #ff0000; font-size: 28rpx; align-items: center; margin-top: 5rpx; } .button-selection { display: flex; flex-direction: column; justify-content: center; align-items: center; } .button-selection2 { justify-content: space-between; align-content: space-between; flex-shrink:1; } .little-gap-top { margin-top: 10rpx; } .big-gap-top { margin-top: 100rpx; } .button-show { display: flex; align-self: center; justify-content: center; } .bottom-button { justify-content: space-around; flex-shrink:0; } .text-box{ margin-bottom: 0rpx; margin-left: 50rpx; margin-right: 50rpx; padding: 40rpx 0; display: flex; min-height: 650rpx; max-width: 600rpx; width:600rpx; background-color: #ffffff; justify-content: center; align-items: center; text-align: left; font-size: 30rpx; color: #353535; line-height: 2em; word-wrap: break-word; border: 1px solid cornflowerblue; } /* 錄音 */ .speak-style{ position: relative; height: 240rpx; width: 240rpx; border-radius: 20rpx; margin: 0 auto; background: #26A5FF; } .record-style{ position: fixed; bottom: 0; left: 0; height: 120rpx; width: 100%; } .btn-style{ margin-left: 30rpx; margin-right: 30rpx; } .sound-style{ position: absolute; width: 74rpx; height:150rpx; margin-top: 45rpx; margin-left: 83rpx; } /* 彈幕 */ .button{ position: absolute; bottom: 0; width: 100%; } .aon{ position: absolute; white-space:nowrap; animation-timing-function: linear; animation-fill-mode: none; } .doommview{ z-index: 3; height: 80%; width: 100%; /* position: absolute; */ } @keyframes first{ from{left: 100%; } to{left: -100%;} }
彈幕部分原先是硬代碼實現的,後來在小程序聯盟裏請教後才得知,css裏有能夠實現動畫特效的功能,就順便修改了一下。仍是有點顯示方面BUG的,不折騰了。
其它代碼仍是參照我原來的那個文章裏介紹的吧:微信小程序——智能小祕「遙知之」源碼分享(語義理解基於olami)(注:這個是原來不支持語音識別的版本) ,基本變更比較少。
想要全局直觀的看完整代碼,歡迎訪問該項目對應碼雲連接:http://git.oschina.net/happycxz/nlp_olami_yaozhizhi_wechat_littleapp_demo
>>>>>>>>>>>>>>>>>>>>>>>> 歡迎轉載 <<<<<<<<<<<<<<<<<<<<<<<<
本文原地址:http://www.cnblogs.com/happycxz/p/7562702.html
「遙知之」微信小程序完整源碼下載:
碼雲:http://git.oschina.net/happycxz/nlp_olami_yaozhizhi_wechat_littleapp_demo
github: https://github.com/happycxz/nlp_olami_yaozhizhi_wechat_littleapp_demo
此次小程序的版本更新,仍是上一次的延續,上次老版本未能支持上語音識別,用起來很不方便,網上也找不到相應的免費的接口,因而索性湊了點時間專門本身搭個HTTPS服務出來,方便一樣想在微信小程序上DEBUG語音識別功能的夥伴們和興趣開發者們調試和作些小玩意,好在,總算是一路走過來了,特別感謝kn007大神提供的silk decoder源碼以及ffmpeg轉碼腳本,關於此議題(解碼轉換QQ微信的SILK v3編碼音頻爲MP3或其餘格式)在他本人的博客中火熱地討論了一年多了,感興趣的也能夠去膜拜一下這位大神。