@jambonz/speech-utils 0.0.19 → 0.0.21

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,48 @@ 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 trimSilence = filePath.endsWith('.r8');
335
+ const post = bent('POST', 'buffer', {
336
+ 'X-Microsoft-OutputFormat': trimSilence ? 'raw-8khz-16bit-mono-pcm' : 'audio-16khz-32kbitrate-mono-mp3',
337
+ 'Content-Type': 'application/ssml+xml',
338
+ 'User-Agent': 'Jambonz'
339
+ });
340
+ const mp3 = await post(custom_tts_endpoint_url, content);
341
+ return mp3;
342
+ } catch (err) {
343
+ logger.info({err}, '_synthMicrosoftByHttp returned error');
344
+ throw err;
345
+ }
346
+ }
347
+
300
348
  const synthMicrosoft = async(logger, {
301
349
  credentials,
302
350
  stats,
@@ -306,7 +354,17 @@ const synthMicrosoft = async(logger, {
306
354
  filePath
307
355
  }) => {
308
356
  try {
309
- const {api_key: apiKey, region, use_custom_tts, custom_tts_endpoint} = credentials;
357
+ const {api_key: apiKey, region, use_custom_tts, custom_tts_endpoint, custom_tts_endpoint_url} = credentials;
358
+ if (use_custom_tts && custom_tts_endpoint_url) {
359
+ return await _synthOnPremMicrosoft(logger, {
360
+ credentials,
361
+ stats,
362
+ language,
363
+ voice,
364
+ text,
365
+ filePath
366
+ });
367
+ }
310
368
  const trimSilence = filePath.endsWith('.r8');
311
369
  let content = text;
312
370
  const speechConfig = SpeechConfig.fromSubscription(apiKey, region);
@@ -314,12 +372,13 @@ const synthMicrosoft = async(logger, {
314
372
  speechConfig.speechSynthesisVoiceName = voice;
315
373
  if (use_custom_tts && custom_tts_endpoint) {
316
374
  speechConfig.endpointId = custom_tts_endpoint;
317
-
375
+ }
376
+ if (use_custom_tts && !content.startsWith('<speak')) {
318
377
  /**
319
378
  * Note: it seems that to use custom voice ssml is required with the voice attribute
320
379
  * Otherwise sending plain text we get "Voice does not match"
321
380
  */
322
- if (!content.startsWith('<speak')) content = `<speak>${text}</speak>`;
381
+ content = `<speak>${text}</speak>`;
323
382
  }
324
383
  speechConfig.speechSynthesisOutputFormat = trimSilence ?
325
384
  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.21",
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
  },