@jambonz/speech-utils 0.1.12 → 0.1.15

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.
@@ -13,6 +13,11 @@ jobs:
13
13
  with:
14
14
  node-version: lts/*
15
15
  - run: npm install
16
+ - name: Install Docker Compose
17
+ run: |
18
+ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
19
+ sudo chmod +x /usr/local/bin/docker-compose
20
+ docker-compose --version
16
21
  - run: npm run jslint
17
22
  - run: sudo apt update && sudo apt install -y squid
18
23
  - run: sudo cp test/squid.conf /etc/squid/squid.conf
package/lib/config.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const JAMBONES_TTS_TRIM_SILENCE = process.env.JAMBONES_TTS_TRIM_SILENCE;
2
2
  const JAMBONES_DISABLE_TTS_STREAMING = process.env.JAMBONES_DISABLE_TTS_STREAMING;
3
3
  const JAMBONES_DISABLE_AZURE_TTS_STREAMING = process.env.JAMBONES_DISABLE_AZURE_TTS_STREAMING;
4
+ const JAMBONES_EAGERLY_PRE_CACHE_AUDIO = process.env.JAMBONES_EAGERLY_PRE_CACHE_AUDIO;
4
5
 
5
6
  const JAMBONES_HTTP_PROXY_IP = process.env.JAMBONES_HTTP_PROXY_IP;
6
7
  const JAMBONES_HTTP_PROXY_PORT = process.env.JAMBONES_HTTP_PROXY_PORT;
@@ -18,6 +19,7 @@ module.exports = {
18
19
  JAMBONES_HTTP_PROXY_IP,
19
20
  JAMBONES_HTTP_PROXY_PORT,
20
21
  JAMBONES_TTS_CACHE_DURATION_MINS,
22
+ JAMBONES_EAGERLY_PRE_CACHE_AUDIO,
21
23
  TMP_FOLDER,
22
24
  HTTP_TIMEOUT
23
25
  };
@@ -44,6 +44,7 @@ const {
44
44
  JAMBONES_HTTP_PROXY_IP,
45
45
  JAMBONES_HTTP_PROXY_PORT,
46
46
  JAMBONES_TTS_CACHE_DURATION_MINS,
47
+ JAMBONES_EAGERLY_PRE_CACHE_AUDIO,
47
48
  } = require('./config');
48
49
  const EXPIRES = JAMBONES_TTS_CACHE_DURATION_MINS;
49
50
  const OpenAI = require('openai');
@@ -86,7 +87,7 @@ const trimTrailingSilence = (buffer) => {
86
87
  */
