echogarden 1.0.4 → 1.1.0

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.
Files changed (122) hide show
  1. package/README.md +26 -23
  2. package/data/schemas/options.json +177 -36
  3. package/dist/alignment/SpeechAlignment.d.ts +1 -1
  4. package/dist/alignment/SpeechAlignment.js +1 -1
  5. package/dist/alignment/SpeechAlignment.js.map +1 -1
  6. package/dist/api/API.d.ts +1 -0
  7. package/dist/api/API.js +1 -0
  8. package/dist/api/API.js.map +1 -1
  9. package/dist/api/APIOptions.d.ts +1 -0
  10. package/dist/api/Alignment.d.ts +3 -3
  11. package/dist/api/Alignment.js +5 -10
  12. package/dist/api/Alignment.js.map +1 -1
  13. package/dist/api/LanguageDetection.d.ts +5 -7
  14. package/dist/api/LanguageDetection.js +3 -2
  15. package/dist/api/LanguageDetection.js.map +1 -1
  16. package/dist/api/Recognition.d.ts +4 -5
  17. package/dist/api/Recognition.js +5 -8
  18. package/dist/api/Recognition.js.map +1 -1
  19. package/dist/api/SourceSeparation.d.ts +2 -0
  20. package/dist/api/SourceSeparation.js +4 -2
  21. package/dist/api/SourceSeparation.js.map +1 -1
  22. package/dist/api/Synthesis.d.ts +3 -1
  23. package/dist/api/Synthesis.js +9 -10
  24. package/dist/api/Synthesis.js.map +1 -1
  25. package/dist/api/Translation.d.ts +1 -1
  26. package/dist/api/Translation.js +4 -8
  27. package/dist/api/Translation.js.map +1 -1
  28. package/dist/api/TranslationAlignment.d.ts +31 -0
  29. package/dist/api/TranslationAlignment.js +121 -0
  30. package/dist/api/TranslationAlignment.js.map +1 -0
  31. package/dist/api/VoiceActivityDetection.d.ts +5 -1
  32. package/dist/api/VoiceActivityDetection.js +38 -2
  33. package/dist/api/VoiceActivityDetection.js.map +1 -1
  34. package/dist/audio/AudioPlayer.js +6 -1
  35. package/dist/audio/AudioPlayer.js.map +1 -1
  36. package/dist/cli/CLI.js +85 -0
  37. package/dist/cli/CLI.js.map +1 -1
  38. package/dist/dsp/FFT.js.map +1 -1
  39. package/dist/math/MedianFilter.d.ts +5 -0
  40. package/dist/math/MedianFilter.js +102 -0
  41. package/dist/math/MedianFilter.js.map +1 -0
  42. package/dist/math/VectorMath.d.ts +0 -2
  43. package/dist/math/VectorMath.js +1 -25
  44. package/dist/math/VectorMath.js.map +1 -1
  45. package/dist/recognition/OpenAICloudSTT.d.ts +1 -1
  46. package/dist/recognition/OpenAICloudSTT.js.map +1 -1
  47. package/dist/recognition/SileroSTT.d.ts +22 -1
  48. package/dist/recognition/SileroSTT.js +122 -95
  49. package/dist/recognition/SileroSTT.js.map +1 -1
  50. package/dist/recognition/WhisperCppSTT.js +1 -1
  51. package/dist/recognition/WhisperCppSTT.js.map +1 -1
  52. package/dist/recognition/WhisperSTT.d.ts +52 -19
  53. package/dist/recognition/WhisperSTT.js +645 -494
  54. package/dist/recognition/WhisperSTT.js.map +1 -1
  55. package/dist/server/Server.js.map +1 -1
  56. package/dist/source-separation/MDXNetSourceSeparation.d.ts +5 -3
  57. package/dist/source-separation/MDXNetSourceSeparation.js +26 -19
  58. package/dist/source-separation/MDXNetSourceSeparation.js.map +1 -1
  59. package/dist/speech-language-detection/SileroLanguageDetection.d.ts +15 -9
  60. package/dist/speech-language-detection/SileroLanguageDetection.js +23 -16
  61. package/dist/speech-language-detection/SileroLanguageDetection.js.map +1 -1
  62. package/dist/synthesis/EspeakTTS.js +4 -0
  63. package/dist/synthesis/EspeakTTS.js.map +1 -1
  64. package/dist/synthesis/GoogleCloudTTS.js.map +1 -1
  65. package/dist/synthesis/VitsTTS.d.ts +8 -6
  66. package/dist/synthesis/VitsTTS.js +36 -31
  67. package/dist/synthesis/VitsTTS.js.map +1 -1
  68. package/dist/tests/Test.js.map +1 -1
  69. package/dist/utilities/OnnxUtilities.d.ts +14 -0
  70. package/dist/utilities/OnnxUtilities.js +43 -0
  71. package/dist/utilities/OnnxUtilities.js.map +1 -0
  72. package/dist/utilities/Utilities.d.ts +4 -8
  73. package/dist/utilities/Utilities.js +35 -58
  74. package/dist/utilities/Utilities.js.map +1 -1
  75. package/dist/voice-activity-detection/SileroVAD.d.ts +5 -3
  76. package/dist/voice-activity-detection/SileroVAD.js +9 -11
  77. package/dist/voice-activity-detection/SileroVAD.js.map +1 -1
  78. package/docs/API.md +54 -34
  79. package/docs/CLI.md +25 -13
  80. package/docs/Contributing.md +4 -2
  81. package/docs/Engines.md +43 -32
  82. package/docs/Licenses.md +3 -4
  83. package/docs/Options.md +47 -11
  84. package/docs/Releases.md +4 -0
  85. package/docs/Server.md +8 -6
  86. package/docs/Tasklist.md +39 -52
  87. package/docs/Technical.md +1 -1
  88. package/package.json +8 -12
  89. package/src/alignment/SpeechAlignment.ts +1 -1
  90. package/src/api/API.ts +1 -0
  91. package/src/api/APIOptions.ts +1 -0
  92. package/src/api/Alignment.ts +10 -14
  93. package/src/api/LanguageDetection.ts +14 -10
  94. package/src/api/Recognition.ts +17 -10
  95. package/src/api/SourceSeparation.ts +7 -2
  96. package/src/api/Synthesis.ts +26 -11
  97. package/src/api/Translation.ts +14 -8
  98. package/src/api/TranslationAlignment.ts +213 -0
  99. package/src/api/VoiceActivityDetection.ts +66 -3
  100. package/src/audio/AudioPlayer.ts +6 -2
  101. package/src/cli/CLI.ts +121 -2
  102. package/src/dsp/FFT.ts +3 -0
  103. package/src/math/MedianFilter.ts +124 -0
  104. package/src/math/VectorMath.ts +1 -36
  105. package/src/recognition/OpenAICloudSTT.ts +27 -27
  106. package/src/recognition/SileroSTT.ts +149 -102
  107. package/src/recognition/WhisperCppSTT.ts +1 -1
  108. package/src/recognition/WhisperSTT.ts +961 -684
  109. package/src/server/Server.ts +1 -1
  110. package/src/source-separation/MDXNetSourceSeparation.ts +35 -19
  111. package/src/speech-language-detection/SileroLanguageDetection.ts +53 -33
  112. package/src/synthesis/EspeakTTS.ts +8 -0
  113. package/src/synthesis/GoogleCloudTTS.ts +12 -1
  114. package/src/synthesis/VitsTTS.ts +57 -46
  115. package/src/tests/Test.ts +1 -1
  116. package/src/utilities/OnnxUtilities.ts +68 -0
  117. package/src/utilities/Utilities.ts +38 -66
  118. package/src/voice-activity-detection/SileroVAD.ts +15 -15
  119. package/dist/utilities/NdArrayUtilities.d.ts +0 -3
  120. package/dist/utilities/NdArrayUtilities.js +0 -23
  121. package/dist/utilities/NdArrayUtilities.js.map +0 -1
  122. package/src/utilities/NdArrayUtilities.ts +0 -31
