轉載請註明原文地址:傳送javascript
olami 開放平臺 sdk 除了支持語音識別功能外,更強大的在於支持語義理解功能,在 Android 平臺和 iOS 平臺都有示例 demo 供你們下載。html
語音在線聽書demo:傳送java
語音記帳demo:傳送jquery
在 web 端,基於 JavaScript 用 olami 開放平臺 sdk 也能夠實現語音識別語義理解。本文就實現了這樣一個小程序,web 客戶端本地用麥克風錄音,錄音的數據用 speex 壓縮,而後跨域向服務器發送請求,返回識別的語音和語義字符串並顯示。android
先上圖:git
以下圖剛載入的時候,未錄音前界面github
點擊開始錄音button後web
一句話說完自動檢測尾音結束標誌而後壓縮上傳給服務器進行識別chrome
將從服務器獲取的識別結果顯示到界面上json
本例中說的語音是:「我要聽三國演義這本書」,用的是 android 平臺聽書 app 創建的語法。
返回的json字串以下:
{ 「data」: { 「asr」: { 「result」: 「我要聽三國演義這本書」, 「speech_status」: 0, 「final」: true, 「status」: 0 }, 「nli」: [ { 「desc_obj」: { 「result」: 「正在努力搜索中,請稍等」, 「status」: 0 }, 「semantic」: [ { 「app」: 「musiccontrol」, 「input」: 「我要聽三國演義這本書」, 「slots」: [ { 「name」: 「songname」, 「value」: 「三國演義」 } ], 「modifier」: [ 「play」 ], 「customer」: 「58df512384ae11f0bb7b487e」 } ], 「type」: 「musiccontrol」 } ] }, 「status」: 「ok」 }
經過解析這段 json,能夠獲得 app 類型,songname (用於查詢書名),modifier 是 play 表示行爲是播放。
這段 json 的語法固然是用戶自定義的,得到了 json 字串就能夠解析獲得程序須要的字段用於對應的操做,從而實現了語義理解功能。olami 開放平臺語法編寫介紹
下面來看看實現的 code,用 eclipse 創建 J2EE 工程 WebVoiceRecognize
初次搭建能夠參考以下網站: 傳送
下面是創建的工程目錄結構,發佈後,網頁打開運行在chrome或者QQ瀏覽器都可。
下面講述下 voiceRecognize.html 這個文件,其餘都是 min.js,只需知道如何調用就能夠了。
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>voice recognize test</title> <script type="text/javascript" src="jquery-1.10.1.min.js"></script> <script type="text/javascript" src="jQuery.md5.js"></script> <script src="speex.min.js"></script> <script src="pcmdata.min.js"></script> </head> <body onload= "load()"> <fieldset style="width:50%;margin:10px auto"> <p align="center" >點擊開始button錄音,點擊中止button中止錄音並進行識別</p> <p align="center"> <input type="button" id="recordbutton" value="開始錄音" onclick="StartRecording()"/> <input type="button" id="speexEncodebutton" value="中止錄音" onclick="speexEncode()"/> </p> <p id ="result" style="margin-bottom:100px;margin-top:50px">result:</p> </p> <script src="recorder.min.js"></script> <script src="uploaddata.min.js"></script> <script> window.AudioContext = window.AudioContext || window.webkitAudioContext; var audioContext = new AudioContext(); var audioInput = null, realAudioInput = null, inputPoint = null, audioRecorder = null; var rafID = null; var analyserContext = null; var recIndex = 0; var recording = false; var bRecorded = false; function load(){ initAudio();//初始化recorder setAuthorization("http://cn.olami.ai/cloudservice/api","51a4bb56ba954655a4fc834bfdc46af1","asr","68bff251789b426896e70e888f919a6d","nli"); setCallBackFromServerResult(getResultFromServer); } function initAudio() { if (!navigator.getUserMedia) navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia; if (!navigator.cancelAnimationFrame) navigator.cancelAnimationFrame = navigator.webkitCancelAnimationFrame || navigator.mozCancelAnimationFrame; if (!navigator.requestAnimationFrame) navigator.requestAnimationFrame = navigator.webkitRequestAnimationFrame || navigator.mozRequestAnimationFrame; navigator.getUserMedia({audio:true}, gotStream, function(e) { alert('Error getting audio'); console.log(e); }); } function gotStream(stream) { inputPoint = audioContext.createGain(); // Create an AudioNode from the stream. realAudioInput = audioContext.createMediaStreamSource(stream); audioInput = realAudioInput; audioInput.connect(inputPoint); audioRecorder = new Recorder( inputPoint ); } function StartRecording() { // start recording if (audioRecorder == null) { initAudio(); alert("need initialize media"); } audioRecorder.clear(); audioRecorder.record(); recording = true; bRecorded = false; ToggleLabels(); RegisterCallBackToRecorder(); } function StopRecording() { audioRecorder.stop(); audioRecorder.getBuffers( gotBuffers ); } function RegisterCallBackToRecorder() {//檢測語音結束後回調 audioRecorder.setCallBack(speexEncode); } function ToggleLabels() { if(recording) { document .getElementById("recordbutton").value = "錄音中ֹ"; document .getElementById("speexEncodebutton").value = "中止錄音"; var btn = document .getElementById("recordbutton").value; }else{ document .getElementById("speexEncodebutton").value = "識別中"; document .getElementById("recordbutton").value = "中止錄音ֹ"; } } window.record = function(e) { if(!recording) { StartRecording(); recording = true; bRecorded = false; } else { StopRecording(); recording = false; bRecorded = true; } ToggleLabels(); }; window.speexEncode = function() { exportSpeex(); }; function exportSpeex() { recording = false; bRecorded = true; ToggleLabels(); audioRecorder.stop(); audioRecorder.exportPCM(uploadSpeexData); } function getResultFromServer() { document .getElementById('result').innerText = JSON.stringify(result); document .getElementById("speexEncodebutton").value = "中止錄音"; document .getElementById("recordbutton").value = "開始錄音ֹ" } </script> </body> </html>
瀏覽器載入的時候,先調用load()進行初始化
function load(){ setAuthorization( "http://cn.olami.ai/cloudservice/api",//serverurl "51a4bb56ba954655a4fc834bfdc46af1", //appkey "asr",//api類型 "68bff251789b426896e70e888f919a6d",//appSecret "nli");//seq setCallBackFromServerResult(getResultFromServer); }
initAudio()中初始化了recorder用於獲取麥克風資源作錄音使用。
setAuthorization函數,參數分別是
url
:服務器地址 appkey
:開放平臺註冊應用後得到的appkey api
:api類型選asr爲語音 appSecret
:開放平臺註冊應用後得到的appSecret nli
:爲seq表示包含語音語義返回,爲stt表示只有語音返回
setCallBackFromServerResult(getResultFromServer) 註冊錄音介紹而且識別出結果後的回調,在回調函數中能夠把結果輸出到界面上。
當點擊開始錄音 button 後,調用
function StartRecording() { // start recording if (audioRecorder == null) { initAudio(); alert("need initialize media"); } audioRecorder.clear(); audioRecorder.record(); recording = true; bRecorded = false; ToggleLabels(); RegisterCallBackToRecorder(); //註冊recoder回調 }
當在錄音的js代碼中,會自動檢測尾音結束,而後回調註冊的函數speexEncode (),點擊中止錄音button同樣調用這個函數
window.speexEncode = function() { exportSpeex(); }; function exportSpeex() { recording = false; bRecorded = true; ToggleLabels();//更新界面的button狀態 audioRecorder.stop(); audioRecorder.exportPCM(uploadSpeexData); }
audioRecorder.exportPCM(uploadSpeexData) 實現了將錄好的 16Kpcm 語音壓縮成 speex 格式並上傳到服務器,從服務器取得結果後調用註冊的
setCallBackFromServerResult(getResultFromServer)函數,而後再函數 getResultFromServer 中進行結果的輸出顯示。
代碼下載地址:
https://github.com/ls0609/Web...
相關網站連接:
olami開放平臺語法官方介紹:https://cn.olami.ai/wiki/?mp=...
olami開放平臺語法編寫簡介:http://blog.csdn.net/ls0609/a...