HTML5 Web Speech API 結合Ext實現瀏覽器語音識別以及輸入
簡介

實現效果
代碼實現
Ext.define('Leetop.WebSpeech', {
mixins : {
observable : 'Ext.util.Observable'
},
autoStart : true,
continuous : true,
interimResults : true,
destroy : function() {
this.recognition = null;
},
constructor : function(config) {
var me = this;
me.addEvents('start', 'error', 'end', 'result', 'unsupport','nomatch');
//Ext事件機制,添加事件
me.mixins.observable.constructor.call(me, config);
//實例化語音識別組件
if (me.SpeechRecognition) {
me.recognition = new me.SpeechRecognition();
Ext.apply(me.recognition, {
continuous : me.continuous,
interimResults : me.interimResults,
onstart : Ext.bind(me.onStart, me),
onerror : Ext.bind(me.onError, me),
onend : Ext.bind(me.onEnd, me),
onnomatch : Ext.bind(me.onNoMatch,me),
onresult : Ext.bind(me.onResult, me)
});
//為語音識別組件綁定事件
} else {
//觸發不支持Web Speech事件
me.fireEvent('unsupport', me);
console.error('Your browser does not support Web Speech!');
}
if (me.autoStart) {
me.start();
}
},
//是否正在監聽麥克風
recognizing : false,
//定義語音輸入組件
SpeechRecognition : window.SpeechRecognition
|| window.webkitSpeechRecognition
|| window.mozSpeechRecognition
|| window.msSpeechRecognition,
//開始監聽用戶的麥克風
start : function() {
var me = this;
me.recognition.lang = me.lang;
me.recognition.start();
},
//停止監聽用戶的麥克風
stop : function() {
var me = this;
this.recognizing = false;
me.recognition.stop();
},
//當開始監聽麥克風的時候觸發start事件
onStart : function() {
this.recognizing = true;
this.fireEvent('start', this, this.recognition);
},
//當監聽麥克風發生錯誤時觸發error事件
onError : function(event) {
this.recognizing = false;
this.fireEvent('error', this, this.recognition, event);
},
//當輸入的語音沒有匹配結果時觸發,目前好像沒有效果
onNoMatch : function(){
this.fireEvent('nomatch',this,this.recognition);
},
//當結果監聽麥克風的時候觸發end事件
onEnd : function(event) {
this.recognizing = false;
this.fireEvent('end', this, this.recognition);
//this.start();
},
//當有識別結果產生時觸發result事件
onResult : function(event) {
console.log(event);
this.fireEvent('result', this, this.recognition, event);
},
//設置語言
setLang : function(lang) {
this.lang = lang;
}
});
使用Speech的時候對其用Ext進行了封裝,使其能夠滿足面向對象編程以及能夠滿足事件驅動編程,設置Speech的時候有兩個關鍵屬性:me.recognition = new me.SpeechRecognition();
Ext.apply(me.recognition, {
continuous : me.continuous,
interimResults : me.interimResults,
onstart : Ext.bind(me.onStart, me),
onerror : Ext.bind(me.onError, me),
onend : Ext.bind(me.onEnd, me),
onnomatch : Ext.bind(me.onNoMatch, me),
onresult : Ext.bind(me.onResult, me)
});
continuous屬性的默認值是false,代表當用戶停止說話時,語音識別將結束。在這個演示中 ,我們將它設置為true,這樣即便用戶暫時停止講話,語音識別也將會繼續。
interimResults屬性的默認值也是false,代表語音識別器的返回值不會改變。在這個演示中,我們把它設置為true,這樣隨著我們的輸入,識別結果有可能會改變。仔細觀看演示,正在識別過程中結果是會改變的,最終的識別結果不會改變。
Ext.define('Leetop.messager.message.Speech', {
extend : 'Ext.panel.Panel',
requires : ['Ext.toolbar.Toolbar', 'Ext.layout.container.Fit',
'Ext.menu.Manager', 'Ext.data.ArrayStore', 'Ext.data.JsonStore',
'Ext.form.field.ComboBox', 'Leetop.WebSpeech'],
cls : 'x-menu ux-start-menu',
floating : true,
shadow : true,
iconCls : 'l-im-voice-input',
height : 110,
width : 275,
title : '語音輸入',
layout : 'fit',
//語言列表
langs : {
trunk : [['English'], ['中文']],
'English' : [{
lang : 'en-AU',
trunk : 'English',
country : 'Australia'
}, {
lang : 'en-CA',
trunk : 'English',
country : 'Canada'
}, {
lang : 'en-IN',
trunk : 'English',
country : 'India'
}, {
lang : 'en-NZ',
trunk : 'English',
country : 'New Zealand'
}, {
lang : 'en-ZA',
trunk : 'English',
country : 'South Africa'
}, {
lang : 'en-GB',
trunk : 'English',
country : 'United Kingdom'
}, {
lang : 'en-US',
trunk : 'English',
country : 'United States'
}],
'中文' : [{
lang : 'cmn-Hans-CN',
trunk : '中文',
country : '普通話 (中國大陸)'
}, {
lang : 'cmn-Hant-TW',
trunk : '中文',
country : '普通話 (香港)'
}, {
lang : 'cmn-Hant-TW',
trunk : '中文',
country : '中文 (臺灣)'
}, {
lang : 'yue-Hant-HK',
trunk : '中文',
country : '粵語 (香港)'
}]
},
timestamp : new Date().getTime(),
//默認語言cmn-Hans-CN是普通話 (中國大陸)的代碼
defaultLang : 'cmn-Hans-CN',
bodyStyle : {
paddingLeft : 10,
paddingTop : 10,
paddingBottom : 10
},
initComponent : function() {
var me = this;
//選擇語言的下拉框
me.trunk = Ext.create('Ext.form.field.ComboBox', {
displayField : 'name',
valueField : 'name',
width : 100,
store : Ext.create('Ext.data.ArrayStore', {
fields : ['name'],
data : me.langs.trunk
}),
editable : false,
queryMode : 'local',
value : '中文',
listeners : {
select : function(combo, records) {
}
}
});
//選擇分支語言的下拉框
me.country = Ext.create('Ext.form.field.ComboBox', {
displayField : 'country',
valueField : 'lang',
width : 150,
store : Ext.create('Ext.data.JsonStore', {
fields : ['lang', 'trunk', 'country'],
data : me.langs['中文']
}),
editable : false,
queryMode : 'local',
value : me.defaultLang,
listeners : {
select : function(combo, records) {
}
}
});
me.tbar = [me.trunk, me.country];
//創建狀態顯示區域,這里將會顯示語音識別的各種狀態
me.status = Ext.create('Ext.panel.Panel', {
html : '語音輸入嘗試使用麥克風,請點擊[允許]按鈕,打開麥克風。',
ui : 'plain'
});
me.items = [me.status];
Ext.menu.Manager.register(me);
me.callParent();
//監聽面板顯示事件,如果第一次顯示則創建Web Speech組件,并綁定事件
me.on('show', function() {
me.active = true;
if (!me.speech) {
me.speech = Ext.create('Leetop.WebSpeech', {
lang : me.defaultLang,
//綁定事件
listeners : {
start : me.onSpeechStart,
error : me.onSpeechError,
result : me.onSpeechResult,
end : me.onSpeechEnd,
unsupport : me.onSpeechUnSupport,
scope : me
}
});
} else {
//第二次顯示的時候,則重新使用麥克風
if (me.speech.recognizing === false) {
me.status.update('語音輸入嘗試使用麥克風,請點擊[允許]按鈕,打開麥克風。');
me.speech.start();
}
}
//當瀏覽器不支持WebSpeech的時候,彈出提示框提示
if (me.unsupport === true) {
Leetop.error('您的瀏覽器不支持WebSpeech!');
me.hide();
return;
}
});
//綁定面板隱藏函數,當面板隱藏時,則停止Speech組件,停止監聽麥克風
me.on('hide', function() {
me.active = false;
if (me.speech) {
me.speech.stop();
}
});
me.on('deactivate', function() {
me.hide();
});
},
onSpeechNoMatch : function() {
var me = this;
me.status.update('無法識別,您可以嘗試慢一點說。');
},
onSpeechUnSupport : function() {
var me = this;
me.unsupport = true;
Leetop.error('您的瀏覽器不支持WebSpeech!');
me.hide();
return;
},
//當麥克風打開時,提示用戶可以說話了
onSpeechStart : function() {
var me = this;
me.status.update('麥克風已經打開,請開始說話。語音輸入將會識別您的語音,并轉換成文字。');
},
//當語音識別結束時,如果是長時間沒有說話導致的識別結束則重新使用麥克風,并提示用戶重新打開麥克風
onSpeechEnd : function() {
var me = this;
if (me.active === true) {
me.status.update('由于您長時間沒有講話,語音輸入重新嘗試使用麥克風。請點擊[允許]按鈕,打開麥克風。')
me.speech.start();
}
},
//當語音識別發生錯誤時,提示用戶發生了錯誤
onSpeechError : function(speech, recognition, event) {
var me = this;
if (event.error == 'no-speech') {
me.status.update('沒有檢測到語音輸入模塊。');
}
if (event.error == 'audio-capture') {
me.status.update('沒有檢測到麥克風,請確認您的電腦已經安裝了麥克風。');
}
if (event.error == 'not-allowed') {
if (event.timeStamp - me.timestamp < 100) {
me.status
.update('調用麥克風被瀏覽器阻止,請<a href="chrome://settings/contentExceptions#media-stream">更改瀏覽器設置</a>。');
} else {
me.status.update('調用麥克風被您拒絕。');
}
}
},
//當語音識別有識別結果產生的時候,提示用戶。當最終的結果產生的時候則插入到輸入框中
onSpeechResult : function(speech, recognition, event) {
var interim_transcript = '';
var me = this, result;
if (typeof(event.results) == 'undefined') {
return;
}
for (var i = event.resultIndex; i < event.results.length; ++i) {
result = event.results[i];
//遍歷識別結果
if (result.isFinal) {
//最終結果
me.status.update('您在說:' + result[0].transcript
+ '<br/>您的語音已經被識別,請繼續說話。');
me.editor.insertAtCursor(result[0].transcript);
} else {
//正在識別重點結果,動態展示識別過程
me.status.update('正在識別,結果:' + result[0].transcript);
}
}
},
destroy : function() {
var me = this;
if (me.speech) {
me.speech.destroy();
}
me.callParent();
},
showBy : function(cmp, pos, off) {
var me = this;
if (me.floating && cmp) {
me.layout.autoSize = true;
me.show();
// Component or Element
cmp = cmp.el || cmp;
// Convert absolute to floatParent-relative coordinates if
// necessary.
var xy = me.el.getAlignToXY(cmp, pos || me.defaultAlign, off);
if (me.floatParent) {
var r = me.floatParent.getTargetEl().getViewRegion();
xy[0] -= r.x;
xy[1] -= r.y;
}
me.showAt(xy);
me.doConstrain();
}
return me;
}
});
總結及演示地址
智能推薦
HTML5新增API
學習目標: typora-copy-images-to: media 1 網絡狀態 我們可以通過window.navigator.onLine來檢測,用戶當前的網絡狀況,返回一個布爾值, 但是不同瀏覽器會存在差異 所以HTML5 給我們提供了2個事件 online 和 offline online用戶網絡連接時被調用 offline用戶網絡斷開時被調用 他們監聽的對象都是window 示例 先引入...
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
猜你喜歡
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...
styled-components —— React 中的 CSS 最佳實踐
https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...