87
88
  async function synthAudio(client, createHash, retrieveHash, logger, stats, { account_sid,
88
89
  vendor, language, voice, gender, text, engine, salt, model, credentials, deploymentId,
89
- disableTtsCache, renderForCaching, disableTtsStreaming, options
90
+ disableTtsCache, renderForCaching = false, disableTtsStreaming, options
90
91
  }) {
91
92
  let audioBuffer;
92
93
  let servedFromCache = false;
@@ -151,21 +152,48 @@ async function synthAudio(client, createHash, retrieveHash, logger, stats, { acc
151
152
  assert.ok(voice, 'synthAudio requires voice when verbio is used');
152
153
  assert.ok(credentials.client_id, 'synthAudio requires client_id when verbio is used');
153
154
  assert.ok(credentials.client_secret, 'synthAudio requires client_secret when verbio is used');
155
+ } else if ('deepgram' === vendor) {
156
+ if (!credentials.deepgram_tts_uri) {
157
+ assert.ok(credentials.api_key, 'synthAudio requires api_key when deepgram is used');
158
+ }
159
+
154
160
  }
161
+
155
162
  const key = makeSynthKey({
156
163
  account_sid,
157
164
  vendor,
158
165
  language: language || '',
159
166
  voice: voice || deploymentId,
160
167
  engine,
161
- text
168
+ text,
169
+ renderForCaching
162
170
  });
163
171
  let filePath;
164
- filePath = makeFilePath(vendor, key, salt);
172
+ filePath = makeFilePath({vendor, key, salt, renderForCaching});
165
173
  debug(`synth key is ${key}`);
166
174
  let cached;
167
175
  if (!disableTtsCache) {
168
176
  cached = await client.get(key);
177
+ /**
178
+ * If we are using tts streaming and also precaching audio, audio could have been cached by streaming (r8)
179
+ * or here in speech-utils due to precaching (mp3), so we need to check for both keys.
180
+ */
181
+ if (!cached && JAMBONES_EAGERLY_PRE_CACHE_AUDIO) {
182
+ const preCachekey = makeSynthKey({
183
+ account_sid,
184
+ vendor,
185
+ language: language || '',
186
+ voice: voice || deploymentId,
187
+ engine,
188
+ text,
189
+ renderForCaching: true
190
+ });
191
+ cached = await client.get(preCachekey);
192
+ if (cached) {
193
+ // Precache audio is available update filpath with precache file extension.
194
+ filePath = makeFilePath({vendor, key, salt, renderForCaching: true});
195
+ }
196
+ }
169
197
  }
170
198
  if (cached) {
171
199
  // found in cache - extend the expiry and use it
@@ -909,13 +937,14 @@ const synthWhisper = async(logger, {credentials, stats, voice, text, renderForCa
909
937
  };
910
938
 
911
939
  const synthDeepgram = async(logger, {credentials, stats, model, text, renderForCaching, disableTtsStreaming}) => {
912
- const {api_key} = credentials;
940
+ const {api_key, deepgram_tts_uri} = credentials;
913
941
  if (!JAMBONES_DISABLE_TTS_STREAMING && !renderForCaching && !disableTtsStreaming) {
914
942
  let params = '';
915
943
  params += `{api_key=${api_key}`;
916
944
  params += ',vendor=deepgram';
917
945
  params += `,voice=${model}`;
918
946
  params += ',write_cache_file=1';
947
+ if (deepgram_tts_uri) params += `,endpoint=${deepgram_tts_uri}`;
919
948
  params += '}';
920
949
 
921
950
  return {
@@ -925,8 +954,9 @@ const synthDeepgram = async(logger, {credentials, stats, model, text, renderForC
925
954
  };
926
955
  }
927
956
  try {
928
- const post = bent('https://api.deepgram.com', 'POST', 'buffer', {
929
- 'Authorization': `Token ${api_key}`,
957
+ const post = bent(deepgram_tts_uri || 'https://api.deepgram.com', 'POST', 'buffer', {
958
+ // on-premise deepgram does not require to have api_key
959
+ ...(api_key && {'Authorization': `Token ${api_key}`}),
930
960
  'Accept': 'audio/mpeg',
931
961
  'Content-Type': 'application/json'
932
962
  });
package/lib/utils.js CHANGED
@@ -16,29 +16,31 @@ const debug = require('debug')('jambonz:realtimedb-helpers');
16
16
  */
17
17
  //const nuanceClientMap = new Map();
18
18
 
19
- function makeSynthKey({account_sid = '', vendor, language, voice, engine = '', text}) {
19
+ function makeSynthKey({
20
+ account_sid = '', vendor, language, voice, engine = '', text,
21
+ renderForCaching = false}) {
20
22
  const hash = crypto.createHash('sha1');
21
23
  hash.update(`${language}:${vendor}:${voice}:${engine}:${text}`);
22
24
  const hexHashKey = hash.digest('hex');
23
25
  const accountKey = account_sid ? `:${account_sid}` : '';
24
- const namespace = vendor.startsWith('custom') ? vendor : getFileExtension(vendor);
26
+ const namespace = vendor.startsWith('custom') ? vendor : getFileExtension({vendor, renderForCaching});
25
27
  const key = `tts${accountKey}:${namespace}:${hexHashKey}`;
26
28
  return key;
27
29
  }
28
30
 
29
- function makeFilePath(vendor, key, salt = '') {
30
- const extension = getFileExtension(vendor);
31
+ function makeFilePath({vendor, key, salt = '', renderForCaching = false}) {
32
+ const extension = getFileExtension({vendor, renderForCaching});
31
33
  return `${TMP_FOLDER}/${key.replace('tts:', `tts-${salt}`)}.${extension}`;
32
34
  }
33
35
 
34
- function getFileExtension(vendor) {
36
+ function getFileExtension({vendor, renderForCaching = false}) {
35
37
  const mp3Extension = 'mp3';
36
38
  const r8Extension = 'r8';
37
39
 
38
40
  switch (vendor) {
39
41
  case 'azure':
40
42
  case 'microsoft':
41
- if (!JAMBONES_DISABLE_TTS_STREAMING || JAMBONES_TTS_TRIM_SILENCE) {
43
+ if (!renderForCaching && !JAMBONES_DISABLE_TTS_STREAMING || JAMBONES_TTS_TRIM_SILENCE) {
42
44
  return r8Extension;
43
45
  } else {
44
46
  return mp3Extension;
@@ -46,7 +48,7 @@ function getFileExtension(vendor) {
46
48
  case 'deepgram':
47
49
  case 'elevenlabs':
48
50
  case 'rimlabs':
49
- if (!JAMBONES_DISABLE_TTS_STREAMING) {
51
+ if (!renderForCaching && !JAMBONES_DISABLE_TTS_STREAMING) {
50
52
  return r8Extension;
51
53
  } else {
52
54
  return mp3Extension;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jambonz/speech-utils",
3
- "version": "0.1.12",
3
+ "version": "0.1.15",
4
4
  "description": "TTS-related speech utilities for jambonz",
5
5
  "main": "index.js",
6
6
  "author": "Dave Horton",