@qvac/sdk 0.19.1 → 0.20.1

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 (75) hide show
  1. package/NOTICE +78 -55
  2. package/README.md +3 -1
  3. package/dist/examples/abot-world.js +3 -3
  4. package/dist/examples/advisory-model-fit.d.ts +59 -0
  5. package/dist/examples/advisory-model-fit.js +156 -0
  6. package/dist/examples/asr/parakeet-nemotron-filesystem.d.ts +2 -0
  7. package/dist/examples/asr/parakeet-nemotron-filesystem.js +170 -0
  8. package/dist/examples/audiogen/edit-music.d.ts +2 -0
  9. package/dist/examples/audiogen/edit-music.js +121 -0
  10. package/dist/examples/audiogen/understand-music.d.ts +2 -0
  11. package/dist/examples/audiogen/understand-music.js +73 -0
  12. package/dist/examples/diffusion-ic-lora-ltx.js +3 -3
  13. package/dist/examples/diffusion-img2vid.js +1 -1
  14. package/dist/examples/diffusion-txt2vid-minimax-h3.d.ts +2 -0
  15. package/dist/examples/diffusion-txt2vid-minimax-h3.js +64 -0
  16. package/dist/examples/diffusion-txt2vid.js +1 -1
  17. package/dist/examples/rag/rag-turbovec.d.ts +2 -0
  18. package/dist/examples/rag/rag-turbovec.js +58 -0
  19. package/dist/examples/tts/audio8.js +5 -5
  20. package/dist/examples/tts/chatterbox-enhanced.js +4 -5
  21. package/dist/examples/tts/chatterbox-multilingual.js +5 -5
  22. package/dist/examples/tts/chatterbox.js +5 -5
  23. package/dist/examples/tts/cosyvoice3.js +5 -5
  24. package/dist/examples/tts/llm-to-tts-streaming.js +12 -2
  25. package/dist/examples/tts/parler.js +5 -5
  26. package/dist/examples/tts/supertonic-enhanced.js +4 -5
  27. package/dist/examples/tts/supertonic-multilingual.js +5 -5
  28. package/dist/examples/tts/supertonic.js +5 -5
  29. package/dist/scripts/contract/build-contract.d.ts +1 -1
  30. package/dist/scripts/contract/constants-registry.d.ts +31 -0
  31. package/dist/scripts/contract/constants-registry.js +13 -2
  32. package/dist/scripts/contract/method-shapes.d.ts +3 -0
  33. package/dist/scripts/contract/method-shapes.js +3 -0
  34. package/dist/src/client/api/assess-model-fit.d.ts +9 -4
  35. package/dist/src/client/api/assess-model-fit.js +9 -4
  36. package/dist/src/client/api/audio-edit.d.ts +36 -0
  37. package/dist/src/client/api/audio-edit.js +38 -0
  38. package/dist/src/client/api/audio-gen-result.d.ts +5 -1
  39. package/dist/src/client/api/audio-gen-result.js +105 -52
  40. package/dist/src/client/api/audio-gen.d.ts +38 -1
  41. package/dist/src/client/api/audio-gen.js +38 -1
  42. package/dist/src/client/api/audio-understand.d.ts +25 -0
  43. package/dist/src/client/api/audio-understand.js +27 -0
  44. package/dist/src/client/api/index.d.ts +3 -0
  45. package/dist/src/client/api/index.js +3 -0
  46. package/dist/src/client/api/text-to-speech.d.ts +31 -4
  47. package/dist/src/client/api/text-to-speech.js +118 -21
  48. package/dist/src/client/api/vector-index.d.ts +143 -0
  49. package/dist/src/client/api/vector-index.js +168 -0
  50. package/dist/src/client/api/world.d.ts +2 -2
  51. package/dist/src/commands/bundle/manifest.d.ts +2 -0
  52. package/dist/src/commands/verify/addon-source.d.ts +6 -0
  53. package/dist/src/commands/verify/bundle-source.d.ts +2 -0
  54. package/dist/src/commands/verify/bundle-source.js +155 -1
  55. package/dist/src/commands/verify/index.js +1 -0
  56. package/dist/src/commands/verify/prebuilds.d.ts +23 -0
  57. package/dist/src/commands/verify/prebuilds.js +129 -13
  58. package/dist/src/commands/verify/resource-collectors.js +2 -1
  59. package/dist/src/expo/plugins/patches/qvac-platform-addons.d.ts +23 -0
  60. package/dist/src/expo/plugins/patches/qvac-platform-addons.js +94 -0
  61. package/dist/src/expo/plugins/withMobileBundle.d.ts +9 -6
  62. package/dist/src/expo/plugins/withMobileBundle.js +54 -34
  63. package/dist/src/index.d.ts +3 -3
  64. package/dist/src/index.js +7 -3
  65. package/dist/src/schemas/sdk-errors-server.d.ts +4 -0
  66. package/dist/src/schemas/sdk-errors-server.js +22 -0
  67. package/dist/src/utils/aggregate-events.d.ts +3 -1
  68. package/dist/src/utils/aggregate-events.js +7 -1
  69. package/dist/src/utils/errors-server.d.ts +12 -0
  70. package/dist/src/utils/errors-server.js +21 -0
  71. package/package.json +23 -17
  72. package/src/electron-forge/index.cjs +86 -14
  73. package/src/expo/plugins/patches/android-link.mjs +18 -9
  74. package/src/expo/plugins/patches/ios-link.mjs +18 -9
  75. package/src/expo/plugins/patches/qvac-platform-addons.ts +124 -0
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Parakeet Nemotron transcription from an audio file.
3
+ *
4
+ * Usage:
5
+ * bun run examples/asr/parakeet-nemotron-filesystem.ts \
6
+ * <audio-file> [locale] [nemotron-gguf] [--streaming]
7
+ * bun run examples/asr/parakeet-nemotron-filesystem.ts \
8
+ * <audio-file> [nemotron-gguf] [--streaming]
9
+ *
10
+ * Uses `PARAKEET_NEMOTRON_0_6B_Q4_0` when the model is omitted and `auto` when
11
+ * the locale is omitted. Pass `--streaming` to stream decoded 16 kHz mono PCM;
12
+ * otherwise, the input is transcribed in batch mode.
13
+ */
14
+ import { loadModel, PARAKEET_NEMOTRON_0_6B_Q4_0, transcribe, transcribeStream, unloadModel } from '@qvac/sdk';
15
+ import { spawn } from 'child_process';
16
+ const SAMPLE_RATE = 16000;
17
+ const BYTES_PER_S16_SAMPLE = 2;
18
+ const INPUT_CHUNK_MS = 160;
19
+ const MILLISECONDS_PER_SECOND = 1000;
20
+ const BYTES_PER_MEGABYTE = 1e6;
21
+ const DEFAULT_LOCALE = 'auto';
22
+ const FFMPEG_PROTOCOLS = 'file,pipe';
23
+ const STREAMING_FLAG = '--streaming';
24
+ const EARLY_OUTPUT_END_MESSAGE = 'The transcription stream ended before the decoder input completed';
25
+ const USAGE = 'Usage: bun run examples/asr/parakeet-nemotron-filesystem.ts ' +
26
+ '<audio-file> [locale] [nemotron-gguf] [--streaming]';
27
+ function parseArguments(args) {
28
+ const streaming = args.includes(STREAMING_FLAG);
29
+ const positional = args.filter((argument) => argument !== STREAMING_FLAG);
30
+ const [audioFilePath, second, third] = positional;
31
+ const secondIsModel = second !== undefined &&
32
+ (second.endsWith('.gguf') || second.includes('/') || second.includes('\\'));
33
+ const locale = secondIsModel ? DEFAULT_LOCALE : (second ?? DEFAULT_LOCALE);
34
+ const modelSource = secondIsModel ? second : third;
35
+ return { audioFilePath, locale, modelSource, streaming };
36
+ }
37
+ function requireAudioFilePath(audioFilePath) {
38
+ if (audioFilePath)
39
+ return audioFilePath;
40
+ throw new Error(USAGE);
41
+ }
42
+ function delay(ms) {
43
+ return new Promise((resolve) => setTimeout(resolve, ms));
44
+ }
45
+ function calculateChunkBytes() {
46
+ const samplesPerChunk = Math.floor((INPUT_CHUNK_MS / MILLISECONDS_PER_SECOND) * SAMPLE_RATE);
47
+ return samplesPerChunk * BYTES_PER_S16_SAMPLE;
48
+ }
49
+ function createDecoder(inputPath) {
50
+ return spawn('ffmpeg', [
51
+ '-protocol_whitelist',
52
+ FFMPEG_PROTOCOLS,
53
+ '-i',
54
+ inputPath,
55
+ '-ar',
56
+ String(SAMPLE_RATE),
57
+ '-ac',
58
+ '1',
59
+ '-f',
60
+ 's16le',
61
+ 'pipe:1'
62
+ ], { stdio: ['ignore', 'pipe', 'inherit'] });
63
+ }
64
+ function waitForDecoder(decoder) {
65
+ return new Promise((resolve) => {
66
+ decoder.once('error', resolve);
67
+ decoder.once('close', (code) => {
68
+ if (code === 0)
69
+ resolve(null);
70
+ else
71
+ resolve(new Error(`ffmpeg exited with code ${code}`));
72
+ });
73
+ });
74
+ }
75
+ function stopDecoder(decoder) {
76
+ if (decoder?.exitCode === null && !decoder.killed)
77
+ decoder.kill();
78
+ }
79
+ async function printTranscription(session) {
80
+ for await (const event of session) {
81
+ if (event.type === 'text' && event.text)
82
+ process.stdout.write(event.text);
83
+ }
84
+ }
85
+ async function rejectWhenOutputEnds(output) {
86
+ await output;
87
+ throw new Error(EARLY_OUTPUT_END_MESSAGE);
88
+ }
89
+ async function writeAvailableChunks(session, pcm, chunkBytes) {
90
+ let offset = 0;
91
+ while (pcm.length - offset >= chunkBytes) {
92
+ session.write(pcm.subarray(offset, offset + chunkBytes));
93
+ offset += chunkBytes;
94
+ await delay(INPUT_CHUNK_MS);
95
+ }
96
+ return pcm.subarray(offset);
97
+ }
98
+ async function feedDecoderOutput(session, decoder, chunkBytes) {
99
+ let incomplete = Buffer.alloc(0);
100
+ for await (const decoded of decoder.stdout) {
101
+ const pcm = incomplete.length === 0 ? Buffer.from(decoded) : Buffer.concat([incomplete, decoded]);
102
+ incomplete = await writeAvailableChunks(session, pcm, chunkBytes);
103
+ }
104
+ return incomplete;
105
+ }
106
+ async function runStreaming(modelId, inputPath) {
107
+ const session = await transcribeStream({ modelId, parakeetStreamingConfig: {} });
108
+ const output = printTranscription(session);
109
+ let decoder;
110
+ let exited;
111
+ let feeding;
112
+ try {
113
+ decoder = createDecoder(inputPath);
114
+ exited = waitForDecoder(decoder);
115
+ feeding = feedDecoderOutput(session, decoder, calculateChunkBytes());
116
+ const incomplete = await Promise.race([feeding, rejectWhenOutputEnds(output)]);
117
+ const decoderError = await exited;
118
+ if (decoderError)
119
+ throw decoderError;
120
+ if (incomplete.length > 0)
121
+ session.write(incomplete);
122
+ session.end();
123
+ await output;
124
+ process.stdout.write('\n');
125
+ }
126
+ finally {
127
+ stopDecoder(decoder);
128
+ session.destroy();
129
+ await Promise.allSettled([exited, feeding, output]);
130
+ }
131
+ }
132
+ function printDownloadProgress(progress) {
133
+ const downloaded = (progress.downloaded / BYTES_PER_MEGABYTE).toFixed(1);
134
+ const total = (progress.total / BYTES_PER_MEGABYTE).toFixed(1);
135
+ const percentage = progress.percentage.toFixed(0);
136
+ const line = `Downloading ${percentage}% (${downloaded}/${total} MB)`;
137
+ process.stderr.write(process.stderr.isTTY ? `\r${line}` : `${line}\n`);
138
+ if (progress.percentage >= 100)
139
+ process.stderr.write('\n');
140
+ }
141
+ async function run() {
142
+ const { audioFilePath, locale, modelSource, streaming } = parseArguments(process.argv.slice(2));
143
+ const inputPath = requireAudioFilePath(audioFilePath);
144
+ let modelId = null;
145
+ try {
146
+ console.log(`Loading Nemotron with locale ${locale}...`);
147
+ modelId = await loadModel({
148
+ modelSrc: modelSource ?? PARAKEET_NEMOTRON_0_6B_Q4_0,
149
+ modelType: 'parakeet-transcription',
150
+ modelConfig: { language: locale, streaming },
151
+ onProgress: printDownloadProgress
152
+ });
153
+ if (streaming) {
154
+ console.log('Streaming with the Nemotron native 320 ms operating point...');
155
+ await runStreaming(modelId, inputPath);
156
+ }
157
+ else {
158
+ console.log('Transcribing in batch mode...');
159
+ console.log(await transcribe({ modelId, audioChunk: inputPath }));
160
+ }
161
+ }
162
+ finally {
163
+ if (modelId)
164
+ await unloadModel({ modelId });
165
+ }
166
+ }
167
+ run().catch((error) => {
168
+ console.error(error);
169
+ process.exitCode = 1;
170
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=edit-music.d.ts.map
@@ -0,0 +1,121 @@
1
+ import { writeFileSync } from 'node:fs';
2
+ import { AUDIOGEN_ACESTEP_5HZ_LM_0_6B_Q8_0, AUDIOGEN_ACESTEP_V15_TURBO_Q4_K_M, AUDIOGEN_QWEN3_EMBEDDING_0_6B_Q8_0, AUDIOGEN_VAE_BF16, audioEdit, loadModel, unloadModel } from '@qvac/sdk';
3
+ // Edit an existing recording with ACE-Step: a Flow-Edit that re-conditions the
4
+ // whole clip from a source prompt to a target prompt, then a Repaint that
5
+ // regenerates one time range against a new prompt. Operations run in order.
6
+ //
7
+ // Usage:
8
+ // bun examples/audiogen/edit-music.ts <source.wav|mp3|...> "original pop song" "guitar pop-rock" [output.wav]
9
+ //
10
+ // The source must run at least REPAINT_END seconds: the Repaint below asks for
11
+ // a fixed window, and a range past the end of the source is rejected with
12
+ // `repaint.start must be within the source duration`.
13
+ //
14
+ // The source is a file path: the SDK decodes it (any FFmpeg-decodable format)
15
+ // to the 48 kHz stereo float PCM the engine expects. Pass raw interleaved
16
+ // stereo 48 kHz Float32 LE PCM in [-1, 1] as a Buffer instead when the audio
17
+ // is already in memory — for example the `pcm` of an earlier `audioGen()` run,
18
+ // converted from Int16 to Float32.
19
+ // Repaint window, in seconds from the start of the source.
20
+ const REPAINT_START = 10;
21
+ const REPAINT_END = 20;
22
+ const sourcePath = process.argv[2];
23
+ const fromCaption = process.argv[3] ?? 'Original pop song';
24
+ const toCaption = process.argv[4] ?? 'Guitar pop-rock';
25
+ const outputPath = process.argv[5] ?? 'audiogen-edit.wav';
26
+ if (!sourcePath) {
27
+ console.error('Usage: bun examples/audiogen/edit-music.ts <source-audio> "<from caption>" "<to caption>" [output.wav]');
28
+ process.exit(1);
29
+ }
30
+ let modelId;
31
+ try {
32
+ console.log('▸ Loading ACE-Step AudioGen models...');
33
+ modelId = await loadModel({
34
+ modelType: 'audiogen',
35
+ modelConfig: {
36
+ textEncModelSrc: AUDIOGEN_QWEN3_EMBEDDING_0_6B_Q8_0,
37
+ lmModelSrc: AUDIOGEN_ACESTEP_5HZ_LM_0_6B_Q8_0,
38
+ // Flow-Edit needs a turbo DiT variant; Repaint works on every variant.
39
+ ditModelSrc: AUDIOGEN_ACESTEP_V15_TURBO_Q4_K_M,
40
+ vaeModelSrc: AUDIOGEN_VAE_BF16,
41
+ useGPU: true
42
+ }
43
+ });
44
+ console.log(`▸ Model loaded: ${modelId}`);
45
+ console.log(`▸ Editing ${sourcePath}: "${fromCaption}" -> "${toCaption}"`);
46
+ const run = audioEdit({
47
+ modelId,
48
+ sourceAudio: sourcePath,
49
+ operations: [
50
+ {
51
+ type: 'flow-edit',
52
+ from: { caption: fromCaption },
53
+ to: { caption: toCaption }
54
+ },
55
+ {
56
+ // Regenerate the repaint window as a synth solo; the rest is kept.
57
+ type: 'repaint',
58
+ caption: 'analog synth solo',
59
+ lyrics: '[Instrumental]',
60
+ start: REPAINT_START,
61
+ end: REPAINT_END,
62
+ mode: 'balanced',
63
+ strength: 0.5
64
+ }
65
+ ],
66
+ // Seeds the first operation; each following operation uses seed + index.
67
+ seed: 22883
68
+ });
69
+ console.log(`▸ requestId: ${run.requestId}`);
70
+ for await (const progress of run.progressStream) {
71
+ const value = progress.total > 0 ? `${progress.step}/${progress.total}` : `${progress.step} (indeterminate)`;
72
+ console.log(`▸ ${progress.stage}: ${value}`);
73
+ }
74
+ const [audio, stats] = await Promise.all([run.audio, run.stats]);
75
+ writeFileSync(outputPath, createWav(audio.pcm, audio.sampleRate, audio.channels, audio.bitsPerSample));
76
+ if (stats)
77
+ console.log(`▸ Stats: ${JSON.stringify(stats)}`);
78
+ console.log(`▸ Saved ${outputPath}`);
79
+ await unloadModel({ modelId });
80
+ modelId = undefined;
81
+ process.exit(0);
82
+ }
83
+ catch (error) {
84
+ if (modelId !== undefined) {
85
+ try {
86
+ await unloadModel({ modelId });
87
+ }
88
+ catch {
89
+ // Preserve the edit error as the primary failure.
90
+ }
91
+ }
92
+ console.error('✖', error);
93
+ process.exit(1);
94
+ }
95
+ function createWav(pcm, sampleRate, channels, bitsPerSample) {
96
+ const header = new ArrayBuffer(44);
97
+ const view = new DataView(header);
98
+ const blockAlign = channels * (bitsPerSample / 8);
99
+ writeAscii(view, 0, 'RIFF');
100
+ view.setUint32(4, 36 + pcm.byteLength, true);
101
+ writeAscii(view, 8, 'WAVE');
102
+ writeAscii(view, 12, 'fmt ');
103
+ view.setUint32(16, 16, true);
104
+ view.setUint16(20, 1, true);
105
+ view.setUint16(22, channels, true);
106
+ view.setUint32(24, sampleRate, true);
107
+ view.setUint32(28, sampleRate * blockAlign, true);
108
+ view.setUint16(32, blockAlign, true);
109
+ view.setUint16(34, bitsPerSample, true);
110
+ writeAscii(view, 36, 'data');
111
+ view.setUint32(40, pcm.byteLength, true);
112
+ const wav = new Uint8Array(44 + pcm.byteLength);
113
+ wav.set(new Uint8Array(header));
114
+ wav.set(pcm, 44);
115
+ return wav;
116
+ }
117
+ function writeAscii(view, offset, value) {
118
+ for (let index = 0; index < value.length; index++) {
119
+ view.setUint8(offset + index, value.charCodeAt(index));
120
+ }
121
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=understand-music.d.ts.map
@@ -0,0 +1,73 @@
1
+ import { AUDIOGEN_ACESTEP_5HZ_LM_0_6B_Q8_0, AUDIOGEN_ACESTEP_V15_TURBO_Q4_K_M, AUDIOGEN_QWEN3_EMBEDDING_0_6B_Q8_0, AUDIOGEN_VAE_BF16, audioUnderstand, loadModel, unloadModel } from '@qvac/sdk';
2
+ // Describe an existing recording with ACE-Step's reverse pipeline: the engine
3
+ // encodes the audio, recovers its FSQ semantic codes, and the LM reports a
4
+ // caption and the clip's musical metadata.
5
+ //
6
+ // Usage:
7
+ // bun examples/audiogen/understand-music.ts <source.wav|mp3|...> [language hint]
8
+ //
9
+ // The source is a file path: the SDK decodes it (any FFmpeg-decodable format)
10
+ // to the 48 kHz stereo float PCM the engine expects. Pass raw interleaved
11
+ // stereo 48 kHz Float32 LE PCM in [-1, 1] as a Buffer instead when the audio
12
+ // is already in memory.
13
+ const sourcePath = process.argv[2];
14
+ const vocalLanguage = process.argv[3];
15
+ if (!sourcePath) {
16
+ console.error('Usage: bun examples/audiogen/understand-music.ts <source-audio> [language]');
17
+ process.exit(1);
18
+ }
19
+ let modelId;
20
+ try {
21
+ console.log('▸ Loading ACE-Step AudioGen models...');
22
+ modelId = await loadModel({
23
+ modelType: 'audiogen',
24
+ modelConfig: {
25
+ textEncModelSrc: AUDIOGEN_QWEN3_EMBEDDING_0_6B_Q8_0,
26
+ lmModelSrc: AUDIOGEN_ACESTEP_5HZ_LM_0_6B_Q8_0,
27
+ ditModelSrc: AUDIOGEN_ACESTEP_V15_TURBO_Q4_K_M,
28
+ vaeModelSrc: AUDIOGEN_VAE_BF16,
29
+ useGPU: true
30
+ }
31
+ });
32
+ console.log(`▸ Model loaded: ${modelId}`);
33
+ console.log(`▸ Analysing ${sourcePath}`);
34
+ const run = audioUnderstand({
35
+ modelId,
36
+ sourceAudio: sourcePath,
37
+ // Forced into the result instead of the LM's guess; omit to let it decide.
38
+ ...(vocalLanguage !== undefined && { vocalLanguage }),
39
+ seed: 11
40
+ });
41
+ console.log(`▸ requestId: ${run.requestId}`);
42
+ for await (const progress of run.progressStream) {
43
+ const value = progress.total > 0 ? `${progress.step}/${progress.total}` : `${progress.step} (indeterminate)`;
44
+ console.log(`▸ ${progress.stage}: ${value}`);
45
+ }
46
+ const [description, stats] = await Promise.all([run.description, run.stats]);
47
+ console.log(`▸ Caption: ${description.caption}`);
48
+ console.log(`▸ ${description.bpm} BPM, ${description.keyscale}, ${description.timesignature}`);
49
+ console.log(`▸ Vocal language: ${description.vocalLanguage}`);
50
+ // The LM's duration is an estimate; the recovered codes fix the true length.
51
+ console.log(`▸ Estimated duration: ${description.duration.toFixed(1)} s`);
52
+ console.log(`▸ Recovered ${description.audioCodes.length} semantic codes`);
53
+ if (stats)
54
+ console.log(`▸ Stats: ${JSON.stringify({ ...stats, understand: undefined })}`);
55
+ // `audioCodes` feeds straight back into audioGen() to re-synthesize the piece
56
+ // without re-running the LM:
57
+ // audioGen({ modelId, caption: description.caption, audioCodes: description.audioCodes })
58
+ await unloadModel({ modelId });
59
+ modelId = undefined;
60
+ process.exit(0);
61
+ }
62
+ catch (error) {
63
+ if (modelId !== undefined) {
64
+ try {
65
+ await unloadModel({ modelId });
66
+ }
67
+ catch {
68
+ // Preserve the understand error as the primary failure.
69
+ }
70
+ }
71
+ console.error('✖', error);
72
+ process.exit(1);
73
+ }
@@ -1,4 +1,4 @@
1
- import { GEMMA_3_12B_Q4_K_XL, loadModel, LTX_2_3_22B_DISTILLED_EMBEDDINGS_CONNECTORS, LTX_2_3_22B_Q5_K_M, LTX_2_3_VAE, LTX_2_3_VAE_1, unloadModel, video } from '@qvac/sdk';
1
+ import { GEMMA_3_12B_Q4_K_XL, loadModel, LTX_2_3_22B_DISTILLED_EMBEDDINGS_CONNECTORS, LTX_2_3_22B_Q5_K_M, LTX_2_3_AUDIO_VAE, LTX_2_3_VIDEO_VAE, unloadModel, video } from '@qvac/sdk';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
4
  const loraPath = process.argv[2];
@@ -24,8 +24,8 @@ try {
24
24
  device: 'gpu',
25
25
  threads: 4,
26
26
  llmModelSrc: GEMMA_3_12B_Q4_K_XL,
27
- vaeModelSrc: LTX_2_3_VAE_1,
28
- audioVaeModelSrc: LTX_2_3_VAE,
27
+ vaeModelSrc: LTX_2_3_VIDEO_VAE,
28
+ audioVaeModelSrc: LTX_2_3_AUDIO_VAE,
29
29
  embeddingsConnectorsModelSrc: LTX_2_3_22B_DISTILLED_EMBEDDINGS_CONNECTORS,
30
30
  diffusion_fa: true,
31
31
  offload_to_cpu: true,
@@ -33,7 +33,7 @@ try {
33
33
  clipVisionModelSrc,
34
34
  diffusion_fa: true,
35
35
  offload_to_cpu: true,
36
- vae_on_cpu: true,
36
+ params_backend: 'vae=cpu',
37
37
  vae_tiling: true
38
38
  },
39
39
  onProgress: (p) => {
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=diffusion-txt2vid-minimax-h3.d.ts.map
@@ -0,0 +1,64 @@
1
+ import { loadModel, unloadModel, video } from '@qvac/sdk';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ // Pass a directory containing the four MiniMax-H3 files, followed by an output path.
5
+ const modelsDir = process.argv[2];
6
+ if (!modelsDir) {
7
+ throw new Error('Usage: diffusion-txt2vid-minimax-h3.ts <models-directory> [output.avi]');
8
+ }
9
+ const outputPath = process.argv[3] || 'minimax-h3.avi';
10
+ const modelSrc = path.resolve(modelsDir, process.env['H3_MODEL'] || 'minimax_h3_fl2va_pruned-Q4_K.gguf');
11
+ const llmModelSrc = path.resolve(modelsDir, process.env['H3_LLM'] || 'qwen3vl_32b_minimax_h3-Q4_K_M.gguf');
12
+ const vaeModelSrc = path.resolve(modelsDir, 'vae/minimax_h3_video_vae_fp16.safetensors');
13
+ const audioVaeModelSrc = path.resolve(modelsDir, 'vae/minimax_h3_audio_vae_fp32.safetensors');
14
+ for (const file of [modelSrc, llmModelSrc, vaeModelSrc, audioVaeModelSrc])
15
+ fs.accessSync(file);
16
+ let modelId;
17
+ try {
18
+ modelId = await loadModel({
19
+ modelType: 'sdcpp-generation',
20
+ modelSrc,
21
+ modelConfig: {
22
+ mode: 'video',
23
+ llmModelSrc,
24
+ vaeModelSrc,
25
+ audioVaeModelSrc,
26
+ device: 'gpu',
27
+ diffusion_fa: true,
28
+ offload_to_cpu: process.env['H3_OFFLOAD_TO_CPU'] !== '0',
29
+ stream_layers: process.env['H3_STREAM_LAYERS'] === '1',
30
+ ...(process.env['H3_BACKEND'] && { backend: process.env['H3_BACKEND'] }),
31
+ ...(process.env['H3_PARAMS_BACKEND'] && { params_backend: process.env['H3_PARAMS_BACKEND'] }),
32
+ ...(process.env['H3_MAX_VRAM'] && { max_vram: process.env['H3_MAX_VRAM'] })
33
+ }
34
+ });
35
+ const { progressStream, outputs, stats } = video({
36
+ modelId,
37
+ mode: 'txt2vid',
38
+ prompt: process.env['PROMPT'] ||
39
+ 'Premium cinematic coffee commercial. A confident adult sits at a small café table at sunrise, slowly lifts one matte black coffee cup, takes a relaxed sip, and smiles. Warm golden rim light, drifting steam, realistic skin, natural hands, shallow depth of field, subtle slow camera push-in, restrained natural motion, polished live-action advertising, no dialogue, no text overlay.',
40
+ negative_prompt: 'extra people, duplicate cup, malformed hands, cup fused to hand, text, subtitles, watermark, cartoon, CGI, blur, flicker, jitter, camera shake',
41
+ width: 960,
42
+ height: 544,
43
+ // H3 uses 17*k+5 frames; 124 frames at 24 FPS is approximately 5.17 seconds.
44
+ video_frames: Number(process.env['FRAMES'] || 124),
45
+ fps: 24,
46
+ steps: 8,
47
+ cfg_scale: 1,
48
+ seed: 11
49
+ });
50
+ const progress = (async () => {
51
+ for await (const tick of progressStream)
52
+ console.log(`Step ${tick.step}/${tick.totalSteps}`);
53
+ })();
54
+ const [buffers, runtimeStats] = await Promise.all([outputs, stats, progress]);
55
+ if (!buffers[0])
56
+ throw new Error('Generation finished without an AVI result');
57
+ fs.writeFileSync(outputPath, buffers[0]);
58
+ console.log(`Saved ${outputPath}`, runtimeStats);
59
+ }
60
+ finally {
61
+ if (modelId)
62
+ await unloadModel({ modelId, clearStorage: false });
63
+ }
64
+ process.exit(0);
@@ -26,7 +26,7 @@ try {
26
26
  vaeModelSrc,
27
27
  diffusion_fa: true,
28
28
  offload_to_cpu: true,
29
- vae_on_cpu: true,
29
+ params_backend: 'vae=cpu',
30
30
  vae_tiling: true
31
31
  },
32
32
  onProgress: (p) => {
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=rag-turbovec.d.ts.map
@@ -0,0 +1,58 @@
1
+ import { createVectorIndex, embed, loadModel, loadVectorIndex, unloadModel, GTE_LARGE_FP16, VectorIndexStorage } from '@qvac/sdk';
2
+ // Retrieval over documents kept in your own store. The SDK holds only the
3
+ // vectors, in a TurboVec index inside the worker; the documents stay in this
4
+ // Map (or any database you choose) and result ids map back to them.
5
+ try {
6
+ const query = process.argv[2] || 'Which moon has methane rain and lakes?';
7
+ console.log(`▸ Query: "${query}"`);
8
+ const documents = new Map([
9
+ ['1', 'Saturn moon Titan has lakes, clouds, and rain made of liquid methane.'],
10
+ ['2', 'Solar panels convert sunlight into electricity using photovoltaic cells.'],
11
+ ['3', 'Honeybees communicate the location of flowers through a waggle dance.'],
12
+ ['4', 'The Pacific Ocean is the largest and deepest ocean on Earth.']
13
+ ]);
14
+ const modelId = await loadModel({
15
+ modelSrc: GTE_LARGE_FP16,
16
+ onProgress: (p) => {
17
+ const mb = (n) => (n / 1e6).toFixed(1);
18
+ const line = `▸ Downloading ${p.percentage.toFixed(0)}% (${mb(p.downloaded)}/${mb(p.total)} MB)`;
19
+ process.stderr.write(process.stderr.isTTY ? `\r${line}` : `${line}\n`);
20
+ if (p.percentage >= 100)
21
+ process.stderr.write('\n');
22
+ }
23
+ });
24
+ console.log('▸ Embedding documents...');
25
+ const { embedding: vectors } = await embed({ modelId, text: [...documents.values()] });
26
+ console.log('▸ Building the vector index...');
27
+ const index = await createVectorIndex({
28
+ dim: vectors[0].length,
29
+ storage: VectorIndexStorage.TURBOVEC_Q4
30
+ });
31
+ await index.add({ ids: [...documents.keys()], vectors });
32
+ console.log(`▸ Indexed ${index.length} vectors of dimension ${index.dim}`);
33
+ console.log('▸ Searching...');
34
+ const { embedding: queryVector } = await embed({ modelId, text: query });
35
+ const hits = await index.search({ query: queryVector, k: 2 });
36
+ console.log('▸ Top matches:');
37
+ for (const hit of hits) {
38
+ console.log(` score=${hit.score.toFixed(4)} id=${hit.id}: ${documents.get(hit.id)}`);
39
+ }
40
+ // Snapshots persist the vectors only. A relative path resolves under the
41
+ // QVAC data directory; pass an absolute path to store it elsewhere.
42
+ const snapshotPath = 'examples/rag-turbovec.qvi';
43
+ const { path: writtenPath } = await index.write({ path: snapshotPath });
44
+ await index.dispose();
45
+ console.log(`▸ Snapshot written to ${writtenPath}`);
46
+ const reloaded = await loadVectorIndex({ path: snapshotPath });
47
+ const [reloadedBest] = await reloaded.search({ query: queryVector, k: 1 });
48
+ await reloaded.dispose();
49
+ if (!reloadedBest || reloadedBest.id !== hits[0]?.id) {
50
+ throw new Error(`Reloaded index returned id=${reloadedBest?.id} but the original returned id=${hits[0]?.id}`);
51
+ }
52
+ console.log(`▸ Reloaded index agrees: best match id=${reloadedBest.id}`);
53
+ await unloadModel({ modelId });
54
+ }
55
+ catch (error) {
56
+ console.error('✖', error);
57
+ process.exit(1);
58
+ }
@@ -4,6 +4,8 @@ import { createWav, playAudio, int16ArrayToBuffer, createWavHeader } from './uti
4
4
  // primary modelSrc is the LM GGUF; the codec decoder loads via modelConfig.
5
5
  // For zero-shot voice cloning also pass audio8CodecEncoderModelSrc plus
6
6
  // referenceAudioSrc/referenceText (a recording and its exact transcript).
7
+ // Only a fallback: the engine reports the rate it actually produced, and
8
+ // `outputSampleRate` (plus the LavaSR enhancer) can move it off this default.
7
9
  const AUDIO8_SAMPLE_RATE = 44100;
8
10
  try {
9
11
  const modelId = await loadModel({
@@ -32,16 +34,14 @@ try {
32
34
  stream: false
33
35
  });
34
36
  const audioBuffer = await result.buffer;
37
+ const sampleRate = (await result.sampleRate) ?? AUDIO8_SAMPLE_RATE;
35
38
  console.log(`▸ TTS complete. Total samples: ${audioBuffer.length}`);
36
39
  console.log('▸ Saving audio to file...');
37
- createWav(audioBuffer, AUDIO8_SAMPLE_RATE, 'audio8-output.wav');
40
+ createWav(audioBuffer, sampleRate, 'audio8-output.wav');
38
41
  console.log('▸ Audio saved to audio8-output.wav');
39
42
  console.log('▸ Playing audio...');
40
43
  const audioData = int16ArrayToBuffer(audioBuffer);
41
- const wavBuffer = Buffer.concat([
42
- createWavHeader(audioData.length, AUDIO8_SAMPLE_RATE),
43
- audioData
44
- ]);
44
+ const wavBuffer = Buffer.concat([createWavHeader(audioData.length, sampleRate), audioData]);
45
45
  playAudio(wavBuffer);
46
46
  console.log('▸ Audio playback complete');
47
47
  await unloadModel({ modelId });
@@ -5,6 +5,7 @@ import { createWav, playAudio, int16ArrayToBuffer, createWavHeader } from './uti
5
5
  // enhancement — there is no on/off flag — and it forces the output to 48 kHz.
6
6
  // Usage: node chatterbox-enhanced.ts [referenceAudioSrc]
7
7
  const [referenceAudioSrc] = process.argv.slice(2);
8
+ // Only a fallback; the engine reports the rate it actually produced.
8
9
  const ENHANCED_SAMPLE_RATE = 48000;
9
10
  try {
10
11
  const modelId = await loadModel({
@@ -33,16 +34,14 @@ try {
33
34
  stream: false
34
35
  });
35
36
  const audioBuffer = await result.buffer;
37
+ const sampleRate = (await result.sampleRate) ?? ENHANCED_SAMPLE_RATE;
36
38
  console.log(`▸ TTS complete. Total samples: ${audioBuffer.length}`);
37
39
  console.log('▸ Saving audio to file...');
38
- createWav(audioBuffer, ENHANCED_SAMPLE_RATE, 'chatterbox-enhanced-output.wav');
40
+ createWav(audioBuffer, sampleRate, 'chatterbox-enhanced-output.wav');
39
41
  console.log('▸ Audio saved to chatterbox-enhanced-output.wav');
40
42
  console.log('▸ Playing audio...');
41
43
  const audioData = int16ArrayToBuffer(audioBuffer);
42
- const wavBuffer = Buffer.concat([
43
- createWavHeader(audioData.length, ENHANCED_SAMPLE_RATE),
44
- audioData
45
- ]);
44
+ const wavBuffer = Buffer.concat([createWavHeader(audioData.length, sampleRate), audioData]);
46
45
  playAudio(wavBuffer);
47
46
  console.log('▸ Audio playback complete');
48
47
  await unloadModel({ modelId });
@@ -2,6 +2,8 @@ import { loadModel, textToSpeech, unloadModel, TTS_T3_MULTILINGUAL_CHATTERBOX_Q4
2
2
  import { createWav, playAudio, int16ArrayToBuffer, createWavHeader } from './utils.js';
3
3
  // Chatterbox multilingual TTS (GGML): Japanese synthesis with MeCab/IPAdic.
4
4
  // Uses registry model constants — downloads automatically from QVAC Registry.
5
+ // Only a fallback: the engine reports the rate it actually produced, and
6
+ // `outputSampleRate` (plus the LavaSR enhancer) can move it off this default.
5
7
  const CHATTERBOX_SAMPLE_RATE = 24000;
6
8
  const OUTPUT_FILE = 'chatterbox-multilingual-output.wav';
7
9
  try {
@@ -32,16 +34,14 @@ try {
32
34
  stream: false
33
35
  });
34
36
  const audioBuffer = await result.buffer;
37
+ const sampleRate = (await result.sampleRate) ?? CHATTERBOX_SAMPLE_RATE;
35
38
  console.log(`▸ TTS complete. Total samples: ${audioBuffer.length}`);
36
39
  console.log('▸ Saving audio to file...');
37
- createWav(audioBuffer, CHATTERBOX_SAMPLE_RATE, OUTPUT_FILE);
40
+ createWav(audioBuffer, sampleRate, OUTPUT_FILE);
38
41
  console.log(`▸ Audio saved to ${OUTPUT_FILE}`);
39
42
  console.log('▸ Playing audio...');
40
43
  const audioData = int16ArrayToBuffer(audioBuffer);
41
- const wavBuffer = Buffer.concat([
42
- createWavHeader(audioData.length, CHATTERBOX_SAMPLE_RATE),
43
- audioData
44
- ]);
44
+ const wavBuffer = Buffer.concat([createWavHeader(audioData.length, sampleRate), audioData]);
45
45
  playAudio(wavBuffer);
46
46
  console.log('▸ Audio playback complete');
47
47
  await unloadModel({ modelId });
@@ -4,6 +4,8 @@ import { createWav, playAudio, int16ArrayToBuffer, createWavHeader } from './uti
4
4
  // Uses registry model constants — downloads automatically from QVAC Registry.
5
5
  // Usage: node chatterbox.ts [referenceAudioSrc]
6
6
  const [referenceAudioSrc] = process.argv.slice(2);
7
+ // Only a fallback: the engine reports the rate it actually produced, and
8
+ // `outputSampleRate` (plus the LavaSR enhancer) can move it off this default.
7
9
  const CHATTERBOX_SAMPLE_RATE = 24000;
8
10
  try {
9
11
  const modelId = await loadModel({
@@ -35,16 +37,14 @@ try {
35
37
  stream: false
36
38
  });
37
39
  const audioBuffer = await result.buffer;
40
+ const sampleRate = (await result.sampleRate) ?? CHATTERBOX_SAMPLE_RATE;
38
41
  console.log(`▸ TTS complete. Total bytes: ${audioBuffer.length}`);
39
42
  console.log('▸ Saving audio to file...');
40
- createWav(audioBuffer, CHATTERBOX_SAMPLE_RATE, 'tts-output.wav');
43
+ createWav(audioBuffer, sampleRate, 'tts-output.wav');
41
44
  console.log('▸ Audio saved to tts-output.wav');
42
45
  console.log('▸ Playing audio...');
43
46
  const audioData = int16ArrayToBuffer(audioBuffer);
44
- const wavBuffer = Buffer.concat([
45
- createWavHeader(audioData.length, CHATTERBOX_SAMPLE_RATE),
46
- audioData
47
- ]);
47
+ const wavBuffer = Buffer.concat([createWavHeader(audioData.length, sampleRate), audioData]);
48
48
  playAudio(wavBuffer);
49
49
  console.log('▸ Audio playback complete');
50
50
  await unloadModel({ modelId });