├── .env.example ├── package.json ├── README.md ├── .gitignore └── app.js /.env.example: -------------------------------------------------------------------------------- 1 | GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "audiofork-transcribe-demo", 3 | "scripts": { 4 | "bgprocess": "forever start -c 'node' index.js" 5 | }, 6 | "dependencies": { 7 | "@google-cloud/speech": "^3.2.0", 8 | "@google-cloud/text-to-speech": "^1.1.2", 9 | "dotenv": "^8.0.0", 10 | "ws": "7.5.10" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Audiofork Google Speech Transcribe Demo 2 | 3 | ## About 4 | This is a sample integration of [Asterisk Audiofork Module](https://github.com/nadirhamid/asterisk-audiofork) and the Google Cloud Speech APIs. This project is intended to process transcriptions in near real time. 5 | 6 | for more info on Asterisk Audiofork Module [please click here](https://github.com/nadirhamid/asterisk-audiofork) 7 | 8 | ## Setup 9 | 10 | 1. NPM install 11 | ``` 12 | npm install 13 | ``` 14 | 15 | 2. Copy example .env 16 | ``` 17 | cp .env.example .env 18 | ``` 19 | 20 | 3. update .env with the path to your Google service-account.json 21 | 22 | ## Run Sample 23 | 24 | ``` 25 | node app.js 26 | ``` 27 | 28 | ## Example Output 29 | 30 | ``` 31 | Running Audio fork Google cloud speech demo 32 | Updated transription: Hello, my name is testing. 33 | ... 34 | Updated transription: Hello, my name is testing. I am 15 years old. 35 | ``` 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # Snowpack dependency directory (https://snowpack.dev/) 45 | web_modules/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | .parcel-cache 78 | 79 | # Next.js build output 80 | .next 81 | out 82 | 83 | # Nuxt.js build / generate output 84 | .nuxt 85 | dist 86 | 87 | # Gatsby files 88 | .cache/ 89 | # Comment in the public line in if your project uses Gatsby and not Next.js 90 | # https://nextjs.org/blog/next-9-1#public-directory-support 91 | # public 92 | 93 | # vuepress build output 94 | .vuepress/dist 95 | 96 | # Serverless directories 97 | .serverless/ 98 | 99 | # FuseBox cache 100 | .fusebox/ 101 | 102 | # DynamoDB Local files 103 | .dynamodb/ 104 | 105 | # TernJS port file 106 | .tern-port 107 | 108 | # Stores VSCode versions used for testing VSCode extensions 109 | .vscode-test 110 | 111 | # yarn v2 112 | .yarn/cache 113 | .yarn/unplugged 114 | .yarn/build-state.yml 115 | .yarn/install-state.gz 116 | .pnp.* 117 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var speech = require('@google-cloud/speech'); 2 | const textToSpeech = require('@google-cloud/text-to-speech'); 3 | var env = require("dotenv"); 4 | 5 | var parsed = env.config({ 6 | path: '.env' 7 | }); 8 | console.log("Running Audio fork Google cloud speech demo"); 9 | console.log("google credentials path is: " + process.env.GOOGLE_APPLICATION_CREDENTIALS); 10 | var now = Date.now(); 11 | const WebSocket = require('ws'); 12 | 13 | const wss = new WebSocket.Server({ 14 | port: 8080 15 | }); 16 | var fs = require('fs'); 17 | async function stt(file) { 18 | console.log("calling stt"); 19 | const speechClient = new speech.SpeechClient(); 20 | //const file = fs.readFileSync(filePath); 21 | const audioBytes = file.toString('base64'); 22 | 23 | const audio = { 24 | content: audioBytes, 25 | }; 26 | const config = { 27 | encoding: 'LINEAR16', 28 | sampleRateHertz: 8000, 29 | languageCode: 'en-US' 30 | }; 31 | const request = { 32 | audio, 33 | config 34 | }; 35 | console.log("calling API"); 36 | return await speechClient.recognize(request); 37 | } 38 | 39 | var bytesThreshold = 1024 * 50; 40 | wss.on('connection', function connection(ws) { 41 | console.log("got connection "); 42 | 43 | var recv = 0; 44 | var buffers = []; 45 | var transcription = ""; 46 | var waiting = false; 47 | 48 | // use setImmediate to wait until waiting = false 49 | function wait() { 50 | return new Promise(function(resolve, reject) { 51 | if (waiting) { 52 | setImmediate(wait); 53 | return; 54 | } 55 | resolve(); 56 | }); 57 | } 58 | 59 | function processTranscriptionPart(part) { 60 | if (transcription === '') { 61 | transcription = part; 62 | return; 63 | } 64 | // add a space so that there is a break between processed segments 65 | transcription += ' ' + part; 66 | } 67 | 68 | ws.on('message', async function incoming(message) { 69 | await wait(); 70 | recv += message.length; 71 | buffers.push(message); 72 | if (recv >= bytesThreshold) { 73 | // tell next messages to wait 74 | waiting = true; 75 | var sending = Buffer.concat(buffers); 76 | recv = 0; 77 | buffers = []; 78 | var data = await stt(sending); 79 | const results = data[0].results; 80 | const part = results.map(function(result) { 81 | return result.alternatives[0].transcript; 82 | }).join('\n'); 83 | processTranscriptionPart(part); 84 | console.log("Updated transription: " + transcription); 85 | // complete the wait 86 | waiting = false; 87 | } 88 | }); 89 | }); 90 | --------------------------------------------------------------------------------