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.
- package/dist/backends/native/index.d.ts +4 -2
- package/dist/backends/native/index.d.ts.map +1 -1
- package/dist/backends/native/index.js +2 -2
- package/dist/backends/native/index.js.map +1 -1
- package/dist/backends/native/tts.d.ts +21 -0
- package/dist/backends/native/tts.d.ts.map +1 -1
- package/dist/backends/native/tts.js +30 -0
- package/dist/backends/native/tts.js.map +1 -1
- package/dist/cache.d.ts +16 -0
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +47 -1
- package/dist/cache.js.map +1 -1
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +66 -296
- package/dist/cli.js.map +1 -1
- package/dist/client/voice-client.d.ts +13 -1
- package/dist/client/voice-client.d.ts.map +1 -1
- package/dist/client/voice-client.js +46 -2
- package/dist/client/voice-client.js.map +1 -1
- package/dist/server/encoding.d.ts +7 -0
- package/dist/server/encoding.d.ts.map +1 -1
- package/dist/server/encoding.js +56 -0
- package/dist/server/encoding.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/setup-types.d.ts +22 -0
- package/dist/setup-types.d.ts.map +1 -0
- package/dist/setup-types.js +6 -0
- package/dist/setup-types.js.map +1 -0
- package/dist/setup.d.ts +68 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +324 -0
- package/dist/setup.js.map +1 -0
- package/package.json +5 -1
|
@@ -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;
|
|
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;
|
|
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;
|
|
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":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAE5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAoB,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;
|
|
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
|
package/dist/cache.d.ts.map
CHANGED
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA
|
|
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 {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
// ============
|
|
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
|
-
|
|
252
|
-
|
|
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
|
-
|
|
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
|
-
|
|
316
|
-
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
|
|
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
|
|
179
|
+
await runSetupBinaries();
|
|
410
180
|
}
|
|
411
181
|
else {
|
|
412
182
|
await setupFromConfig(arg);
|