首页 > 网页设计 > HTML5 Web Speech API 结合Ext实现浏览器语音识别以及输入

HTML5 Web Speech API 结合Ext实现浏览器语音识别以及输入

   Web Speech API是HTML5技术中的一个提供原生语音识别技术的API,Google Chrome在25版之后开始支持Web Speech API,Google也提供了一个官方实例,效果如下:

实现效果

    我根据Google提供的实例中的相关实现,在Web即时通讯系统中结合Ext实现语音输入,Ext作为展示层,将识别的过程进行展示。效果如下:
    开启语音输入时,使用麦克风,浏览器会询问是否允许程序使用麦克风
    当程序监听到用户允许程序使用麦克风之后提示用户可以说话了,程序会识别用户输出的语音
    当用户输入语音后,程序将识别语音,并将识别的过程展现出来,识别的结果可能不是最终结果,下面展示的就是最终结果
    提示产生最终的识别结果,并将提示结果插入到输入框中。

代码实现

    刚才已经介绍了实现效果和语音输入的几个状态和步骤,下面介绍如何实现:
[javascript][/javascript] view plaincopy

  1. Ext.define('Leetop.WebSpeech', {
  2.             mixins : {
  3.                 observable : 'Ext.util.Observable'
  4.             },
  5.             autoStart : true,
  6.             continuous : true,
  7.             interimResults : true,
  8.             destroy : function() {
  9.                 this.recognition = null;
  10.             },
  11.             constructor : function(config) {
  12.                 var me = this;
  13.                 me.addEvents('start', 'error', 'end', 'result', 'unsupport','nomatch');
  14.                 //Ext事件机制,添加事件
  15.                 me.mixins.observable.constructor.call(me, config);
  16.                 //实例化语音识别组件
  17.                 if (me.SpeechRecognition) {
  18.                     me.recognition = new me.SpeechRecognition();
  19.                     Ext.apply(me.recognition, {
  20.                                 continuous : me.continuous,
  21.                                 interimResults : me.interimResults,
  22.                                 onstart : Ext.bind(me.onStart, me),
  23.                                 onerror : Ext.bind(me.onError, me),
  24.                                 onend : Ext.bind(me.onEnd, me),
  25.                                 onnomatch : Ext.bind(me.onNoMatch,me),
  26.                                 onresult : Ext.bind(me.onResult, me)
  27.                             });
  28.                     //为语音识别组件绑定事件
  29.                 } else {
  30.                     //触发不支持Web Speech事件
  31.                     me.fireEvent('unsupport', me);
  32.                     console.error('Your browser does not support Web Speech!');
  33.                 }
  34.                 if (me.autoStart) {
  35.                     me.start();
  36.                 }
  37.             },
  38.             //是否正在监听麦克风
  39.             recognizing : false,
  40.             //定义语音输入组件
  41.             SpeechRecognition : window.SpeechRecognition
  42.                     || window.webkitSpeechRecognition
  43.                     || window.mozSpeechRecognition
  44.                     || window.msSpeechRecognition,
  45.             //开始监听用户的麦克风
  46.             start : function() {
  47.                 var me = this;
  48.                 me.recognition.lang = me.lang;
  49.                 me.recognition.start();
  50.             },
  51.             //停止监听用户的麦克风
  52.             stop : function() {
  53.                 var me = this;
  54.                 this.recognizing = false;
  55.                 me.recognition.stop();
  56.             },
  57.             //当开始监听麦克风的时候触发start事件
  58.             onStart : function() {
  59.                 this.recognizing = true;
  60.                 this.fireEvent('start', this, this.recognition);
  61.             },
  62.             //当监听麦克风发生错误时触发error事件
  63.             onError : function(event) {
  64.                 this.recognizing = false;
  65.                 this.fireEvent('error', this, this.recognition, event);
  66.             },
  67.             //当输入的语音没有匹配结果时触发,目前好像没有效果
  68.             onNoMatch : function(){
  69.                 this.fireEvent('nomatch',this,this.recognition);
  70.             },
  71.             //当结果监听麦克风的时候触发end事件
  72.             onEnd : function(event) {
  73.                 this.recognizing = false;
  74.                 this.fireEvent('end', this, this.recognition);
  75.                 //this.start();
  76.             },
  77.             //当有识别结果产生时触发result事件
  78.             onResult : function(event) {
  79.                 console.log(event);
  80.                 this.fireEvent('result', this, this.recognition, event);
  81.             },
  82.             //设置语言
  83.             setLang : function(lang) {
  84.                 this.lang = lang;
  85.             }
  86.         });

