@gorlitzer-labs/seldon 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -2
- package/bin/seldon.js +31 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,8 +41,19 @@ seldon down # stop everything
|
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
`seldon up` only starts what's installed. demerzel serves the voice UI on
|
|
44
|
-
`http://localhost:8770
|
|
45
|
-
`
|
|
44
|
+
`http://localhost:8770`. Its model set (~25 GB) is a one-time download —
|
|
45
|
+
`seldon install demerzel` **offers to fetch it right there** ([y/N]), and `seldon up`
|
|
46
|
+
offers again if it's still missing. Nothing that big is ever pulled silently.
|
|
47
|
+
Logs live in `~/.seldon/run/`.
|
|
48
|
+
|
|
49
|
+
**Try a different LLM** (e.g. PrismML's Bonsai 2, ~5.9 GB, much smaller than the
|
|
50
|
+
default): set `DEMERZEL_LLM` to any MLX-compatible HF repo before install/up, and
|
|
51
|
+
both the fetch and the runtime follow it:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
DEMERZEL_LLM=mlx-community/<bonsai-2-repo> seldon install demerzel # fetch that model
|
|
55
|
+
DEMERZEL_LLM=mlx-community/<bonsai-2-repo> seldon up # run it
|
|
56
|
+
```
|
|
46
57
|
|
|
47
58
|
## Uninstall
|
|
48
59
|
|
package/bin/seldon.js
CHANGED
|
@@ -184,7 +184,7 @@ function installOne(m, dev) {
|
|
|
184
184
|
return ok;
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
-
function doInstall(ids, { dev } = {}) {
|
|
187
|
+
async function doInstall(ids, { dev } = {}) {
|
|
188
188
|
ids = withRequires(ids);
|
|
189
189
|
console.log(C.bold(`\nInstalling: `) + ids.join(", ") + (dev ? C.dim(" (dev: link from checkout)") : ""));
|
|
190
190
|
console.log(C.bold("\nPreflight:"));
|
|
@@ -194,6 +194,8 @@ function doInstall(ids, { dev } = {}) {
|
|
|
194
194
|
const good = results.filter(([, r]) => r).map(([i]) => i);
|
|
195
195
|
const bad = results.filter(([, r]) => !r).map(([i]) => i);
|
|
196
196
|
console.log("\n" + C.bold("Done. ") + C.green(good.join(", ") || "—") + (bad.length ? " " + C.red("failed: " + bad.join(", ")) : ""));
|
|
197
|
+
// demerzel's models are the heavy part — offer to pull them now, at install time.
|
|
198
|
+
if (good.includes("demerzel")) await ensureDemerzelModels({ ask: true });
|
|
197
199
|
}
|
|
198
200
|
|
|
199
201
|
// ---- uninstall --------------------------------------------------------------
|
|
@@ -314,7 +316,26 @@ function demerzelModelsReady() {
|
|
|
314
316
|
}
|
|
315
317
|
const demerzelInstalled = () => fs.existsSync(path.join(SELDON_HOME, "demerzel", ".venv", "bin", "python"));
|
|
316
318
|
|
|
317
|
-
|
|
319
|
+
// Fetch demerzel's model set (~25 GB) — offered, never silent. Respects the
|
|
320
|
+
// chosen LLM (DEMERZEL_LLM) so `seldon install demerzel` / `seldon up` pull the
|
|
321
|
+
// model you'll actually run. --models forces yes, --no-models forces skip.
|
|
322
|
+
async function ensureDemerzelModels({ ask = true } = {}) {
|
|
323
|
+
if (!demerzelInstalled() || !platformOk(byId.demerzel)) return false;
|
|
324
|
+
if (demerzelModelsReady()) return true;
|
|
325
|
+
const home = path.join(SELDON_HOME, "demerzel");
|
|
326
|
+
const force = process.argv.includes("--models");
|
|
327
|
+
const skip = process.argv.includes("--no-models");
|
|
328
|
+
let doit = force;
|
|
329
|
+
if (!doit && !skip) doit = process.stdin.isTTY
|
|
330
|
+
? await confirm(C.gold("\n Download Demerzel's voice models now (~25 GB, one time)? [y/N] "))
|
|
331
|
+
: false; // never pull 25 GB non-interactively without --models
|
|
332
|
+
if (!doit) { console.log(C.dim(" models not fetched — the voice stays off until they are (seldon up will offer again).")); return false; }
|
|
333
|
+
const llm = process.env.DEMERZEL_LLM;
|
|
334
|
+
console.log(C.dim(` fetching Demerzel models${llm ? ` (LLM ${llm})` : ""} — ~25 GB, resumable…`));
|
|
335
|
+
return run(path.join(home, ".venv/bin/python"), [path.join(home, "scripts/fetch-models.py")], { cwd: home, env: { ...process.env } });
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
async function up() {
|
|
318
339
|
console.log(C.gold("\n seldon — bringing the stack up\n"));
|
|
319
340
|
const go = []; // where-to-go lines
|
|
320
341
|
const later = []; // things that need one action first
|
|
@@ -324,10 +345,14 @@ function up() {
|
|
|
324
345
|
if (demerzelInstalled()) {
|
|
325
346
|
const home = path.join(SELDON_HOME, "demerzel");
|
|
326
347
|
if (!platformOk(dem)) later.push("Voice (demerzel) needs macOS on Apple silicon — skipped here.");
|
|
327
|
-
else if (!demerzelModelsReady()) later.push(`Voice (demerzel) needs its models once (~25 GB):\n ${path.join(home, ".venv/bin/python")} ${path.join(home, "scripts/fetch-models.py")}\n then re-run seldon up`);
|
|
328
348
|
else {
|
|
329
|
-
|
|
330
|
-
|
|
349
|
+
if (!demerzelModelsReady()) await ensureDemerzelModels({ ask: true }); // offer the fetch inline
|
|
350
|
+
if (demerzelModelsReady()) {
|
|
351
|
+
const r = startDaemon("demerzel", path.join(home, ".venv/bin/python"), ["-m", "demerzel.server"], { cwd: home, env: { ...process.env } });
|
|
352
|
+
go.push(`${C.bold("Voice")} ${C.cyan("http://localhost:8770")} ${C.dim(r.already ? "(already up)" : "(starting — models load, ~30s)")}`);
|
|
353
|
+
} else {
|
|
354
|
+
later.push("Voice (demerzel): models not fetched yet — run `seldon up` again when you're ready to pull them.");
|
|
355
|
+
}
|
|
331
356
|
}
|
|
332
357
|
}
|
|
333
358
|
|
|
@@ -484,5 +509,5 @@ const ids = tokens.filter((id) => byId[id]); // only the valid module
|
|
|
484
509
|
const picked = await tui();
|
|
485
510
|
if (!picked) { console.log(C.dim("nothing installed.")); return; }
|
|
486
511
|
if (!picked.length) { console.log(C.dim("nothing selected.")); return; }
|
|
487
|
-
doInstall(picked, { dev });
|
|
512
|
+
await doInstall(picked, { dev });
|
|
488
513
|
})();
|