echogarden 2.1.0 → 2.1.2
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 +18 -15
- package/data/lexicons/heteronyms.en.json +299 -119
- package/data/lexicons/words.en.json +384 -0
- package/dist/nlp/Lexicon.d.ts +2 -0
- package/dist/nlp/Lexicon.js +21 -19
- package/dist/nlp/Lexicon.js.map +1 -1
- package/dist/synthesis/EspeakTTS.js +1 -1
- package/dist/synthesis/EspeakTTS.js.map +1 -1
- package/docs/CLI.md +1 -1
- package/docs/CUDA.md +17 -0
- package/docs/Development.md +9 -1
- package/docs/Engines.md +1 -1
- package/docs/Licenses.md +1 -0
- package/docs/Options.md +15 -14
- package/docs/Tasklist.md +0 -1
- package/docs/Technical.md +18 -11
- package/package.json +4 -4
- package/src/nlp/Lexicon.ts +27 -21
- package/src/synthesis/EspeakTTS.ts +1 -1
package/docs/Options.md
CHANGED
|
@@ -47,11 +47,11 @@ Applies to CLI operations: `speak`, `speak-file`, `speak-url`, `speak-wikipedia`
|
|
|
47
47
|
|
|
48
48
|
**Kokoro**:
|
|
49
49
|
* `kokoro.model`: model variant to use. Can be `82m-v1.0-fp32` or `82m-v1.0-quantized`. **Note**: the quantized model, while having lower memory usage, is significantly slower than the non-quantized (FP32) one. Defaults to `v1.0-fp32`
|
|
50
|
-
* `kokoro.provider`: ONNX execution provider to use. Can be `cpu`, `dml` ([DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration
|
|
50
|
+
* `kokoro.provider`: ONNX execution provider to use. Can be `cpu`, `dml` (Windows only, uses [DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration), or `cuda` (Linux only, requires system-wide installation of CUDA and cuDNN SDKs, see [this guide](./CUDA.md) for more detailed information). **Note**: `dml` provider (DirectML) seems to currently fail on inference. The cause for this error is [still under investigation](https://github.com/echogarden-project/echogarden/issues/94). Defaults to `cpu`
|
|
51
51
|
|
|
52
52
|
**VITS**:
|
|
53
53
|
* `vits.speakerId`: speaker ID, for VITS models that support multiple speakers. Defaults to `0`
|
|
54
|
-
* `vits.provider`: ONNX execution provider to use. Can be `cpu`, `dml` ([DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration
|
|
54
|
+
* `vits.provider`: ONNX execution provider to use. Can be `cpu`, `dml` (Windows only, uses [DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration), or `cuda` (Linux only, requires system-wide installation of CUDA and cuDNN SDKs, see [this guide](./CUDA.md) for more detailed information). Using GPU acceleration for VITS may or may not be faster than CPU, depending on your hardware. Defaults to `cpu`
|
|
55
55
|
|
|
56
56
|
**eSpeak**:
|
|
57
57
|
* `espeak.rate`: speech rate, in eSpeak units. Overrides `speed` when set
|
|
@@ -118,9 +118,10 @@ Applies to CLI operations: `speak`, `speak-file`, `speak-url`, `speak-wikipedia`
|
|
|
118
118
|
Applies to CLI operation: `list-voices`, API method: `requestVoiceList`
|
|
119
119
|
|
|
120
120
|
**General**:
|
|
121
|
-
* `
|
|
122
|
-
* `
|
|
123
|
-
* `
|
|
121
|
+
* `engine`: engine to list voices for. Required
|
|
122
|
+
* `language`: language code to filter by. Optional
|
|
123
|
+
* `voice`: name or name pattern to filter by. Optional
|
|
124
|
+
* `voiceGender`: gender to filter by. Optional
|
|
124
125
|
|
|
125
126
|
Also accepted are the following engine-specific options that may be required in order to retrieve the voice list:
|
|
126
127
|
* `googleCloud.apiKey`
|
|
@@ -134,7 +135,7 @@ Also accepted are the following engine-specific options that may be required in
|
|
|
134
135
|
Applies to CLI operation: `transcribe`, API method: `recognize`
|
|
135
136
|
|
|
136
137
|
**General**:
|
|
137
|
-
* `engine`: identifier of the recognition engine to use,
|
|
138
|
+
* `engine`: identifier of the recognition engine to use, can be `whisper`, `whisper.cpp`, `vosk` or `silero` (see [the full engine list](Engines.md) for more detailed information)
|
|
138
139
|
* `language`: language code ([ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)) for the audio, like `en`, `fr`, `de`. Auto-detected if not set
|
|
139
140
|
* `crop`: crop to active parts using voice activity detection before starting recognition. Defaults to `true`
|
|
140
141
|
* `isolate`: apply source separation to isolate voice before starting recognition. Defaults to `false`
|
|
@@ -156,8 +157,8 @@ Applies to CLI operation: `transcribe`, API method: `recognize`
|
|
|
156
157
|
* `whisper.repetitionThreshold`: minimal repetition / compressibility score to cause a part not to be auto-prompted to the next part. Defaults to `2.4`
|
|
157
158
|
* `whisper.decodeTimestampTokens`: enable/disable decoding of timestamp tokens. Setting to `false` can reduce the occurrence of hallucinations and token repetition loops, possibly due to the overall reduction in the number of tokens decoded. This has no impact on the accuracy of timestamps, since they are derived independently using cross-attention weights. However, there are cases where this can cause the model to end a part prematurely, especially in singing and less speech-like voice segments, or when there are multiple speakers. Defaults to `true`
|
|
158
159
|
* `whisper.timestampAccuracy`: timestamp accuracy. can be `medium` or `high`. `medium` uses a reduced subset of attention heads for alignment, `high` uses all attention heads and is thus more accurate at the word level, but slower for larger models. Defaults to `high` for the `tiny` and `base` models, and `medium` for the larger models
|
|
159
|
-
* `whisper.encoderProvider`: identifier for the ONNX execution provider to use with the encoder model. Can be `cpu`, `dml` ([DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration
|
|
160
|
-
* `whisper.decoderProvider`: identifier for the ONNX execution provider to use with the decoder model. Can be `cpu`, `dml` ([DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration
|
|
160
|
+
* `whisper.encoderProvider`: identifier for the ONNX execution provider to use with the encoder model. Can be `cpu`, `dml` (Windows only, uses [DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration), or `cuda` (Linux only, requires system-wide installation of CUDA and cuDNN SDKs, see [this guide](./CUDA.md) for more detailed information). In general, GPU-based encoding should be significantly faster. Defaults to `cpu`, or `dml` if available
|
|
161
|
+
* `whisper.decoderProvider`: identifier for the ONNX execution provider to use with the decoder model. Can be `cpu`, `dml` (Windows only, uses [DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration), or `cuda` (Linux only, requires system-wide installation of CUDA and cuDNN SDKs, see [this guide](./CUDA.md) for more detailed information).. Using GPU acceleration for the decoder may be faster than CPU, especially for larger models, but that depends on your particular combination of CPU and GPU. Defaults to `cpu`, and on Windows, `dml` if available, for larger models (`small`, `medium`, `large`)
|
|
161
162
|
* `whisper.seed`: provide a custom random seed for token selection when temperature is greater than 0. Uses a constant seed by default to ensure reproducibility
|
|
162
163
|
|
|
163
164
|
**Whisper.cpp**:
|
|
@@ -182,7 +183,7 @@ Applies to CLI operation: `transcribe`, API method: `recognize`
|
|
|
182
183
|
|
|
183
184
|
**Silero**:
|
|
184
185
|
* `silero.modelPath`: path to a Silero model. Note that latest `en`, `de`, `fr` and `uk` models are automatically installed when needed based on the selected language. This should only be used to manually specify a different model, otherwise specify `language` instead
|
|
185
|
-
* `silero.provider`: ONNX execution provider to use. Can be `cpu`, `dml` ([DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration
|
|
186
|
+
* `silero.provider`: ONNX execution provider to use. Can be `cpu`, `dml` (Windows only, uses [DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration), or `cuda` (Linux only, requires system-wide installation of CUDA and cuDNN SDKs, see [this guide](./CUDA.md) for more detailed information). Defaults to `cpu`, or `dml` if available
|
|
186
187
|
|
|
187
188
|
**Google Cloud**:
|
|
188
189
|
* `googleCloud.apiKey`: Google Cloud API key (required)
|
|
@@ -244,7 +245,7 @@ Applies to the `whisper` engine only. To provide Whisper options for `dtw-ra`, u
|
|
|
244
245
|
* `whisper.model`: Whisper model to use. Defaults to `tiny` or `tiny.en`
|
|
245
246
|
* `whisper.endTokenThreshold`: minimal probability to accept an end token for a recognized part. The probability is measured via the softmax between the end token's logit and the second highest logit. You can try to adjust this threshold in cases the model is ending a part with too few, or many tokens decoded. Defaults to `0.9`. On the last audio part, it is always effectively set to `Infinity`, to ensure the remaining transcript tokens are decoded in full
|
|
246
247
|
* `whisper.maxTokensPerPart`: maximum number of tokens to decode per part. Should help avoid edge cases where the model never reaches an end token for the part, which otherwise may cause the model to decode too many tokens and eventually crash. Defaults to 250
|
|
247
|
-
* `whisper.timestampAccuracy`: timestamp accuracy. can be `medium` or `high`. `medium` uses a reduced subset of attention heads for alignment, `high` uses all attention heads and is thus more accurate at the word level, but slower for larger models. Defaults to `high` for the `tiny` and `base` models, and `medium` for the larger models. Note: setting `high` for model `large-v3-turbo` reverts to `medium
|
|
248
|
+
* `whisper.timestampAccuracy`: timestamp accuracy. can be `medium` or `high`. `medium` uses a reduced subset of attention heads for alignment, `high` uses all attention heads and is thus more accurate at the word level, but slower for larger models. Defaults to `high` for the `tiny` and `base` models, and `medium` for the larger models. Note: setting `high` for model `large-v3-turbo` reverts to `medium`, due to poor results with the `high` setting for that model (possibly related to the 16-bit quantization).
|
|
248
249
|
* `whisper.encoderProvider`: encoder ONNX provider. See details in recognition section above
|
|
249
250
|
* `whisper.decoderProvider`: decoder ONNX provider. See details in recognition section above
|
|
250
251
|
|
|
@@ -360,7 +361,7 @@ Applies to CLI operation: `detect-speech-langauge`, API method: `detectSpeechLan
|
|
|
360
361
|
* `whisper.decoderProvider`: decoder ONNX execution provider. See details in recognition section above
|
|
361
362
|
|
|
362
363
|
**Silero**:
|
|
363
|
-
* `silero.provider`: ONNX execution provider to use. Can be `cpu`, `dml` ([DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration
|
|
364
|
+
* `silero.provider`: ONNX execution provider to use. Can be `cpu`, `dml` (Windows only, uses [DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration), or `cuda` (Linux only, requires system-wide installation of CUDA and cuDNN SDKs, see [this guide](./CUDA.md) for more detailed information). Using GPU may be faster, but the initialization overhead is larger. **Note**: `dml` provider seems to be unstable at the moment for this model. Defaults to `cpu`
|
|
364
365
|
|
|
365
366
|
### Text language detection
|
|
366
367
|
|
|
@@ -385,7 +386,7 @@ Applies to CLI operation: `detect-voice-activity`, API method: `detectVoiceActiv
|
|
|
385
386
|
|
|
386
387
|
**Silero**:
|
|
387
388
|
* `silero.frameDuration`: Silero frame duration (ms). Can be `30`, `60` or `90`. Defaults to `90`
|
|
388
|
-
* `silero.provider`: ONNX provider to use. Can be `cpu`, `dml` ([DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration
|
|
389
|
+
* `silero.provider`: ONNX provider to use. Can be `cpu`, `dml` (Windows only, uses [DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration), or `cuda` (Linux only, requires system-wide installation of CUDA and cuDNN SDKs, see [this guide](./CUDA.md) for more detailed information). Using GPU is likely to be slower than CPU due to inference being independently executed on each audio frame. Defaults to `cpu` (recommended)
|
|
389
390
|
|
|
390
391
|
## Speech denoising
|
|
391
392
|
|
|
@@ -402,7 +403,7 @@ Applies to CLI operation: `denoise`, API method: `denoise`
|
|
|
402
403
|
|
|
403
404
|
**NSNet2**:
|
|
404
405
|
* `nsnet2.model`: can be `baseline-16khz` or `baseline-48khz`. Defaults to `baseline-48khz`
|
|
405
|
-
* `nsnet2.provider`: ONNX execution provider (**Note**: `dml` provider seems to fail with these models). Defaults to `cpu`
|
|
406
|
+
* `nsnet2.provider`: ONNX execution provider. Can be `cpu`, `dml` or `cuda` (**Note**: `dml` provider seems to fail with these models). Defaults to `cpu`
|
|
406
407
|
* `maxAttenuation`: maximum amount of attenuation, in decibels, applied to an FFT bin when filtering the audio frames. Defaults to `30`
|
|
407
408
|
|
|
408
409
|
## Source separation
|
|
@@ -416,7 +417,7 @@ Applies to CLI operation: `isolate`, API method: `isolate`
|
|
|
416
417
|
**MDX-NET**:
|
|
417
418
|
|
|
418
419
|
* `mdxNet.model`: model to use. Currently available models are `UVR_MDXNET_1_9703`, `UVR_MDXNET_2_9682`, `UVR_MDXNET_3_9662`, `UVR_MDXNET_KARA`, and higher quality models `UVR_MDXNET_Main` and `Kim_Vocal_2`. Defaults to `UVR_MDXNET_1_9703`
|
|
419
|
-
* `mdxNet.provider`: ONNX execution provider to use. Can be `cpu`, `dml` ([DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration
|
|
420
|
+
* `mdxNet.provider`: ONNX execution provider to use. Can be `cpu`, `dml` (Windows only, uses [DirectML](https://microsoft.github.io/DirectML/)-based GPU acceleration), or `cuda` (Linux only, requires system-wide installation of CUDA and cuDNN SDKs, see [this guide](./CUDA.md) for more detailed information). Defaults to `dml` if available (Windows) or `cpu` (other platforms)
|
|
420
421
|
|
|
421
422
|
# Common options
|
|
422
423
|
|
package/docs/Tasklist.md
CHANGED
|
@@ -118,7 +118,6 @@
|
|
|
118
118
|
* When `splitToSentences` is set to `false`, the timeline doesn't include proper sentences. Find a way to pass larger sections to the TTS, but still have proper sentences in the timeline
|
|
119
119
|
|
|
120
120
|
### Synthesis / preprocessing
|
|
121
|
-
* Extend the heteronyms JSON document with additional words like "conducts", "survey", "protest", "transport", "abuse", "combat", "combats", "affect", "contest", "detail", "marked", "contrast", "construct", "constructs", "console", "recall", "permit", "permits", "prospect", "prospects", "proceed", "proceeds", "invite", "reject", "deserts", "transcript", "transcripts", "compact", "impact", "impacts", "estimate"
|
|
122
121
|
* Full date normalization (e.g. `21 August 2023`, `21 Aug 2023`, `August 21, 2023`)
|
|
123
122
|
* Add support for capitalized-only rules, and possibly also all uppercase / all lowercase rules
|
|
124
123
|
* Add support for multiple words in `precededBy` and `succeededBy`
|
package/docs/Technical.md
CHANGED
|
@@ -2,36 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
* Echogarden is written in TypeScript and targets the Node.js platform.
|
|
4
4
|
* It uses ESM modules and latest ECMAScript and TypeScript features.
|
|
5
|
-
* It does not depend on essential binary executables. Instead, all of its engines either use pure JavaScript, WebAssembly, WASI, or the ONNX runtime, with some exceptions: the CLI does invoke a command line `ffmpeg` tool, auto-downloaded
|
|
5
|
+
* It does not depend on essential binary executables. Instead, all of its engines either use pure JavaScript, WebAssembly, WASI, or the ONNX runtime, with some exceptions: the CLI does invoke a command line `ffmpeg` tool, auto-downloaded using its internal package system.
|
|
6
6
|
* It does not depend on essential native node.js modules requiring install-time compilation with `node-gyp`. This greatly simplifies the installation experience for end-users (the ONNX runtime bundles precompiled NAPI modules for all supported platforms - it doesn't require any compilation during its installation).
|
|
7
7
|
|
|
8
8
|
## Package system
|
|
9
9
|
|
|
10
10
|
Echogarden uses its own package system to download and install various components as needed. These components can be TTS voices, STT models, or other types of models and data.
|
|
11
11
|
|
|
12
|
-
Packages are downloaded as `.tar.gz` files, and are extracted to `[data-folder]/packages/[package-
|
|
12
|
+
Packages are downloaded as `.tar.gz` files, and are extracted to `[data-folder]/packages/[package-id-string]`. Each package has its own subdirectory.
|
|
13
13
|
|
|
14
14
|
`[data-folder]` is located at:
|
|
15
15
|
* `%AppData%\Local\echogarden` on Windows
|
|
16
16
|
* `Users/User/Library/Application Support/echogarden` on macOS
|
|
17
17
|
* `/home/user/.local/share/echogarden` on Linux
|
|
18
18
|
|
|
19
|
+
`[package-id-string]` is formatted as:
|
|
20
|
+
```
|
|
21
|
+
[engine name]-[package id]-[date as yyyymmdd]
|
|
22
|
+
```
|
|
23
|
+
|
|
19
24
|
By using downloadable packages, the installed size is made significantly smaller and the installation faster. The total size of all available packages is currently about 50GB (may not be up-to-date).
|
|
20
25
|
|
|
21
|
-
The packages are currently hosted and downloaded from a dedicated
|
|
26
|
+
The packages are currently hosted and downloaded from a [dedicated Hugging Face repository](https://huggingface.co/echogarden/echogarden-packages).
|
|
22
27
|
|
|
23
28
|
## Can the base install size be made smaller?
|
|
24
29
|
|
|
25
|
-
The base installed (uncompressed) size, including dependencies, is around
|
|
30
|
+
The base installed (uncompressed) size, including dependencies, is around 400MB (may not be up-to-date). This is without any models or voices, which are downloaded as needed.
|
|
26
31
|
|
|
27
32
|
Currently, the largest contributors to the size are:
|
|
28
33
|
|
|
29
|
-
* `onnxruntime-node` (NAPI):
|
|
30
|
-
* `kuromoji` (JavaScript) 40MB
|
|
31
|
-
* `
|
|
32
|
-
* `
|
|
34
|
+
* `onnxruntime-node` (core inference runtime, NAPI): 180MB
|
|
35
|
+
* `kuromoji` (Japanese tokenizer, JavaScript) 40MB
|
|
36
|
+
* `espeak-ng-emscripten` (core synthesis and phonemization engine, WASM): 23MB
|
|
37
|
+
* `tiktoken` (tokenizer library, WASM): 22MB
|
|
38
|
+
* `flite-wasi` (synthesis engine, WASI): 20MB
|
|
39
|
+
* `jieba-wasm` (Chinese tokenizer, WASM): 14MB
|
|
33
40
|
|
|
34
|
-
`onnxruntime-node` is large because it bundles pre-compiled binaries for multiple platforms. `kuromoji` is large because of its dictionary files and some unessential test code it bundles. The other
|
|
41
|
+
`onnxruntime-node` is large because it bundles pre-compiled binaries for multiple platforms. `kuromoji` is large because of its dictionary files and some unessential test code it bundles. The other packages include large WASM binaries.
|
|
35
42
|
|
|
36
43
|
So, yes, in the future it may be possible to reduce the core installed size by dynamically installing some of these dependencies, or using modified, "slimmed-down" versions of some packages.
|
|
37
44
|
|
|
@@ -44,7 +51,7 @@ However, it is a lot of work, and only a subset of the engines can be supported
|
|
|
44
51
|
* Significantly slower inference when using CPU for ONNX models
|
|
45
52
|
* No cross-domain network connectivity - can't connect to Google Cloud, Microsoft, Amazon etc. without a proxy
|
|
46
53
|
* Large initial download size would make it too heavy and slow to load as part of a standard web page directly
|
|
47
|
-
* Large memory
|
|
54
|
+
* Large memory requirements for the various ONNX models, starting at about 800MB - 1GB, which is a bit too much for a browser
|
|
48
55
|
* Due to the high code complexity, data size, and memory consumption, it is unlikely that a browser extension, internally bundling some of the models, would be accepted to the Chrome and Firefox web stores
|
|
49
56
|
* Will require a virtual file system to store models and make use of downloadable packages
|
|
50
57
|
* Requires duplicating a lot of prior work, porting many node.js-only APIs, and increasing code complexity
|
|
@@ -71,5 +78,5 @@ Also, `option=value` is more similar to the syntax used in the configuration fil
|
|
|
71
78
|
|
|
72
79
|
* `src`: TypeScript source code
|
|
73
80
|
* `dist`: compiled JavaScript modules
|
|
74
|
-
* `data`: various data files, including phonetic lexicons and language code conversion tables. `data/schemas` stores JSON schemas for all configuration options, auto-generated using [`ts-json-schema-generator`](https://github.com/vega/ts-json-schema-generator) directly from the TypeScript code, and used by the CLI to parse and validate the options provided
|
|
81
|
+
* `data`: various data files, including phonetic lexicons and language code conversion tables. `data/schemas` stores JSON schemas for all configuration options, auto-generated using [`ts-json-schema-generator`](https://github.com/vega/ts-json-schema-generator) directly from the TypeScript code, and used by the CLI to parse and validate the options provided. `data/lexicons` contains phonetic lexicons used in speech synthesis and alignment
|
|
75
82
|
* `docs`: documentation
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "echogarden",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.2",
|
|
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,7 +52,7 @@
|
|
|
52
52
|
"echogarden": "./dist/cli/CLILauncher.js"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@aws-sdk/client-polly": "^3.
|
|
55
|
+
"@aws-sdk/client-polly": "^3.747.0",
|
|
56
56
|
"@aws-sdk/client-transcribe-streaming": "^3.744.0",
|
|
57
57
|
"@echogarden/audio-io": "^0.3.0",
|
|
58
58
|
"@echogarden/espeak-ng-emscripten": "^0.3.3",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"microsoft-cognitiveservices-speech-sdk": "^1.42.0",
|
|
86
86
|
"msgpack-lite": "^0.1.26",
|
|
87
87
|
"onnxruntime-node": "^1.20.1",
|
|
88
|
-
"openai": "^4.
|
|
88
|
+
"openai": "^4.85.1",
|
|
89
89
|
"sam-js": "^0.3.1",
|
|
90
90
|
"strip-ansi": "^7.1.0",
|
|
91
91
|
"tar": "^7.4.3",
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
"@types/graceful-fs": "^4.1.9",
|
|
113
113
|
"@types/jsdom": "^21.1.7",
|
|
114
114
|
"@types/msgpack-lite": "^0.1.11",
|
|
115
|
-
"@types/node": "^22.13.
|
|
115
|
+
"@types/node": "^22.13.4",
|
|
116
116
|
"@types/tar": "^6.1.13",
|
|
117
117
|
"@types/ws": "^8.5.14",
|
|
118
118
|
"ts-json-schema-generator": "^2.3.0",
|
package/src/nlp/Lexicon.ts
CHANGED
|
@@ -3,9 +3,9 @@ import { getShortLanguageCode } from '../utilities/Locale.js'
|
|
|
3
3
|
import { resolveToModuleRootDir } from '../utilities/PathUtilities.js'
|
|
4
4
|
|
|
5
5
|
export function tryGetFirstLexiconSubstitution(sentenceWords: string[], wordIndex: number, lexicons: Lexicon[], languageCode: string) {
|
|
6
|
-
|
|
6
|
+
for (let i = lexicons.length - 1; i >= 0; i--) {
|
|
7
|
+
const lexicon = lexicons[i]
|
|
7
8
|
|
|
8
|
-
for (const lexicon of reversedLexicons) {
|
|
9
9
|
const match = tryGetLexiconSubstitution(sentenceWords, wordIndex, lexicon, languageCode)
|
|
10
10
|
|
|
11
11
|
if (match) {
|
|
@@ -20,51 +20,51 @@ export function tryGetLexiconSubstitution(sentenceWords: string[], wordIndex: nu
|
|
|
20
20
|
let word = sentenceWords[wordIndex]
|
|
21
21
|
|
|
22
22
|
if (!word) {
|
|
23
|
-
return
|
|
23
|
+
return undefined
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
const shortLanguageCode = getShortLanguageCode(languageCode)
|
|
27
27
|
const lexiconForLanguage = lexicon[shortLanguageCode]
|
|
28
28
|
|
|
29
29
|
if (!lexiconForLanguage) {
|
|
30
|
-
return
|
|
30
|
+
return undefined
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
const lexiconEntry = lexiconForLanguage[word]
|
|
34
34
|
|
|
35
35
|
if (!lexiconEntry) {
|
|
36
|
-
return
|
|
36
|
+
return undefined
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
for (let i = 0; i < lexiconEntry.length; i++) {
|
|
40
|
-
const
|
|
40
|
+
const candidateEntry = lexiconEntry[i]
|
|
41
41
|
|
|
42
|
-
const
|
|
42
|
+
const pronunciationPhonemesText = candidateEntry?.pronunciation?.espeak?.[languageCode]
|
|
43
43
|
|
|
44
|
-
if (!
|
|
44
|
+
if (!pronunciationPhonemesText) {
|
|
45
45
|
continue
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
const precedingWord = sentenceWords[wordIndex - 1]
|
|
49
|
-
const
|
|
48
|
+
const precedingWord = sentenceWords[wordIndex - 1] ?? ''
|
|
49
|
+
const followingWord = sentenceWords[wordIndex + 1] ?? ''
|
|
50
50
|
|
|
51
|
-
const precededBy =
|
|
52
|
-
const notPrecededBy =
|
|
51
|
+
const precededBy = candidateEntry?.precededBy ?? []
|
|
52
|
+
const notPrecededBy = candidateEntry?.notPrecededBy ?? []
|
|
53
53
|
|
|
54
|
-
const
|
|
55
|
-
const
|
|
54
|
+
const followedBy = candidateEntry?.followedBy ?? candidateEntry?.succeededBy ?? []
|
|
55
|
+
const notFollowedBy = candidateEntry?.notFollowedBy ?? candidateEntry?.notSucceededBy ?? []
|
|
56
56
|
|
|
57
|
-
const hasNegativePattern = notPrecededBy.includes(precedingWord) ||
|
|
58
|
-
const hasPositivePattern = precededBy.includes(precedingWord) ||
|
|
57
|
+
const hasNegativePattern = notPrecededBy.includes(precedingWord) || notFollowedBy.includes(followingWord)
|
|
58
|
+
const hasPositivePattern = precededBy.includes(precedingWord) || followedBy.includes(followingWord)
|
|
59
59
|
|
|
60
|
-
if (i
|
|
61
|
-
const substitutionPhonemes =
|
|
60
|
+
if (i === lexiconEntry.length - 1 || (hasPositivePattern && !hasNegativePattern)) {
|
|
61
|
+
const substitutionPhonemes = pronunciationPhonemesText.split(/ +/g)
|
|
62
62
|
|
|
63
63
|
return substitutionPhonemes
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
return
|
|
67
|
+
return undefined
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
export async function loadLexiconFile(jsonFilePath: string): Promise<Lexicon> {
|
|
@@ -77,6 +77,9 @@ export async function loadLexiconsForLanguage(language: string, customLexiconPat
|
|
|
77
77
|
const lexicons: Lexicon[] = []
|
|
78
78
|
|
|
79
79
|
if (getShortLanguageCode(language) == 'en') {
|
|
80
|
+
const wordsLexicon = await loadLexiconFile(resolveToModuleRootDir('data/lexicons/words.en.json'))
|
|
81
|
+
lexicons.push(wordsLexicon)
|
|
82
|
+
|
|
80
83
|
const heteronymsLexicon = await loadLexiconFile(resolveToModuleRootDir('data/lexicons/heteronyms.en.json'))
|
|
81
84
|
lexicons.push(heteronymsLexicon)
|
|
82
85
|
}
|
|
@@ -112,8 +115,11 @@ export type LexiconEntry = {
|
|
|
112
115
|
precededBy?: string[]
|
|
113
116
|
notPrecededBy?: string[]
|
|
114
117
|
|
|
115
|
-
|
|
116
|
-
|
|
118
|
+
followedBy?: string[]
|
|
119
|
+
notFollowedBy?: string[]
|
|
120
|
+
|
|
121
|
+
succeededBy?: string[] // Deprecated. Replaced by 'followedBy'
|
|
122
|
+
notSucceededBy?: string[] // Deprecated. Replaced by 'notFollowedBy'
|
|
117
123
|
|
|
118
124
|
example?: string
|
|
119
125
|
}
|
|
@@ -324,7 +324,7 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
|
|
|
324
324
|
throw new Error('Unexpected: token timeline should exist and have at least one token')
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
-
if (tokenTimeline.length !== 1
|
|
327
|
+
if (tokenTimeline.length !== 1 || tokenTimeline[0].text !== '') {
|
|
328
328
|
continue
|
|
329
329
|
}
|
|
330
330
|
|