├── .gitignore ├── component.json ├── package.json ├── index.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | components 2 | node_modules 3 | build 4 | test.html -------------------------------------------------------------------------------- /component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "speech", 3 | "repo": "yyx990803/speech", 4 | "description": "Chrome speech recognition wrapper", 5 | "keywords": ["speech", "recognition"], 6 | "dependencies": { 7 | "component/emitter": "*" 8 | }, 9 | "version": "1.0.0", 10 | "license": "MIT", 11 | "scripts": [ "index.js" ] 12 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "speechjs", 3 | "version": "0.0.1", 4 | "description": "Chrome speech recognition API wrapper", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/yyx990803/speech.git" 9 | }, 10 | "keywords": [ 11 | "speech" 12 | ], 13 | "author": "Evan You", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/yyx990803/speech/issues" 17 | }, 18 | "homepage": "https://github.com/yyx990803/speech", 19 | "dependencies": { 20 | "component-emitter": "^1.1.2" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var Emitter, cmitter = 'emitter' 2 | 3 | try { 4 | Emitter = require(cmitter) 5 | } catch (e) { 6 | Emitter = require('component-emitter') 7 | } 8 | 9 | function Speech (options) { 10 | 11 | // default options 12 | this.options = { 13 | debugging: false, 14 | continuous: false, 15 | interimResults: false, 16 | autoRestart: false 17 | } 18 | 19 | // merge user options 20 | if (Object.prototype.toString.call(options) === '[object Object]') { 21 | for (var op in options) { 22 | this.options[op] = options[op] 23 | } 24 | } 25 | 26 | this.active = false 27 | this.manualStopped = false 28 | this.history = [] 29 | this.lastIndex = -1 30 | this.lastResult = '' 31 | this.recognition = new webkitSpeechRecognition() 32 | 33 | var rec = this.recognition, 34 | self = this 35 | 36 | rec.continuous = self.options.continuous 37 | rec.interimResults = self.options.interimResults 38 | if (options.lang) rec.lang = options.lang 39 | 40 | rec.onstart = function () { 41 | self.active = true 42 | this.manualStopped = false 43 | self.emit('start') 44 | } 45 | 46 | rec.onresult = function (e) { 47 | if (!e.results || !e.results.length) return 48 | 49 | var updatedResult = e.results[e.resultIndex], 50 | transcript = updatedResult[0].transcript.replace(/^\s*/, '') 51 | 52 | // new sentence? 53 | if (e.resultIndex !== self.lastIndex) { 54 | self.lastIndex = e.resultIndex 55 | self.lastResult = '' 56 | } 57 | 58 | // avoid some redundancy 59 | if (transcript === self.lastResult && !updatedResult.isFinal) return 60 | if (transcript.length < self.lastResult.length) return 61 | 62 | self.lastResult = transcript 63 | 64 | if (updatedResult.isFinal) { 65 | // final sentence! we can do work! 66 | self.history.push(transcript) 67 | self.emit('finalResult', transcript) 68 | } else { 69 | // interim, let's update stuff on screen 70 | self.emit('interimResult', transcript) 71 | } 72 | 73 | if (self.options.debugging) { 74 | console.log(transcript + (updatedResult.isFinal ? ' (final)' : '')) 75 | } 76 | } 77 | 78 | rec.onerror = function (e) { 79 | self.emit('error', e) 80 | } 81 | 82 | rec.onend = function () { 83 | self.active = false 84 | self.history = [] 85 | self.lastIndex = -1 86 | self.lastResult = '' 87 | self.emit('end') 88 | if (self.options.autoRestart && !self.manualStopped) { 89 | self.start() 90 | } 91 | } 92 | 93 | Emitter(this) 94 | 95 | } 96 | 97 | Speech.prototype.start = function () { 98 | if (this.active) return 99 | this.recognition.start() 100 | } 101 | 102 | Speech.prototype.stop = function () { 103 | if (!this.active) return 104 | this.manualStopped = true 105 | this.recognition.stop() 106 | } 107 | 108 | module.exports = Speech -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Speech 2 | 3 | Simple wrapper for Chrome's web speech recoginition API. 4 | 5 | Demo 6 | 7 | ### Basic Usage 8 | 9 | ``` js 10 | 11 | var Speech = require('speech') 12 | var recognizer = new Speech({ 13 | lang: 'cmn-Hans-CN', // Mandarin Chinese, default is English. 14 | // all boolean options default to false 15 | debugging: true, // will console.log all results 16 | continuous: true, // will not stop after one sentence 17 | interimResults: true, // trigger events on iterim results 18 | autoRestart: true, // recommended when using continuous:true 19 | // because the API sometimes stops itself 20 | // possibly due to network error. 21 | }) 22 | 23 | // simply listen to events 24 | // chainable API 25 | recognizer 26 | .on('start', function () { 27 | console.log('started') 28 | }) 29 | .on('end', function () { 30 | console.log('ended') 31 | }) 32 | .on('error', function (event) { 33 | console.log(event.error) 34 | }) 35 | .on('interimResult', function (msg) { 36 | document.body.innerHTML = msg 37 | }) 38 | .on('finalResult', function (msg) { 39 | document.body.innerHTML = msg 40 | }) 41 | .start() 42 | 43 | ``` 44 | 45 | You can also access Chrome's native recognition object: 46 | 47 | ``` js 48 | recognizer.recognition.continuous = false 49 | ``` 50 | 51 | ### Language Options 52 | 53 | ``` js 54 | 55 | // from http://www.google.com/intl/en/chrome/demos/speech.html 56 | var langs = 57 | [['Afrikaans', ['af-ZA']], 58 | ['Bahasa Indonesia',['id-ID']], 59 | ['Bahasa Melayu', ['ms-MY']], 60 | ['Català', ['ca-ES']], 61 | ['Čeština', ['cs-CZ']], 62 | ['Deutsch', ['de-DE']], 63 | ['English', ['en-AU', 'Australia'], 64 | ['en-CA', 'Canada'], 65 | ['en-IN', 'India'], 66 | ['en-NZ', 'New Zealand'], 67 | ['en-ZA', 'South Africa'], 68 | ['en-GB', 'United Kingdom'], 69 | ['en-US', 'United States']], 70 | ['Español', ['es-AR', 'Argentina'], 71 | ['es-BO', 'Bolivia'], 72 | ['es-CL', 'Chile'], 73 | ['es-CO', 'Colombia'], 74 | ['es-CR', 'Costa Rica'], 75 | ['es-EC', 'Ecuador'], 76 | ['es-SV', 'El Salvador'], 77 | ['es-ES', 'España'], 78 | ['es-US', 'Estados Unidos'], 79 | ['es-GT', 'Guatemala'], 80 | ['es-HN', 'Honduras'], 81 | ['es-MX', 'México'], 82 | ['es-NI', 'Nicaragua'], 83 | ['es-PA', 'Panamá'], 84 | ['es-PY', 'Paraguay'], 85 | ['es-PE', 'Perú'], 86 | ['es-PR', 'Puerto Rico'], 87 | ['es-DO', 'República Dominicana'], 88 | ['es-UY', 'Uruguay'], 89 | ['es-VE', 'Venezuela']], 90 | ['Euskara', ['eu-ES']], 91 | ['Français', ['fr-FR']], 92 | ['Galego', ['gl-ES']], 93 | ['Hrvatski', ['hr_HR']], 94 | ['IsiZulu', ['zu-ZA']], 95 | ['Íslenska', ['is-IS']], 96 | ['Italiano', ['it-IT', 'Italia'], 97 | ['it-CH', 'Svizzera']], 98 | ['Magyar', ['hu-HU']], 99 | ['Nederlands', ['nl-NL']], 100 | ['Norsk bokmål', ['nb-NO']], 101 | ['Polski', ['pl-PL']], 102 | ['Português', ['pt-BR', 'Brasil'], 103 | ['pt-PT', 'Portugal']], 104 | ['Română', ['ro-RO']], 105 | ['Slovenčina', ['sk-SK']], 106 | ['Suomi', ['fi-FI']], 107 | ['Svenska', ['sv-SE']], 108 | ['Türkçe', ['tr-TR']], 109 | ['български', ['bg-BG']], 110 | ['Pусский', ['ru-RU']], 111 | ['Српски', ['sr-RS']], 112 | ['한국어', ['ko-KR']], 113 | ['中文', ['cmn-Hans-CN', '普通话 (中国大陆)'], 114 | ['cmn-Hans-HK', '普通话 (香港)'], 115 | ['cmn-Hant-TW', '中文 (台灣)'], 116 | ['yue-Hant-HK', '粵語 (香港)']], 117 | ['日本語', ['ja-JP']], 118 | ['Lingua latīna', ['la']]]; 119 | 120 | ``` --------------------------------------------------------------------------------