echogarden 2.6.0 → 2.8.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/data/lexicons/heteronyms.en.json +6 -2
- package/data/lexicons/words.en.json +379 -19
- package/dist/alignment/SemanticTextAlignment.js +6 -7
- package/dist/alignment/SemanticTextAlignment.js.map +1 -1
- package/dist/api/Alignment.js +2 -2
- package/dist/api/Alignment.js.map +1 -1
- package/dist/api/Recognition.js +2 -2
- package/dist/api/Recognition.js.map +1 -1
- package/dist/api/SourceSeparation.js +1 -1
- package/dist/api/SpeechTranslation.js +2 -2
- package/dist/api/SpeechTranslation.js.map +1 -1
- package/dist/api/Synthesis.js +7 -7
- package/dist/api/Synthesis.js.map +1 -1
- package/dist/api/TimelineTranslationAlignment.js +2 -2
- package/dist/api/TimelineTranslationAlignment.js.map +1 -1
- package/dist/api/TranslationAlignment.js +2 -2
- package/dist/api/TranslationAlignment.js.map +1 -1
- package/dist/audio/AudioBufferConversion.d.ts +5 -6
- package/dist/audio/AudioBufferConversion.js +16 -248
- package/dist/audio/AudioBufferConversion.js.map +1 -1
- package/dist/audio/AudioPlayer.js +2 -2
- package/dist/audio/AudioPlayer.js.map +1 -1
- package/dist/audio/AudioRecorder.js +1 -1
- package/dist/audio/AudioRecorder.js.map +1 -1
- package/dist/audio/AudioUtilities.d.ts +2 -8
- package/dist/audio/AudioUtilities.js +4 -3
- package/dist/audio/AudioUtilities.js.map +1 -1
- package/dist/cli/CLI.js +4 -4
- package/dist/cli/CLI.js.map +1 -1
- package/dist/codecs/FFMpegTranscoder.d.ts +1 -4
- package/dist/codecs/TIMITCodec.js +1 -2
- package/dist/codecs/TIMITCodec.js.map +1 -1
- package/dist/denoising/RNNoise.js +5 -5
- package/dist/denoising/RNNoise.js.map +1 -1
- package/dist/dsp/FFT.js +13 -19
- package/dist/dsp/FFT.js.map +1 -1
- package/dist/dsp/Rubberband.js +5 -5
- package/dist/dsp/Rubberband.js.map +1 -1
- package/dist/dsp/Sonic.js +6 -6
- package/dist/dsp/Sonic.js.map +1 -1
- package/dist/dsp/SpeexResampler.js +11 -11
- package/dist/dsp/SpeexResampler.js.map +1 -1
- package/dist/encodings/Ascii.js +1 -1
- package/dist/encodings/Ascii.js.map +1 -1
- package/dist/encodings/Utf16.js +1 -1
- package/dist/encodings/Utf16.js.map +1 -1
- package/dist/encodings/Utf8.js +1 -1
- package/dist/encodings/Utf8.js.map +1 -1
- package/dist/nlp/EspeakPhonemizer.js +1 -1
- package/dist/nlp/EspeakPhonemizer.js.map +1 -1
- package/dist/nlp/Segmentation.d.ts +13 -10
- package/dist/nlp/Segmentation.js +129 -106
- package/dist/nlp/Segmentation.js.map +1 -1
- package/dist/nlp/TextNormalizer.js +74 -42
- package/dist/nlp/TextNormalizer.js.map +1 -1
- package/dist/recognition/AmazonTranscribeSTT.js +2 -2
- package/dist/recognition/AmazonTranscribeSTT.js.map +1 -1
- package/dist/recognition/SileroSTT.js +2 -2
- package/dist/recognition/SileroSTT.js.map +1 -1
- package/dist/recognition/WhisperSTT.js +4 -16
- package/dist/recognition/WhisperSTT.js.map +1 -1
- package/dist/subtitles/Subtitles.js +52 -7
- package/dist/subtitles/Subtitles.js.map +1 -1
- package/dist/synthesis/AwsPollyTTS.d.ts +1 -4
- package/dist/synthesis/CoquiServerTTS.d.ts +1 -4
- package/dist/synthesis/DeepgramTTS.d.ts +1 -4
- package/dist/synthesis/ElevenLabsTTS.d.ts +1 -4
- package/dist/synthesis/ElevenLabsTTS.js +11 -10
- package/dist/synthesis/ElevenLabsTTS.js.map +1 -1
- package/dist/synthesis/EspeakTTS.js +8 -8
- package/dist/synthesis/EspeakTTS.js.map +1 -1
- package/dist/synthesis/FliteTTS.d.ts +1 -4
- package/dist/synthesis/GnuSpeechTTS.d.ts +1 -7
- package/dist/synthesis/GoogleCloudTTS.d.ts +1 -4
- package/dist/synthesis/KokoroTTS.js +21 -10
- package/dist/synthesis/KokoroTTS.js.map +1 -1
- package/dist/synthesis/SapiTTS.js +1 -2
- package/dist/synthesis/SapiTTS.js.map +1 -1
- package/dist/synthesis/SvoxPicoTTS.js +25 -25
- package/dist/synthesis/SvoxPicoTTS.js.map +1 -1
- package/dist/text-translation/DeepLTextTranslation.js +4 -3
- package/dist/text-translation/DeepLTextTranslation.js.map +1 -1
- package/dist/text-translation/NLLBTextTranslation.js +7 -6
- package/dist/text-translation/NLLBTextTranslation.js.map +1 -1
- package/dist/utilities/StringUtilities.d.ts +1 -1
- package/dist/utilities/StringUtilities.js +5 -5
- package/dist/utilities/StringUtilities.js.map +1 -1
- package/dist/utilities/Timeline.d.ts +2 -3
- package/dist/utilities/Timeline.js +96 -147
- package/dist/utilities/Timeline.js.map +1 -1
- package/dist/utilities/WikipediaReader.js +3 -3
- package/dist/utilities/WikipediaReader.js.map +1 -1
- package/dist/voice-activity-detection/WebRtcVAD.js +4 -4
- package/dist/voice-activity-detection/WebRtcVAD.js.map +1 -1
- package/docs/Tasklist.md +1 -6
- package/package.json +13 -11
- package/src/alignment/SemanticTextAlignment.ts +6 -7
- package/src/api/Alignment.ts +2 -2
- package/src/api/Recognition.ts +2 -2
- package/src/api/SourceSeparation.ts +1 -1
- package/src/api/SpeechTranslation.ts +2 -2
- package/src/api/Synthesis.ts +7 -7
- package/src/api/TimelineTranslationAlignment.ts +2 -2
- package/src/api/TranslationAlignment.ts +2 -2
- package/src/audio/AudioBufferConversion.ts +17 -263
- package/src/audio/AudioPlayer.ts +3 -3
- package/src/audio/AudioRecorder.ts +1 -1
- package/src/audio/AudioUtilities.ts +5 -3
- package/src/cli/CLI.ts +4 -4
- package/src/codecs/TIMITCodec.ts +1 -2
- package/src/denoising/RNNoise.ts +5 -5
- package/src/dsp/FFT.ts +22 -19
- package/src/dsp/Rubberband.ts +5 -5
- package/src/dsp/Sonic.ts +6 -6
- package/src/dsp/SpeexResampler.ts +11 -11
- package/src/encodings/Ascii.ts +1 -1
- package/src/encodings/Utf16.ts +1 -1
- package/src/encodings/Utf8.ts +1 -1
- package/src/nlp/EspeakPhonemizer.ts +1 -1
- package/src/nlp/Segmentation.ts +146 -111
- package/src/nlp/TextNormalizer.ts +94 -52
- package/src/recognition/AmazonTranscribeSTT.ts +2 -2
- package/src/recognition/SileroSTT.ts +2 -2
- package/src/recognition/WhisperSTT.ts +4 -18
- package/src/subtitles/Subtitles.ts +69 -8
- package/src/synthesis/ElevenLabsTTS.ts +12 -11
- package/src/synthesis/EspeakTTS.ts +9 -8
- package/src/synthesis/KokoroTTS.ts +24 -12
- package/src/synthesis/SapiTTS.ts +1 -2
- package/src/synthesis/SvoxPicoTTS.ts +27 -25
- package/src/text-translation/DeepLTextTranslation.ts +4 -3
- package/src/text-translation/NLLBTextTranslation.ts +8 -6
- package/src/typings/Fillers.d.ts +0 -16
- package/src/utilities/StringUtilities.ts +5 -6
- package/src/utilities/Timeline.ts +100 -170
- package/src/utilities/WikipediaReader.ts +3 -3
- package/src/voice-activity-detection/WebRtcVAD.ts +5 -4
- package/dist/codecs/WaveCodec.d.ts +0 -19
- package/dist/codecs/WaveCodec.js +0 -224
- package/dist/codecs/WaveCodec.js.map +0 -1
- package/dist/nlp/CompromiseNLP.d.ts +0 -15
- package/dist/nlp/CompromiseNLP.js +0 -79
- package/dist/nlp/CompromiseNLP.js.map +0 -1
- package/dist/utilities/BinaryArrayConversion.d.ts +0 -14
- package/dist/utilities/BinaryArrayConversion.js +0 -92
- package/dist/utilities/BinaryArrayConversion.js.map +0 -1
- package/dist/utilities/WasmMemoryManager.d.ts +0 -153
- package/dist/utilities/WasmMemoryManager.js +0 -440
- package/dist/utilities/WasmMemoryManager.js.map +0 -1
- package/src/codecs/WaveCodec.ts +0 -281
- package/src/nlp/CompromiseNLP.ts +0 -119
- package/src/utilities/BinaryArrayConversion.ts +0 -117
- package/src/utilities/WasmMemoryManager.ts +0 -566
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { splitToParagraphs,
|
|
1
|
+
import { splitToParagraphs, wordCharacterRegExp } from '../nlp/Segmentation.js';
|
|
2
2
|
import { Logger } from './Logger.js';
|
|
3
3
|
export async function parseWikipediaArticle(articleName, language) {
|
|
4
4
|
const logger = new Logger();
|
|
@@ -12,13 +12,13 @@ export async function parseWikipediaArticle(articleName, language) {
|
|
|
12
12
|
const sectionsText = [];
|
|
13
13
|
for (const section of sections) {
|
|
14
14
|
const sectionTitle = section.title();
|
|
15
|
-
if (
|
|
15
|
+
if (wordCharacterRegExp.test(sectionTitle)) {
|
|
16
16
|
sectionsText.push(sectionTitle);
|
|
17
17
|
}
|
|
18
18
|
const sectionParagraphs = splitToParagraphs(section.text(), 'single', 'preserve');
|
|
19
19
|
for (const paragraph of sectionParagraphs) {
|
|
20
20
|
const paragraphText = paragraph;
|
|
21
|
-
if (
|
|
21
|
+
if (wordCharacterRegExp.test(paragraphText)) {
|
|
22
22
|
sectionsText.push(paragraphText);
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WikipediaReader.js","sourceRoot":"","sources":["../../src/utilities/WikipediaReader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"WikipediaReader.js","sourceRoot":"","sources":["../../src/utilities/WikipediaReader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAC/E,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,WAAmB,EAAE,QAAgB;IAChF,MAAM,MAAM,GAAG,IAAI,MAAM,EAAE,CAAA;IAE3B,MAAM,MAAM,CAAC,UAAU,CAAC,4BAA4B,CAAC,CAAA;IAErD,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAA;IAEtD,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;IAEvD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;IACpD,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAA;IACpC,MAAM,YAAY,GAAa,EAAE,CAAA;IAEjC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAChC,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,EAAE,CAAA;QAEpC,IAAI,mBAAmB,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;YAC5C,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QAChC,CAAC;QAED,MAAM,iBAAiB,GAAG,iBAAiB,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAA;QAEjF,KAAK,MAAM,SAAS,IAAI,iBAAiB,EAAE,CAAC;YAC3C,MAAM,aAAa,GAAG,SAAS,CAAA;YAE/B,IAAI,mBAAmB,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;gBAC7C,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;YACjC,CAAC;QACF,CAAC;IACF,CAAC;IAED,MAAM,CAAC,GAAG,EAAE,CAAA;IAEZ,OAAO,YAAY,CAAA;AACpB,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as AudioBufferConversion from '../audio/AudioBufferConversion.js';
|
|
2
|
-
import {
|
|
2
|
+
import { wrapEmscriptenModuleHeap } from 'wasm-heap-manager';
|
|
3
3
|
export async function detectVoiceActivity(rawAudio, frameDuration = 10, mode = 0) {
|
|
4
4
|
if (rawAudio.sampleRate != 16000) {
|
|
5
5
|
throw new Error('Audio sample rate must be 16KHz');
|
|
@@ -9,7 +9,7 @@ export async function detectVoiceActivity(rawAudio, frameDuration = 10, mode = 0
|
|
|
9
9
|
}
|
|
10
10
|
export async function fvad(samples, sampleRate, frameDuration, mode) {
|
|
11
11
|
const m = await getFvadInstance();
|
|
12
|
-
const
|
|
12
|
+
const wasmHeap = wrapEmscriptenModuleHeap(m);
|
|
13
13
|
const fvad_new = m._fvad_new;
|
|
14
14
|
const fvad_free = m._fvad_free;
|
|
15
15
|
const fvad_reset = m._fvad_reset;
|
|
@@ -26,7 +26,7 @@ export async function fvad(samples, sampleRate, frameDuration, mode) {
|
|
|
26
26
|
throw new Error(`fvad_set_mode failed for mode ${mode}`);
|
|
27
27
|
}
|
|
28
28
|
const frameSampleCount = Math.floor(sampleRate * (frameDuration / 1000));
|
|
29
|
-
const frameSamplesRef =
|
|
29
|
+
const frameSamplesRef = wasmHeap.allocInt16Array(frameSampleCount);
|
|
30
30
|
const result = [];
|
|
31
31
|
for (let sampleOffset = 0; sampleOffset < samples.length; sampleOffset += frameSampleCount) {
|
|
32
32
|
const frame = samples.subarray(sampleOffset, sampleOffset + frameSampleCount);
|
|
@@ -39,7 +39,7 @@ export async function fvad(samples, sampleRate, frameDuration, mode) {
|
|
|
39
39
|
result.push(fvadResult);
|
|
40
40
|
}
|
|
41
41
|
fvad_free(instancePtr);
|
|
42
|
-
|
|
42
|
+
wasmHeap.freeAll();
|
|
43
43
|
return result;
|
|
44
44
|
}
|
|
45
45
|
let fvadInstance;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WebRtcVAD.js","sourceRoot":"","sources":["../../src/voice-activity-detection/WebRtcVAD.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,qBAAqB,MAAM,mCAAmC,CAAA;
|
|
1
|
+
{"version":3,"file":"WebRtcVAD.js","sourceRoot":"","sources":["../../src/voice-activity-detection/WebRtcVAD.ts"],"names":[],"mappings":"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"}
|
package/docs/Tasklist.md
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
* IPA -> Kirshenbaum translation is still not completely similar to what is output by eSpeak. Also, in rare situations, it outputs characters that are not accepted by eSpeak and eSpeak errors. Investigate when that happens and how to improve on this
|
|
8
8
|
|
|
9
9
|
### Subtitles
|
|
10
|
-
* Phrase splitting may split on number separators like the `,` in `100,000`. The new segmentation library would resolve that
|
|
11
10
|
|
|
12
11
|
### Browser extension
|
|
13
12
|
* Investigate why WebSpeech events sometimes completely stop working in the middle of an utterance for no apparent reason. Sometimes this is permanent, until the extension is restarted. Is this a browser issue?
|
|
@@ -78,7 +77,6 @@
|
|
|
78
77
|
|
|
79
78
|
### API
|
|
80
79
|
* Validate timelines to ensure timestamps are always increasing: no negative timestamps or timestamps over the duration of the audio. No sentences without words, etc. and correct if needed
|
|
81
|
-
* See whether it's possible to detect and include / remove Emoji characters in timelines
|
|
82
80
|
* Add support for phrases in timelines
|
|
83
81
|
* Accept voice list caching options in `SynthesisOptions`
|
|
84
82
|
|
|
@@ -93,7 +91,6 @@
|
|
|
93
91
|
|
|
94
92
|
### Subtitles
|
|
95
93
|
* Split long words if needed
|
|
96
|
-
* Clauses shouldn't be split in the middle of numbers, like the `,` in `123,456`
|
|
97
94
|
* Decide how many punctuation characters to allow before breaking to a new line (currently it's infinite)
|
|
98
95
|
* If a subtitle is too short and at the end of the audio, try to extend it back if possible (for example, if the previous subtitle is already extended, take back from it)
|
|
99
96
|
* Add more clause separators, for even more special cases
|
|
@@ -104,7 +101,6 @@
|
|
|
104
101
|
* Option to disable alignment (only for some engines). Alternative: use a low granularity DTW setting that is very fast to compute
|
|
105
102
|
* Find places to add commas (",") to improve speech fluency. VITS voices don't normally add speech breaks if there is no punctuation
|
|
106
103
|
* An isolated dash " - " can be converted to a " , " to ensure there's a break in the speech
|
|
107
|
-
* Ensure abbreviations like "Ph.d" or similar names are segmented and read correctly (does `cldr` treat it as a word? Maybe eSpeak doesn't recognize it as a word). "C#" and ".NET" as well
|
|
108
104
|
* Find a way to manually reset voice list cache
|
|
109
105
|
* When synthesized text isn't pre-split to sentences, apply sentence splits by using the existing method to convert the output of word timelines to sentence/segment timelines
|
|
110
106
|
* Some `sapi` voices and `msspeech` languages output phones that are converted to Microsoft alphabet, not IPA symbols. Try to see if these can be translated to IPA
|
|
@@ -120,7 +116,7 @@
|
|
|
120
116
|
### Synthesis / preprocessing
|
|
121
117
|
* Full date normalization (e.g. `21 August 2023`, `21 Aug 2023`, `August 21, 2023`)
|
|
122
118
|
* Add support for capitalized-only rules, and possibly also all uppercase / all lowercase rules
|
|
123
|
-
* Add support for multiple words in `precededBy` and `
|
|
119
|
+
* Add support for multiple consecutive words in `precededBy` and `followedBy` conditions
|
|
124
120
|
* Support substituting to graphemes in lexicons, not only phonemes
|
|
125
121
|
* Cache lexicons to avoid parsing the JSON each time it is loaded (this may not be needed for if the file is relatively small)
|
|
126
122
|
* Is it possible to pre-phonemize common words like "the" or is it a bad idea / not necessary?
|
|
@@ -159,7 +155,6 @@
|
|
|
159
155
|
|
|
160
156
|
### Source separation / MDX-NET
|
|
161
157
|
* Option to customize overlap
|
|
162
|
-
* Add more models
|
|
163
158
|
|
|
164
159
|
### Server
|
|
165
160
|
* Option to allow or disallow local file paths as arguments to API methods (as a security safeguard)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "echogarden",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.0",
|
|
4
4
|
"description": "An easy-to-use speech toolset. Includes tools for synthesis, recognition, alignment, speech translation, language detection, source separation and more.",
|
|
5
5
|
"author": "Rotem Dan",
|
|
6
6
|
"license": "GPL-3.0",
|
|
@@ -52,27 +52,27 @@
|
|
|
52
52
|
"echogarden": "./dist/cli/CLILauncher.js"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@aws-sdk/client-polly": "^3.
|
|
56
|
-
"@aws-sdk/client-transcribe-streaming": "^3.
|
|
57
|
-
"@echogarden/audio-io": "^0.
|
|
55
|
+
"@aws-sdk/client-polly": "^3.810.0",
|
|
56
|
+
"@aws-sdk/client-transcribe-streaming": "^3.810.0",
|
|
57
|
+
"@echogarden/audio-io": "^0.4.1",
|
|
58
58
|
"@echogarden/espeak-ng-emscripten": "^0.3.3",
|
|
59
59
|
"@echogarden/fasttext-wasm": "^0.1.0",
|
|
60
60
|
"@echogarden/flite-wasi": "^0.1.1",
|
|
61
61
|
"@echogarden/fvad-wasm": "^0.2.0",
|
|
62
62
|
"@echogarden/gnuspeech-wasm": "^0.2.1",
|
|
63
|
+
"@echogarden/icu-segmentation-wasm": "^0.2.1",
|
|
63
64
|
"@echogarden/pffft-wasm": "^0.4.2",
|
|
64
65
|
"@echogarden/rnnoise-wasm": "^0.2.0",
|
|
65
66
|
"@echogarden/rubberband-wasm": "^0.2.0",
|
|
66
67
|
"@echogarden/sonic-wasm": "^0.2.0",
|
|
67
68
|
"@echogarden/speex-resampler-wasm": "^0.3.0",
|
|
68
69
|
"@echogarden/svoxpico-wasm": "^0.2.0",
|
|
69
|
-
"@echogarden/
|
|
70
|
+
"@echogarden/text-segmentation": "^0.3.1",
|
|
71
|
+
"@echogarden/transformers-nodejs-lite": "^2.17.1-lite.4",
|
|
72
|
+
"@echogarden/wave-codec": "^0.3.3",
|
|
70
73
|
"@mozilla/readability": "^0.6.0",
|
|
71
|
-
"alawmulaw": "^6.0.0",
|
|
72
74
|
"chalk": "^5.4.1",
|
|
73
|
-
"cldr-segmentation": "^2.2.1",
|
|
74
75
|
"command-exists": "^1.2.9",
|
|
75
|
-
"compromise": "^14.14.4",
|
|
76
76
|
"fs-extra": "^11.3.0",
|
|
77
77
|
"gaxios": "^6.7.1",
|
|
78
78
|
"graceful-fs": "^4.2.11",
|
|
@@ -84,14 +84,16 @@
|
|
|
84
84
|
"kuromoji": "^0.1.2",
|
|
85
85
|
"microsoft-cognitiveservices-speech-sdk": "^1.43.1",
|
|
86
86
|
"msgpack-lite": "^0.1.26",
|
|
87
|
-
"onnxruntime-node": "^1.
|
|
88
|
-
"openai": "^4.
|
|
87
|
+
"onnxruntime-node": "^1.22.0",
|
|
88
|
+
"openai": "^4.98.0",
|
|
89
|
+
"regexp-composer": "^0.3.0",
|
|
89
90
|
"sam-js": "^0.3.1",
|
|
90
91
|
"strip-ansi": "^7.1.0",
|
|
91
92
|
"tar": "^7.4.3",
|
|
92
93
|
"tiktoken": "^1.0.21",
|
|
93
94
|
"tinyld": "^1.3.4",
|
|
94
95
|
"wasm-feature-detect": "^1.8.0",
|
|
96
|
+
"wasm-heap-manager": "^0.2.2",
|
|
95
97
|
"ws": "^8.18.2",
|
|
96
98
|
"wtf_wikipedia": "^10.4.0"
|
|
97
99
|
},
|
|
@@ -112,7 +114,7 @@
|
|
|
112
114
|
"@types/graceful-fs": "^4.1.9",
|
|
113
115
|
"@types/jsdom": "^21.1.7",
|
|
114
116
|
"@types/msgpack-lite": "^0.1.11",
|
|
115
|
-
"@types/node": "^22.15.
|
|
117
|
+
"@types/node": "^22.15.18",
|
|
116
118
|
"@types/tar": "^6.1.13",
|
|
117
119
|
"@types/ws": "^8.18.1",
|
|
118
120
|
"ts-json-schema-generator": "^2.4.0",
|
|
@@ -3,7 +3,7 @@ import { Logger } from '../utilities/Logger.js'
|
|
|
3
3
|
import { loadPackage } from '../utilities/PackageManager.js'
|
|
4
4
|
import { alignDTWWindowed } from './DTWSequenceAlignmentWindowed.js'
|
|
5
5
|
import { cosineDistance } from '../math/VectorMath.js'
|
|
6
|
-
import {
|
|
6
|
+
import { includesPunctuation, isWord, parseText } from '../nlp/Segmentation.js'
|
|
7
7
|
import { Timeline, extractEntries } from '../utilities/Timeline.js'
|
|
8
8
|
|
|
9
9
|
export async function alignTimelineToTextSemantically(timeline: Timeline, text: string, textLangCode: string) {
|
|
@@ -26,13 +26,12 @@ export async function alignTimelineToTextSemantically(timeline: Timeline, text:
|
|
|
26
26
|
|
|
27
27
|
const timelineWordEntriesFiltered = timelineWordEntryGroups.flat()
|
|
28
28
|
|
|
29
|
-
const
|
|
29
|
+
const segmentedText = await parseText(text, textLangCode)
|
|
30
30
|
|
|
31
31
|
const textWordGroups: string[][] = []
|
|
32
32
|
|
|
33
|
-
for (const
|
|
34
|
-
|
|
35
|
-
wordGroup = wordGroup.filter(word => isWord(word))
|
|
33
|
+
for (const sentenceEntry of segmentedText.sentences) {
|
|
34
|
+
const wordGroup = sentenceEntry.words.nonPunctuationWords
|
|
36
35
|
|
|
37
36
|
textWordGroups.push(wordGroup)
|
|
38
37
|
}
|
|
@@ -197,8 +196,8 @@ export async function alignWordsToWordsSemantically(wordsGroups1: string[][], wo
|
|
|
197
196
|
|
|
198
197
|
// Align
|
|
199
198
|
function costFunction(a: TokenEmbeddingData, b: TokenEmbeddingData) {
|
|
200
|
-
const aIsPunctuation =
|
|
201
|
-
const bIsPunctuation =
|
|
199
|
+
const aIsPunctuation = includesPunctuation(a.text)
|
|
200
|
+
const bIsPunctuation = includesPunctuation(b.text)
|
|
202
201
|
|
|
203
202
|
if (aIsPunctuation === bIsPunctuation) {
|
|
204
203
|
return cosineDistance(a.embeddingVector, b.embeddingVector)
|
package/src/api/Alignment.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { AudioSourceParam, RawAudio, ensureRawAudio, getRawAudioDuration, normal
|
|
|
5
5
|
import { Logger } from '../utilities/Logger.js'
|
|
6
6
|
|
|
7
7
|
import * as API from './API.js'
|
|
8
|
-
import { Timeline, addTimeOffsetToTimeline,
|
|
8
|
+
import { Timeline, addTimeOffsetToTimeline, addWordTextOffsetsToTimelineInPlace, wordTimelineToSegmentSentenceTimeline } from '../utilities/Timeline.js'
|
|
9
9
|
import { formatLanguageCodeWithName, getDefaultDialectForLanguageCodeIfPossible, getShortLanguageCode, parseLangIdentifier } from '../utilities/Locale.js'
|
|
10
10
|
import { type WhisperAlignmentOptions } from '../recognition/WhisperSTT.js'
|
|
11
11
|
import chalk from 'chalk'
|
|
@@ -329,7 +329,7 @@ export async function align(input: AudioSourceParam, transcript: string, options
|
|
|
329
329
|
}
|
|
330
330
|
|
|
331
331
|
// Add text offsets
|
|
332
|
-
|
|
332
|
+
addWordTextOffsetsToTimelineInPlace(mappedTimeline, transcript)
|
|
333
333
|
|
|
334
334
|
// Make segment timeline
|
|
335
335
|
const { segmentTimeline } = await wordTimelineToSegmentSentenceTimeline(mappedTimeline, transcript, language, options.plainText?.paragraphBreaks, options.plainText?.whitespace)
|
package/src/api/Recognition.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { AudioSourceParam, RawAudio, ensureRawAudio, normalizeAudioLevelInPlace,
|
|
|
5
5
|
import { Logger } from '../utilities/Logger.js'
|
|
6
6
|
|
|
7
7
|
import * as API from './API.js'
|
|
8
|
-
import { Timeline,
|
|
8
|
+
import { Timeline, addWordTextOffsetsToTimelineInPlace, wordTimelineToSegmentSentenceTimeline } from '../utilities/Timeline.js'
|
|
9
9
|
import { formatLanguageCodeWithName, parseLangIdentifier } from '../utilities/Locale.js'
|
|
10
10
|
import { loadPackage } from '../utilities/PackageManager.js'
|
|
11
11
|
import chalk from 'chalk'
|
|
@@ -312,7 +312,7 @@ export async function recognize(input: AudioSourceParam, options: RecognitionOpt
|
|
|
312
312
|
}
|
|
313
313
|
|
|
314
314
|
// Add text offsets
|
|
315
|
-
|
|
315
|
+
addWordTextOffsetsToTimelineInPlace(timeline, transcript)
|
|
316
316
|
|
|
317
317
|
// Make segment timeline
|
|
318
318
|
const { segmentTimeline } = await wordTimelineToSegmentSentenceTimeline(timeline, transcript, languageCode, 'single', 'preserve')
|
|
@@ -48,7 +48,7 @@ export async function isolate(input: AudioSourceParam, options: SourceSeparation
|
|
|
48
48
|
// Release memory for the converted input audio since it's not needed anymore
|
|
49
49
|
inputRawAudioAs44100Stereo = undefined
|
|
50
50
|
|
|
51
|
-
await logger.startAsync(`Convert isolated audio to
|
|
51
|
+
await logger.startAsync(`Convert isolated audio back to original sample rate (${inputRawAudio.sampleRate} Hz) and channel count (${inputRawAudio.audioChannels.length})`)
|
|
52
52
|
isolatedRawAudio = await ensureRawAudio(isolatedRawAudio, inputRawAudio.sampleRate, inputRawAudio.audioChannels.length)
|
|
53
53
|
|
|
54
54
|
await logger.startAsync(`Subtract from original waveform to extract background audio`)
|
|
@@ -4,7 +4,7 @@ import { logToStderr } from '../utilities/Utilities.js'
|
|
|
4
4
|
import { AudioSourceParam, RawAudio, ensureRawAudio, normalizeAudioLevelInPlace, trimAudioEnd } from '../audio/AudioUtilities.js'
|
|
5
5
|
import { Logger } from '../utilities/Logger.js'
|
|
6
6
|
|
|
7
|
-
import { Timeline,
|
|
7
|
+
import { Timeline, addWordTextOffsetsToTimelineInPlace, wordTimelineToSegmentSentenceTimeline } from '../utilities/Timeline.js'
|
|
8
8
|
import { type WhisperOptions } from '../recognition/WhisperSTT.js'
|
|
9
9
|
import { formatLanguageCodeWithName, getShortLanguageCode, normalizeIdentifierToLanguageCode, parseLangIdentifier } from '../utilities/Locale.js'
|
|
10
10
|
import { EngineMetadata } from './Common.js'
|
|
@@ -201,7 +201,7 @@ export async function translateSpeech(input: AudioSourceParam, options: SpeechTr
|
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
if (wordTimeline) {
|
|
204
|
-
|
|
204
|
+
addWordTextOffsetsToTimelineInPlace(wordTimeline, transcript)
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
if (!segmentTimeline) {
|
package/src/api/Synthesis.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { clip, sha256AsHex, stringifyAndFormatJson, logToStderr, yieldToEventLoo
|
|
|
6
6
|
import { RawAudio, concatAudioSegments, downmixToMono, encodeRawAudioToWave, getSamplePeakDecibels, getEmptyRawAudio, getRawAudioDuration, trimAudioEnd, trimAudioStart, attenuateIfClippingInPlace, normalizeAudioLevelInPlace } from '../audio/AudioUtilities.js'
|
|
7
7
|
import { Logger } from '../utilities/Logger.js'
|
|
8
8
|
|
|
9
|
-
import { isWordOrSymbolWord,
|
|
9
|
+
import { isWordOrSymbolWord, parseText, splitToParagraphs } from '../nlp/Segmentation.js'
|
|
10
10
|
import { type RubberbandOptions } from '../dsp/Rubberband.js'
|
|
11
11
|
import { loadLexiconsForLanguage } from '../nlp/Lexicon.js'
|
|
12
12
|
|
|
@@ -116,9 +116,9 @@ async function synthesizeSegments(segments: string[], options: SynthesisOptions,
|
|
|
116
116
|
let timeOffset = 0
|
|
117
117
|
|
|
118
118
|
for (let segmentIndex = 0; segmentIndex < segments.length; segmentIndex++) {
|
|
119
|
-
const segmentText = segments[segmentIndex]
|
|
119
|
+
const segmentText = segments[segmentIndex]
|
|
120
120
|
|
|
121
|
-
logger.log(`\n${chalk.magentaBright(`Synthesizing segment ${segmentIndex + 1}/${segments.length}`)}: '${segmentText}'`)
|
|
121
|
+
logger.log(`\n${chalk.magentaBright(`Synthesizing segment ${segmentIndex + 1}/${segments.length}`)}: '${segmentText.trim()}'`)
|
|
122
122
|
|
|
123
123
|
const segmentStartTime = timeOffset
|
|
124
124
|
|
|
@@ -132,9 +132,9 @@ async function synthesizeSegments(segments: string[], options: SynthesisOptions,
|
|
|
132
132
|
|
|
133
133
|
let sentences: string[]
|
|
134
134
|
|
|
135
|
-
if ((options.splitToSentences || options.engine
|
|
136
|
-
|
|
137
|
-
sentences = sentences.
|
|
135
|
+
if ((options.splitToSentences || options.engine === 'vits' || options.engine === 'kokoro') && !options.ssml) {
|
|
136
|
+
const parsedText = await parseText(segmentText, options.language!)
|
|
137
|
+
sentences = parsedText.sentences.map(sentenceEntry => sentenceEntry.text)
|
|
138
138
|
|
|
139
139
|
if (sentences.length == 0) {
|
|
140
140
|
sentences = ['']
|
|
@@ -156,7 +156,7 @@ async function synthesizeSegments(segments: string[], options: SynthesisOptions,
|
|
|
156
156
|
|
|
157
157
|
const sentenceText = sentences[sentenceIndex].trim()
|
|
158
158
|
|
|
159
|
-
logger.log(`\n${chalk.magentaBright(`Synthesizing sentence ${sentenceIndex + 1}/${sentences.length}`)}: "${sentenceText}"`)
|
|
159
|
+
logger.log(`\n${chalk.magentaBright(`Synthesizing sentence ${sentenceIndex + 1}/${sentences.length}`)}: "${sentenceText.trim()}"`)
|
|
160
160
|
|
|
161
161
|
const sentenceStartTime = timeOffset
|
|
162
162
|
|
|
@@ -4,7 +4,7 @@ import { SubtitlesConfig } from '../subtitles/Subtitles.js'
|
|
|
4
4
|
import { formatLanguageCodeWithName, getShortLanguageCode, parseLangIdentifier } from '../utilities/Locale.js'
|
|
5
5
|
import { Logger } from '../utilities/Logger.js'
|
|
6
6
|
import { extendDeep } from '../utilities/ObjectUtilities.js'
|
|
7
|
-
import { Timeline,
|
|
7
|
+
import { Timeline, addWordTextOffsetsToTimelineInPlace, wordTimelineToSegmentSentenceTimeline } from '../utilities/Timeline.js'
|
|
8
8
|
import * as API from './API.js'
|
|
9
9
|
|
|
10
10
|
export async function alignTimelineTranslation(inputTimeline: Timeline, translatedTranscript: string, options: TimelineTranslationAlignmentOptions): Promise<TimelineTranslationAlignmentResult> {
|
|
@@ -95,7 +95,7 @@ export async function alignTimelineTranslation(inputTimeline: Timeline, translat
|
|
|
95
95
|
|
|
96
96
|
logger.start(`Postprocess timeline`)
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
addWordTextOffsetsToTimelineInPlace(mappedWordTimeline, translatedTranscript)
|
|
99
99
|
|
|
100
100
|
const { segmentTimeline: mappedTimeline } = await wordTimelineToSegmentSentenceTimeline(mappedWordTimeline, translatedTranscript, targetLanguage)
|
|
101
101
|
|
|
@@ -5,7 +5,7 @@ import { AudioSourceParam, RawAudio, ensureRawAudio, normalizeAudioLevelInPlace,
|
|
|
5
5
|
import { Logger } from '../utilities/Logger.js'
|
|
6
6
|
|
|
7
7
|
import * as API from './API.js'
|
|
8
|
-
import { Timeline,
|
|
8
|
+
import { Timeline, addWordTextOffsetsToTimelineInPlace, wordTimelineToSegmentSentenceTimeline } from '../utilities/Timeline.js'
|
|
9
9
|
import { formatLanguageCodeWithName, getShortLanguageCode, normalizeIdentifierToLanguageCode, parseLangIdentifier } from '../utilities/Locale.js'
|
|
10
10
|
import { type WhisperAlignmentOptions } from '../recognition/WhisperSTT.js'
|
|
11
11
|
import chalk from 'chalk'
|
|
@@ -124,7 +124,7 @@ export async function alignTranslation(input: AudioSourceParam, translatedTransc
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
// Add text offsets
|
|
127
|
-
|
|
127
|
+
addWordTextOffsetsToTimelineInPlace(mappedTimeline, translatedTranscript)
|
|
128
128
|
|
|
129
129
|
// Make segment timeline
|
|
130
130
|
const { segmentTimeline } = await wordTimelineToSegmentSentenceTimeline(mappedTimeline, translatedTranscript, sourceLanguage, options.plainText?.paragraphBreaks, options.plainText?.whitespace)
|