@qvac/tts-ggml 0.11.1 → 0.13.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 +104 -18
- package/addon-unavailable.js +12 -28
- package/binding.js +1 -52
- package/examples/moss-sfx-fit.js +14 -7
- package/index.d.ts +5 -3
- package/index.js +1 -3
- package/lib/fit.d.ts +3 -3
- package/lib/fit.js +5 -11
- package/package.json +37 -41
- package/test/integration/fit.test.js +115 -18
- package/test/integration/moss-fit.test.js +13 -13
- package/test/integration/moss-sfx-fit.test.js +14 -14
- package/test/integration/moss-speech.test.js +19 -5
- package/test/integration/moss.test.js +92 -55
- package/test/mobile/integration.auto.cjs +10 -0
- package/test/mobile/test-groups.json +6 -2
- package/test/utils/gpuOnly.js +15 -0
- package/test/utils/mossBackend.js +34 -0
- package/test/utils/mossGpuValidation.js +70 -0
- package/test/utils/perf-helper.js +275 -0
- package/test/utils/testThreads.js +5 -0
- package/lib/backends.d.ts +0 -10
- package/lib/backends.js +0 -76
package/README.md
CHANGED
|
@@ -29,7 +29,8 @@ Xclipse/Mali → Vulkan). Parler supports Apple/Metal, linux CUDA, and the
|
|
|
29
29
|
validated Android paths, including Vulkan on ARM Mali (see
|
|
30
30
|
[Backends & GPU acceleration](#backends--gpu-acceleration)). Audio8 supports
|
|
31
31
|
CUDA/Vulkan offload on Linux and Vulkan on Windows. MOSS GPU offload is
|
|
32
|
-
validated on Apple/Metal
|
|
32
|
+
validated on Apple/Metal; desktop CUDA/Vulkan validation requires the native
|
|
33
|
+
and registry prerequisites described under [MOSS](#moss).
|
|
33
34
|
|
|
34
35
|
[qvac-tts-cpp]: https://github.com/tetherto/qvac-fabric-speech.cpp/tree/master/engines/tts
|
|
35
36
|
|
|
@@ -54,8 +55,9 @@ validated on Apple/Metal.
|
|
|
54
55
|
iOS, picked up when staged next to the model (see
|
|
55
56
|
[Core ML sidecars on Apple](#core-ml-sidecars-on-apple)).
|
|
56
57
|
- **Dynamic backend loading on Android** — per-arch CPU + Vulkan +
|
|
57
|
-
OpenCL `.so` files ship under
|
|
58
|
-
and
|
|
58
|
+
OpenCL `.so` files ship under
|
|
59
|
+
`prebuilds/<bare-target>/qvac__tts-ggml-android-arm64/` and the addon picks
|
|
60
|
+
them up at runtime from next to its native module (see
|
|
59
61
|
[Backends & GPU acceleration](#backends--gpu-acceleration)).
|
|
60
62
|
- **Cancellation** via `model.cancel()` — stops T3 decode on the next
|
|
61
63
|
token; in-flight S3Gen chunk runs to completion.
|
|
@@ -150,11 +152,10 @@ package selected at install time through `os`/`cpu` filtered
|
|
|
150
152
|
|
|
151
153
|
Do not depend on desktop platform packages directly. Supported installers are
|
|
152
154
|
npm 7+, pnpm, bun, and Yarn Berry. Yarn v1 and `--omit=optional` installs skip
|
|
153
|
-
the platform package and fail at require time
|
|
154
|
-
package
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
loaded ggml backends. Unsupported targets must
|
|
155
|
+
the platform package and fail at require time, and at `bare-pack` time, naming
|
|
156
|
+
the missing package. Each platform package is an ordinary Bare addon whose
|
|
157
|
+
`prebuilds/<host>/` holds the native module and, next to it, the dynamically
|
|
158
|
+
loaded ggml backends the module finds on its own. Unsupported targets must
|
|
158
159
|
[build from source](#build-from-source); installation does not automatically
|
|
159
160
|
compile a local addon.
|
|
160
161
|
|
|
@@ -805,13 +806,13 @@ registration and the addon falls back to Vulkan or CPU.
|
|
|
805
806
|
|
|
806
807
|
Android prebuilds enable `GGML_BACKEND_DL=ON` and ship per-arch
|
|
807
808
|
backend `.so` files under
|
|
808
|
-
`prebuilds
|
|
809
|
+
`prebuilds/android-arm64/qvac__tts-ggml-android-arm64/` of
|
|
810
|
+
`@qvac/tts-ggml-android-arm64`; `bare-link` puts them next to the module in
|
|
811
|
+
the app, where the addon looks when `backendsDir` is unset.
|
|
809
812
|
|
|
810
813
|
The engine `dlopen()`s the highest-tier CPU variant the device's
|
|
811
814
|
HWCAPs support and one of the GPU `.so` files based on the policy
|
|
812
|
-
table above.
|
|
813
|
-
'prebuilds')` (or rely on the default fallback the package ships)
|
|
814
|
-
so the runtime knows where to look. `openclCacheDir` is also
|
|
815
|
+
table above. `openclCacheDir` is
|
|
815
816
|
Android-specific; setting it to a writable path lets the OpenCL
|
|
816
817
|
backend persist its compiled program cache across launches.
|
|
817
818
|
`vulkanCacheDir` is the Vulkan analogue (Supertonic + `useGPU: true`):
|
|
@@ -1060,6 +1061,82 @@ falls back to CPU and sets `response.stats.gpuUnsupported`. `backendsDir`
|
|
|
1060
1061
|
reaches MOSS like every other engine, so builds that load ggml backends at
|
|
1061
1062
|
runtime find them.
|
|
1062
1063
|
|
|
1064
|
+
The same controls apply to MOSS-TTSD and MOSS-Speech. `nGpuLayers` is a
|
|
1065
|
+
boolean GPU request for these engines (zero = CPU, non-zero = GPU), not a
|
|
1066
|
+
partial layer count. The addon forwards these controls to the native engine;
|
|
1067
|
+
it does not choose a different backend or change the CPU default.
|
|
1068
|
+
`response.stats.backendId` identifies the language-model backend (2 = CUDA,
|
|
1069
|
+
3 = Vulkan); it is not a measurement of every codec operation.
|
|
1070
|
+
|
|
1071
|
+
The combined desktop CUDA/Vulkan speech changes in
|
|
1072
|
+
[Vulkan #308](https://github.com/tetherto/qvac-fabric-speech.cpp/pull/308),
|
|
1073
|
+
including [CUDA #321](https://github.com/tetherto/qvac-fabric-speech.cpp/pull/321),
|
|
1074
|
+
merged to native master at `84b02694001cfea863167776dbc185474a816656`.
|
|
1075
|
+
This checkout consumes the merged [registry #423](https://github.com/tetherto/qvac-registry-vcpkg/pull/423)
|
|
1076
|
+
at `e31be272ecdf9f20970302ebf8a2943d47803001`: `speech-cpp` 2026-10-12#1
|
|
1077
|
+
pins that merged revision, and `ggml-speech` 2026-10-07#1 pins
|
|
1078
|
+
`06f1b66806626a635904f31db6914ad2d0e71197`. The earlier native `f4d4c257`
|
|
1079
|
+
passed ten smaller-model CUDA/Vulkan cases; those results do not establish GPU
|
|
1080
|
+
validation of the final native revision or the packaged addon. Rebuild the addon
|
|
1081
|
+
before running its GPU tests. Native desktop results also do not establish
|
|
1082
|
+
Android support or speech-quality signoff.
|
|
1083
|
+
|
|
1084
|
+
The registry `baseline` is the main commit containing #423. The shared exact
|
|
1085
|
+
`speech-cpp` overrides and backend implementation are already on qvac main.
|
|
1086
|
+
This baseline update completes the TTS registry configuration; packaged-addon
|
|
1087
|
+
CUDA/Vulkan inference still requires validation on provisioned GPU hosts before
|
|
1088
|
+
claiming a validated release.
|
|
1089
|
+
|
|
1090
|
+
From `packages/tts-ggml`, resolve the checked-in manifest without building or
|
|
1091
|
+
downloading models (with `VCPKG_ROOT` set):
|
|
1092
|
+
|
|
1093
|
+
```sh
|
|
1094
|
+
vcpkg install --dry-run --triplet x64-linux --x-feature=cuda --x-feature=vulkan
|
|
1095
|
+
```
|
|
1096
|
+
|
|
1097
|
+
On a macOS host without a Linux cross-compiler, prefix that dry-run command
|
|
1098
|
+
with `VCPKG_FEATURE_FLAGS=-compilertracking` to check registry resolution only.
|
|
1099
|
+
For a bounded native build on a suitably provisioned Linux GPU host:
|
|
1100
|
+
|
|
1101
|
+
```sh
|
|
1102
|
+
CMAKE_BUILD_PARALLEL_LEVEL=2 VCPKG_MAX_CONCURRENCY=2 npm run build:cuda
|
|
1103
|
+
```
|
|
1104
|
+
|
|
1105
|
+
The normal PR workflow requires approval of the `fork-ci` environment for
|
|
1106
|
+
external forks. Obtain that approval through the existing gate; a manual
|
|
1107
|
+
workflow dispatch is not a substitute for fork approval.
|
|
1108
|
+
|
|
1109
|
+
On a desktop with those prerequisites, stage the TTS and TTSD backbones,
|
|
1110
|
+
codec decoder/encoder and the bundled `test/reference-audio/jfk.wav`, plus
|
|
1111
|
+
the Speech model/codec. Set
|
|
1112
|
+
`QVAC_TEST_MOSS_MODEL_DIR` and `QVAC_TEST_MOSS_SPEECH_MODEL_DIR` to their
|
|
1113
|
+
respective directories. Run each available backend in a fresh process:
|
|
1114
|
+
|
|
1115
|
+
```sh
|
|
1116
|
+
QVAC_TEST_MOSS_FULL_GPU=true TTS_CPP_GPU_BACKEND=cuda npx --no-install brittle-bare test/integration/moss.test.js test/integration/moss-speech.test.js
|
|
1117
|
+
QVAC_TEST_MOSS_FULL_GPU=true TTS_CPP_GPU_BACKEND=vulkan npx --no-install brittle-bare test/integration/moss.test.js test/integration/moss-speech.test.js
|
|
1118
|
+
```
|
|
1119
|
+
|
|
1120
|
+
The tests check the exact pinned backend, `backendDevice` and
|
|
1121
|
+
`gpuUnsupported` for TTS batch/streaming/cloning, TTSD dialogue, and Speech
|
|
1122
|
+
text/audio replies. CPU control cases still require CPU even with a GPU pin.
|
|
1123
|
+
`QVAC_TEST_MOSS_FULL_GPU=true` fails before model loading unless both model
|
|
1124
|
+
directories, the TTS/TTSD/Speech backbones, all three codec GGUFs, and the
|
|
1125
|
+
reference WAV exist. It also requires an explicit backend pin (case-insensitive),
|
|
1126
|
+
rejects `NO_GPU=true` and mobile CPU-only cases, and checks that every required
|
|
1127
|
+
case completes. Run both files together without test filters: a successful full
|
|
1128
|
+
run has 12 passing tests, including the two completion checks, and no skips.
|
|
1129
|
+
Preflight only checks asset presence; actual model loading and inference must
|
|
1130
|
+
also pass. These commands cover TTS, TTSD and Speech, not MOSS-SoundEffect (SFX).
|
|
1131
|
+
No addon CUDA/Vulkan hardware run has been completed for this test change yet.
|
|
1132
|
+
|
|
1133
|
+
Without strict mode, developer behavior is unchanged: an unpinned run accepts
|
|
1134
|
+
the normal GPU cascade, missing model directories skip tests, and missing
|
|
1135
|
+
encoder/TTSD assets omit cloning/dialogue cases. Such runs are not full GPU
|
|
1136
|
+
validation. `npm run test:node` covers backend selection and strict validation
|
|
1137
|
+
failures without loading models. Do not load these multi-GB models on
|
|
1138
|
+
memory-constrained hosts.
|
|
1139
|
+
|
|
1063
1140
|
## MOSS-SoundEffect
|
|
1064
1141
|
|
|
1065
1142
|
MOSS-SoundEffect-v2 generates a sound effect from a text description: a Qwen3
|
|
@@ -1228,7 +1305,7 @@ instance. Runtime stats add `promptTokens`, `generatedTokens`, `replyTokens`,
|
|
|
1228
1305
|
| `promptText` | string | — | CosyVoice3-only: verbatim transcript of `referenceAudio` — set for zero-shot cloning, omit for cross-lingual; without a reference it overrides the baked voice's transcript |
|
|
1229
1306
|
| `mecabDictDir` | string | — | Chatterbox MTL Japanese (`ja`): compiled MeCab/IPAdic dictionary directory |
|
|
1230
1307
|
| `cangjieTsvPath` | string | — | Chatterbox MTL Chinese (`zh`): `Cangjie5_TC` TSV path |
|
|
1231
|
-
| `backendsDir` | string |
|
|
1308
|
+
| `backendsDir` | string | the module's own | Directory the addon scans, as given, for dynamically-loaded ggml backend `.so` / `.dll` files. Unset scans the directory the native module was loaded from (`prebuilds/<host>/qvac__tts-ggml-<suffix>/` in a platform package, the app's native library directory after `bare-link`); ignored on platforms that statically link the backend |
|
|
1232
1309
|
| `openclCacheDir` | string | unset | Android-only: directory where the OpenCL backend persists its compiled program-binary cache. Setting it across runs avoids re-JITing the kernels on every fresh process |
|
|
1233
1310
|
| `vulkanCacheDir` | string | unset | Supertonic + `useGPU: true` only: writable directory where the Vulkan backend persists its compiled pipeline cache (`GGML_VK_PIPELINE_CACHE_DIR`). Moves the one-time first-dispatch pipeline-compile cost (seconds on Mali) off the first `run()` — paid once per install instead of once per process — and enables a load-time pre-warm. Fully opt-in: unset -> no cross-process cache, no pre-warm, behaviour unchanged |
|
|
1234
1311
|
| `config.language` | string | `"en"` | Chatterbox MTL accepts `es/fr/de/pt/it/zh/ja/ko/...`; turbo & Supertonic are English; MOSS takes it as a prompt hint (`en`, `zh`, ...) |
|
|
@@ -1348,12 +1425,14 @@ const {
|
|
|
1348
1425
|
|
|
1349
1426
|
`assessFit` projects a load against the memory free right now. It reads GGUF metadata and never weight data, so the registry's weightless copy of each file answers the same as the file itself and the projection can run before anything is downloaded. It is a module export, not an instance method: nothing is loaded to call it.
|
|
1350
1427
|
|
|
1428
|
+
`assessFit` returns a Promise. Fits run one at a time within this addon.
|
|
1429
|
+
|
|
1351
1430
|
A request is a `createInstance` config plus the workload, so it carries the same keys the load takes and the engine's own config builder reads it.
|
|
1352
1431
|
|
|
1353
1432
|
```js
|
|
1354
1433
|
const TTSGgml = require('@qvac/tts-ggml')
|
|
1355
1434
|
|
|
1356
|
-
const fit = TTSGgml.assessFit({
|
|
1435
|
+
const fit = await TTSGgml.assessFit({
|
|
1357
1436
|
engineType: 'supertonic',
|
|
1358
1437
|
supertonicModelPath: '/models/supertonic.gguf',
|
|
1359
1438
|
useGPU: true,
|
|
@@ -1393,7 +1472,7 @@ Everything else comes from the load config: `nGpuLayers` and `useGPU` carry the
|
|
|
1393
1472
|
|
|
1394
1473
|
`deviceSharesHostMemory` reports that the device pool is system RAM, so host bytes compete with device bytes.
|
|
1395
1474
|
|
|
1396
|
-
A model the engine cannot read
|
|
1475
|
+
A model the engine cannot read resolves to `status: "error"`, as does a voice with no fitter, which reports `reason: "unsupported-engine"`. MOSS-TTS, MOSS-TTSD and MOSS-SoundEffect are supported. MOSS-Speech has no SDK fit projection. A broken request, or a host with no native binding, rejects.
|
|
1397
1476
|
|
|
1398
1477
|
MOSS-TTS and MOSS-TTSD share the `moss` fitter. `promptRows` is the complete
|
|
1399
1478
|
native prompt length, including special tokens, encoded speaker references and
|
|
@@ -1404,7 +1483,7 @@ The fitter does not open reference recordings. Use the TTSD backbone to assess
|
|
|
1404
1483
|
dialogue, supplying its complete prompt and total reference workload.
|
|
1405
1484
|
|
|
1406
1485
|
```js
|
|
1407
|
-
const fit = TTSGgml.assessFit({
|
|
1486
|
+
const fit = await TTSGgml.assessFit({
|
|
1408
1487
|
engineType: 'moss',
|
|
1409
1488
|
mossBackbonePath: './moss-tts-delay-f16.gguf',
|
|
1410
1489
|
mossCodecDecoderPath: './moss-codec-decoder-f16.gguf',
|
|
@@ -1426,7 +1505,7 @@ The supertonic fitter covers the fused graph path: a validated GPU, or a CPU wit
|
|
|
1426
1505
|
### MOSS-SoundEffect fit
|
|
1427
1506
|
|
|
1428
1507
|
```js
|
|
1429
|
-
const fit = TTSGgml.assessFit({
|
|
1508
|
+
const fit = await TTSGgml.assessFit({
|
|
1430
1509
|
engineType: 'moss-sfx',
|
|
1431
1510
|
mossSoundEffectPath: './moss-sfx-v2-q8_0.gguf',
|
|
1432
1511
|
prompt: 'Rain falling on a tin roof.',
|
|
@@ -1571,11 +1650,18 @@ npm install
|
|
|
1571
1650
|
npx bare-make generate # configures + fetches the tts-cpp port
|
|
1572
1651
|
npx bare-make build
|
|
1573
1652
|
npx bare-make install # copies the .bare into prebuilds/<triple>/
|
|
1653
|
+
npm run link:platform # stages node_modules/@qvac/tts-ggml-<host>
|
|
1574
1654
|
```
|
|
1575
1655
|
|
|
1656
|
+
`require('#host-addon')` only ever loads a platform package, so a source
|
|
1657
|
+
build becomes loadable once `npm run link:platform` (run by
|
|
1658
|
+
`npm run build:native`) wraps `prebuilds/<host>/` as that host's
|
|
1659
|
+
`@qvac/tts-ggml-<host>` package in `node_modules/`.
|
|
1660
|
+
|
|
1576
1661
|
The vcpkg port is hosted in
|
|
1577
1662
|
[`tetherto/qvac-registry-vcpkg`][registry] and pulls
|
|
1578
|
-
[`qvac-
|
|
1663
|
+
[`qvac-fabric-speech.cpp`](https://github.com/tetherto/qvac-fabric-speech.cpp)
|
|
1664
|
+
(`engines/tts`) at a pinned REF. See
|
|
1579
1665
|
[`vcpkg-configuration.json`](./vcpkg-configuration.json) for the
|
|
1580
1666
|
baseline commit.
|
|
1581
1667
|
|
package/addon-unavailable.js
CHANGED
|
@@ -1,31 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
// "#host-addon" target for hosts with no platform package. Hosts that have one
|
|
4
|
+
// map straight to it with no fallback, so a missing install fails bare-pack (and
|
|
5
|
+
// fails at run time naming the package) instead of producing a bundle that only
|
|
6
|
+
// throws once launched.
|
|
7
|
+
const host = require.addon ? require.addon.host : 'unknown'
|
|
5
8
|
|
|
6
|
-
throw new Error(
|
|
7
|
-
|
|
8
|
-
function currentHost() {
|
|
9
|
-
return require.addon ? require.addon.host : null
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function buildMessage(host) {
|
|
13
|
-
if (!host || !PREBUILT_HOSTS.includes(host)) {
|
|
14
|
-
return (
|
|
15
|
-
META_PACKAGE +
|
|
16
|
-
' has no prebuilt binaries for host ' +
|
|
17
|
-
(host || UNKNOWN_HOST) +
|
|
18
|
-
'. Prebuilt hosts: ' +
|
|
19
|
-
PREBUILT_HOSTS.join(', ') +
|
|
20
|
-
'. Build from source with bare-make.'
|
|
21
|
-
)
|
|
22
|
-
}
|
|
23
|
-
return (
|
|
24
|
-
META_PACKAGE +
|
|
25
|
-
' found no native prebuild for ' +
|
|
9
|
+
throw new Error(
|
|
10
|
+
'@qvac/tts-ggml has no prebuilt binaries for host ' +
|
|
26
11
|
host +
|
|
27
|
-
'
|
|
28
|
-
|
|
29
|
-
'
|
|
30
|
-
|
|
31
|
-
}
|
|
12
|
+
'. Platform packages exist for linux-x64, linux-arm64, darwin-arm64, ' +
|
|
13
|
+
'darwin-x64, win32-x64, android-arm64 and ios (ios-arm64, ' +
|
|
14
|
+
'ios-arm64-simulator, ios-x64-simulator). Build from source with bare-make.'
|
|
15
|
+
)
|
package/binding.js
CHANGED
|
@@ -1,52 +1 @@
|
|
|
1
|
-
module.exports =
|
|
2
|
-
|
|
3
|
-
// `require.addon()` reads the prebuild shipped inside this package. Since the
|
|
4
|
-
// per-platform split (0.9.0) there is none, so the real binding almost always
|
|
5
|
-
// comes from the `#host-addon` platform package. Runtimes have been seen to
|
|
6
|
-
// answer `require.addon()` with this package's own JavaScript entry instead of
|
|
7
|
-
// failing, which used to be returned verbatim: callers then got a module with
|
|
8
|
-
// no `createInstance`, and the first symptom was an unrelated TypeError deep in
|
|
9
|
-
// a model load. Anything that is not the native binding is treated as a miss.
|
|
10
|
-
function loadAddon() {
|
|
11
|
-
let cause = null
|
|
12
|
-
|
|
13
|
-
try {
|
|
14
|
-
const addon = require.addon()
|
|
15
|
-
if (isNativeBinding(addon)) return addon
|
|
16
|
-
cause = new Error(
|
|
17
|
-
'@qvac/tts-ggml: require.addon() answered with a module that is not the native binding ' +
|
|
18
|
-
'(no createInstance function), so the prebuild in this package was treated as absent.'
|
|
19
|
-
)
|
|
20
|
-
} catch (err) {
|
|
21
|
-
cause = err
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return loadPlatformPackageAddon(cause)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function loadPlatformPackageAddon(cause) {
|
|
28
|
-
let addon
|
|
29
|
-
|
|
30
|
-
try {
|
|
31
|
-
addon = require('#host-addon')
|
|
32
|
-
} catch (err) {
|
|
33
|
-
if (err.cause === undefined) err.cause = cause
|
|
34
|
-
throw err
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (!isNativeBinding(addon)) {
|
|
38
|
-
const err = new Error(
|
|
39
|
-
'@qvac/tts-ggml resolved #host-addon to a module that is not the native binding: ' +
|
|
40
|
-
'it has no createInstance function. Check that the platform package for this host ' +
|
|
41
|
-
'is installed and is not shadowed by another module of the same name.'
|
|
42
|
-
)
|
|
43
|
-
err.cause = cause
|
|
44
|
-
throw err
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return addon
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function isNativeBinding(addon) {
|
|
51
|
-
return addon !== null && typeof addon === 'object' && typeof addon.createInstance === 'function'
|
|
52
|
-
}
|
|
1
|
+
module.exports = require('#host-addon')
|
package/examples/moss-sfx-fit.js
CHANGED
|
@@ -8,11 +8,18 @@ if (!model || !prompt || seconds === undefined) {
|
|
|
8
8
|
throw new Error('Usage: bare examples/moss-sfx-fit.js <model.gguf> <prompt> <seconds>')
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
async function main() {
|
|
12
|
+
const fit = await TTSGgml.assessFit({
|
|
13
|
+
engineType: 'moss-sfx',
|
|
14
|
+
mossSoundEffectPath: model,
|
|
15
|
+
prompt,
|
|
16
|
+
seconds: Number(seconds),
|
|
17
|
+
useGPU: false
|
|
18
|
+
})
|
|
19
|
+
console.log(fit.report || `${fit.status}: ${fit.reason}`)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
main().catch((err) => {
|
|
23
|
+
console.error(err)
|
|
24
|
+
process.exit(1)
|
|
17
25
|
})
|
|
18
|
-
console.log(fit.report || `${fit.status}: ${fit.reason}`)
|
package/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { type QvacResponse } from "@qvac/infer-base";
|
|
2
2
|
import * as errorModule from "./lib/error";
|
|
3
|
-
import { resolveBackendsDir as resolveBackendsDirImpl } from "./lib/backends";
|
|
4
3
|
import { assessFit as assessFitImpl, type Audio8FitRequest, type MossFitRequest, type MossSoundEffectFitRequest, type ChatterboxFitRequest, type CosyvoiceFitRequest, type ParlerFitRequest, type SupertonicFitRequest, type TtsFitEngine, type TtsFitRequest, type TtsFitResult, type TtsFitStatus } from "./lib/fit";
|
|
5
4
|
import { type SentenceDelimiterPreset } from "./lib/textStreamAccumulator";
|
|
6
5
|
declare const ENGINE_CHATTERBOX = "chatterbox";
|
|
@@ -607,7 +606,11 @@ interface TTSGgmlOptions extends ParlerDescriptionFields, Audio8VoiceFields, TTS
|
|
|
607
606
|
* streaming (batch synthesis only).
|
|
608
607
|
*/
|
|
609
608
|
denoiser?: LavaSRDenoiserOptions;
|
|
610
|
-
/**
|
|
609
|
+
/**
|
|
610
|
+
* Directory the addon scans for dynamically loaded ggml backends, as given.
|
|
611
|
+
* Unset scans the addon's own: the one its platform package or the app
|
|
612
|
+
* installed next to the native module.
|
|
613
|
+
*/
|
|
611
614
|
backendsDir?: string;
|
|
612
615
|
/** Directory where ggml-opencl persists its compiled program binary. */
|
|
613
616
|
openclCacheDir?: string;
|
|
@@ -1211,7 +1214,6 @@ declare namespace TTSGgml {
|
|
|
1211
1214
|
type MossFitRequest = NamespaceMossFit;
|
|
1212
1215
|
type MossSoundEffectFitRequest = NamespaceMossSoundEffectFit;
|
|
1213
1216
|
type CosyvoiceFitRequest = NamespaceCosyvoiceFit;
|
|
1214
|
-
const resolveBackendsDir: typeof resolveBackendsDirImpl;
|
|
1215
1217
|
const assessFit: typeof assessFitImpl;
|
|
1216
1218
|
}
|
|
1217
1219
|
export = TTSGgml;
|
package/index.js
CHANGED
|
@@ -46,7 +46,6 @@ const infer_base_1 = require("@qvac/infer-base");
|
|
|
46
46
|
const tts_1 = require("./tts");
|
|
47
47
|
const errorModule = __importStar(require("./lib/error"));
|
|
48
48
|
const pocketConfig_1 = require("./lib/pocketConfig");
|
|
49
|
-
const backends_1 = require("./lib/backends");
|
|
50
49
|
const fit_1 = require("./lib/fit");
|
|
51
50
|
const textChunker_1 = require("./lib/textChunker");
|
|
52
51
|
const textStreamAccumulator_1 = require("./lib/textStreamAccumulator");
|
|
@@ -1293,7 +1292,7 @@ class TTSGgml {
|
|
|
1293
1292
|
this._assignSynthesisOptions(options);
|
|
1294
1293
|
this._enhancerGgufPath = resolveEnhancerGgufPath(normalizedFiles, options.enhancer);
|
|
1295
1294
|
this._denoiserGgufPath = resolveDenoiserGgufPath(normalizedFiles, options.denoiser);
|
|
1296
|
-
this._backendsDir = firstNonEmpty(options.backendsDir, this._config.backendsDir
|
|
1295
|
+
this._backendsDir = firstNonEmpty(options.backendsDir, this._config.backendsDir);
|
|
1297
1296
|
this._openclCacheDir = firstNonEmpty(options.openclCacheDir, this._config.openclCacheDir);
|
|
1298
1297
|
this._vulkanCacheDir = firstNonEmpty(options.vulkanCacheDir, this._config.vulkanCacheDir);
|
|
1299
1298
|
assertGpuIntentConsistent(this._config.useGPU, this._nGpuLayers);
|
|
@@ -3311,7 +3310,6 @@ class TTSGgml {
|
|
|
3311
3310
|
(function (TTSGgml) {
|
|
3312
3311
|
TTSGgml.QvacErrorAddonTTSGgml = errorModule.QvacErrorAddonTTSGgml;
|
|
3313
3312
|
TTSGgml.ERR_CODES = errorModule.ERR_CODES;
|
|
3314
|
-
TTSGgml.resolveBackendsDir = backends_1.resolveBackendsDir;
|
|
3315
3313
|
TTSGgml.assessFit = fit_1.assessFit;
|
|
3316
3314
|
})(TTSGgml || (TTSGgml = {}));
|
|
3317
3315
|
module.exports.QvacErrorAddonTTSGgml =
|
package/lib/fit.d.ts
CHANGED
|
@@ -139,9 +139,9 @@ export interface TtsFitResult {
|
|
|
139
139
|
*
|
|
140
140
|
* `engineType` picks the fitter, the same key a load uses, and is required
|
|
141
141
|
* here: a fit request carries none of the file keys a load is inferred from.
|
|
142
|
-
* A model the engine cannot read
|
|
142
|
+
* A model the engine cannot read resolves to `status: "error"`, as does a
|
|
143
143
|
* voice with no fitter; a broken request, or a host with no native binding,
|
|
144
|
-
*
|
|
144
|
+
* rejects. Fits run one at a time within this addon.
|
|
145
145
|
*/
|
|
146
|
-
export declare function assessFit(request: TtsFitRequest): TtsFitResult
|
|
146
|
+
export declare function assessFit(request: TtsFitRequest): Promise<TtsFitResult>;
|
|
147
147
|
export {};
|
package/lib/fit.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.assessFit = assessFit;
|
|
4
|
-
const backends_1 = require("./backends");
|
|
5
4
|
/**
|
|
6
5
|
* Projects one voice against the memory free right now, reading GGUF metadata
|
|
7
6
|
* and never weight data. The registry's weightless copy of each file answers
|
|
@@ -13,17 +12,12 @@ const backends_1 = require("./backends");
|
|
|
13
12
|
*
|
|
14
13
|
* `engineType` picks the fitter, the same key a load uses, and is required
|
|
15
14
|
* here: a fit request carries none of the file keys a load is inferred from.
|
|
16
|
-
* A model the engine cannot read
|
|
15
|
+
* A model the engine cannot read resolves to `status: "error"`, as does a
|
|
17
16
|
* voice with no fitter; a broken request, or a host with no native binding,
|
|
18
|
-
*
|
|
17
|
+
* rejects. Fits run one at a time within this addon.
|
|
19
18
|
*/
|
|
20
|
-
function assessFit(request) {
|
|
21
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports -- native binding
|
|
19
|
+
async function assessFit(request) {
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports -- the native binding loads on first use.
|
|
22
21
|
const binding = require('../binding.js');
|
|
23
|
-
return binding.assessFit(
|
|
24
|
-
...request,
|
|
25
|
-
backendsDir: typeof request.backendsDir === 'string' && request.backendsDir.length > 0
|
|
26
|
-
? request.backendsDir
|
|
27
|
-
: (0, backends_1.resolveBackendsDir)()
|
|
28
|
-
});
|
|
22
|
+
return await binding.assessFit(request);
|
|
29
23
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qvac/tts-ggml",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Text to Speech (TTS) addon for qvac (ggml backend, wrapping the chatterbox + supertonic + parler + cosyvoice3 + audio8 + moss + moss-sfx + moss-speech + Pocket engines from tts-cpp)",
|
|
5
|
-
"addon": true,
|
|
6
5
|
"qvac": {
|
|
7
6
|
"ggml-speech": "2026-10-07#1"
|
|
8
7
|
},
|
|
@@ -12,52 +11,32 @@
|
|
|
12
11
|
"imports": {
|
|
13
12
|
"#host-addon": {
|
|
14
13
|
"linux": {
|
|
15
|
-
"x64":
|
|
16
|
-
|
|
17
|
-
"./addon-unavailable.js"
|
|
18
|
-
],
|
|
19
|
-
"arm64": [
|
|
20
|
-
"@qvac/tts-ggml-linux-arm64",
|
|
21
|
-
"./addon-unavailable.js"
|
|
22
|
-
],
|
|
14
|
+
"x64": "@qvac/tts-ggml-linux-x64",
|
|
15
|
+
"arm64": "@qvac/tts-ggml-linux-arm64",
|
|
23
16
|
"default": "./addon-unavailable.js"
|
|
24
17
|
},
|
|
25
18
|
"darwin": {
|
|
26
|
-
"arm64":
|
|
27
|
-
|
|
28
|
-
"./addon-unavailable.js"
|
|
29
|
-
],
|
|
30
|
-
"x64": [
|
|
31
|
-
"@qvac/tts-ggml-darwin-x64",
|
|
32
|
-
"./addon-unavailable.js"
|
|
33
|
-
],
|
|
19
|
+
"arm64": "@qvac/tts-ggml-darwin-arm64",
|
|
20
|
+
"x64": "@qvac/tts-ggml-darwin-x64",
|
|
34
21
|
"default": "./addon-unavailable.js"
|
|
35
22
|
},
|
|
36
23
|
"win32": {
|
|
37
|
-
"x64":
|
|
38
|
-
"@qvac/tts-ggml-win32-x64",
|
|
39
|
-
"./addon-unavailable.js"
|
|
40
|
-
],
|
|
24
|
+
"x64": "@qvac/tts-ggml-win32-x64",
|
|
41
25
|
"default": "./addon-unavailable.js"
|
|
42
26
|
},
|
|
43
27
|
"android": {
|
|
44
|
-
"arm64":
|
|
45
|
-
"@qvac/tts-ggml-android-arm64",
|
|
46
|
-
"./addon-unavailable.js"
|
|
47
|
-
],
|
|
28
|
+
"arm64": "@qvac/tts-ggml-android-arm64",
|
|
48
29
|
"default": "./addon-unavailable.js"
|
|
49
30
|
},
|
|
50
|
-
"ios":
|
|
51
|
-
"@qvac/tts-ggml-ios",
|
|
52
|
-
"./addon-unavailable.js"
|
|
53
|
-
],
|
|
31
|
+
"ios": "@qvac/tts-ggml-ios",
|
|
54
32
|
"default": "./addon-unavailable.js"
|
|
55
33
|
}
|
|
56
34
|
},
|
|
57
35
|
"scripts": {
|
|
58
36
|
"build": "npm run build:ts && npm run build:native",
|
|
59
|
-
"build:native": "bare-make generate -D BUILD_FUZZING=OFF && bare-make build && bare-make install",
|
|
60
|
-
"build:native:cuda": "bare-make generate -D ENABLE_CUDA=ON -D BUILD_FUZZING=OFF && bare-make build && bare-make install",
|
|
37
|
+
"build:native": "bare-make generate -D BUILD_FUZZING=OFF && bare-make build && bare-make install && npm run link:platform",
|
|
38
|
+
"build:native:cuda": "bare-make generate -D ENABLE_CUDA=ON -D BUILD_FUZZING=OFF && bare-make build && bare-make install && npm run link:platform",
|
|
39
|
+
"link:platform": "node ../../scripts/ci/slice-platform-packages.mjs --link-local --workdir .",
|
|
61
40
|
"build:cuda": "npm run build:ts && npm run build:native:cuda",
|
|
62
41
|
"build:ts": "tsc -p tsconfig.build.json",
|
|
63
42
|
"build:pack": "npm run build:ts && mkdir -p dist && npm pack --pack-destination dist",
|
|
@@ -86,10 +65,10 @@
|
|
|
86
65
|
"example:moss-sfx": "bare examples/moss-sound-effect.js \"Heavy rain falling on a tin roof with distant thunder.\" 5",
|
|
87
66
|
"example:moss-speech": "bare examples/moss-speech.js test/reference-audio/jfk.wav",
|
|
88
67
|
"lint": "npm run lint:js && npm run lint:ts && npm run test:types",
|
|
89
|
-
"lint:js": "prettier --check \"test/**/*.js\" \"scripts/run-cpp-fuzz.js\" \"scripts/__tests__/package-contract.test.js\" \"scripts/__tests__/
|
|
68
|
+
"lint:js": "prettier --check \"test/**/*.js\" \"scripts/run-cpp-fuzz.js\" \"scripts/__tests__/package-contract.test.js\" \"scripts/__tests__/run-cpp-fuzz.test.js\" \"binding.js\" \"addon-unavailable.js\" && lunte \"test/**/*.js\" \"scripts/run-cpp-fuzz.js\" \"scripts/__tests__/package-contract.test.js\" \"scripts/__tests__/run-cpp-fuzz.test.js\" \"binding.js\" \"addon-unavailable.js\"",
|
|
90
69
|
"lint:ts": "eslint \"src/**/*.ts\" --max-warnings=0",
|
|
91
70
|
"lint:ts:fix": "eslint \"src/**/*.ts\" --fix",
|
|
92
|
-
"format": "prettier --write \"test/**/*.js\" \"scripts/__tests__/package-contract.test.js\" \"
|
|
71
|
+
"format": "prettier --write \"test/**/*.js\" \"scripts/__tests__/package-contract.test.js\" \"binding.js\" \"addon-unavailable.js\"",
|
|
93
72
|
"test:unit": "npm run build:ts && brittle-bare test/unit/**/*.test.js && npm run test:node",
|
|
94
73
|
"test:node": "node --test scripts/__tests__/*.test.js",
|
|
95
74
|
"test": "npm run test:types && npm run test:unit && npm run test:integration",
|
|
@@ -147,6 +126,11 @@
|
|
|
147
126
|
"test/pocket-worklet",
|
|
148
127
|
"test/reference-audio",
|
|
149
128
|
"test/utils/runTTS.js",
|
|
129
|
+
"test/utils/mossBackend.js",
|
|
130
|
+
"test/utils/mossGpuValidation.js",
|
|
131
|
+
"test/utils/gpuOnly.js",
|
|
132
|
+
"test/utils/testThreads.js",
|
|
133
|
+
"test/utils/perf-helper.js",
|
|
150
134
|
"test/utils/runChatterboxTTS.js",
|
|
151
135
|
"test/utils/runSupertonicTTS.js",
|
|
152
136
|
"test/utils/runParlerTTS.js",
|
|
@@ -221,7 +205,7 @@
|
|
|
221
205
|
},
|
|
222
206
|
"dependencies": {
|
|
223
207
|
"@qvac/error": "^0.1.0",
|
|
224
|
-
"@qvac/infer-base": "^0.
|
|
208
|
+
"@qvac/infer-base": "^0.8.0",
|
|
225
209
|
"@qvac/langdetect-text": "^0.1.2",
|
|
226
210
|
"@qvac/logging": "^0.1.0",
|
|
227
211
|
"bare-fs": "^4.5.6",
|
|
@@ -232,12 +216,24 @@
|
|
|
232
216
|
"bare-stream": "^2.7.0",
|
|
233
217
|
"bare-url": "^2.4.3"
|
|
234
218
|
},
|
|
235
|
-
"types": "index.d.ts",
|
|
236
219
|
"optionalDependencies": {
|
|
237
|
-
"@qvac/tts-ggml-linux-x64": "0.
|
|
238
|
-
"@qvac/tts-ggml-linux-arm64": "0.
|
|
239
|
-
"@qvac/tts-ggml-darwin-arm64": "0.
|
|
240
|
-
"@qvac/tts-ggml-darwin-x64": "0.
|
|
241
|
-
"@qvac/tts-ggml-win32-x64": "0.
|
|
220
|
+
"@qvac/tts-ggml-linux-x64": "0.13.0",
|
|
221
|
+
"@qvac/tts-ggml-linux-arm64": "0.13.0",
|
|
222
|
+
"@qvac/tts-ggml-darwin-arm64": "0.13.0",
|
|
223
|
+
"@qvac/tts-ggml-darwin-x64": "0.13.0",
|
|
224
|
+
"@qvac/tts-ggml-win32-x64": "0.13.0"
|
|
225
|
+
},
|
|
226
|
+
"types": "index.d.ts",
|
|
227
|
+
"peerDependencies": {
|
|
228
|
+
"@qvac/tts-ggml-android-arm64": "0.13.0",
|
|
229
|
+
"@qvac/tts-ggml-ios": "0.13.0"
|
|
230
|
+
},
|
|
231
|
+
"peerDependenciesMeta": {
|
|
232
|
+
"@qvac/tts-ggml-android-arm64": {
|
|
233
|
+
"optional": true
|
|
234
|
+
},
|
|
235
|
+
"@qvac/tts-ggml-ios": {
|
|
236
|
+
"optional": true
|
|
237
|
+
}
|
|
242
238
|
}
|
|
243
239
|
}
|