modular-voice-agent-sdk 2.6.1 → 2.7.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.
@@ -1,7 +1,9 @@
1
1
  export { NativeSTT } from './stt';
2
2
  export { NativeLLM } from './llm';
3
- export { NativeTTS } from './tts';
3
+ export { NativeTTS, synthesizeToWav } from './tts';
4
+ export type { SynthesizeToWavOptions } from './tts';
4
5
  export type { TTSModelProvider } from './tts-providers';
5
6
  export { PiperTTSProvider, KokoroTTSProvider } from './tts-providers';
6
- export { getCacheDir, getModelsDir, getBinDir, getModelPath, getBinaryPath, defaultBinaries, } from '../../cache';
7
+ export { getCacheDir, getModelsDir, getBinDir, getModelPath, getBinaryPath, defaultBinaries, getCacheStatus, checkModelsInstalled, } from '../../cache';
8
+ export type { ModelConfig, SetupConfig, ModelStatus } from '../../cache';
7
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/backends/native/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAGtE,OAAO,EACL,WAAW,EACX,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,aAAa,EACb,eAAe,GAChB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/backends/native/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AACnD,YAAY,EAAE,sBAAsB,EAAE,MAAM,OAAO,CAAC;AACpD,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAGtE,OAAO,EACL,WAAW,EACX,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,aAAa,EACb,eAAe,EACf,cAAc,EACd,oBAAoB,GACrB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
@@ -1,7 +1,7 @@
1
1
  export { NativeSTT } from './stt';
2
2
  export { NativeLLM } from './llm';
3
- export { NativeTTS } from './tts';
3
+ export { NativeTTS, synthesizeToWav } from './tts';
4
4
  export { PiperTTSProvider, KokoroTTSProvider } from './tts-providers';
5
5
  // Cache utilities (Node.js only)
6
- export { getCacheDir, getModelsDir, getBinDir, getModelPath, getBinaryPath, defaultBinaries, } from '../../cache';
6
+ export { getCacheDir, getModelsDir, getBinDir, getModelPath, getBinaryPath, defaultBinaries, getCacheStatus, checkModelsInstalled, } from '../../cache';
7
7
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/backends/native/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEtE,iCAAiC;AACjC,OAAO,EACL,WAAW,EACX,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,aAAa,EACb,eAAe,GAChB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/backends/native/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAGnD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEtE,iCAAiC;AACjC,OAAO,EACL,WAAW,EACX,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,aAAa,EACb,eAAe,EACf,cAAc,EACd,oBAAoB,GACrB,MAAM,aAAa,CAAC"}
@@ -17,4 +17,25 @@ export declare class NativeTTS implements TTSPipeline {
17
17
  private parseWav;
18
18
  isReady(): boolean;
19
19
  }
20
+ export interface SynthesizeToWavOptions {
21
+ modelDir: string;
22
+ speakerId?: number;
23
+ provider?: TTSModelProvider;
24
+ /** Defaults to getBinaryPath('sherpa-onnx-offline-tts') */
25
+ binaryPath?: string;
26
+ speedScale?: number;
27
+ numThreads?: number;
28
+ }
29
+ /**
30
+ * One-shot TTS: synthesize text directly to a WAV Buffer.
31
+ * Handles NativeTTS setup, synthesis, and WAV encoding in a single call.
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * import { synthesizeToWav } from 'modular-voice-agent-sdk/native';
36
+ * const wav = await synthesizeToWav('Hello!', { modelDir: '/path/to/model', speakerId: 3 });
37
+ * fs.writeFileSync('hello.wav', wav);
38
+ * ```
39
+ */
40
+ export declare function synthesizeToWav(text: string, options: SynthesizeToWavOptions): Promise<Buffer>;
20
41
  //# sourceMappingURL=tts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tts.d.ts","sourceRoot":"","sources":["../../../src/backends/native/tts.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,gBAAgB,EAAe,aAAa,EAAE,MAAM,aAAa,CAAC;AAElH,OAAO,EAAE,gBAAgB,EAAoB,MAAM,iBAAiB,CAAC;AAErE,qBAAa,SAAU,YAAW,WAAW;IAC3C,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,EAAE,mBAAmB,EAAE,QAAQ,CAAC,EAAE,gBAAgB;IAS9D,UAAU,CAAC,WAAW,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAazD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAqCtD,OAAO,CAAC,QAAQ;IAsBhB,OAAO,IAAI,OAAO;CAGnB"}
