@jambonz/speech-utils 0.1.21 → 0.1.22
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 +25 -4
- package/package.json +1 -1
- package/test/synth.js +16 -0
package/lib/synth-audio.js
CHANGED
|
@@ -170,6 +170,8 @@ async function synthAudio(client, createHash, retrieveHash, logger, stats, { acc
|
|
|
170
170
|
renderForCaching
|
|
171
171
|
});
|
|
172
172
|
let filePath;
|
|
173
|
+
// used only for custom vendor
|
|
174
|
+
let fileExtension;
|
|
173
175
|
filePath = makeFilePath({vendor, voice, key, salt, renderForCaching});
|
|
174
176
|
debug(`synth key is ${key}`);
|
|
175
177
|
let cached;
|
|
@@ -201,7 +203,17 @@ async function synthAudio(client, createHash, retrieveHash, logger, stats, { acc
|
|
|
201
203
|
debug('result WAS found in cache');
|
|
202
204
|
servedFromCache = true;
|
|
203
205
|
stats.increment('tts.cache.requests', ['found:yes']);
|
|
204
|
-
|
|
206
|
+
if (vendor.startsWith('custom')) {
|
|
207
|
+
// custom vendors support multiple mime types such as: mp3, wav, r8, r16 ...etc,
|
|
208
|
+
// mime type/file extension is available when http response has header Content-type.
|
|
209
|
+
// In cache, file extension is store together with audiBuffer in a json.
|
|
210
|
+
// Normal cache audio will be base64 string
|
|
211
|
+
const payload = JSON.parse(cached);
|
|
212
|
+
filePath = filePath.replace(/\.[^\.]*$/g, payload.fileExtension);
|
|
213
|
+
audioBuffer = Buffer.from(payload.audioBuffer, 'base64');
|
|
214
|
+
} else {
|
|
215
|
+
audioBuffer = Buffer.from(cached, 'base64');
|
|
216
|
+
}
|
|
205
217
|
client.expire(key, EXPIRES).catch((err) => logger.info(err, 'Error setting expires'));
|
|
206
218
|
}
|
|
207
219
|
if (!cached) {
|
|
@@ -268,7 +280,7 @@ async function synthAudio(client, createHash, retrieveHash, logger, stats, { acc
|
|
|
268
280
|
renderForCaching, disableTtsStreaming});
|
|
269
281
|
break;
|
|
270
282
|
case vendor.startsWith('custom') ? vendor : 'cant_match_value':
|
|
271
|
-
({ audioBuffer, filePath } = await synthCustomVendor(logger,
|
|
283
|
+
({ audioBuffer, filePath, fileExtension } = await synthCustomVendor(logger,
|
|
272
284
|
{credentials, stats, language, voice, text, filePath}));
|
|
273
285
|
break;
|
|
274
286
|
default:
|
|
@@ -282,7 +294,14 @@ async function synthAudio(client, createHash, retrieveHash, logger, stats, { acc
|
|
|
282
294
|
debug(`tts rtt time for ${text.length} chars on ${vendorLabel}: ${rtt}`);
|
|
283
295
|
logger.info(`tts rtt time for ${text.length} chars on ${vendorLabel}: ${rtt}`);
|
|
284
296
|
|
|
285
|
-
|
|
297
|
+
const base64Audio = audioBuffer.toString('base64');
|
|
298
|
+
const cacheContent = vendor.startsWith('custom') ?
|
|
299
|
+
JSON.stringify({
|
|
300
|
+
audioBuffer: base64Audio,
|
|
301
|
+
fileExtension
|
|
302
|
+
}) : base64Audio;
|
|
303
|
+
|
|
304
|
+
client.setex(key, EXPIRES, cacheContent)
|
|
286
305
|
.catch((err) => logger.error(err, `error calling setex on key ${key}`));
|
|
287
306
|
}
|
|
288
307
|
|
|
@@ -729,9 +748,11 @@ const synthCustomVendor = async(logger, {credentials, stats, language, voice, te
|
|
|
729
748
|
const regex = /\.[^\.]*$/g;
|
|
730
749
|
const mime = response.headers['content-type'];
|
|
731
750
|
const buffer = await response.arrayBuffer();
|
|
751
|
+
const fileExtension = getFileExtFromMime(mime);
|
|
732
752
|
return {
|
|
733
753
|
audioBuffer: buffer,
|
|
734
|
-
filePath: filePath.replace(regex,
|
|
754
|
+
filePath: filePath.replace(regex, fileExtension),
|
|
755
|
+
fileExtension
|
|
735
756
|
};
|
|
736
757
|
} catch (err) {
|
|
737
758
|
logger.info({err}, `Vendor ${vendor} returned error`);
|
package/package.json
CHANGED
package/test/synth.js
CHANGED
|
@@ -554,6 +554,7 @@ test('Custom Vendor speech synth tests', async(t) => {
|
|
|
554
554
|
text: 'This is a test. This is only a test',
|
|
555
555
|
});
|
|
556
556
|
t.ok(!opts.servedFromCache, `successfully synthesized custom vendor audio to ${opts.filePath}`);
|
|
557
|
+
t.ok(opts.filePath.endsWith('wav'), 'audio is cached as wav file');
|
|
557
558
|
let obj = await getJSON(`http://127.0.0.1:3100/lastRequest/somethingnew`);
|
|
558
559
|
t.ok(obj.headers.Authorization == 'Bearer some_jwt_token', 'Custom Vendor Authentication Header is correct');
|
|
559
560
|
t.ok(obj.body.language == 'en-US', 'Custom Vendor Language is correct');
|
|
@@ -561,6 +562,21 @@ test('Custom Vendor speech synth tests', async(t) => {
|
|
|
561
562
|
t.ok(obj.body.type == 'text', 'Custom Vendor type is correct');
|
|
562
563
|
t.ok(obj.body.text == 'This is a test. This is only a test', 'Custom Vendor text is correct');
|
|
563
564
|
|
|
565
|
+
// Checking if cache is stored with wav format
|
|
566
|
+
opts = await synthAudio(stats, {
|
|
567
|
+
vendor: 'custom:somethingnew',
|
|
568
|
+
credentials: {
|
|
569
|
+
use_for_tts: 1,
|
|
570
|
+
custom_tts_url: "http://127.0.0.1:3100/somethingnew",
|
|
571
|
+
auth_token: 'some_jwt_token'
|
|
572
|
+
},
|
|
573
|
+
language: 'en-US',
|
|
574
|
+
voice: 'English-US.Female-1',
|
|
575
|
+
text: 'This is a test. This is only a test',
|
|
576
|
+
});
|
|
577
|
+
t.ok(opts.servedFromCache, `successfully get custom vendor cached audio to ${opts.filePath}`);
|
|
578
|
+
t.ok(opts.filePath.endsWith('wav'), 'audio is cached as wav file');
|
|
579
|
+
|
|
564
580
|
opts = await synthAudio(stats, {
|
|
565
581
|
vendor: 'custom:somethingnew2',
|
|
566
582
|
credentials: {
|