@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.
@@ -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
- audioBuffer = Buffer.from(cached, 'base64');
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
- client.setex(key, EXPIRES, audioBuffer.toString('base64'))
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, getFileExtFromMime(mime))
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jambonz/speech-utils",
3
- "version": "0.1.21",
3
+ "version": "0.1.22",
4
4
  "description": "TTS-related speech utilities for jambonz",
5
5
  "main": "index.js",
6
6
  "author": "Dave Horton",
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: {