zoukankan      html  css  js  c++  java
  • 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浏览器
  • 相关阅读:
    self 和 super 关键字
    NSString类
    函数和对象方法的区别
    求两个数是否互质及最大公约数
    TJU Problem 1644 Reverse Text
    TJU Problem 2520 Quicksum
    TJU Problem 2101 Bullseye
    TJU Problem 2548 Celebrity jeopardy
    poj 2586 Y2K Accounting Bug
    poj 2109 Power of Cryptography
  • 原文地址:https://www.cnblogs.com/snake-hand/p/3188564.html
Copyright © 2011-2022 走看看