@qvac/tts-ggml 0.13.0 → 0.14.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.
Files changed (66) hide show
  1. package/README.md +51 -10
  2. package/docs/pocket-tts.md +12 -10
  3. package/index.d.ts +43 -1130
  4. package/index.js +127 -3042
  5. package/lib/addonEvents.d.ts +26 -0
  6. package/lib/addonEvents.js +51 -0
  7. package/lib/conditioning.d.ts +50 -0
  8. package/lib/conditioning.js +184 -0
  9. package/lib/engineDetection.d.ts +14 -0
  10. package/lib/engineDetection.js +110 -0
  11. package/lib/engineIds.d.ts +15 -0
  12. package/lib/engineIds.js +39 -0
  13. package/lib/engineParams.d.ts +3 -0
  14. package/lib/engineParams.js +34 -0
  15. package/lib/engineSetup.d.ts +153 -0
  16. package/lib/engineSetup.js +2 -0
  17. package/lib/engines/audio8.d.ts +83 -0
  18. package/lib/engines/audio8.js +262 -0
  19. package/lib/engines/chatterbox.d.ts +10 -0
  20. package/lib/engines/chatterbox.js +112 -0
  21. package/lib/engines/cosyvoice.d.ts +87 -0
  22. package/lib/engines/cosyvoice.js +267 -0
  23. package/lib/engines/moss.d.ts +26 -0
  24. package/lib/engines/moss.js +177 -0
  25. package/lib/engines/mossSoundEffect.d.ts +41 -0
  26. package/lib/engines/mossSoundEffect.js +117 -0
  27. package/lib/engines/mossSpeech.d.ts +86 -0
  28. package/lib/engines/mossSpeech.js +228 -0
  29. package/lib/engines/parler.d.ts +71 -0
  30. package/lib/engines/parler.js +287 -0
  31. package/lib/engines/supertonic.d.ts +11 -0
  32. package/lib/engines/supertonic.js +115 -0
  33. package/lib/exclusiveQueue.d.ts +16 -0
  34. package/lib/exclusiveQueue.js +45 -0
  35. package/lib/jobFields.d.ts +20 -0
  36. package/lib/jobFields.js +73 -0
  37. package/lib/modelFiles.d.ts +207 -0
  38. package/lib/modelFiles.js +117 -0
  39. package/lib/nativeParams.d.ts +12 -0
  40. package/lib/nativeParams.js +73 -0
  41. package/lib/optionValidation.d.ts +2 -0
  42. package/lib/optionValidation.js +103 -0
  43. package/lib/options.d.ts +4 -0
  44. package/lib/options.js +17 -0
  45. package/lib/pocketLifecycle.d.ts +67 -0
  46. package/lib/pocketLifecycle.js +170 -0
  47. package/lib/reload.d.ts +12 -0
  48. package/lib/reload.js +76 -0
  49. package/lib/sentenceStream.d.ts +85 -0
  50. package/lib/sentenceStream.js +367 -0
  51. package/lib/setup.d.ts +7 -0
  52. package/lib/setup.js +169 -0
  53. package/lib/streamingSupport.d.ts +8 -0
  54. package/lib/streamingSupport.js +77 -0
  55. package/lib/types.d.ts +465 -0
  56. package/lib/types.js +2 -0
  57. package/lib/voiceControls.d.ts +12 -0
  58. package/lib/voiceControls.js +23 -0
  59. package/package.json +11 -10
  60. package/test/integration/audio8.test.js +6 -12
  61. package/test/integration/gpu-smoke.test.js +2 -11
  62. package/test/integration/lavasr-enhancer.test.js +2 -15
  63. package/test/integration/moss-sfx.test.js +29 -4
  64. package/test/integration/moss.test.js +1 -1
  65. package/test/utils/desktopGpuBackend.js +21 -0
  66. package/test/utils/runTTS.js +1 -1
