@jambonz/speech-utils 0.0.19 → 0.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,7 +14,13 @@ const {
14
14
  CancellationDetails,
15
15
  SpeechSynthesisOutputFormat
16
16
  } = sdk;
17
- const {makeSynthKey, createNuanceClient, createKryptonClient, createRivaClient, noopLogger} = require('./utils');
17
+ const {
18
+ makeSynthKey,
19
+ createNuanceClient,
20
+ createKryptonClient,
21
+ createRivaClient,
22
+ noopLogger
23
+ } = require('./utils');
18
24
  const getNuanceAccessToken = require('./get-nuance-access-token');
19
25
  const {
20
26
  SynthesisRequest,
@@ -297,6 +303,47 @@ const synthIbm = async(logger, {credentials, stats, voice, text}) => {
297
303
  }
298
304
  };
299
305
 
306
+ async function _synthOnPremMicrosoft(logger, {
307
+ credentials,
308
+ stats,
309
+ language,
310
+ voice,
311
+ text,
312
+ filePath
313
+ }) {
314
+ const {use_custom_tts, custom_tts_endpoint_url} = credentials;
315
+ let content = text;
316
+
317
+ if (use_custom_tts && !content.startsWith('<speak')) {
318
+ /**
319
+ * Note: it seems that to use custom voice ssml is required with the voice attribute
320
+ * Otherwise sending plain text we get "Voice does not match"
321
+ */
322
+ content = `<speak>${text}</speak>`;
323
+ }
324
+
325
+ if (content.startsWith('<speak>')) {
326
+ /* microsoft enforces some properties and uses voice xml element so if the user did not supply do it for them */
327
+ const words = content.slice(7, -8).trim().replace(/(\r\n|\n|\r)/gm, ' ');
328
+ // eslint-disable-next-line max-len
329
+ content = `<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="https://www.w3.org/2001/mstts" xml:lang="${language}"><voice name="${voice}">${words}</voice></speak>`;
330
+ logger.info({content}, 'synthMicrosoft');
331
+ }
332
+
333
+ try {
334
+ const post = bent('POST', 'buffer', {
335
+ 'X-Microsoft-OutputFormat': 'audio-16khz-128kbitrate-mono-mp3',
336
+ 'Content-Type': 'application/ssml+xml',
337
+ 'User-Agent': 'Jambonz'
338
+ });
339
+ const mp3 = await post(custom_tts_endpoint_url, content);
340
+ return mp3;
341
+ } catch (err) {
342
+ logger.info({err}, '_synthMicrosoftByHttp returned error');
343
+ throw err;
344
+ }
345
+ }
346
+
300
347
  const synthMicrosoft = async(logger, {
301
348
  credentials,
302
349
  stats,
@@ -306,7 +353,17 @@ const synthMicrosoft = async(logger, {
306
353
  filePath
307
354
  }) => {
308
355
  try {
309
- const {api_key: apiKey, region, use_custom_tts, custom_tts_endpoint} = credentials;
356
+ const {api_key: apiKey, region, use_custom_tts, custom_tts_endpoint, custom_tts_endpoint_url} = credentials;
357
+ if (use_custom_tts && custom_tts_endpoint_url) {
358
+ return await _synthOnPremMicrosoft(logger, {
359
+ credentials,
360
+ stats,
361
+ language,
362
+ voice,
363
+ text,
364
+ filePath
365
+ });
366
+ }
310
367
  const trimSilence = filePath.endsWith('.r8');
311
368
  let content = text;
312
369
  const speechConfig = SpeechConfig.fromSubscription(apiKey, region);
@@ -314,12 +371,13 @@ const synthMicrosoft = async(logger, {
314
371
  speechConfig.speechSynthesisVoiceName = voice;
315
372
  if (use_custom_tts && custom_tts_endpoint) {
316
373
  speechConfig.endpointId = custom_tts_endpoint;
317
-
374
+ }
375
+ if (use_custom_tts && !content.startsWith('<speak')) {
318
376
  /**
319
377
  * Note: it seems that to use custom voice ssml is required with the voice attribute
320
378
  * Otherwise sending plain text we get "Voice does not match"
321
379
  */
322
- if (!content.startsWith('<speak')) content = `<speak>${text}</speak>`;
380
+ content = `<speak>${text}</speak>`;
323
381
  }
324
382
  speechConfig.speechSynthesisOutputFormat = trimSilence ?
325
383
  SpeechSynthesisOutputFormat.Raw8Khz16BitMonoPcm :
package/lib/utils.js CHANGED
@@ -106,7 +106,6 @@ const createRivaClient = async(rivaUri) => {
106
106
  return client;
107
107
  };
108
108
 
109
-
110
109
  module.exports = {
111
110
  makeSynthKey,
112
111
  makeNuanceKey,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jambonz/speech-utils",
3
- "version": "0.0.19",
3
+ "version": "0.0.20",
4
4
  "description": "TTS-related speech utilities for jambonz",
5
5
  "main": "index.js",
6
6
  "author": "Dave Horton",
@@ -32,7 +32,7 @@
32
32
  "form-urlencoded": "^6.1.0",
33
33
  "google-protobuf": "^3.21.2",
34
34
  "ibm-watson": "^8.0.0",
35
- "microsoft-cognitiveservices-speech-sdk": "^1.26.0",
35
+ "microsoft-cognitiveservices-speech-sdk": "^1.31.0",
36
36
  "ioredis": "^5.3.2",
37
37
  "undici": "^5.21.0"
38
38
  },