1
+ {"version":3,"file":"tts.d.ts","sourceRoot":"","sources":["../../../src/backends/native/tts.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,gBAAgB,EAAe,aAAa,EAAE,MAAM,aAAa,CAAC;AAElH,OAAO,EAAE,gBAAgB,EAAoB,MAAM,iBAAiB,CAAC;AAIrE,qBAAa,SAAU,YAAW,WAAW;IAC3C,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,EAAE,mBAAmB,EAAE,QAAQ,CAAC,EAAE,gBAAgB;IAS9D,UAAU,CAAC,WAAW,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAazD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAqCtD,OAAO,CAAC,QAAQ;IAsBhB,OAAO,IAAI,OAAO;CAGnB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,MAAM,CAAC,CAuBjB"}
@@ -11,6 +11,8 @@ import { join } from 'path';
11
11
  import { tmpdir } from 'os';
12
12
  import { BufferedAudioPlayable } from '../../types';
13
13
  import { PiperTTSProvider } from './tts-providers';
14
+ import { getBinaryPath } from '../../cache';
15
+ import { encodeWav } from '../../server/encoding';
14
16
  export class NativeTTS {
15
17
  config;
16
18
  provider;
@@ -84,4 +86,32 @@ export class NativeTTS {
84
86
  return this.ready;
85
87
  }
86
88
  }
89
+ /**
90
+ * One-shot TTS: synthesize text directly to a WAV Buffer.
91
+ * Handles NativeTTS setup, synthesis, and WAV encoding in a single call.
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * import { synthesizeToWav } from 'modular-voice-agent-sdk/native';
96
+ * const wav = await synthesizeToWav('Hello!', { modelDir: '/path/to/model', speakerId: 3 });
97
+ * fs.writeFileSync('hello.wav', wav);
98
+ * ```
99
+ */
100
+ export async function synthesizeToWav(text, options) {
101
+ const binaryPath = options.binaryPath ?? getBinaryPath('sherpa-onnx-offline-tts');
102
+ const tts = new NativeTTS({
103
+ binaryPath,
104
+ modelDir: options.modelDir,
105
+ speakerId: options.speakerId,
106
+ speedScale: options.speedScale,
107
+ numThreads: options.numThreads,
108
+ }, options.provider);
109
+ await tts.initialize();
110
+ const playable = await tts.synthesize(text);
111
+ const raw = playable.getRawAudio();
112
+ if (!raw) {
113
+ throw new Error('TTS synthesis produced no audio');
114
+ }
115
+ return encodeWav(raw.audio, raw.sampleRate);
116
+ }
87
117
  //# sourceMappingURL=tts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tts.js","sourceRoot":"","sources":["../../../src/backends/native/tts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tts.js","sourceRoot":"","sources":["../../../src/backends/native/tts.ts"],"names":[],"mappings":"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"}
package/dist/cache.d.ts CHANGED
@@ -5,6 +5,8 @@
5
5
  * NOTE: This module uses Node.js APIs (os, path) and is SERVER-ONLY.
6
6
  * For browser model caching, use the ModelStore passed to backend constructors.
7
7
  */
8
+ import type { SetupConfig, ModelStatus } from './setup-types';
9
+ export type { ModelConfig, SetupConfig, ModelStatus } from './setup-types';
8
10
  /**
9
11
  * Get the cache directory for mvas assets.
10
12
  * Default: ~/.cache/mvas
@@ -37,4 +39,18 @@ export declare const defaultBinaries: {
37
39
  llamaCompletion: string;
38
40
  sherpaOnnxTts: string;
39
41
  };
42
+ /**
43
+ * Check the installation status of all models defined in a setup config.
44
+ * Returns per-model status indicating whether each is installed and its expected path.
45
+ *
46
+ * @param configOrPath - A SetupConfig object, or a path to a JSON config file
47
+ */
48
+ export declare function getCacheStatus(configOrPath: string | SetupConfig): ModelStatus[];
49
+ /**
50
+ * Check whether all models in a setup config are installed.
51
+ *
52
+ * @param configOrPath - A SetupConfig object, or a path to a JSON config file
53
+ * @returns true if every model is present on disk
54
+ */
55
+ export declare function checkModelsInstalled(configOrPath: string | SetupConfig): boolean;
40
56
  //# sourceMappingURL=cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH;;;;GAIG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;GAEG;AACH,eAAO,MAAM,eAAe;;;;CAI3B,CAAC"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAe,WAAW,EAAE,MAAM,eAAe,CAAC;AAE3E,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE3E;;;;GAIG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;GAEG;AACH,eAAO,MAAM,eAAe;;;;CAI3B,CAAC;AAaF;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,WAAW,GAAG,WAAW,EAAE,CAuBhF;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAEhF"}
package/dist/cache.js CHANGED
@@ -5,8 +5,9 @@
5
5
  * NOTE: This module uses Node.js APIs (os, path) and is SERVER-ONLY.
6
6
  * For browser model caching, use the ModelStore passed to backend constructors.
7
7
  */
8
+ import { existsSync, readFileSync } from 'fs';
8
9
  import { homedir } from 'os';
9
- import { join } from 'path';
10
+ import { basename, join } from 'path';
10
11
  /**
11
12
  * Get the cache directory for mvas assets.
12
13
  * Default: ~/.cache/mvas
@@ -49,4 +50,49 @@ export const defaultBinaries = {
49
50
  llamaCompletion: 'llama-completion',
50
51
  sherpaOnnxTts: 'sherpa-onnx-offline-tts',
51
52
  };
53
+ function resolveModelPath(config) {
54
+ const urlFilename = basename(new URL(config.url).pathname);
55
+ if (config.extract) {
56
+ const targetDir = config.directory || urlFilename.replace(/\.(tar\.bz2|tar\.gz|tbz2|tgz|zip)$/, '');
57
+ return join(getModelsDir(), targetDir);
58
+ }
59
+ return join(getModelsDir(), config.filename || urlFilename);
60
+ }
61
+ /**
62
+ * Check the installation status of all models defined in a setup config.
63
+ * Returns per-model status indicating whether each is installed and its expected path.
64
+ *
65
+ * @param configOrPath - A SetupConfig object, or a path to a JSON config file
66
+ */
67
+ export function getCacheStatus(configOrPath) {
68
+ let config;
69
+ if (typeof configOrPath === 'string') {
70
+ const content = readFileSync(configOrPath, 'utf-8');
71
+ config = JSON.parse(content);
72
+ }
73
+ else {
74
+ config = configOrPath;
75
+ }
76
+ if (!config.models || typeof config.models !== 'object') {
77
+ throw new Error('Config must have a "models" object');
78
+ }
79
+ return Object.entries(config.models).map(([name, modelConfig]) => {
80
+ const expectedPath = resolveModelPath(modelConfig);
81
+ return {
82
+ name,
83
+ installed: existsSync(expectedPath),
84
+ path: expectedPath,
85
+ expectedFilename: modelConfig.filename || basename(new URL(modelConfig.url).pathname),
86
+ };
87
+ });
88
+ }
89
+ /**
90
+ * Check whether all models in a setup config are installed.
91
+ *
92
+ * @param configOrPath - A SetupConfig object, or a path to a JSON config file
93
+ * @returns true if every model is present on disk
94
+ */
95
+ export function checkModelsInstalled(configOrPath) {
96
+ return getCacheStatus(configOrPath).every((m) => m.installed);
97
+ }
52
98
  //# sourceMappingURL=cache.js.map
package/dist/cache.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B;;;;GAIG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;AACrE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,QAAQ,CAAC,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,KAAK,CAAC,CAAC;AACpC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,OAAO,IAAI,CAAC,YAAY,EAAE,EAAE,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI,CAAC,SAAS,EAAE,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,UAAU,EAAE,aAAa;IACzB,eAAe,EAAE,kBAAkB;IACnC,aAAa,EAAE,yBAAyB;CACzC,CAAC"}
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts CHANGED
@@ -2,6 +2,8 @@
2
2
  /**
3
3
  * Modular Voice Agent SDK CLI
4
4
  *
5
+ * Thin wrapper around the programmatic setup API.
6
+ *
5
7
  * Usage:
6
8
  * npx mvas setup <config.json> - Download models from config file
7
9
  * npx mvas setup --binaries-only - Set up native binaries only
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG"}
package/dist/cli.js CHANGED
@@ -2,70 +2,60 @@
2
2
  /**
3
3
  * Modular Voice Agent SDK CLI
4
4
  *
5
+ * Thin wrapper around the programmatic setup API.
6
+ *
5
7
  * Usage:
6
8
  * npx mvas setup <config.json> - Download models from config file
7
9
  * npx mvas setup --binaries-only - Set up native binaries only
8
10
  * npx mvas help - Show help
9
11
  */
10
- import { spawn, execSync, spawnSync } from 'child_process';
11
- import { existsSync, readFileSync, mkdirSync, unlinkSync, readdirSync, statSync, createReadStream } from 'fs';
12
- import { createHash } from 'crypto';
13
- import { fileURLToPath } from 'url';
14
- import { dirname, join, basename } from 'path';
15
- import { homedir } from 'os';
16
- const __filename = fileURLToPath(import.meta.url);
17
- const __dirname = dirname(__filename);
18
- // ============ Cache Paths ============
19
- function getCacheDir() {
20
- return process.env.MVAS_CACHE || join(homedir(), '.cache', 'mvas');
21
- }
22
- function getModelsDir() {
23
- return join(getCacheDir(), 'models');
24
- }
25
- // ============ Hash Verification ============
26
- async function computeSha256(filePath) {
27
- return new Promise((resolve, reject) => {
28
- const hash = createHash('sha256');
29
- const stream = createReadStream(filePath);
30
- stream.on('data', (data) => hash.update(data));
31
- stream.on('end', () => resolve(hash.digest('hex')));
32
- stream.on('error', reject);
33
- });
34
- }
35
- async function verifyFile(filePath, config) {
36
- if (!existsSync(filePath)) {
37
- return { valid: false, reason: 'file does not exist' };
38
- }
39
- const stats = statSync(filePath);
40
- // Check size if provided
41
- if (config.size !== undefined) {
42
- if (stats.size !== config.size) {
43
- return {
44
- valid: false,
45
- reason: `size mismatch (got ${formatBytes(stats.size)}, expected ${formatBytes(config.size)})`
46
- };
47
- }
48
- }
49
- else {
50
- // No size specified - check if file is suspiciously small (< 1MB for models)
51
- if (stats.size < 1024 * 1024) {
52
- return { valid: false, reason: `file too small (${formatBytes(stats.size)})` };
53
- }
54
- }
55
- // Check hash if provided
56
- if (config.sha256) {
57
- console.log(' Verifying checksum...');
58
- const actualHash = await computeSha256(filePath);
59
- if (actualHash !== config.sha256.toLowerCase()) {
60
- return {
61
- valid: false,
62
- reason: `checksum mismatch`
63
- };
64
- }
12
+ import { readdirSync, statSync } from 'fs';
13
+ import { join } from 'path';
14
+ import { getCacheDir, getModelsDir } from './cache';
15
+ import { setup, setupBinaries } from './setup';
16
+ // ============ CLI Progress Reporter ============
17
+ function cliProgressReporter(event) {
18
+ switch (event.type) {
19
+ case 'start':
20
+ console.log('Modular Voice Agent SDK Setup');
21
+ console.log('====================');
22
+ console.log(`Models directory: ${event.modelsDir}`);
23
+ break;
24
+ case 'model_start':
25
+ console.log(`\n==> ${event.model?.toUpperCase()} model`);
26
+ break;
27
+ case 'model_skip':
28
+ console.log(` ✓ ${event.message}`);
29
+ break;
30
+ case 'model_downloading':
31
+ console.log(` ${event.message}`);
32
+ break;
33
+ case 'model_resuming':
34
+ console.log(` ${event.message}`);
35
+ break;
36
+ case 'model_extracting':
37
+ console.log(` ${event.message}`);
38
+ break;
39
+ case 'model_verifying':
40
+ console.log(` ${event.message}`);
41
+ break;
42
+ case 'model_verification_failed':
43
+ console.log(` ⚠️ ${event.message}`);
44
+ break;
45
+ case 'model_done':
46
+ console.log(` ✓ Done!`);
47
+ break;
48
+ case 'model_failed':
49
+ console.error(` ❌ ${event.message}`);
50
+ break;
51
+ case 'complete':
52
+ console.log('\n============================================================');
53
+ console.log('Setup complete!');
54
+ console.log('============================================================');
55
+ break;
65
56
  }
66
- return { valid: true };
67
57
  }
68
- // ============ Download Helpers ============
58
+ // ============ Helpers ============
69
59
  function formatBytes(bytes) {
70
60
  if (bytes < 1024)
71
61
  return `${bytes} B`;
@@ -75,216 +65,12 @@ function formatBytes(bytes) {
75
65
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
76
66
  return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
77
67
  }
78
- /**
79
- * Download a file using curl with resume support.
80
- * curl -C - automatically resumes partial downloads.
81
- */
82
- function downloadWithCurl(url, destPath) {
83
- return new Promise((resolve, reject) => {
84
- // Check if partial file exists
85
- const isResume = existsSync(destPath);
86
- if (isResume) {
87
- const stats = statSync(destPath);
88
- console.log(` Resuming from ${formatBytes(stats.size)}...`);
89
- }
90
- // curl with:
91
- // -L: follow redirects
92
- // -C -: auto-resume from where it left off
93
- // --progress-bar: show progress
94
- // -f: fail on HTTP errors (4xx, 5xx)
95
- // -o: output file
96
- // --write-out: output HTTP code for debugging
97
- const child = spawn('curl', [
98
- '-L',
99
- '-C', '-',
100
- '--progress-bar',
101
- '-f', // Fail on HTTP errors
102
- '-o', destPath,
103
- '--write-out', '\\nHTTP_CODE:%{http_code}\\n',
104
- url
105
- ], {
106
- stdio: ['inherit', 'inherit', 'pipe'], // Capture stderr for error info
107
- });
108
- let stderrData = '';
109
- child.stderr?.on('data', (data) => {
110
- stderrData += data.toString();
111
- });
112
- child.on('close', (code) => {
113
- if (code === 0) {
114
- resolve();
115
- }
116
- else if (code === 33) {
117
- // curl exit 33 = range request not supported, but file may be complete
118
- resolve();
119
- }
120
- else if (code === 22) {
121
- // curl exit 22 = HTTP error (when -f is used)
122
- // Try to extract HTTP code from stderr
123
- const httpMatch = stderrData.match(/HTTP_CODE:(\d+)/);
124
- const httpCode = httpMatch ? httpMatch[1] : 'unknown';
125
- reject(new Error(`HTTP error ${httpCode} - URL may be invalid or not found`));
126
- }
127
- else {
128
- reject(new Error(`curl exited with code ${code}`));
129
- }
130
- });
131
- child.on('error', (err) => {
132
- reject(new Error(`Failed to run curl: ${err.message}. Make sure curl is installed.`));
133
- });
134
- });
135
- }
136
- function extractArchive(archivePath, destDir) {
137
- const ext = archivePath.toLowerCase();
138
- if (ext.endsWith('.tar.bz2') || ext.endsWith('.tbz2')) {
139
- execSync(`tar -xjf "${archivePath}" -C "${destDir}"`, { stdio: 'inherit' });
140
- }
141
- else if (ext.endsWith('.tar.gz') || ext.endsWith('.tgz')) {
142
- execSync(`tar -xzf "${archivePath}" -C "${destDir}"`, { stdio: 'inherit' });
143
- }
144
- else if (ext.endsWith('.zip')) {
145
- execSync(`unzip -o "${archivePath}" -d "${destDir}"`, { stdio: 'inherit' });
146
- }
147
- else {
148
- throw new Error(`Unknown archive format: ${archivePath}`);
149
- }
150
- }
151
- // ============ Model Download ============
152
- async function downloadModel(type, config, modelsDir) {
153
- console.log(`\n==> ${type.toUpperCase()} model`);
154
- const url = config.url;
155
- const urlFilename = basename(new URL(url).pathname);
156
- if (config.extract) {
157
- // Archive - download, extract, cleanup
158
- const archivePath = join(modelsDir, urlFilename);
159
- const targetDir = config.directory || urlFilename.replace(/\.(tar\.bz2|tar\.gz|tbz2|tgz|zip)$/, '');
160
- const finalPath = join(modelsDir, targetDir);
161
- if (existsSync(finalPath)) {
162
- console.log(` ✓ Already exists: ${targetDir}`);
163
- return;
164
- }
165
- console.log(` Downloading: ${url}`);
166
- console.log(` Extracting to: ${targetDir}`);
167
- await downloadWithCurl(url, archivePath);
168
- // Verify archive if hash provided
169
- if (config.sha256 || config.size) {
170
- const result = await verifyFile(archivePath, config);
171
- if (!result.valid) {
172
- console.log(` ⚠️ Verification failed: ${result.reason}`);
173
- console.log(` Deleting partial file and retrying...`);
174
- unlinkSync(archivePath);
175
- await downloadWithCurl(url, archivePath);
176
- }
177
- }
178
- extractArchive(archivePath, modelsDir);
179
- // Cleanup archive
180
- try {
181
- unlinkSync(archivePath);
182
- }
183
- catch { /* ignore */ }
184
- console.log(` ✓ Done!`);
185
- }
186
- else {
187
- // Single file
188
- const filename = config.filename || urlFilename;
189
- const destPath = join(modelsDir, filename);
190
- // Check if file exists and is valid
191
- if (existsSync(destPath)) {
192
- const result = await verifyFile(destPath, config);
193
- if (result.valid) {
194
- console.log(` ✓ Already exists: ${filename}`);
195
- return;
196
- }
197
- console.log(` Existing file invalid: ${result.reason}`);
198
- console.log(` Re-downloading...`);
199
- }
200
- console.log(` URL: ${url}`);
201
- console.log(` Saving as: ${filename}`);
202
- if (config.size) {
203
- console.log(` Expected size: ${formatBytes(config.size)}`);
204
- }
205
- await downloadWithCurl(url, destPath);
206
- // Verify after download
207
- if (config.sha256 || config.size) {
208
- const result = await verifyFile(destPath, config);
209
- if (!result.valid) {
210
- console.log(` ⚠️ Verification failed: ${result.reason}`);
211
- console.log(` You may need to delete the file and re-run setup.`);
212
- return;
213
- }
214
- if (config.sha256) {
215
- console.log(` ✓ Checksum verified`);
216
- }
217
- }
218
- console.log(` ✓ Done!`);
219
- }
220
- }
68
+ // ============ Commands ============
221
69
  async function setupFromConfig(configPath) {
222
- if (!existsSync(configPath)) {
223
- console.error(`Error: Config file not found: ${configPath}`);
224
- process.exit(1);
225
- }
226
- let config;
227
- try {
228
- const content = readFileSync(configPath, 'utf-8');
229
- config = JSON.parse(content);
230
- }
231
- catch (err) {
232
- console.error(`Error: Invalid JSON in config file: ${configPath}`);
233
- console.error(err instanceof Error ? err.message : err);
234
- process.exit(1);
235
- }
236
- if (!config.models || typeof config.models !== 'object') {
237
- console.error('Error: Config must have a "models" object');
238
- process.exit(1);
239
- }
240
- // Check curl is available
241
- const curlCheck = spawnSync('curl', ['--version']);
242
- if (curlCheck.error) {
243
- console.error('Error: curl is required but not found. Please install curl.');
244
- process.exit(1);
245
- }
246
- const modelsDir = getModelsDir();
247
- mkdirSync(modelsDir, { recursive: true });
248
- console.log('Modular Voice Agent SDK Setup');
249
- console.log('====================');
250
70
  console.log(`Config: ${configPath}`);
251
- console.log(`Models directory: ${modelsDir}`);
252
- // Iterate over ALL model keys in config (not just stt/llm/tts)
253
- const modelTypes = Object.keys(config.models);
254
- if (modelTypes.length === 0) {
255
- console.error('Error: No models defined in config');
256
- process.exit(1);
257
- }
258
- let downloadedCount = 0;
259
- let failedCount = 0;
260
- const failures = [];
261
- for (const type of modelTypes) {
262
- const modelConfig = config.models[type];
263
- if (modelConfig) {
264
- try {
265
- await downloadModel(type, modelConfig, modelsDir);
266
- downloadedCount++;
267
- }
268
- catch (err) {
269
- failedCount++;
270
- const errorMsg = err instanceof Error ? err.message : String(err);
271
- failures.push(`${type}: ${errorMsg}`);
272
- console.error(` ❌ Failed: ${errorMsg}`);
273
- }
274
- }
275
- }
276
- // Report failures
277
- if (failedCount > 0) {
278
- console.error(`\n⚠️ ${failedCount} download(s) failed:`);
279
- for (const failure of failures) {
280
- console.error(` - ${failure}`);
281
- }
282
- }
283
- console.log('\n============================================================');
284
- console.log('Setup complete!');
285
- console.log('============================================================');
71
+ const result = await setup(configPath, { onProgress: cliProgressReporter });
72
+ const modelsDir = getModelsDir();
286
73
  console.log(`\nModels location: ${modelsDir}`);
287
- // List what's there with sizes
288
74
  const files = readdirSync(modelsDir);
289
75
  if (files.length > 0) {
290
76
  console.log('\nDownloaded models:');
@@ -295,44 +81,28 @@ async function setupFromConfig(configPath) {
295
81
  console.log(` - ${file} ${size}`);
296
82
  }
297
83
  }
84
+ if (result.failed > 0) {
85
+ console.error(`\n⚠️ ${result.failed} download(s) failed:`);
86
+ for (const m of result.models) {
87
+ if (!m.success) {
88
+ console.error(` - ${m.name}: ${m.error}`);
89
+ }
90
+ }
91
+ }
298
92
  console.log('\n💡 To set up native binaries (whisper-cli, llama-completion, llama-mtmd-cli, sherpa-onnx):');
299
93
  console.log(' npx mvas setup --binaries-only');
300
94
  }
301
- // ============ Binaries Setup ============
302
- async function setupBinaries() {
303
- // Find and run the setup script for binaries only
304
- const scriptPath = join(__dirname, '..', 'scripts', 'setup-binaries.sh');
305
- // Check if the binaries-only script exists, otherwise use original script with a message
306
- const originalScript = join(__dirname, '..', 'scripts', 'setup.sh');
307
- const targetScript = existsSync(scriptPath) ? scriptPath : originalScript;
308
- if (!existsSync(targetScript)) {
309
- console.error('Error: Setup script not found');
310
- process.exit(1);
311
- }
95
+ async function runSetupBinaries() {
312
96
  console.log('Setting up native binaries...');
313
97
  console.log('This will configure: whisper-cli, llama-completion, llama-mtmd-cli, sherpa-onnx');
314
98
  console.log('');
315
- const child = spawn('bash', [targetScript, '--binaries-only'], {
316
- stdio: 'inherit',
317
- });
318
- child.on('error', (err) => {
319
- if (err.message.includes('ENOENT')) {
320
- console.error('Error: bash not found. Please run the setup script manually:');
321
- console.error(` bash ${targetScript}`);
322
- }
323
- else {
324
- console.error('Error running setup:', err.message);
325
- }
99
+ try {
100
+ await setupBinaries();
101
+ }
102
+ catch (err) {
103
+ console.error(err instanceof Error ? err.message : String(err));
326
104
  process.exit(1);
327
- });
328
- return new Promise((resolve) => {
329
- child.on('close', (code) => {
330
- if (code !== 0) {
331
- process.exit(code ?? 1);
332
- }
333
- resolve();
334
- });
335
- });
105
+ }
336
106
  }
337
107
  // ============ Help ============
338
108
  function printHelp() {
@@ -406,7 +176,7 @@ async function main() {
406
176
  process.exit(1);
407
177
  }
408
178
  if (arg === '--binaries-only' || arg === '--binaries') {
409
- await setupBinaries();
179
+ await runSetupBinaries();
410
180
  }
411
181
  else {
412
182
  await setupFromConfig(arg);