HTML5 Web Speech API 结合Ext实现浏览器语音识别以及输入
简介
Web Speech API是HTML5技术中的一个提供原生语音识别技术的API,Google Chrome在25版之后开始支持Web Speech API,Google也提供了一个
官方实例,效果如下:
实现效果
我根据Google提供的实例中的相关实现,在Web即时通讯系统中结合Ext实现语音输入,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,这样随着我们的输入,识别结果有可能会改变。仔细观看演示,正在识别过程中结果是会改变的,最终的识别结果不会改变。
下面具体介绍如何使用Leetop.WebSpeech这个类,以及在界面中进行展示:
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; } });
总结及演示地址
Google Chrome的语音识别率相当高,口齿清楚的话识别率在95%以上,而且能够识别“学而不思则罔”,“学而时习之”,“国破山河在”,“年年有余”,“周鸿祎”等文言文、古诗、成语、人名等特殊的语音,相当强悍。
大家可以去
www.ibcio.com体验语音输入的效果,
www.ibcio.com中的即时通讯提供了文本、视频、窗口抖动、表情、图片等即时通讯服务,大家可以去体验一下HTML5结合Ext带来的Web桌面的效果。
建议大家使用Google Chrome浏览器