使用Speech的时候对其用Ext进行了封装,使其能够满足面向对象编程以及能够满足事件驱动编程,设置Speech的时候有两个关键属性:

[javascript][/javascript] view plaincopy

  1. me.recognition = new me.SpeechRecognition();
  2. Ext.apply(me.recognition, {
  3.     continuous : me.continuous,
  4.     interimResults : me.interimResults,
  5.     onstart : Ext.bind(me.onStart, me),
  6.     onerror : Ext.bind(me.onError, me),
  7.     onend : Ext.bind(me.onEnd, me),
  8.     onnomatch : Ext.bind(me.onNoMatch, me),
  9.     onresult : Ext.bind(me.onResult, me)
  10. });

continuous属性的默认值是false,代表当用户停止说话时,语音识别将结束。在这个演示中 ,我们将它设置为true,这样即便用户暂时停止讲话,语音识别也将会继续。

interimResults属性的默认值也是false,代表语音识别器的返回值不会改变。在这个演示中,我们把它设置为true,这样随着我们的输入,识别结果有可能会改变。仔细观看演示,正在识别过程中结果是会改变的,最终的识别结果不会改变。
下面具体介绍如何使用Leetop.WebSpeech这个类,以及在界面中进行展示:
[javascript][/javascript] view plaincopy

  1. Ext.define('Leetop.messager.message.Speech', {
  2.     extend : 'Ext.panel.Panel',
  3.     requires : ['Ext.toolbar.Toolbar', 'Ext.layout.container.Fit',
  4.             'Ext.menu.Manager', 'Ext.data.ArrayStore', 'Ext.data.JsonStore',
  5.             'Ext.form.field.ComboBox', 'Leetop.WebSpeech'],
  6.     cls : 'x-menu ux-start-menu',
  7.     floating : true,
  8.     shadow : true,
  9.     iconCls : 'l-im-voice-input',
  10.     height : 110,
  11.     width : 275,
  12.     title : '语音输入',
  13.     layout : 'fit',
  14.     //语言列表
  15.     langs : {
  16.         trunk : [['English'], ['中文']],
  17.         'English' : [{
  18.                     lang : 'en-AU',
  19.                     trunk : 'English',
  20.                     country : 'Australia'
  21.                 }, {
  22.                     lang : 'en-CA',
  23.                     trunk : 'English',
  24.                     country : 'Canada'
  25.                 }, {
  26.                     lang : 'en-IN',
  27.                     trunk : 'English',
  28.                     country : 'India'
  29.                 }, {
  30.                     lang : 'en-NZ',
  31.                     trunk : 'English',
  32.                     country : 'New Zealand'
  33.                 }, {
  34.                     lang : 'en-ZA',
  35.                     trunk : 'English',
  36.                     country : 'South Africa'
  37.                 }, {
  38.                     lang : 'en-GB',
  39.                     trunk : 'English',
  40.                     country : 'United Kingdom'
  41.                 }, {
  42.                     lang : 'en-US',
  43.                     trunk : 'English',
  44.                     country : 'United States'
  45.                 }],
  46.         '中文' : [{
  47.                     lang : 'cmn-Hans-CN',
  48.                     trunk : '中文',
  49.                     country : '普通话 (中国大陆)'
  50.                 }, {
  51.                     lang : 'cmn-Hant-TW',
  52.                     trunk : '中文',
  53.                     country : '普通话 (香港)'
  54.                 }, {
  55.                     lang : 'cmn-Hant-TW',
  56.                     trunk : '中文',
  57.                     country : '中文 (台灣)'
  58.                 }, {
  59.                     lang : 'yue-Hant-HK',
  60.                     trunk : '中文',
  61.                     country : '粵語 (香港)'
  62.                 }]
  63.     },
  64.     timestamp : new Date().getTime(),
  65.     //默认语言cmn-Hans-CN是普通话 (中国大陆)的代码
  66.     defaultLang : 'cmn-Hans-CN',
  67.     bodyStyle : {
  68.         paddingLeft : 10,
  69.         paddingTop : 10,
  70.         paddingBottom : 10
  71.     },
  72.     initComponent : function() {
  73.         var me = this;
  74.         //选择语言的下拉框
  75.         me.trunk = Ext.create('Ext.form.field.ComboBox', {
  76.                     displayField : 'name',
  77.                     valueField : 'name',
  78.                     width : 100,
  79.                     store : Ext.create('Ext.data.ArrayStore', {
  80.                                 fields : ['name'],
  81.                                 data : me.langs.trunk
  82.                             }),
  83.                     editable : false,
  84.                     queryMode : 'local',
  85.                     value : '中文',
  86.                     listeners : {
  87.                         select : function(combo, records) {
  88.                         }
  89.                     }
  90.                 });
  91.         //选择分支语言的下拉框
  92.         me.country = Ext.create('Ext.form.field.ComboBox', {
  93.                     displayField : 'country',
  94.                     valueField : 'lang',
  95.                     width : 150,
  96.                     store : Ext.create('Ext.data.JsonStore', {
  97.                                 fields : ['lang', 'trunk', 'country'],
  98.                                 data : me.langs['中文']
  99.                             }),
  100.                     editable : false,
  101.                     queryMode : 'local',
  102.                     value : me.defaultLang,
  103.                     listeners : {
  104.                         select : function(combo, records) {
  105.                         }
  106.                     }
  107.                 });
  108.         me.tbar = [me.trunk, me.country];
  109.         //创建状态显示区域,这里将会显示语音识别的各种状态
  110.         me.status = Ext.create('Ext.panel.Panel', {
  111.                     html : '语音输入尝试使用麦克风,请点击[允许]按钮,打开麦克风。',
  112.                     ui : 'plain'
  113.                 });
  114.         me.items = [me.status];
  115.         Ext.menu.Manager.register(me);
  116.         me.callParent();
  117.         //监听面板显示事件,如果第一次显示则创建Web Speech组件,并绑定事件
  118.         me.on('show', function() {
  119.                     me.active = true;
  120.                     if (!me.speech) {
  121.                         me.speech = Ext.create('Leetop.WebSpeech', {
  122.                                     lang : me.defaultLang,
  123.                                     //绑定事件
  124.                                     listeners : {
  125.                                         start : me.onSpeechStart,
  126.                                         error : me.onSpeechError,
  127.                                         result : me.onSpeechResult,
  128.                                         end : me.onSpeechEnd,
  129.                                         unsupport : me.onSpeechUnSupport,
  130.                                         scope : me
  131.                                     }
  132.                                 });
  133.                     } else {
  134.                         //第二次显示的时候,则重新使用麦克风
  135.                         if (me.speech.recognizing === false) {
  136.                             me.status.update('语音输入尝试使用麦克风,请点击[允许]按钮,打开麦克风。');
  137.                             me.speech.start();
  138.                         }
  139.                     }
  140.                     //当浏览器不支持WebSpeech的时候,弹出提示框提示
  141.                     if (me.unsupport === true) {
  142.                         Leetop.error('您的浏览器不支持WebSpeech!');
  143.                         me.hide();
  144.                         return;
  145.                     }
  146.                 });
  147.         //绑定面板隐藏函数,当面板隐藏时,则停止Speech组件,停止监听麦克风
  148.         me.on('hide', function() {
  149.                     me.active = false;
  150.                     if (me.speech) {
  151.                         me.speech.stop();
  152.                     }
  153.                 });
  154.         me.on('deactivate', function() {
  155.                     me.hide();
  156.                 });
  157.     },
  158.     onSpeechNoMatch : function() {
  159.         var me = this;
  160.         me.status.update('无法识别,您可以尝试慢一点说。');
  161.     },
  162.     onSpeechUnSupport : function() {
  163.         var me = this;
  164.         me.unsupport = true;
  165.         Leetop.error('您的浏览器不支持WebSpeech!');
  166.         me.hide();
  167.         return;
  168.     },
  169.     //当麦克风打开时,提示用户可以说话了
  170.     onSpeechStart : function() {
  171.         var me = this;
  172.         me.status.update('麦克风已经打开,请开始说话。语音输入将会识别您的语音,并转换成文字。');
  173.     },
  174.     //当语音识别结束时,如果是长时间没有说话导致的识别结束则重新使用麦克风,并提示用户重新打开麦克风
  175.     onSpeechEnd : function() {
  176.         var me = this;
  177.         if (me.active === true) {
  178.             me.status.update('由于您长时间没有讲话,语音输入重新尝试使用麦克风。请点击[允许]按钮,打开麦克风。')
  179.             me.speech.start();
  180.         }
  181.     },
  182.     //当语音识别发生错误时,提示用户发生了错误
  183.     onSpeechError : function(speech, recognition, event) {
  184.         var me = this;
  185.         if (event.error == 'no-speech') {
  186.             me.status.update('没有检测到语音输入模块。');
  187.         }
  188.         if (event.error == 'audio-capture') {
  189.             me.status.update('没有检测到麦克风,请确认您的电脑已经安装了麦克风。');
  190.         }
  191.         if (event.error == 'not-allowed') {
  192.             if (event.timeStamp - me.timestamp < 100) {
  193.                 me.status
  194.                         .update('调用麦克风被浏览器阻止,请<a href="chrome://settings/contentExceptions#media-stream">更改浏览器设置</a>。');
  195.             } else {
  196.                 me.status.update('调用麦克风被您拒绝。');
  197.             }
  198.         }
  199.     },
  200.     //当语音识别有识别结果产生的时候,提示用户。当最终的结果产生的时候则插入到输入框中
  201.     onSpeechResult : function(speech, recognition, event) {
  202.         var interim_transcript = '';
  203.         var me = this, result;
  204.         if (typeof(event.results) == 'undefined') {
  205.             return;
  206.         }
  207.         for (var i = event.resultIndex; i < event.results.length; ++i) {
  208.             result = event.results[i];
  209.             //遍历识别结果
  210.             if (result.isFinal) {
  211.                 //最终结果
  212.                 me.status.update('您在说:' + result[0].transcript
  213.                         + '<br/>您的语音已经被识别,请继续说话。');
  214.                 me.editor.insertAtCursor(result[0].transcript);
  215.             } else {
  216.                 //正在识别重点结果,动态展示识别过程
  217.                 me.status.update('正在识别,结果:' + result[0].transcript);
  218.             }
  219.         }
  220.     },
  221.     destroy : function() {
  222.         var me = this;
  223.         if (me.speech) {
  224.             me.speech.destroy();
  225.         }
  226.         me.callParent();
  227.     },
  228.     showBy : function(cmp, pos, off) {
  229.         var me = this;
  230.         if (me.floating && cmp) {
  231.             me.layout.autoSize = true;
  232.             me.show();
  233.             // Component or Element
  234.             cmp = cmp.el || cmp;
  235.             // Convert absolute to floatParent-relative coordinates if
  236.             // necessary.
  237.             var xy = me.el.getAlignToXY(cmp, pos || me.defaultAlign, off);
  238.             if (me.floatParent) {
  239.                 var r = me.floatParent.getTargetEl().getViewRegion();
  240.                 xy[0] -= r.x;
  241.                 xy[1] -= r.y;
  242.             }
  243.             me.showAt(xy);
  244.             me.doConstrain();
  245.         }
  246.         return me;
  247.     }
  248. });

总结及演示地址

Google Chrome的语音识别率相当高,口齿清楚的话识别率在95%以上,而且能够识别“学而不思则罔”,“学而时习之”,“国破山河在”,“年年有余”,“周鸿祎”等文言文、古诗、成语、人名等特殊的语音,相当强悍。
大家可以去www.ibcio.com体验语音输入的效果,www.ibcio.com中的即时通讯提供了文本、视频、窗口抖动、表情、图片等即时通讯服务,大家可以去体验一下HTML5结合Ext带来的Web桌面的效果。
建议大家使用Google Chrome浏览器

本文固定链接: http://www.devba.com/index.php/archives/1743.html | 开发吧

报歉!评论已关闭.