@@ -34,6 +34,7 @@ const {
34
34
  const { resolveRefWavPath } = require('../utils/runChatterboxTTS')
35
35
  const { TTS_TEST_THREADS } = require('../utils/testThreads')
36
36
  const { GPU_ONLY_USE_GPU } = require('../utils/gpuOnly')
37
+ const { assertDesktopGpuBackend } = require('../utils/desktopGpuBackend')
37
38
 
38
39
  const platform = os.platform()
39
40
  const isMobile = platform === 'ios' || platform === 'android'
@@ -42,11 +43,6 @@ const isMobile = platform === 'ios' || platform === 'android'
42
43
  // fallback from a failure to a warning (e.g. a Linux host with no Vulkan SDK).
43
44
  const NO_GPU = proc.env && proc.env.NO_GPU === 'true'
44
45
  const RELAX = proc.env && proc.env.QVAC_TTS_GPU_SMOKE_RELAX === '1'
45
- const GPU_BACKEND_IDS = { metal: 1, cuda: 2, vulkan: 3, opencl: 4 }
46
- // CI rows whose prebuild bundles more than one usable GPU backend (the linux
47
- // runners carry CUDA and Vulkan) pin the engine cascade through
48
- // TTS_CPP_GPU_BACKEND; the enhancer assertion expects whatever the row pinned
49
- // and falls back to the platform's cascade default when unset.
50
46
  const PINNED_GPU_BACKEND = (proc.env && proc.env.TTS_CPP_GPU_BACKEND) || ''
51
47
 
52
48
  const ENHANCED_RATE = 48000
@@ -92,10 +88,6 @@ function expectsGpu() {
92
88
  )
93
89
  }
94
90
 
95
- function expectedDesktopEnhancerBackendId() {
96
- return GPU_BACKEND_IDS[PINNED_GPU_BACKEND] || GPU_BACKEND_IDS.vulkan
97
- }
98
-
99
91
  // Strict check that the LavaSR *enhancer* network engaged the GPU. Reads the
100
92
  // enhancer-specific backend surfaced by ChatterboxModel/SupertonicModel
101
93
  // runtimeStats (enhancerBackendDevice: -1 none / 0 CPU / 1 GPU;
