@qvac/tts-ggml 0.10.0 → 0.11.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 +251 -23
- package/examples/moss-sfx-fit.js +18 -0
- package/examples/moss-sound-effect.js +125 -0
- package/examples/moss-speech.js +136 -0
- package/examples/pcm-chunk-player.js +35 -10
- package/index.d.ts +116 -6
- package/index.js +391 -2
- package/lib/fit.d.ts +22 -2
- package/package.json +33 -16
- package/test/integration/addon.test.js +8 -7
- package/test/integration/chatterbox-mtl.test.js +14 -9
- package/test/integration/chatterbox-speed.test.js +4 -2
- package/test/integration/cosyvoice3-clone.test.js +3 -3
- package/test/integration/cosyvoice3-lavasr.test.js +15 -11
- package/test/integration/cosyvoice3.test.js +14 -8
- package/test/integration/fit.test.js +7 -3
- package/test/integration/lavasr-enhancer.test.js +3 -2
- package/test/integration/moss-fit.test.js +57 -0
- package/test/integration/moss-sfx-fit.test.js +63 -0
- package/test/integration/moss-sfx.test.js +96 -0
- package/test/integration/moss-speech.test.js +110 -0
- package/test/integration/moss.test.js +21 -16
- package/test/integration/multiple-runs.test.js +69 -58
- package/test/integration/output-sample-rate.test.js +4 -2
- package/test/integration/parler-wer.test.js +7 -8
- package/test/integration/parler.test.js +27 -21
- package/test/mobile/integration.auto.cjs +15 -0
- package/tts.d.ts +20 -0
- /package/test/{mobile → pocket-worklet}/pocket-worklet-host.cpp +0 -0
- /package/test/{mobile → pocket-worklet}/pocket-worklet.cjs +0 -0
|
@@ -7,18 +7,17 @@
|
|
|
7
7
|
|
|
8
8
|
const os = require('bare-os')
|
|
9
9
|
const path = require('bare-path')
|
|
10
|
-
const proc = require('bare-process')
|
|
11
10
|
const test = require('brittle')
|
|
12
11
|
|
|
13
12
|
const { loadParlerTTS, runParlerTTS } = require('../utils/runParlerTTS')
|
|
14
13
|
const { ensureParlerModel } = require('../utils/downloadModel')
|
|
15
14
|
const { recordTtsStats } = require('../utils/perf-helper')
|
|
16
15
|
const { TTS_TEST_THREADS } = require('../utils/testThreads')
|
|
16
|
+
const { NO_GPU, SKIP_PARLER_GPU_ONLY, PARLER_GPU_ONLY_USE_GPU } = require('../utils/gpuOnly')
|
|
17
17
|
|
|
18
18
|
const platform = os.platform()
|
|
19
19
|
const isMobile = platform === 'ios' || platform === 'android'
|
|
20
20
|
const isApple = platform === 'darwin' || platform === 'ios'
|
|
21
|
-
const NO_GPU = proc.env && proc.env.NO_GPU === 'true'
|
|
22
21
|
|
|
23
22
|
function getBaseDir() {
|
|
24
23
|
return isMobile && global.testDir ? global.testDir : '.'
|
|
@@ -137,7 +136,7 @@ test(
|
|
|
137
136
|
|
|
138
137
|
test(
|
|
139
138
|
'Parler TTS (ggml): description matrix — conflicts throw, per-call wins, defaults work',
|
|
140
|
-
{ timeout: 600000 },
|
|
139
|
+
{ timeout: 600000, skip: SKIP_PARLER_GPU_ONLY },
|
|
141
140
|
async (t) => {
|
|
142
141
|
const baseDir = getBaseDir()
|
|
143
142
|
const download = await ensureParlerModel({ targetDir: path.join(baseDir, 'models') })
|
|
@@ -191,7 +190,8 @@ test(
|
|
|
191
190
|
threads: TTS_TEST_THREADS,
|
|
192
191
|
parlerModelPath: download.path,
|
|
193
192
|
voice: 'Laura',
|
|
194
|
-
seed: 42
|
|
193
|
+
seed: 42,
|
|
194
|
+
useGPU: PARLER_GPU_ONLY_USE_GPU
|
|
195
195
|
})
|
|
196
196
|
try {
|
|
197
197
|
// Per-call description conflict (same level) rejects.
|
|
@@ -234,7 +234,8 @@ test(
|
|
|
234
234
|
threads: TTS_TEST_THREADS,
|
|
235
235
|
parlerModelPath: download.path,
|
|
236
236
|
description: 'A calm female voice, very clear audio.',
|
|
237
|
-
seed: 42
|
|
237
|
+
seed: 42,
|
|
238
|
+
useGPU: PARLER_GPU_ONLY_USE_GPU
|
|
238
239
|
})
|
|
239
240
|
try {
|
|
240
241
|
await t.exception(
|
|
@@ -252,7 +253,7 @@ test(
|
|
|
252
253
|
|
|
253
254
|
test(
|
|
254
255
|
'Parler TTS (ggml): emotion flag changes the audio; per-call switch needs no reload',
|
|
255
|
-
{ timeout: 600000 },
|
|
256
|
+
{ timeout: 600000, skip: SKIP_PARLER_GPU_ONLY },
|
|
256
257
|
async (t) => {
|
|
257
258
|
const baseDir = getBaseDir()
|
|
258
259
|
const download = await ensureParlerModel({ targetDir: path.join(baseDir, 'models') })
|
|
@@ -265,7 +266,8 @@ test(
|
|
|
265
266
|
threads: TTS_TEST_THREADS,
|
|
266
267
|
parlerModelPath: download.path,
|
|
267
268
|
voice: 'Laura',
|
|
268
|
-
seed: 42
|
|
269
|
+
seed: 42,
|
|
270
|
+
useGPU: PARLER_GPU_ONLY_USE_GPU
|
|
269
271
|
})
|
|
270
272
|
try {
|
|
271
273
|
const text = 'The weather is wonderful today.'
|
|
@@ -300,7 +302,7 @@ test(
|
|
|
300
302
|
|
|
301
303
|
test(
|
|
302
304
|
'Parler TTS (ggml): fixed seed is deterministic across runs and reload',
|
|
303
|
-
{ timeout: 600000 },
|
|
305
|
+
{ timeout: 600000, skip: SKIP_PARLER_GPU_ONLY },
|
|
304
306
|
async (t) => {
|
|
305
307
|
const baseDir = getBaseDir()
|
|
306
308
|
const download = await ensureParlerModel({ targetDir: path.join(baseDir, 'models') })
|
|
@@ -314,7 +316,8 @@ test(
|
|
|
314
316
|
parlerModelPath: download.path,
|
|
315
317
|
voice: 'Laura',
|
|
316
318
|
emotion: 'neutral',
|
|
317
|
-
seed: 42
|
|
319
|
+
seed: 42,
|
|
320
|
+
useGPU: PARLER_GPU_ONLY_USE_GPU
|
|
318
321
|
})
|
|
319
322
|
try {
|
|
320
323
|
const text = 'Deterministic synthesis check.'
|
|
@@ -345,7 +348,7 @@ test(
|
|
|
345
348
|
|
|
346
349
|
test(
|
|
347
350
|
'Parler TTS (ggml): runStream emits per-sentence chunks with one pinned description',
|
|
348
|
-
{ timeout: 600000 },
|
|
351
|
+
{ timeout: 600000, skip: SKIP_PARLER_GPU_ONLY },
|
|
349
352
|
async (t) => {
|
|
350
353
|
const baseDir = getBaseDir()
|
|
351
354
|
const download = await ensureParlerModel({ targetDir: path.join(baseDir, 'models') })
|
|
@@ -360,6 +363,7 @@ test(
|
|
|
360
363
|
engine: TTSGgml.ENGINE_PARLER,
|
|
361
364
|
files: { parlerModel: download.path },
|
|
362
365
|
seed: 42,
|
|
366
|
+
config: { useGPU: PARLER_GPU_ONLY_USE_GPU },
|
|
363
367
|
opts: { stats: true }
|
|
364
368
|
})
|
|
365
369
|
await model.load()
|
|
@@ -393,7 +397,7 @@ test(
|
|
|
393
397
|
|
|
394
398
|
test(
|
|
395
399
|
'Parler TTS (ggml): native streaming emits monotonic chunks equal to batch',
|
|
396
|
-
{ timeout: 900000 },
|
|
400
|
+
{ timeout: 900000, skip: SKIP_PARLER_GPU_ONLY },
|
|
397
401
|
async (t) => {
|
|
398
402
|
const baseDir = getBaseDir()
|
|
399
403
|
const download = await ensureParlerModel({ targetDir: path.join(baseDir, 'models') })
|
|
@@ -526,22 +530,24 @@ test(
|
|
|
526
530
|
|
|
527
531
|
// Desktop quant + backend coverage: q8_0 + f16 for indic/mini, q8_0 for large.
|
|
528
532
|
// Runs on the platform's GPU-if-available backend (Metal on Apple GPU runners,
|
|
529
|
-
// CPU otherwise).
|
|
530
|
-
//
|
|
531
|
-
//
|
|
533
|
+
// CPU otherwise). mini f16 and large are the slowest tiers on CPU (roughly
|
|
534
|
+
// 45-80 s per synthesis), so they run on Metal only. large self-gates on RAM; any tier that isn't
|
|
535
|
+
// staged skips (t.pass) so a not-yet-registered tier never fails CI. Registered
|
|
536
|
+
// per PR #3372. Desktop-only: the mobile Parler surface is covered by the
|
|
537
|
+
// gpu-smoke legs.
|
|
532
538
|
const PARLER_QUANT_MATRIX = [
|
|
533
|
-
{ variant: 'indic', quant: 'q8_0' },
|
|
534
|
-
{ variant: 'indic', quant: 'f16' },
|
|
535
|
-
{ variant: 'mini', quant: 'q8_0' },
|
|
536
|
-
{ variant: 'mini', quant: 'f16' },
|
|
537
|
-
{ variant: 'large', quant: 'q8_0' }
|
|
539
|
+
{ variant: 'indic', quant: 'q8_0', gpuOnly: false },
|
|
540
|
+
{ variant: 'indic', quant: 'f16', gpuOnly: false },
|
|
541
|
+
{ variant: 'mini', quant: 'q8_0', gpuOnly: false },
|
|
542
|
+
{ variant: 'mini', quant: 'f16', gpuOnly: true },
|
|
543
|
+
{ variant: 'large', quant: 'q8_0', gpuOnly: true }
|
|
538
544
|
]
|
|
539
545
|
const LARGE_MIN_RAM_BYTES = 16 * 1024 ** 3
|
|
540
546
|
|
|
541
|
-
for (const { variant, quant } of PARLER_QUANT_MATRIX) {
|
|
547
|
+
for (const { variant, quant, gpuOnly } of PARLER_QUANT_MATRIX) {
|
|
542
548
|
test(
|
|
543
549
|
`Parler TTS (ggml): ${variant} ${quant} synthesizes 44.1 kHz audio on the target backend`,
|
|
544
|
-
{ timeout: 900000, skip: isMobile },
|
|
550
|
+
{ timeout: 900000, skip: isMobile || (gpuOnly && SKIP_PARLER_GPU_ONLY) },
|
|
545
551
|
async (t) => {
|
|
546
552
|
if (variant === 'large' && os.totalmem() < LARGE_MIN_RAM_BYTES) {
|
|
547
553
|
t.pass(
|
|
@@ -50,6 +50,14 @@ async function runLavasrEnhancerTest (options = {}) { // eslint-disable-line no-
|
|
|
50
50
|
return runIntegrationModule('../integration/lavasr-enhancer.test.js', options)
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
async function runMossSfxTest (options = {}) { // eslint-disable-line no-unused-vars
|
|
54
|
+
return runIntegrationModule('../integration/moss-sfx.test.js', options)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function runMossSpeechTest (options = {}) { // eslint-disable-line no-unused-vars
|
|
58
|
+
return runIntegrationModule('../integration/moss-speech.test.js', options)
|
|
59
|
+
}
|
|
60
|
+
|
|
53
61
|
async function runMossTest (options = {}) { // eslint-disable-line no-unused-vars
|
|
54
62
|
return runIntegrationModule('../integration/moss.test.js', options)
|
|
55
63
|
}
|
|
@@ -70,6 +78,10 @@ async function runParlerTest (options = {}) { // eslint-disable-line no-unused-v
|
|
|
70
78
|
return runIntegrationModule('../integration/parler.test.js', options)
|
|
71
79
|
}
|
|
72
80
|
|
|
81
|
+
async function runPocketIntegrationTest (options = {}) { // eslint-disable-line no-unused-vars
|
|
82
|
+
return runIntegrationModule('../integration/pocket.integration.test.js', options)
|
|
83
|
+
}
|
|
84
|
+
|
|
73
85
|
async function runRtfBenchmarkTest (options = {}) { // eslint-disable-line no-unused-vars
|
|
74
86
|
return runIntegrationModule('../integration/rtf-benchmark.test.js', options)
|
|
75
87
|
}
|
|
@@ -106,11 +118,14 @@ module.exports = {
|
|
|
106
118
|
runFitTest,
|
|
107
119
|
runGpuSmokeTest,
|
|
108
120
|
runLavasrEnhancerTest,
|
|
121
|
+
runMossSfxTest,
|
|
122
|
+
runMossSpeechTest,
|
|
109
123
|
runMossTest,
|
|
110
124
|
runMultipleRunsTest,
|
|
111
125
|
runOutputSampleRateTest,
|
|
112
126
|
runParlerWerTest,
|
|
113
127
|
runParlerTest,
|
|
128
|
+
runPocketIntegrationTest,
|
|
114
129
|
runRtfBenchmarkTest,
|
|
115
130
|
runStreamingBenchmarkTest,
|
|
116
131
|
runSupertonicMtlTest,
|
package/tts.d.ts
CHANGED
|
@@ -17,6 +17,26 @@ export interface TTSJobData {
|
|
|
17
17
|
instruct?: string;
|
|
18
18
|
referenceAudio?: string;
|
|
19
19
|
referenceText?: string;
|
|
20
|
+
seconds?: number;
|
|
21
|
+
negativePrompt?: string;
|
|
22
|
+
steps?: number;
|
|
23
|
+
guidance?: number;
|
|
24
|
+
shift?: number;
|
|
25
|
+
messages?: Array<{
|
|
26
|
+
role: string;
|
|
27
|
+
text?: string;
|
|
28
|
+
audio?: Int16Array | Float32Array;
|
|
29
|
+
sampleRate?: number;
|
|
30
|
+
}>;
|
|
31
|
+
replyVoice?: Int16Array | Float32Array;
|
|
32
|
+
replyVoiceSampleRate?: number;
|
|
33
|
+
textReply?: boolean;
|
|
34
|
+
maxReplySeconds?: number;
|
|
35
|
+
maxNewTokens?: number;
|
|
36
|
+
greedy?: boolean;
|
|
37
|
+
temperature?: number;
|
|
38
|
+
topP?: number;
|
|
39
|
+
topK?: number;
|
|
20
40
|
}
|
|
21
41
|
export interface TTSWeightData {
|
|
22
42
|
filename: string;
|
|
File without changes
|
|
File without changes
|