@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.
- package/lib/synth-audio.js +63 -4
- package/lib/utils.js +0 -1
- package/package.json +2 -2
package/lib/synth-audio.js
CHANGED
|
@@ -14,7 +14,13 @@ const {
|
|
|
14
14
|
CancellationDetails,
|
|
15
15
|
SpeechSynthesisOutputFormat
|
|
16
16
|
} = sdk;
|
|
17
|
-
const {
|
|
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
|
-
|
|
381
|
+
content = `<speak>${text}</speak>`;
|
|
323
382
|
}
|
|
324
383
|
speechConfig.speechSynthesisOutputFormat = trimSilence ?
|
|
325
384
|
SpeechSynthesisOutputFormat.Raw8Khz16BitMonoPcm :
|
package/lib/utils.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jambonz/speech-utils",
|
|
3
|
-
"version": "0.0.
|
|
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.
|
|
35
|
+
"microsoft-cognitiveservices-speech-sdk": "^1.31.0",
|
|
36
36
|
"ioredis": "^5.3.2",
|
|
37
37
|
"undici": "^5.21.0"
|
|
38
38
|
},
|