@@ -5,7 +5,7 @@ import { inspect } from 'node:util'
5
5
  import { RandomGenerator } from './RandomGenerator.js'
6
6
  import { randomUUID, randomBytes } from 'node:crypto'
7
7
  import { Logger } from './Logger.js'
8
- import { ChildProcessWithoutNullStreams } from 'node:child_process'
8
+ import { ChildProcessWithoutNullStreams, exec } from 'node:child_process'
9
9
 
10
10
  const log = logToStderr
11
11
 
@@ -69,6 +69,10 @@ export function simplifyPunctuationCharacters(text: string) {
69
69
  .replaceAll(`:`, `:`)
70
70
  .replaceAll(`;`, `;`)
71
71
  .replaceAll(`。`, `.`)
72
+
73
+ .replaceAll(`?`, `?`)
74
+ .replaceAll(`!`, `!`)
75
+ .replaceAll(`؟`, `?`)
72
76
  }
73
77
 
74
78
  export function writeToStderr(message: any) {
@@ -427,7 +431,7 @@ export async function resolveModuleMainPath(moduleName: string) {
427
431
  const { resolve } = await import('import-meta-resolve')
428
432
  const { fileURLToPath } = await import('url')
429
433
 
430
- return fileURLToPath(await resolve(moduleName, import.meta.url))
434
+ return fileURLToPath(resolve(moduleName, import.meta.url))
431
435
  }
432
436
 
433
437
  export function getWithDefault<T>(value: T | undefined, defaultValue: T) {
@@ -480,89 +484,47 @@ export function getUTF32Chars(str: string) {
480
484
  return { utf32chars, mapping }
481
485
  }
482
486
 
483
- export function getRepetitionScoreRelativeToFirstSubstring(tokens: string[] | number[]) {
484
- const maxOrder = Math.floor(tokens.length)
487
+ export function getTokenRepetitionScore(tokens: string[] | number[]) {
488
+ const maxCycleLength = Math.floor(tokens.length / 2)
485
489
 
486
- const matchCountForOrder: number[] = []
490
+ const matchLengthForCycleLength: number[] = [0]
487
491
 
488
- for (let i = 0; i <= maxOrder; i++) {
489
- matchCountForOrder.push(0)
490
- }
492
+ for (let cycleLength = 1; cycleLength <= maxCycleLength; cycleLength++) {
493
+ let matchCount = 0
491
494
 
492
- for (let offset = 0; offset < tokens.length; offset++) {
493
- for (let order = 1; order <= maxOrder; order++) {
494
- const referenceToken = tokens[-1 + order]
495
- const targetToken = tokens[offset + order]
495
+ for (let leftIndex = cycleLength; leftIndex < tokens.length; leftIndex++) {
496
+ const referenceIndex = leftIndex - cycleLength
496
497
 
497
- if (targetToken == referenceToken) {
498
- matchCountForOrder[order] += 1
499
- } else {
498
+ if (tokens[leftIndex] !== tokens[referenceIndex]) {
500
499
  break
501
500
  }
502
- }
503
- }
504
-
505
- const scores = matchCountForOrder.map((count, index) => count * index)
506
-
507
- let maxScoreOrder = -1
508
- let maxScore = -Infinity
509
-
510
- for (let i = 1; i <= matchCountForOrder.length; i++) {
511
- const score = scores[i]
512
-
513
- if (score > maxScore) {
514
- maxScoreOrder = i
515
- maxScore = score
516
- }
517
- }
518
-
519
- return { maxScore, maxScoreOrder }
520
- }
521
-
522
- export function getConsecutiveRepetitionScoreRelativeToFirstSubstring(tokens: string[] | number[]) {
523
- function countRepetitionForLength(len: number) {
524
- let count = 0
525
-
526
- for (let offset = len; offset < tokens.length; offset += len) {
527
- for (let i = 0; i < len; i++) {
528
- if (tokens[i] != tokens[offset + i]) {
529
- return count
530
- }
531
- }
532
501
 
533
- count += 1
502
+ matchCount += 1
534
503
  }
535
504
 
536
- return count
537
- }
538
-
539
- const maxLength = Math.floor(tokens.length / 2)
505
+ const score = matchCount
540
506
 
541
- const repeatCountForLength: number[] = []
542
-
543
- for (let i = 0; i <= maxLength; i++) {
544
- repeatCountForLength.push(0)
507
+ matchLengthForCycleLength.push(score)
545
508
  }
546
509
 
547
- for (let targetLen = 1; targetLen <= maxLength; targetLen++) {
548
- repeatCountForLength[targetLen] = countRepetitionForLength(targetLen)
549
- }
510
+ let longestMatch = -Infinity
511
+ let longestCycleRepetition = -Infinity
550
512
 
551
- const scores = repeatCountForLength.map((count, index) => count * index)
513
+ for (let i = 1; i <= matchLengthForCycleLength.length; i++) {
514
+ const matchLength = matchLengthForCycleLength[i]
552
515
 
553
- let maxScoreLength = -1
554
- let maxScore = -Infinity
516
+ if (matchLength > longestMatch) {
517
+ longestMatch = matchLength
518
+ }
555
519
 
556
- for (let i = 1; i <= repeatCountForLength.length; i++) {
557
- const score = scores[i]
520
+ const cycleCount = matchLength / i
558
521
 
559
- if (score > maxScore) {
560
- maxScoreLength = i
561
- maxScore = score
522
+ if (cycleCount > longestCycleRepetition) {
523
+ longestCycleRepetition = cycleCount
562
524
  }
563
525
  }
564
526
 
565
- return { maxScore, maxScoreLength, repeatCountForLength }
527
+ return { longestMatch, longestCycleRepetition }
566
528
  }
567
529
 
568
530
  export async function resolveModuleScriptPath(moduleName: string) {
@@ -647,3 +609,13 @@ export function getIntegerRange(start: number, end: number): number[] {
647
609
 
648
610
  return result
649
611
  }
612
+
613
+ export function containsInvalidCodepoint(str: string) {
614
+ for (const char of str) {
615
+ if (char.codePointAt(0) === 65533) {
616
+ return true
617
+ }
618
+ }
619
+
620
+ return false
621
+ }
@@ -2,10 +2,14 @@ import type * as Onnx from 'onnxruntime-node'
2
2
 
3
3
  import { concatFloat32Arrays } from '../utilities/Utilities.js'
4
4
  import { RawAudio } from '../audio/AudioUtilities.js'
5
-
6
- let sileroVad: SileroVAD
7
-
8
- export async function detectVoiceActivity(rawAudio: RawAudio, modelPath: string, frameDuration: 30 | 60 | 90) {
5
+ import { OnnxExecutionProvider, getOnnxSessionOptions } from '../utilities/OnnxUtilities.js'
6
+
7
+ export async function detectVoiceActivity(
8
+ rawAudio: RawAudio,
9
+ modelPath: string,
10
+ frameDuration: 30 | 60 | 90,
11
+ executionProviders: OnnxExecutionProvider[]) {
12
+
9
13
  if (rawAudio.sampleRate != 16000) {
10
14
  throw new Error('Audio sample rate must be 16KHz')
11
15
  }
@@ -14,9 +18,7 @@ export async function detectVoiceActivity(rawAudio: RawAudio, modelPath: string,
14
18
 
15
19
  const frameLength = Math.floor(16000 * (frameDuration / 1000))
16
20
 
17
- if (!sileroVad) {
18
- sileroVad = new SileroVAD(modelPath)
19
- }
21
+ const sileroVad = new SileroVAD(modelPath, executionProviders)
20
22
 
21
23
  const frameProbabilities: number[] = []
22
24
 
@@ -42,10 +44,9 @@ export class SileroVAD {
42
44
  modelStateC?: Onnx.Tensor
43
45
  modelSampleRate?: Onnx.Tensor
44
46
 
45
- modelPath: string
46
-
47
- constructor(modelPath: string) {
48
- this.modelPath = modelPath
47
+ constructor(
48
+ public readonly modelPath: string,
49
+ public readonly executionProviders: OnnxExecutionProvider[]) {
49
50
  }
50
51
 
51
52
  async predictAudioFrame(frame: Float32Array) {
@@ -66,6 +67,7 @@ export class SileroVAD {
66
67
 
67
68
  return probability
68
69
  }
70
+
69
71
  private async initializeIfNeeded() {
70
72
  if (this.session) {
71
73
  return
@@ -81,10 +83,8 @@ export class SileroVAD {
81
83
 
82
84
  this.modelSampleRate = new Onnx.Tensor('int64', new BigInt64Array([BigInt(16000)]), [])
83
85
 
84
- const onnxOptions: Onnx.InferenceSession.SessionOptions = {
85
- logSeverityLevel: 3
86
- }
86
+ const onnxSessionOptions = getOnnxSessionOptions({ executionProviders: this.executionProviders })
87
87
 
88
- this.session = await Onnx.InferenceSession.create(this.modelPath, onnxOptions)
88
+ this.session = await Onnx.InferenceSession.create(this.modelPath, onnxSessionOptions)
89
89
  }
90
90
  }
@@ -1,3 +0,0 @@
1
- import ndarray from 'ndarray';
2
- export declare function ndarraySoftMax(vector: ndarray.NdArray, temperature?: number): void;
3
- export declare function ndarrayMedianFilter(vector: ndarray.NdArray, width: number): void;
@@ -1,23 +0,0 @@
1
- // import ops from 'ndarray-ops'
2
- import { medianFilter, softmax } from '../math/VectorMath.js';
3
- export function ndarraySoftMax(vector, temperature = 1.0) {
4
- const vectorAsArray = new Array(vector.shape[0]);
5
- for (let i = 0; i < vectorAsArray.length; i++) {
6
- vectorAsArray[i] = vector.get(i);
7
- }
8
- const result = softmax(vectorAsArray, temperature);
9
- for (let i = 0; i < vectorAsArray.length; i++) {
10
- vector.set(i, result[i]);
11
- }
12
- }
13
- export function ndarrayMedianFilter(vector, width) {
14
- const vectorAsArray = new Array(vector.shape[0]);
15
- for (let i = 0; i < vectorAsArray.length; i++) {
16
- vectorAsArray[i] = vector.get(i);
17
- }
18
- const result = medianFilter(vectorAsArray, width);
19
- for (let i = 0; i < vectorAsArray.length; i++) {
20
- vector.set(i, result[i]);
21
- }
22
- }
23
- //# sourceMappingURL=NdArrayUtilities.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"NdArrayUtilities.js","sourceRoot":"","sources":["../../src/utilities/NdArrayUtilities.ts"],"names":[],"mappings":"AACA,gCAAgC;AAChC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAE7D,MAAM,UAAU,cAAc,CAAC,MAAuB,EAAE,WAAW,GAAG,GAAG;IACxE,MAAM,aAAa,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAEhD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/C,aAAa,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IACjC,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,WAAW,CAAC,CAAA;IAElD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/C,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IACzB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAuB,EAAE,KAAa;IACzE,MAAM,aAAa,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAEhD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/C,aAAa,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IACjC,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;IAEjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/C,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IACzB,CAAC;AACF,CAAC"}
@@ -1,31 +0,0 @@
1
- import ndarray from 'ndarray'
2
- // import ops from 'ndarray-ops'
3
- import { medianFilter, softmax } from '../math/VectorMath.js'
4
-
5
- export function ndarraySoftMax(vector: ndarray.NdArray, temperature = 1.0) {
6
- const vectorAsArray = new Array(vector.shape[0])
7
-
8
- for (let i = 0; i < vectorAsArray.length; i++) {
9
- vectorAsArray[i] = vector.get(i)
10
- }
11
-
12
- const result = softmax(vectorAsArray, temperature)
13
-
14
- for (let i = 0; i < vectorAsArray.length; i++) {
15
- vector.set(i, result[i])
16
- }
17
- }
18
-
19
- export function ndarrayMedianFilter(vector: ndarray.NdArray, width: number) {
20
- const vectorAsArray = new Array(vector.shape[0])
21
-
22
- for (let i = 0; i < vectorAsArray.length; i++) {
23
- vectorAsArray[i] = vector.get(i)
24
- }
25
-
26
- const result = medianFilter(vectorAsArray, width)
27
-
28
- for (let i = 0; i < vectorAsArray.length; i++) {
29
- vector.set(i, result[i])
30
- }
31
- }