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浏览器
  • 相关阅读:
    jeecms 强大的采集功能优化 转载 https://blog.csdn.net/jeff06143132/article/details/7099003
    JEECMS自定义标签开发步骤
    jeecms之全文检索
    jeecms怎么修改后台访问路径?
    jeecms 基本架构研究
    Java JNI初探
    《高效程序员的45个习惯》
    Java并发编程:Thread类的使用
    Thread详解
    JAVA多线程实现的四种方式
  • 原文地址:https://www.cnblogs.com/snake-hand/p/3188564.html
Copyright © 2011-2022 走看看