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.
- package/README.md +26 -23
- package/data/schemas/options.json +177 -36
- package/dist/alignment/SpeechAlignment.d.ts +1 -1
- package/dist/alignment/SpeechAlignment.js +1 -1
- package/dist/alignment/SpeechAlignment.js.map +1 -1
- package/dist/api/API.d.ts +1 -0
- package/dist/api/API.js +1 -0
- package/dist/api/API.js.map +1 -1
- package/dist/api/APIOptions.d.ts +1 -0
- package/dist/api/Alignment.d.ts +3 -3
- package/dist/api/Alignment.js +5 -10
- package/dist/api/Alignment.js.map +1 -1
- package/dist/api/LanguageDetection.d.ts +5 -7
- package/dist/api/LanguageDetection.js +3 -2
- package/dist/api/LanguageDetection.js.map +1 -1
- package/dist/api/Recognition.d.ts +4 -5
- package/dist/api/Recognition.js +5 -8
- package/dist/api/Recognition.js.map +1 -1
- package/dist/api/SourceSeparation.d.ts +2 -0
- package/dist/api/SourceSeparation.js +4 -2
- package/dist/api/SourceSeparation.js.map +1 -1
- package/dist/api/Synthesis.d.ts +3 -1
- package/dist/api/Synthesis.js +9 -10
- package/dist/api/Synthesis.js.map +1 -1
- package/dist/api/Translation.d.ts +1 -1
- package/dist/api/Translation.js +4 -8
- package/dist/api/Translation.js.map +1 -1
- package/dist/api/TranslationAlignment.d.ts +31 -0
- package/dist/api/TranslationAlignment.js +121 -0
- package/dist/api/TranslationAlignment.js.map +1 -0
- package/dist/api/VoiceActivityDetection.d.ts +5 -1
- package/dist/api/VoiceActivityDetection.js +38 -2
- package/dist/api/VoiceActivityDetection.js.map +1 -1
- package/dist/audio/AudioPlayer.js +6 -1
- package/dist/audio/AudioPlayer.js.map +1 -1
- package/dist/cli/CLI.js +85 -0
- package/dist/cli/CLI.js.map +1 -1
- package/dist/dsp/FFT.js.map +1 -1
- package/dist/math/MedianFilter.d.ts +5 -0
- package/dist/math/MedianFilter.js +102 -0
- package/dist/math/MedianFilter.js.map +1 -0
- package/dist/math/VectorMath.d.ts +0 -2
- package/dist/math/VectorMath.js +1 -25
- package/dist/math/VectorMath.js.map +1 -1
- package/dist/recognition/OpenAICloudSTT.d.ts +1 -1
- package/dist/recognition/OpenAICloudSTT.js.map +1 -1
- package/dist/recognition/SileroSTT.d.ts +22 -1
- package/dist/recognition/SileroSTT.js +122 -95
- package/dist/recognition/SileroSTT.js.map +1 -1
- package/dist/recognition/WhisperCppSTT.js +1 -1
- package/dist/recognition/WhisperCppSTT.js.map +1 -1
- package/dist/recognition/WhisperSTT.d.ts +52 -19
- package/dist/recognition/WhisperSTT.js +645 -494
- package/dist/recognition/WhisperSTT.js.map +1 -1
- package/dist/server/Server.js.map +1 -1
- package/dist/source-separation/MDXNetSourceSeparation.d.ts +5 -3
- package/dist/source-separation/MDXNetSourceSeparation.js +26 -19
- package/dist/source-separation/MDXNetSourceSeparation.js.map +1 -1
- package/dist/speech-language-detection/SileroLanguageDetection.d.ts +15 -9
- package/dist/speech-language-detection/SileroLanguageDetection.js +23 -16
- package/dist/speech-language-detection/SileroLanguageDetection.js.map +1 -1
- package/dist/synthesis/EspeakTTS.js +4 -0
- package/dist/synthesis/EspeakTTS.js.map +1 -1
- package/dist/synthesis/GoogleCloudTTS.js.map +1 -1
- package/dist/synthesis/VitsTTS.d.ts +8 -6
- package/dist/synthesis/VitsTTS.js +36 -31
- package/dist/synthesis/VitsTTS.js.map +1 -1
- package/dist/tests/Test.js.map +1 -1
- package/dist/utilities/OnnxUtilities.d.ts +14 -0
- package/dist/utilities/OnnxUtilities.js +43 -0
- package/dist/utilities/OnnxUtilities.js.map +1 -0
- package/dist/utilities/Utilities.d.ts +4 -8
- package/dist/utilities/Utilities.js +35 -58
- package/dist/utilities/Utilities.js.map +1 -1
- package/dist/voice-activity-detection/SileroVAD.d.ts +5 -3
- package/dist/voice-activity-detection/SileroVAD.js +9 -11
- package/dist/voice-activity-detection/SileroVAD.js.map +1 -1
- package/docs/API.md +54 -34
- package/docs/CLI.md +25 -13
- package/docs/Contributing.md +4 -2
- package/docs/Engines.md +43 -32
- package/docs/Licenses.md +3 -4
- package/docs/Options.md +47 -11
- package/docs/Releases.md +4 -0
- package/docs/Server.md +8 -6
- package/docs/Tasklist.md +39 -52
- package/docs/Technical.md +1 -1
- package/package.json +8 -12
- package/src/alignment/SpeechAlignment.ts +1 -1
- package/src/api/API.ts +1 -0
- package/src/api/APIOptions.ts +1 -0
- package/src/api/Alignment.ts +10 -14
- package/src/api/LanguageDetection.ts +14 -10
- package/src/api/Recognition.ts +17 -10
- package/src/api/SourceSeparation.ts +7 -2
- package/src/api/Synthesis.ts +26 -11
- package/src/api/Translation.ts +14 -8
- package/src/api/TranslationAlignment.ts +213 -0
- package/src/api/VoiceActivityDetection.ts +66 -3
- package/src/audio/AudioPlayer.ts +6 -2
- package/src/cli/CLI.ts +121 -2
- package/src/dsp/FFT.ts +3 -0
- package/src/math/MedianFilter.ts +124 -0
- package/src/math/VectorMath.ts +1 -36
- package/src/recognition/OpenAICloudSTT.ts +27 -27
- package/src/recognition/SileroSTT.ts +149 -102
- package/src/recognition/WhisperCppSTT.ts +1 -1
- package/src/recognition/WhisperSTT.ts +961 -684
- package/src/server/Server.ts +1 -1
- package/src/source-separation/MDXNetSourceSeparation.ts +35 -19
- package/src/speech-language-detection/SileroLanguageDetection.ts +53 -33
- package/src/synthesis/EspeakTTS.ts +8 -0
- package/src/synthesis/GoogleCloudTTS.ts +12 -1
- package/src/synthesis/VitsTTS.ts +57 -46
- package/src/tests/Test.ts +1 -1
- package/src/utilities/OnnxUtilities.ts +68 -0
- package/src/utilities/Utilities.ts +38 -66
- package/src/voice-activity-detection/SileroVAD.ts +15 -15
- package/dist/utilities/NdArrayUtilities.d.ts +0 -3
- package/dist/utilities/NdArrayUtilities.js +0 -23
- package/dist/utilities/NdArrayUtilities.js.map +0 -1
- 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(
|
|
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
|
|
484
|
-
const
|
|
487
|
+
export function getTokenRepetitionScore(tokens: string[] | number[]) {
|
|
488
|
+
const maxCycleLength = Math.floor(tokens.length / 2)
|
|
485
489
|
|
|
486
|
-
const
|
|
490
|
+
const matchLengthForCycleLength: number[] = [0]
|
|
487
491
|
|
|
488
|
-
for (let
|
|
489
|
-
|
|
490
|
-
}
|
|
492
|
+
for (let cycleLength = 1; cycleLength <= maxCycleLength; cycleLength++) {
|
|
493
|
+
let matchCount = 0
|
|
491
494
|
|
|
492
|
-
|
|
493
|
-
|
|
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 (
|
|
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
|
-
|
|
502
|
+
matchCount += 1
|
|
534
503
|
}
|
|
535
504
|
|
|
536
|
-
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
const maxLength = Math.floor(tokens.length / 2)
|
|
505
|
+
const score = matchCount
|
|
540
506
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
for (let i = 0; i <= maxLength; i++) {
|
|
544
|
-
repeatCountForLength.push(0)
|
|
507
|
+
matchLengthForCycleLength.push(score)
|
|
545
508
|
}
|
|
546
509
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
}
|
|
510
|
+
let longestMatch = -Infinity
|
|
511
|
+
let longestCycleRepetition = -Infinity
|
|
550
512
|
|
|
551
|
-
|
|
513
|
+
for (let i = 1; i <= matchLengthForCycleLength.length; i++) {
|
|
514
|
+
const matchLength = matchLengthForCycleLength[i]
|
|
552
515
|
|
|
553
|
-
|
|
554
|
-
|
|
516
|
+
if (matchLength > longestMatch) {
|
|
517
|
+
longestMatch = matchLength
|
|
518
|
+
}
|
|
555
519
|
|
|
556
|
-
|
|
557
|
-
const score = scores[i]
|
|
520
|
+
const cycleCount = matchLength / i
|
|
558
521
|
|
|
559
|
-
if (
|
|
560
|
-
|
|
561
|
-
maxScore = score
|
|
522
|
+
if (cycleCount > longestCycleRepetition) {
|
|
523
|
+
longestCycleRepetition = cycleCount
|
|
562
524
|
}
|
|
563
525
|
}
|
|
564
526
|
|
|
565
|
-
return {
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
|
85
|
-
logSeverityLevel: 3
|
|
86
|
-
}
|
|
86
|
+
const onnxSessionOptions = getOnnxSessionOptions({ executionProviders: this.executionProviders })
|
|
87
87
|
|
|
88
|
-
this.session = await Onnx.InferenceSession.create(this.modelPath,
|
|
88
|
+
this.session = await Onnx.InferenceSession.create(this.modelPath, onnxSessionOptions)
|
|
89
89
|
}
|
|
90
90
|
}
|
|
@@ -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
|
-
}
|