UNPKG

watson-developer-cloud

Version:
191 lines 8.49 kB
"use strict"; /** * Copyright 2014 IBM Corp. All Rights Reserved. * * 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 */ var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var extend = require("extend"); var ibm_cloud_sdk_core_1 = require("ibm-cloud-sdk-core"); var pick = require("object.pick"); var stream_1 = require("stream"); var websocket = require("websocket"); var w3cWebSocket = websocket.w3cwebsocket; var PAYLOAD_PARAMS_ALLOWED = [ 'text', 'accept', 'timings' ]; var QUERY_PARAMS_ALLOWED = [ 'watson-token', 'voice', 'customization_id', 'x-watson-learning-opt-out', 'x-watson-metadata', 'access_token' ]; /** * pipe()-able Node.js Readable stream - accepts text in the constructor and emits binary audio data in its 'message' events * * Cannot be instantiated directly, instead created by calling #synthesizeUsingWebSocket() * * Uses WebSockets under the hood. * @param {Object} options * @constructor */ var SynthesizeStream = /** @class */ (function (_super) { __extends(SynthesizeStream, _super); /** * pipe()-able Node.js Readable stream - accepts text and emits binary audio data in its 'message' events * * Uses WebSockets under the hood. * * * Note that the WebSocket connection is not established until the first chunk of data is recieved. This allows for IAM token request management by the SDK. * * @param {Object} options * @param {String} options.text - The text that us to be synthesized. Provide plain text or text that is annotated with SSML. SSML input can include the SSML <mark> element. Pass a maximum of 5 KB of text. * @param {String} options.accept - The requested audio format (MIME type) of the audio. * @param {String[]} [options.timings] - An array that specifies whether the service is to return word timing information for all strings of the input text * @param {String} [options.voice='en-US_MichaelVoice'] - The voice that is to be used for the synthesis. * @param {String} [options.customization_id] - The customization ID (GUID) of a custom voice model that is to be used for the synthesis. * @param {String} [options.url='wss://stream.watsonplatform.net/speech-to-text/api'] base URL for service * @param {String} [options.watson-token] - Auth token * @param {String} [options.access_token] - IAM auth token * @param {Object} [options.headers] - Only works in Node.js, not in browsers. Allows for custom headers to be set, including an Authorization header (preventing the need for auth tokens) * @param {Boolean} [options.x-watson-learning-opt-out=false] - set to true to opt-out of allowing Watson to use this request to improve it's services * @param {String} [options.x-watson-metadata] - Associates a customer ID with data that is passed over the connection. * @param {IamTokenManagerV1} [options.token_manager] - Token manager for authenticating with IAM * @param {Boolean} [options.rejectUnauthorized] - If true, disable SSL verification for the WebSocket connection * * @constructor */ function SynthesizeStream(options) { var _this = _super.call(this, options) || this; _this.options = options; _this.initialized = false; _this.authenticated = options.token_manager ? false : true; return _this; } SynthesizeStream.prototype.initialize = function () { var options = this.options; var queryParams = pick(options, QUERY_PARAMS_ALLOWED); var queryString = ibm_cloud_sdk_core_1.qs.stringify(queryParams); var url = (options.url || 'wss://stream.watsonplatform.net/text-to-speech/api') .replace(/^http/, 'ws') + '/v1/synthesize?' + queryString; var socket = (this.socket = new w3cWebSocket(url, null, null, options.headers, null, { tlsOptions: { rejectUnauthorized: options.rejectUnauthorized } })); // use class context within arrow functions var self = this; socket.onopen = function () { var payload = pick(options, PAYLOAD_PARAMS_ALLOWED); socket.send(JSON.stringify(payload)); /** * emitted once the WebSocket connection has been established * @event SynthesizeStream#open */ self.emit('open'); }; socket.onmessage = function (message) { var chunk = message.data; // some messages are strings - emit those unencoded, but push them to // the stream as binary var data = typeof chunk === 'string' ? chunk : Buffer.from(chunk); /** * Emit any messages received over the wire, mainly used for debugging. * * @event SynthesizeStream#message * @param {Object} message - frame object received from service * @param {Object} data - a data attribute of the frame that's either a string or a Buffer/TypedArray */ self.emit('message', message, data); self.push(Buffer.from(chunk)); }; socket.onerror = function (event) { var err = new Error('WebSocket connection error'); err.name = SynthesizeStream.WEBSOCKET_CONNECTION_ERROR; err['event'] = event; self.emit('error', err); self.push(null); }; socket.onclose = function (event) { self.push(null); /** * @event SynthesizeStream#close * @param {Number} reasonCode * @param {String} description */ self.emit('close', event.code, event.reason); }; this.initialized = true; }; SynthesizeStream.prototype._read = function () { var _this = this; // even though we aren't controlling the read from websocket, // we can take advantage of the fact that _read is async and hack // this funtion to retrieve a token if the service is using IAM auth this.setAuthorizationHeaderToken(function (err) { if (err) { _this.emit('error', err); _this.push(null); return; } if (!_this.initialized) { _this.initialize(); } }); }; /** * This function retrieves an IAM access token and stores it in the * request header before calling the callback function, which will * execute the next iteration of `_read()` * * * @private * @param {Function} callback */ SynthesizeStream.prototype.setAuthorizationHeaderToken = function (callback) { var _this = this; if (!this.authenticated) { this.options.token_manager.getToken(function (err, token) { if (err) { callback(err); } var authHeader = { authorization: 'Bearer ' + token }; _this.options.headers = extend(authHeader, _this.options.headers); _this.authenticated = true; callback(null); }); } else { callback(null); } }; SynthesizeStream.WEBSOCKET_CONNECTION_ERROR = 'WebSocket connection error'; return SynthesizeStream; }(stream_1.Readable)); module.exports = SynthesizeStream; //# sourceMappingURL=synthesize-stream.js.map