From 5a12633df8576e3e43a0d570b55c61237f59870b Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Thu, 30 Jun 2016 09:59:39 -0700 Subject: [PATCH 1/5] Add Speech API streaming example. --- speech/package.json | 9 ++- speech/recognize_streaming.js | 147 ++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 speech/recognize_streaming.js diff --git a/speech/package.json b/speech/package.json index 84e4f4fede..523fb7323d 100644 --- a/speech/package.json +++ b/speech/package.json @@ -9,9 +9,10 @@ "node": ">=0.10.x" }, "dependencies": { - "googleapis": "^7.1.0" - }, - "devDependencies": { - "async": "^1.5.2" + "async": "^1.5.2", + "google-auto-auth": "^0.2.4", + "google-proto-files": "^0.2.4", + "googleapis": "^7.1.0", + "grpc": "^0.15.0" } } diff --git a/speech/recognize_streaming.js b/speech/recognize_streaming.js new file mode 100644 index 0000000000..1a0dfaf983 --- /dev/null +++ b/speech/recognize_streaming.js @@ -0,0 +1,147 @@ +// Copyright 2016, Google, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +var async = require('async'); +var fs = require('fs'); +var path = require('path'); +var grpc = require('grpc'); +var googleProtoFiles = require('google-proto-files'); +var googleAuth = require('google-auto-auth'); + +// [START proto] +var PROTO_ROOT_DIR = googleProtoFiles('..'); +var PROTO_FILE_PATH = googleProtoFiles('cloud', 'speech', 'v1', 'cloud_speech.proto'); + +var protoDescriptor = grpc.load({ + root: PROTO_ROOT_DIR, + file: path.relative(PROTO_ROOT_DIR, PROTO_FILE_PATH) +}, 'proto', { + binaryAsBase64: true, + convertFieldsToCamelCase: true +}); +var speechProto = protoDescriptor.google.cloud.speech.v1; +// [END proto] + +// [START authenticating] +function getSpeechService (callback) { + var authClient = googleAuth({ + scopes: [ + 'https://www.googleapis.com/auth/cloud-platform' + ] + }); + + authClient.getAuthClient(function (err, authClient) { + if (err) { + return callback(err); + } + + var credentials = grpc.credentials.combineChannelCredentials( + grpc.credentials.createSsl(), + grpc.credentials.createFromGoogleCredential(authClient) + ); + + var stub = new speechProto.Speech('speech.googleapis.com', credentials); + return callback(null, stub); + }); +} +// [END authenticating] + +// [START construct_request] +function prepareRequest (inputFile, callback) { + fs.readFile(inputFile, function (err, audioFile) { + if (err) { + return callback(err); + } + console.log('Got audio file!'); + // var payload = new speechProto.RecognizeRequest({ + // initialRequest: new speechProto.InitialRecognizeRequest({ + // encoding: 'LINEAR16', + // sampleRate: 16000, + // interimResults: true, + // continuous: false, + // enableEndpointerEvents: true + // }), + // audioRequest: new speechProto.AudioRequest({ + // content: audioFile + // }) + // }); + return callback(null, audioFile); + }); +} +// [END construct_request] + +function main (inputFile, callback) { + var audioFile; + + async.waterfall([ + function (cb) { + prepareRequest(inputFile, cb); + }, + function (_audioFile, cb) { + audioFile = _audioFile; + getSpeechService(cb); + }, + // [START send_request] + function sendRequest (speechService, cb) { + console.log('Analyzing speech...'); + var responses = []; + var call = speechService.recognize(); + + // Listen for various responses + call.on('error', cb); + call.on('data', function (recognizeResponse) { + if (recognizeResponse) { + responses.push(recognizeResponse); + } + }); + call.on('end', function () { + cb(null, responses); + }); + + // Write the initial recognize reqeust + call.write(new speechProto.RecognizeRequest({ + initialRequest: new speechProto.InitialRecognizeRequest({ + encoding: 'LINEAR16', + sampleRate: 16000, + interimResults: false, + continuous: false, + enableEndpointerEvents: false + }) + })); + + // Write an audio request + call.write(new speechProto.RecognizeRequest({ + audioRequest: new speechProto.AudioRequest({ + content: audioFile + }) + })); + + // Signal that we're done writing + call.end(); + } + // [END send_request] + ], callback); +} + +// [START run_application] +if (module === require.main) { + if (process.argv.length < 3) { + console.log('Usage: node recognize_streaming '); + process.exit(); + } + var inputFile = process.argv[2]; + main(inputFile, console.log); +} +// [END run_application] From babecf95b7f3a56daa2b0b52297a3517c33765b0 Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Thu, 30 Jun 2016 10:02:38 -0700 Subject: [PATCH 2/5] Remove comment. --- speech/recognize_streaming.js | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/speech/recognize_streaming.js b/speech/recognize_streaming.js index 1a0dfaf983..6015b1a525 100644 --- a/speech/recognize_streaming.js +++ b/speech/recognize_streaming.js @@ -59,24 +59,12 @@ function getSpeechService (callback) { // [END authenticating] // [START construct_request] -function prepareRequest (inputFile, callback) { +function getAudioFile (inputFile, callback) { fs.readFile(inputFile, function (err, audioFile) { if (err) { return callback(err); } console.log('Got audio file!'); - // var payload = new speechProto.RecognizeRequest({ - // initialRequest: new speechProto.InitialRecognizeRequest({ - // encoding: 'LINEAR16', - // sampleRate: 16000, - // interimResults: true, - // continuous: false, - // enableEndpointerEvents: true - // }), - // audioRequest: new speechProto.AudioRequest({ - // content: audioFile - // }) - // }); return callback(null, audioFile); }); } @@ -87,7 +75,7 @@ function main (inputFile, callback) { async.waterfall([ function (cb) { - prepareRequest(inputFile, cb); + getAudioFile(inputFile, cb); }, function (_audioFile, cb) { audioFile = _audioFile; From 750a6c1c41e04295da82780a9591be1a065c428d Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Thu, 30 Jun 2016 10:10:44 -0700 Subject: [PATCH 3/5] Add test. --- speech/README.md | 15 +++++++++++ speech/recognize_streaming.js | 3 +++ test/speech/recognize_streaming.test.js | 35 +++++++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 test/speech/recognize_streaming.test.js diff --git a/speech/README.md b/speech/README.md index 5a32bcfaac..6be6555ea6 100644 --- a/speech/README.md +++ b/speech/README.md @@ -42,3 +42,18 @@ Example: [recognition_docs]: https://cloud.google.com/speech/ [recognition_code]: recognize.js + +### Recognition (Streaming) + +View the [documentation][recognition_streaming_docs] or the [source code][recognition_streaming_code]. + +__Run the sample:__ + +Usage: `node recognize_streaming ` + +Example: + + node recognize_streaming "/path/to/audio.file" + +[recognition_streaming_docs]: https://cloud.google.com/speech/ +[recognition_streaming_code]: recognize_streaming.js diff --git a/speech/recognize_streaming.js b/speech/recognize_streaming.js index 6015b1a525..b15e9133ba 100644 --- a/speech/recognize_streaming.js +++ b/speech/recognize_streaming.js @@ -52,6 +52,7 @@ function getSpeechService (callback) { grpc.credentials.createFromGoogleCredential(authClient) ); + console.log('Loading speech service...'); var stub = new speechProto.Speech('speech.googleapis.com', credentials); return callback(null, stub); }); @@ -133,3 +134,5 @@ if (module === require.main) { main(inputFile, console.log); } // [END run_application] + +exports.main = main; diff --git a/test/speech/recognize_streaming.test.js b/test/speech/recognize_streaming.test.js new file mode 100644 index 0000000000..f3dff00f52 --- /dev/null +++ b/test/speech/recognize_streaming.test.js @@ -0,0 +1,35 @@ +// Copyright 2016, Google, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +var path = require('path'); +var recognizeExample = require('../../speech/recognize_streaming'); + +describe('speech:recognize_streaming', function () { + it('should list entries', function (done) { + recognizeExample.main( + path.join(__dirname, '../../speech/resources/audio.raw'), + function (err, results) { + assert(!err); + assert(results); + assert(results.length === 1); + assert(results[0].results); + assert(console.log.calledWith('Got audio file!')); + assert(console.log.calledWith('Loading speech service...')); + assert(console.log.calledWith('Analyzing speech...')); + done(); + } + ); + }); +}); From f5a710fe31c0e673dc1b2c71060823b7c4015d50 Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Thu, 30 Jun 2016 10:18:31 -0700 Subject: [PATCH 4/5] Fix failing test. --- test/functions/sendgrid.test.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/functions/sendgrid.test.js b/test/functions/sendgrid.test.js index 9c3b84cf38..470e5013b3 100644 --- a/test/functions/sendgrid.test.js +++ b/test/functions/sendgrid.test.js @@ -175,7 +175,7 @@ function getMockContext () { }; } -describe('functions:pubsub', function () { +describe('functions:sendgrid', function () { it('Send fails if not a POST request', function () { var expectedMsg = 'Only POST requests are accepted'; var mocks = getMocks(); @@ -566,7 +566,9 @@ describe('functions:pubsub', function () { bucket: 'event-bucket', name: name }); - + sendgridSample.mocks.job.on('error', function (err) { + assert.equal(err, error); + }); setTimeout(function () { sendgridSample.mocks.job.emit('error', error); }, 10); From 88f1399171982c089cc535b7f3062f1e251cc73e Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Thu, 30 Jun 2016 12:41:58 -0700 Subject: [PATCH 5/5] Rename variable. --- speech/recognize_streaming.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/speech/recognize_streaming.js b/speech/recognize_streaming.js index b15e9133ba..9bf67f6350 100644 --- a/speech/recognize_streaming.js +++ b/speech/recognize_streaming.js @@ -36,13 +36,13 @@ var speechProto = protoDescriptor.google.cloud.speech.v1; // [START authenticating] function getSpeechService (callback) { - var authClient = googleAuth({ + var googleAuthClient = googleAuth({ scopes: [ 'https://www.googleapis.com/auth/cloud-platform' ] }); - authClient.getAuthClient(function (err, authClient) { + googleAuthClient.getAuthClient(function (err, authClient) { if (err) { return callback(err); }