echogarden 2.1.2 → 2.2.1
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/README.md +6 -1
- package/data/lexicons/heteronyms.en.json +31 -6
- package/data/lexicons/words.en.json +60 -0
- package/data/schemas/options.json +20 -4
- package/dist/api/Recognition.d.ts +3 -1
- package/dist/api/Recognition.js +17 -0
- package/dist/api/Recognition.js.map +1 -1
- package/dist/api/Synthesis.d.ts +2 -2
- package/dist/api/Synthesis.js +3 -3
- package/dist/api/Synthesis.js.map +1 -1
- package/dist/codecs/FFMpegTranscoder.js +2 -0
- package/dist/codecs/FFMpegTranscoder.js.map +1 -1
- package/dist/nlp/EspeakPhonemizer.d.ts +2 -2
- package/dist/nlp/EspeakPhonemizer.js +36 -36
- package/dist/nlp/PhoneConversion.d.ts +1 -0
- package/dist/nlp/PhoneConversion.js +151 -222
- package/dist/nlp/PhoneConversion.js.map +1 -1
- package/dist/recognition/DeepgramSTT.d.ts +11 -0
- package/dist/recognition/DeepgramSTT.js +64 -0
- package/dist/recognition/DeepgramSTT.js.map +1 -0
- package/dist/recognition/GoogleCloudSTT.js.map +1 -1
- package/dist/synthesis/{ElevenlabsTTS.d.ts → ElevenLabsTTS.d.ts} +3 -3
- package/dist/synthesis/{ElevenlabsTTS.js → ElevenLabsTTS.js} +3 -3
- package/dist/synthesis/{ElevenlabsTTS.js.map → ElevenLabsTTS.js.map} +1 -1
- package/dist/synthesis/EspeakTTS.d.ts +1 -1
- package/dist/synthesis/EspeakTTS.js +11 -7
- package/dist/synthesis/EspeakTTS.js.map +1 -1
- package/dist/synthesis/KokoroTTS.js +14 -14
- package/dist/synthesis/VitsTTS.js +9 -9
- package/dist/utilities/Utilities.d.ts +1 -0
- package/dist/utilities/Utilities.js +5 -0
- package/dist/utilities/Utilities.js.map +1 -1
- package/dist/utilities/WasmMemoryManager.d.ts +1 -1
- package/docs/CUDA.md +6 -6
- package/docs/Development.md +1 -1
- package/docs/Engines.md +1 -0
- package/docs/Options.md +5 -1
- package/package.json +6 -6
- package/src/api/Recognition.ts +29 -1
- package/src/api/Synthesis.ts +7 -7
- package/src/codecs/FFMpegTranscoder.ts +2 -0
- package/src/nlp/EspeakPhonemizer.ts +36 -36
- package/src/nlp/PhoneConversion.ts +176 -225
- package/src/recognition/DeepgramSTT.ts +136 -0
- package/src/recognition/GoogleCloudSTT.ts +0 -1
- package/src/synthesis/{ElevenlabsTTS.ts → ElevenLabsTTS.ts} +4 -4
- package/src/synthesis/EspeakTTS.ts +12 -7
- package/src/synthesis/KokoroTTS.ts +15 -15
- package/src/synthesis/VitsTTS.ts +9 -9
- package/src/utilities/Utilities.ts +6 -0
|
@@ -5,7 +5,7 @@ export function ipaPhoneToKirshenbaum(ipaPhone: string) {
|
|
|
5
5
|
const convertedChar = ipaToKirshenbaum[char]
|
|
6
6
|
|
|
7
7
|
if (convertedChar == undefined) {
|
|
8
|
-
throw new Error(`
|
|
8
|
+
throw new Error(`Couldn't convert IPA character '${char}' (part of phone '${ipaPhone}' the Kirshenbaum notation`)
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
result += convertedChar || '_'
|
|
@@ -252,257 +252,208 @@ const ipaToTimit: { [p: string]: string[] | undefined } = {
|
|
|
252
252
|
'ɾ': ['dx'],
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
'
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
'ɪ': 'I',
|
|
300
|
-
'ɟ': 'J',
|
|
301
|
-
'K': 'K',
|
|
302
|
-
'ɫ': 'L',
|
|
303
|
-
'ɱ': 'M',
|
|
304
|
-
'ŋ': 'N',
|
|
305
|
-
'ɔ': 'O',
|
|
306
|
-
'Φ': 'P',
|
|
307
|
-
'ɣ': 'Q',
|
|
308
|
-
'ʀ': 'R',
|
|
309
|
-
'ʃ': 'S',
|
|
310
|
-
'θ': 'T',
|
|
311
|
-
'ʊ': 'U',
|
|
312
|
-
'ʌ': 'V',
|
|
313
|
-
'œ': 'W',
|
|
314
|
-
'χ': 'X',
|
|
315
|
-
'ø': 'Y',
|
|
316
|
-
'ʒ': 'Z',
|
|
317
|
-
'̪': '[',
|
|
318
|
-
'\\': '\\',
|
|
319
|
-
']': ']',
|
|
320
|
-
'^': '^',
|
|
321
|
-
'_': '_',
|
|
322
|
-
'`': '`',
|
|
323
|
-
'a': 'a',
|
|
324
|
-
'b': 'b',
|
|
325
|
-
'c': 'c',
|
|
326
|
-
'd': 'd',
|
|
327
|
-
'e': 'e',
|
|
328
|
-
'f': 'f',
|
|
329
|
-
'ɡ': 'g',
|
|
330
|
-
'h': 'h',
|
|
331
|
-
'i': 'i',
|
|
332
|
-
'j': 'j',
|
|
333
|
-
'k': 'k',
|
|
334
|
-
'l': 'l',
|
|
335
|
-
'm': 'm',
|
|
336
|
-
'n': 'n',
|
|
337
|
-
'o': 'o',
|
|
338
|
-
'p': 'p',
|
|
339
|
-
'q': 'q',
|
|
340
|
-
'r': 'r',
|
|
341
|
-
's': 's',
|
|
342
|
-
't': 't',
|
|
343
|
-
'u': 'u',
|
|
344
|
-
'v': 'v',
|
|
345
|
-
'w': 'w',
|
|
346
|
-
'x': 'x',
|
|
347
|
-
'y': 'y',
|
|
348
|
-
'z': 'z',
|
|
349
|
-
'{': '{',
|
|
350
|
-
'|': '|',
|
|
351
|
-
'}': '}',
|
|
352
|
-
'̃': '~',
|
|
353
|
-
'': '',
|
|
354
|
-
|
|
355
|
-
// Extensions
|
|
356
|
-
'ɚ': '3',
|
|
357
|
-
'ɹ': 'r',
|
|
255
|
+
export const ipaToKirshenbaum: Record<string, string> = {
|
|
256
|
+
//// Vowels
|
|
257
|
+
|
|
258
|
+
// Close
|
|
259
|
+
'i': 'i',
|
|
260
|
+
'y': 'y',
|
|
261
|
+
'ɨ': 'i"',
|
|
262
|
+
'ʉ': 'u"',
|
|
263
|
+
'ɯ': 'u-',
|
|
264
|
+
'u': 'u',
|
|
265
|
+
|
|
266
|
+
// Near-close
|
|
267
|
+
'ɪ': 'I',
|
|
268
|
+
'ɩ': 'I',
|
|
269
|
+
'ᵻ': 'I',
|
|
270
|
+
'ʏ': 'I.',
|
|
271
|
+
'ʊ': 'U',
|
|
272
|
+
'ɷ': 'U',
|
|
273
|
+
|
|
274
|
+
// Close-mid
|
|
275
|
+
'e': 'e',
|
|
276
|
+
'ø': 'Y',
|
|
277
|
+
//'ɘ': '@<umd>', // Reference
|
|
278
|
+
'ɘ': '@', // Simplified
|
|
279
|
+
'ɵ': '@.',
|
|
280
|
+
//'ɵ': '8', // eSpeak
|
|
281
|
+
'ɤ': 'o-',
|
|
282
|
+
'o': 'o',
|
|
283
|
+
|
|
284
|
+
// Mid:
|
|
285
|
+
'ə': '@',
|
|
286
|
+
|
|
287
|
+
// Open-mid:
|
|
288
|
+
'ɛ': 'E',
|
|
289
|
+
'œ': 'W',
|
|
290
|
+
//'ɜ': '3', // eSpeak
|
|
291
|
+
'ɜ': 'V"',
|
|
292
|
+
'ɞ': 'O"',
|
|
293
|
+
'ʌ': 'V',
|
|
294
|
+
'ɔ': 'O',
|
|
295
|
+
|
|
296
|
+
// Near-open
|
|
297
|
+
//'æ': '&', // Reference. note: passing '&' to eSpeak in SSML (XML) mode will cause an error due to escaping conflict
|
|
298
|
+
'æ': 'a', // eSpeak
|
|
358
299
|
'ɐ': 'a#',
|
|
359
|
-
'ᵻ': 'i',
|
|
360
|
-
'̩': ','
|
|
361
|
-
}
|
|
362
300
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
//
|
|
366
|
-
|
|
367
|
-
|
|
301
|
+
// Open
|
|
302
|
+
'a': 'a',
|
|
303
|
+
//'ɶ': '&.', // Reference. note: passing '&' to eSpeak in SSML (XML) mode will cause an error due to escaping conflict
|
|
304
|
+
'ɶ': 'W#', // eSpeak
|
|
305
|
+
'ä': 'a"',
|
|
306
|
+
'ɒ̈': 'A".',
|
|
307
|
+
'ɑ': 'A',
|
|
308
|
+
//'ɒ': 'A.', // Reference
|
|
309
|
+
'ɒ': '0', // eSpeak
|
|
310
|
+
|
|
311
|
+
// Rhotic
|
|
312
|
+
'ɚ': 'R',
|
|
313
|
+
//'ɚ': '3', // eSpeak
|
|
314
|
+
//'ɝ': 'R<umd>', // Reference
|
|
315
|
+
'ɝ': 'R', // Simplified
|
|
316
|
+
|
|
317
|
+
// More vowels
|
|
318
|
+
'ᵊ': '',
|
|
319
|
+
|
|
320
|
+
//// Consonants
|
|
321
|
+
|
|
322
|
+
// Nasals
|
|
368
323
|
'm': 'm',
|
|
324
|
+
'ɱ': 'M',
|
|
325
|
+
'n̪': 'n[',
|
|
326
|
+
'n': 'n',
|
|
327
|
+
'ɳ': 'n.',
|
|
328
|
+
'ṇ': 'n.',
|
|
329
|
+
'ɲ': 'n^',
|
|
330
|
+
'ŋ': 'N',
|
|
331
|
+
'ɴ': 'n"',
|
|
332
|
+
//'n͡g': 'n<lbv>',
|
|
333
|
+
|
|
334
|
+
// Stops
|
|
369
335
|
'p': 'p',
|
|
370
336
|
'b': 'b',
|
|
337
|
+
't̪': 't[',
|
|
338
|
+
'd̪': 'd[',
|
|
339
|
+
't': 't',
|
|
340
|
+
'd': 'd',
|
|
341
|
+
'ʈ': 't.',
|
|
342
|
+
'ṭ': 't.',
|
|
343
|
+
'ɖ': 'd.',
|
|
344
|
+
'ḍ': 'd.',
|
|
345
|
+
'c': 'c',
|
|
346
|
+
'ɟ': 'J',
|
|
347
|
+
'k': 'k',
|
|
348
|
+
'ɡ': 'g',
|
|
349
|
+
'q': 'q',
|
|
350
|
+
'ɢ': 'G',
|
|
351
|
+
//'k͡p': 't<lbv>',
|
|
352
|
+
//'ɡ͡b': 'd<lbv>',
|
|
353
|
+
'ʔ': '?',
|
|
354
|
+
|
|
355
|
+
// Fricatives
|
|
356
|
+
'φ': 'P',
|
|
371
357
|
'Φ': 'P',
|
|
372
358
|
'β': 'B',
|
|
373
|
-
'ʙ': 'b<trl>',
|
|
374
|
-
'pʼ': 'p`',
|
|
375
|
-
'ɓ': 'b`',
|
|
376
|
-
'ʘ': 'p!',
|
|
377
|
-
'ɱ': 'M',
|
|
378
359
|
'f': 'f',
|
|
379
360
|
'v': 'v',
|
|
380
|
-
'ʋ': 'r<lbd>',
|
|
381
|
-
'n\u032a': 'n[',
|
|
382
|
-
't\u032a': 't[',
|
|
383
361
|
'θ': 'T',
|
|
384
362
|
'ð': 'D',
|
|
385
|
-
'r\u032a': 'r[',
|
|
386
|
-
'l\u032a': 'l[',
|
|
387
|
-
't\u032a\u02bc': 't[`',
|
|
388
|
-
'ɗ': 'd`',
|
|
389
|
-
'ʇ': 't!',
|
|
390
|
-
'n': 'n',
|
|
391
|
-
't': 't',
|
|
392
|
-
'd': 'd',
|
|
393
363
|
's': 's',
|
|
394
364
|
'z': 'z',
|
|
395
|
-
'ɬ': 's<lat>',
|
|
396
|
-
'ɮ': 'z<lat>',
|
|
397
|
-
'ɹ': 'r',
|
|
398
|
-
'l': 'l',
|
|
399
|
-
'ʀ': 'r<trl>',
|
|
400
|
-
'ɾ': '*',
|
|
401
|
-
'ɺ': '*<lat>',
|
|
402
|
-
't\u02bc': 't`',
|
|
403
|
-
'ʗ': 'c!',
|
|
404
|
-
'ʖ': 'l!',
|
|
405
|
-
'ɳ': 'n.',
|
|
406
|
-
'ʈ': 't.',
|
|
407
|
-
'ɖ': 'd.',
|
|
408
365
|
'ʂ': 's.',
|
|
366
|
+
'ṣ': 's.',
|
|
409
367
|
'ʐ': 'z.',
|
|
410
|
-
|
|
411
|
-
'ɭ': 'l.',
|
|
412
|
-
'ɽ': '*.',
|
|
368
|
+
'ẓ': 'z.',
|
|
413
369
|
'ʃ': 'S',
|
|
414
370
|
'ʒ': 'Z',
|
|
415
|
-
'n^': 'n^',
|
|
416
|
-
'c': 'c',
|
|
417
|
-
'ɟ': 'J',
|
|
418
371
|
'ç': 'C',
|
|
419
372
|
'ʝ': 'C<vcd>',
|
|
420
|
-
'j': 'j',
|
|
421
|
-
'ɥ': 'j<rnd>',
|
|
422
|
-
'ʎ': 'l^',
|
|
423
|
-
'ʄ': 'J`',
|
|
424
|
-
'ŋ': 'N',
|
|
425
|
-
'k': 'k',
|
|
426
|
-
'g': 'g',
|
|
427
373
|
'x': 'x',
|
|
428
374
|
'ɣ': 'Q',
|
|
429
|
-
'
|
|
430
|
-
'
|
|
431
|
-
//'
|
|
432
|
-
'k\u02bc': 'k`',
|
|
433
|
-
'g\u02bc': 'g`',
|
|
434
|
-
'ʞ': 'k!',
|
|
435
|
-
'n\u2030g': 'n<lbv>',
|
|
436
|
-
'k\u2030p': 't<lbv>',
|
|
437
|
-
'g\u2030b': 'n<lbv>',
|
|
375
|
+
'χ': 'X',
|
|
376
|
+
'ʁ': 'g"', // Reference
|
|
377
|
+
//'ʁ': 'r', // eSpeak
|
|
438
378
|
'ʍ': 'w<vls>',
|
|
439
379
|
'w': 'w',
|
|
440
|
-
'ɴ': 'n'',
|
|
441
|
-
'q': 'q',
|
|
442
|
-
'ɢ': 'G',
|
|
443
|
-
'χ': 'X',
|
|
444
|
-
'ʁ': 'g'',
|
|
445
|
-
//'ʀ': 'r'',
|
|
446
|
-
'ʠ': 'q`',
|
|
447
|
-
'ʛ': 'G`',
|
|
448
380
|
'ħ': 'H',
|
|
449
381
|
'ʕ': 'H<vcd>',
|
|
450
|
-
'ʔ': '?',
|
|
451
382
|
'h': 'h',
|
|
452
383
|
'ɦ': 'h<?>',
|
|
453
|
-
'i': 'i',
|
|
454
|
-
'y': 'y',
|
|
455
|
-
'ɪ': 'I',
|
|
456
|
-
'ʏ': 'I.',
|
|
457
|
-
'e': 'e',
|
|
458
|
-
'ø': 'Y',
|
|
459
|
-
'ɛ': 'E',
|
|
460
|
-
'œ': 'W',
|
|
461
|
-
'æ': '&',
|
|
462
|
-
'ɶ': '&.',
|
|
463
|
-
'ɨ': 'i'',
|
|
464
|
-
'ʉ': 'u'',
|
|
465
|
-
'ɘ': '@<umd>',
|
|
466
|
-
'ɝ': 'R<umd>',
|
|
467
|
-
'ə': '@',
|
|
468
|
-
'ɚ': 'R',
|
|
469
|
-
'ɵ': '@.',
|
|
470
|
-
//'ɜ': 'V'',
|
|
471
|
-
'ɜ': '3',
|
|
472
|
-
'ɞ': 'O'',
|
|
473
|
-
'a': 'a',
|
|
474
|
-
'ɯ': 'u-',
|
|
475
|
-
'u': 'u',
|
|
476
|
-
'ʊ': 'U',
|
|
477
|
-
'ɤ': 'o-',
|
|
478
|
-
'o': 'o',
|
|
479
|
-
'ʌ': 'V',
|
|
480
|
-
'ɔ': 'O',
|
|
481
|
-
'ɑ': 'A',
|
|
482
|
-
'ɒ': 'A.',
|
|
483
384
|
|
|
484
|
-
|
|
485
|
-
'
|
|
486
|
-
'
|
|
487
|
-
'
|
|
488
|
-
'
|
|
489
|
-
''
|
|
490
|
-
'
|
|
491
|
-
'
|
|
492
|
-
'
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
'
|
|
497
|
-
'
|
|
498
|
-
'
|
|
499
|
-
|
|
500
|
-
'
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
'
|
|
385
|
+
// Approximants
|
|
386
|
+
'ʋ': 'r<lbd>',
|
|
387
|
+
'ɹ̪': 'r[',
|
|
388
|
+
'ɹ': 'r',
|
|
389
|
+
'ɻ': 'r.',
|
|
390
|
+
'ɻ̣': 'r.',
|
|
391
|
+
'j': 'j',
|
|
392
|
+
'ɥ': 'j<rnd>',
|
|
393
|
+
'ɰ': 'j<vel>',
|
|
394
|
+
|
|
395
|
+
// Laterals
|
|
396
|
+
'l̪': 'l[',
|
|
397
|
+
'l': 'l',
|
|
398
|
+
'ɭ': 'l.',
|
|
399
|
+
'ḷ': 'l.',
|
|
400
|
+
'ʎ': 'l^',
|
|
401
|
+
'ʟ': 'L',
|
|
402
|
+
|
|
403
|
+
// Trills
|
|
404
|
+
'ʙ': 'b<trl>',
|
|
405
|
+
//'r': 'r<trl>', // Reference alv trl
|
|
406
|
+
'r': 'R', // eSpeak
|
|
407
|
+
'ʀ': 'r"', // Reference uvl trl
|
|
408
|
+
|
|
409
|
+
// Flaps
|
|
410
|
+
'ɾ': '*',
|
|
411
|
+
'ɽ': '*.',
|
|
412
|
+
'ṛ': '*.',
|
|
413
|
+
|
|
414
|
+
// Ejectives
|
|
415
|
+
'pʼ': 'p`',
|
|
416
|
+
'tʼ': 't`',
|
|
417
|
+
'cʼ': 'c`',
|
|
418
|
+
'kʼ': 'k`',
|
|
419
|
+
'qʼ': 'q`',
|
|
420
|
+
'ʠ': 'q`',
|
|
421
|
+
|
|
422
|
+
// Implosives
|
|
423
|
+
'ɓ': 'b`',
|
|
424
|
+
'ɗ': 'd`',
|
|
425
|
+
'ʄ': 'J`',
|
|
426
|
+
'ɠ': 'g`',
|
|
427
|
+
'ʛ': 'G`',
|
|
428
|
+
|
|
429
|
+
// Clicks
|
|
430
|
+
'ʘ': 'p!',
|
|
431
|
+
'ǀ': 't!',
|
|
432
|
+
'ʇ': 't!',
|
|
433
|
+
'ǃ': 'c!',
|
|
434
|
+
'ǂ': 'c!',
|
|
435
|
+
'ʗ': 'c!',
|
|
436
|
+
'ʞ': 'k!',
|
|
437
|
+
'ǁ': 'l!',
|
|
438
|
+
'ʖ': 'l!',
|
|
439
|
+
|
|
440
|
+
// Lateral fricative
|
|
441
|
+
'ɬ': 'L',
|
|
442
|
+
'ɮ': 'z<lat>',
|
|
443
|
+
'ɫ': 'L',
|
|
444
|
+
|
|
445
|
+
// Lateral flap
|
|
446
|
+
'ɺ': '*<lat>',
|
|
447
|
+
|
|
448
|
+
// Other consonants
|
|
449
|
+
'ʰ': '#',
|
|
450
|
+
'ʲ': ';',
|
|
451
|
+
'̪': '[',
|
|
452
|
+
'̃': '~',
|
|
453
|
+
|
|
454
|
+
// Stress marks and other misc characters
|
|
455
|
+
'ˈ': '\'',
|
|
504
456
|
'ˌ': ',',
|
|
505
|
-
'
|
|
506
|
-
'
|
|
457
|
+
'ː': ':',
|
|
458
|
+
'-': '-',
|
|
507
459
|
}
|
|
508
|
-
*/
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { request } from 'gaxios'
|
|
2
|
+
import { RawAudio } from '../audio/AudioUtilities.js'
|
|
3
|
+
import { Logger } from '../utilities/Logger.js'
|
|
4
|
+
import { extendDeep } from '../utilities/ObjectUtilities.js'
|
|
5
|
+
import { Timeline, TimelineEntry } from '../utilities/Timeline.js'
|
|
6
|
+
import * as FFMpegTranscoder from '../codecs/FFMpegTranscoder.js'
|
|
7
|
+
|
|
8
|
+
export async function recognize(rawAudio: RawAudio, languageCode: string | undefined, options: DeepgramSTTOptions) {
|
|
9
|
+
const logger = new Logger()
|
|
10
|
+
|
|
11
|
+
logger.start('Initialize Deepgram recognition')
|
|
12
|
+
|
|
13
|
+
options = extendDeep(defaultDeepgramSTTOptions, options)
|
|
14
|
+
|
|
15
|
+
if (!options.apiKey) {
|
|
16
|
+
throw new Error('No Deepgram API key provided')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Prepare API request
|
|
20
|
+
const params: Record<string, string> = {
|
|
21
|
+
model: options.model || 'whisper-large',
|
|
22
|
+
encoding: 'flac',
|
|
23
|
+
//punctuate: 'true', // Problem when enabled: words in timeline are not capitalized, causing errors
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Set language or enable auto-detection
|
|
27
|
+
if (languageCode) {
|
|
28
|
+
params.language = languageCode
|
|
29
|
+
} else {
|
|
30
|
+
params.detect_language = 'true'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Set audio encoding parameters
|
|
34
|
+
logger.start('Convert audio to FLAC format')
|
|
35
|
+
|
|
36
|
+
const audioData = await FFMpegTranscoder.encodeFromChannels(
|
|
37
|
+
rawAudio,
|
|
38
|
+
FFMpegTranscoder.getDefaultFFMpegOptionsForSpeech('flac')
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
logger.start('Send request to Deepgram API')
|
|
42
|
+
|
|
43
|
+
const response = await request<any>({
|
|
44
|
+
method: 'POST',
|
|
45
|
+
|
|
46
|
+
url: 'https://api.deepgram.com/v1/listen',
|
|
47
|
+
|
|
48
|
+
params,
|
|
49
|
+
|
|
50
|
+
headers: {
|
|
51
|
+
'Authorization': `Token ${options.apiKey}`,
|
|
52
|
+
'Content-Type': 'audio/flac',
|
|
53
|
+
'Accept': 'application/json'
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
body: audioData,
|
|
57
|
+
|
|
58
|
+
responseType: 'json',
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const deepgramResponse: DeepgramResponse = response.data
|
|
62
|
+
|
|
63
|
+
const firstAlternative = deepgramResponse.results?.channels[0]?.alternatives[0]
|
|
64
|
+
|
|
65
|
+
// Extract transcript and create timeline
|
|
66
|
+
const transcript = firstAlternative?.transcript || ''
|
|
67
|
+
|
|
68
|
+
let timeline: Timeline = []
|
|
69
|
+
|
|
70
|
+
// Extract word-level timing information if available
|
|
71
|
+
const words = firstAlternative?.words || []
|
|
72
|
+
|
|
73
|
+
if (words.length > 0) {
|
|
74
|
+
timeline = words.map((word: DeepgramWordEntry): TimelineEntry => ({
|
|
75
|
+
type: 'word',
|
|
76
|
+
text: word.word,
|
|
77
|
+
startTime: word.start,
|
|
78
|
+
endTime: word.end,
|
|
79
|
+
confidence: word.confidence,
|
|
80
|
+
}))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
logger.end()
|
|
84
|
+
|
|
85
|
+
return { transcript, timeline }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface DeepgramSTTOptions {
|
|
89
|
+
apiKey?: string
|
|
90
|
+
model?: string
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export const defaultDeepgramSTTOptions: DeepgramSTTOptions = {
|
|
94
|
+
apiKey: undefined,
|
|
95
|
+
model: 'nova-2'
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
interface DeepgramWordEntry {
|
|
99
|
+
word: string
|
|
100
|
+
start: number
|
|
101
|
+
end: number
|
|
102
|
+
confidence: number
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
interface DeepgramAlternative {
|
|
106
|
+
transcript: string
|
|
107
|
+
confidence: number
|
|
108
|
+
words: DeepgramWordEntry[]
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
interface DeepgramChannel {
|
|
112
|
+
alternatives: DeepgramAlternative[]
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
interface DeepgramResponse {
|
|
116
|
+
metadata?: {
|
|
117
|
+
transaction_key: string
|
|
118
|
+
request_id: string
|
|
119
|
+
sha256: string
|
|
120
|
+
created: string
|
|
121
|
+
duration: number
|
|
122
|
+
channels: number
|
|
123
|
+
models: string[]
|
|
124
|
+
|
|
125
|
+
model_info?: {
|
|
126
|
+
name: string
|
|
127
|
+
version: string
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
results?: {
|
|
132
|
+
channels: DeepgramChannel[]
|
|
133
|
+
|
|
134
|
+
detected_language?: string
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -7,11 +7,11 @@ import { extendDeep } from '../utilities/ObjectUtilities.js'
|
|
|
7
7
|
|
|
8
8
|
const log = logToStderr
|
|
9
9
|
|
|
10
|
-
export async function synthesize(text: string, voiceId: string, modelId: string, options:
|
|
10
|
+
export async function synthesize(text: string, voiceId: string, modelId: string, options: ElevenLabsTTSOptions) {
|
|
11
11
|
const logger = new Logger()
|
|
12
12
|
logger.start('Request synthesis from ElevenLabs')
|
|
13
13
|
|
|
14
|
-
options = extendDeep(
|
|
14
|
+
options = extendDeep(defaultElevenLabsTTSOptions, options)
|
|
15
15
|
|
|
16
16
|
let response: GaxiosResponse<any>
|
|
17
17
|
|
|
@@ -118,7 +118,7 @@ export async function getVoiceList(apiKey: string) {
|
|
|
118
118
|
return voices
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
export interface
|
|
121
|
+
export interface ElevenLabsTTSOptions {
|
|
122
122
|
apiKey?: string
|
|
123
123
|
stability?: number
|
|
124
124
|
similarityBoost?: number
|
|
@@ -126,7 +126,7 @@ export interface ElevenlabsTTSOptions {
|
|
|
126
126
|
useSpeakerBoost?: boolean
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
export const
|
|
129
|
+
export const defaultElevenLabsTTSOptions = {
|
|
130
130
|
apiKey: undefined,
|
|
131
131
|
stability: 0.5,
|
|
132
132
|
similarityBoost: 0.5,
|
|
@@ -169,9 +169,12 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
|
|
|
169
169
|
|
|
170
170
|
fragment = simplifyPunctuationCharacters(fragment)
|
|
171
171
|
|
|
172
|
-
fragment = fragment
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
//fragment = encodeHTMLAngleBrackets(fragment)
|
|
173
|
+
fragment = fragment.replaceAll('<', '_').replaceAll('>', '_')
|
|
174
|
+
|
|
175
|
+
if (fragment.split('').every(c => c === ':')) {
|
|
176
|
+
fragment = ','
|
|
177
|
+
}
|
|
175
178
|
|
|
176
179
|
if (espeakOptions.insertSeparators && canInsertSeparators) {
|
|
177
180
|
const separator = ` | `
|
|
@@ -597,9 +600,9 @@ export const defaultEspeakOptions: EspeakOptions = {
|
|
|
597
600
|
insertSeparators: false
|
|
598
601
|
}
|
|
599
602
|
|
|
600
|
-
export async function testKirshenbaumPhonemization(text: string) {
|
|
601
|
-
const ipaPhonemizedSentence = (await phonemizeSentence(text,
|
|
602
|
-
const kirshenbaumPhonemizedSentence = (await phonemizeSentence(text,
|
|
603
|
+
export async function testKirshenbaumPhonemization(text: string, language = 'en-us') {
|
|
604
|
+
const ipaPhonemizedSentence = (await phonemizeSentence(text, language)).flatMap(clause => clause)
|
|
605
|
+
const kirshenbaumPhonemizedSentence = (await phonemizeSentence(text, language, undefined, false)).flatMap(clause => clause)
|
|
603
606
|
|
|
604
607
|
const ipaFragments = ipaPhonemizedSentence.map(word => word.join(''))
|
|
605
608
|
|
|
@@ -610,6 +613,8 @@ export async function testKirshenbaumPhonemization(text: string) {
|
|
|
610
613
|
ipaPhoneToKirshenbaum(phoneme)).join(''))
|
|
611
614
|
|
|
612
615
|
for (let i = 0; i < fragments.length; i++) {
|
|
613
|
-
|
|
616
|
+
if (fragments[i] !== kirshenbaumFragments[i]) {
|
|
617
|
+
log(`IPA: ${ipaFragments[i]} | converted: ${fragments[i]} | ground truth: ${kirshenbaumFragments[i]}`)
|
|
618
|
+
}
|
|
614
619
|
}
|
|
615
620
|
}
|