@@ -134,12 +126,7 @@ function assertEnhancerGpuBackend(t, stats) {
134
126
  if (platform === 'darwin' || platform === 'ios') {
135
127
  t.is(id, 1, `enhancer/${platform}: expected Metal backendId=1, got ${backendIdToName(id)}`)
136
128
  } else if (platform === 'linux' || platform === 'win32') {
137
- const expectedId = expectedDesktopEnhancerBackendId()
138
- t.is(
139
- id,
140
- expectedId,
141
- `enhancer/${platform}: expected ${backendIdToName(expectedId)} backendId=${expectedId}, got ${backendIdToName(id)}`
142
- )
129
+ assertDesktopGpuBackend(t, `enhancer/${platform}`, dev, id, PINNED_GPU_BACKEND)
143
130
  } else if (platform === 'android') {
144
131
  t.ok(
145
132
  id === 3 || id === 4,
@@ -1,10 +1,12 @@
1
1
  'use strict'
2
2
 
3
3
  const path = require('bare-path')
4
+ const fs = require('bare-fs')
4
5
  const proc = require('bare-process')
5
6
  const test = require('brittle')
6
7
 
7
8
  const TTSGgml = require('@qvac/tts-ggml')
9
+ const { assertMossBackend } = require('../utils/mossBackend')
8
10
 
9
11
  const SFX_SAMPLE_RATE = 48000
10
12
  const TENTHS_PER_SECOND = 10
@@ -14,13 +16,35 @@ const MODEL_DIR_ENV = 'QVAC_TEST_MOSS_SFX_MODEL_DIR'
14
16
  const QUICK_STEPS = 2
15
17
  const SHORT_SECONDS = 1.5
16
18
  const LONGER_SECONDS = 2.5
17
- const CPU_DEVICE = 0
18
- const GPU_DEVICE = 1
19
+ const PINNED_GPU_BACKEND = (proc.env && proc.env.TTS_CPP_GPU_BACKEND) || ''
19
20
 
20
21
  const modelDir = (proc.env && proc.env[MODEL_DIR_ENV]) || ''
21
22
  const skipWithoutModels = modelDir === ''
22
23
  const noGpu = proc.env && proc.env.NO_GPU === 'true'
23
24
 
25
+ if (proc.env && proc.env.QVAC_TEST_MOSS_FULL_GPU === 'true') {
26
+ if (noGpu || !['cuda', 'vulkan', 'metal', 'opencl'].includes(PINNED_GPU_BACKEND.toLowerCase())) {
27
+ throw new Error(
28
+ 'MOSS-SFX full GPU validation requires an explicit GPU backend and NO_GPU=false'
29
+ )
30
+ }
31
+ if (
32
+ !modelDir ||
33
+ !fs.existsSync(modelDir) ||
34
+ !fs
35
+ .readdirSync(modelDir)
36
+ .some(
37
+ (name) =>
38
+ /^moss-sfx(-[a-z0-9_]+)*\.gguf$/i.test(name) &&
39
+ fs.statSync(path.join(modelDir, name)).isFile()
40
+ )
41
+ ) {
42
+ throw new Error(
43
+ 'MOSS-SFX full GPU validation requires QVAC_TEST_MOSS_SFX_MODEL_DIR with a GGUF'
44
+ )
45
+ }
46
+ }
47
+
24
48
  function createSfxModel(useGPU = false) {
25
49
  return new TTSGgml({
26
50
  engine: TTSGgml.ENGINE_MOSS_SFX,
@@ -70,7 +94,7 @@ test(
70
94
  try {
71
95
  const result = await generate(model, { seconds: SHORT_SECONDS })
72
96
  assertClip(t, 'cpu clip', result, SHORT_SECONDS)
73
- t.is(result.stats.backendDevice, CPU_DEVICE, 'the clip ran on the CPU')
97
+ assertMossBackend(t, 'cpu clip', result.stats, false, PINNED_GPU_BACKEND)
74
98
  } finally {
75
99
  await model.unload()
76
100
  }
@@ -88,7 +112,8 @@ test(
88
112
  const longer = await generate(model, { seconds: LONGER_SECONDS, negativePrompt: 'music' })
89
113
  assertClip(t, 'short clip', short, SHORT_SECONDS)
90
114
  assertClip(t, 'longer clip', longer, LONGER_SECONDS)
91
- t.is(short.stats.backendDevice, GPU_DEVICE, 'the clips ran on the GPU')
115
+ assertMossBackend(t, 'short clip', short.stats, true, PINNED_GPU_BACKEND)
116
+ assertMossBackend(t, 'longer clip', longer.stats, true, PINNED_GPU_BACKEND)
92
117
  } finally {
93
118
  await model.unload()
94
119
  }
@@ -290,7 +290,7 @@ test(
290
290
  { dialogueReferences: references, seed: 7, files: { modelDir: path.resolve(modelDir) } },
291
291
  async (model) => {
292
292
  t.ok(
293
- DIALOGUE_BACKBONE_RE.test(path.basename(model._mossBackbonePath)),
293
+ DIALOGUE_BACKBONE_RE.test(path.basename(model._setup.paths.mossBackbonePath)),
294
294
  'dialogue picks the TTSD backbone'
295
295
  )
296
296
  const started = Date.now()
@@ -0,0 +1,21 @@
1
+ 'use strict'
2
+
3
+ const GPU_DEVICE = 1
4
+ const GPU_BACKEND_IDS = { metal: 1, cuda: 2, vulkan: 3, opencl: 4 }
5
+ const AUTOMATIC_BACKEND_IDS = [GPU_BACKEND_IDS.cuda, GPU_BACKEND_IDS.vulkan]
6
+
7
+ function expectedBackendIds(pinnedBackend) {
8
+ if (!pinnedBackend) return AUTOMATIC_BACKEND_IDS
9
+ const name = pinnedBackend.toLowerCase()
10
+ return Object.prototype.hasOwnProperty.call(GPU_BACKEND_IDS, name) ? [GPU_BACKEND_IDS[name]] : []
11
+ }
12
+
13
+ function assertDesktopGpuBackend(t, label, device, backendId, pinnedBackend = '') {
14
+ t.is(device, GPU_DEVICE, `${label}: GPU device required`)
15
+ t.ok(
16
+ expectedBackendIds(pinnedBackend).includes(backendId),
17
+ `${label}: expected ${pinnedBackend || 'CUDA or Vulkan'} backend, got backendId=${backendId}`
18
+ )
19
+ }
20
+
21
+ module.exports = { assertDesktopGpuBackend }
@@ -58,7 +58,7 @@ async function runTTSWithSplit(model, params, expectation = {}, options = {}) {
58
58
  const splitLanguage =
59
59
  typeof params.splitLanguage === 'string' && params.splitLanguage.length > 0
60
60
  ? params.splitLanguage
61
- : model?._config?.language || 'en'
61
+ : model?._setup?.config?.language || 'en'
62
62
  const splitOpts = {
63
63
  language: splitLanguage,
64
64
  mergeToMaxScalars: false,