├── cli.js ├── examples └── stream.js ├── package.json ├── listen.js ├── index.js └── README.md /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var spawn = require('electron-spawn') 4 | var s = spawn(require.resolve('./listen.js'), process.argv.slice(2).join(' ')) 5 | s.stdout.pipe(process.stdout) 6 | s.stderr.pipe(process.stderr) 7 | -------------------------------------------------------------------------------- /examples/stream.js: -------------------------------------------------------------------------------- 1 | // to be run with 'electron-spawn' 2 | 3 | var Speech = require('./index') 4 | 5 | var s = Speech({ continuous: true }) 6 | s.pipe(process.stdout) 7 | s.listen() 8 | 9 | s.on('end', function() { process.exit(0) }) 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron-speech", 3 | "description": "speech recognition cli and api for node using electron", 4 | "version": "1.0.7", 5 | "repository": { 6 | "url": "git://github.com/noffle/electron-speech.git" 7 | }, 8 | "main": "index.js", 9 | "scripts": { 10 | "start": "electron-spawn listen.js" 11 | }, 12 | "bin": { 13 | "electron-speech": "cli.js" 14 | }, 15 | "dependencies": { 16 | "defined": "^1.0.0", 17 | "electron-spawn": "^5.0.0", 18 | "minimist": "^1.2.0", 19 | "readable-stream": "^2.0.5" 20 | }, 21 | "keywords": [ 22 | "web", 23 | "speech", 24 | "electron", 25 | "recognition", 26 | "stt" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /listen.js: -------------------------------------------------------------------------------- 1 | var speech = require('./index') 2 | var argv = require('minimist')(process.argv.slice(2)) 3 | 4 | var continuous = argv.continuous || argv.c 5 | var quiet = argv.quiet || argv.q 6 | 7 | var c = speech({ language: 'en_US', continuous: continuous }) 8 | 9 | c.listen() 10 | 11 | c.on('ready', function () { 12 | if (!quiet) { 13 | console.log('listening..') 14 | } 15 | }) 16 | 17 | c.on('text', function (text) { 18 | console.log(text) 19 | 20 | if (!continuous) { 21 | process.exit(0) 22 | } 23 | }) 24 | 25 | c.on('error', function (err) { 26 | console.error('error:', err) 27 | }) 28 | 29 | c.on('end', function () { 30 | console.log('done') 31 | process.exit(0) 32 | }) 33 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var EventEmitter = require('events') 2 | var util = require('util') 3 | var defined = require('defined') 4 | var Readable = require('readable-stream') 5 | 6 | module.exports = Speech 7 | 8 | util.inherits(Speech, EventEmitter) 9 | util.inherits(Speech, Readable) 10 | 11 | function Speech (opts) { 12 | if (!(this instanceof Speech)) { return new Speech(opts) } 13 | if (!('webkitSpeechRecognition' in window)) { 14 | this.emit('error', 'no speech api support') 15 | return 16 | } 17 | 18 | opts = defined(opts, {}) 19 | 20 | EventEmitter.call(this) 21 | Readable.call(this) 22 | 23 | this.recognition = new webkitSpeechRecognition() 24 | this.recognition.lang = defined(opts.lang, 'en-US') 25 | this.continuous = defined(opts.continuous, false) 26 | 27 | this._read = function (size) {} 28 | } 29 | 30 | Speech.prototype.listen = function () { 31 | var done = false 32 | var self = this 33 | var recognition = this.recognition 34 | recognition.continuous = this.continuous 35 | recognition.interimResults = false 36 | recognition.onstart = function () { 37 | self.emit('ready') 38 | } 39 | recognition.onresult = function (event) { 40 | if (done) { 41 | return 42 | } 43 | for (var i = event.resultIndex; i < event.results.length; i++) { 44 | var result = event.results[i] 45 | if (result.isFinal) { 46 | var alt = result[0] 47 | result = alt.transcript.trim() 48 | self.emit('text', result) 49 | self.push(result + '\n') 50 | 51 | if (!self.continuous) { 52 | recognition.stop() 53 | done = true 54 | self.push(null) 55 | } 56 | } 57 | } 58 | } 59 | recognition.onerror = function (err) { 60 | console.log('err', err.error) 61 | self.emit('error', err.error) 62 | } 63 | recognition.onend = function () { 64 | self.emit('end') 65 | } 66 | 67 | recognition.start() 68 | } 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # electron-speech 2 | 3 | > Speech recognition in node and the browser using Electron. 4 | 5 | ## THIS MODULE NO LONGER WORKS 6 | 7 | It 8 | [seems](http://stackoverflow.com/questions/36214413/webkitspeechrecognition-returning-network-error-in-electron) 9 | that Google 10 | [has](https://groups.google.com/a/chromium.org/forum/#!topic/chromium-html5/JJe6KD7-bb8) 11 | shut down the Chrome Speech API for use in shell environments like Electron, which `electron-speech` relies on. 12 | 13 | Some other directions to pursue instead include: 14 | 15 | 1. [webkitSpeechRecognition in the browser](https://gist.github.com/noffle/968d694c3bffa055cfd3a4d9b1b13380). This works if you are using a Chrome-based browser that isn't a shell like Electron. 16 | 2. [Sonus](https://github.com/evancohen/sonus): node module that is optimized 17 | for low powered devices and provides *customizable* offline hotword detection 18 | with real-time streaming results (via [Google Cloud 19 | Speech](https://github.com/googlecloudplatform/google-cloud-node#google-cloud-speech-alpha) 20 | and others). 21 | 3. If you are looking for a purely offline option: 22 | [node-pocketsphinx](https://github.com/cmusphinx/node-pocketsphinx) 23 | 4. [Jasper](https://jasperproject.github.io/) looks promising, but is 24 | Python-based. Go forth and write a node wrapper around it! 25 | 26 | ## Prerequisites 27 | 28 | If you want to use the API from a script using Node, you will need to launch 29 | your script using the 30 | [`electron-spawn`](https://www.npmjs.com/package/electron-spawn) command instead 31 | of the `node` command: 32 | 33 | ```sh 34 | $ npm install -g electron-spawn 35 | 36 | $ electron-spawn example.js 37 | ``` 38 | 39 | ## Usage 40 | 41 | ### CLI 42 | 43 | This module installs the `electron-speech` command: 44 | 45 | ``` 46 | $ electron-speech 47 | listening.. 48 | (whatever is said is written here, to stdout) 49 | ``` 50 | 51 | `-q|--quiet` to omit the `listening..` message. (it's on stderr anyways though) 52 | 53 | `-c|--continuous` to keep on listening after each result. 54 | 55 | ### API 56 | 57 | ```javascript 58 | var Speech = require('electron-speech') 59 | 60 | var recog = Speech({ 61 | lang: 'en-US', 62 | continuous: true 63 | }) 64 | 65 | recog.on('text', function (text) { 66 | console.log(text) 67 | }); 68 | 69 | recog.listen() 70 | ``` 71 | 72 | ### Methods 73 | 74 | #### var speech = Speech(opts) 75 | 76 | Returns `speech`, an EventEmitter and Readable stream. 77 | 78 | `opts` accepts multiple keys: 79 | 80 | - `opts.lang` - recognize speech in the language `lang`. Defaults to `'en-US'`. 81 | - `opts.continuous` - if true, `text` events will keep on being emitted as recognition 82 | occurs. 83 | 84 | #### speech.listen() 85 | 86 | Starts listening to speech via the microphone. `'ready`'` will be emitted once speech 87 | recognition has begun. 88 | 89 | #### speech.pipe(stream) 90 | 91 | Uses `speech` as a readable stream for text rather than an event emitter. 92 | Results have newlines appended to them for parsing convenience. 93 | 94 | #### speech.on('ready') 95 | 96 | Emitted when the microphone has begun to listen for speech. 97 | 98 | #### speech.on('text', function (text) {}) 99 | 100 | Emitted when speech has been recognized. 101 | 102 | #### speech.on('error', function (err) {}) 103 | 104 | Emitted when an error has occurred in recognition. 105 | 106 | #### speech.on('close') 107 | 108 | Emitted when recognition has ended. Does not fire if `continuous` was set to 109 | true. 110 | 111 | ## License 112 | 113 | ISC 114 | --------------------------------------------------------------------------------