Motivation
Vernacula.CLI currently overloads `--model
` as both the Parakeet
bundle path
and the models root for sibling backends. That's a
historical artefact — Granite, Cohere, Qwen3, VibeVoice, and Whisper all
do `Path.Combine(modelDir, Config.SubDir)` and so silently treat
`--model` as the root. But Parakeet (`new ParakeetAsr(modelDir, ...)`)
and `VadSegmenter` load files flat from the directory you pass; they
need a
bundle, not a root.
Practical consequence: pointing `--model` at the desktop app's
`~/.local/share/Vernacula/models` works for Granite/Cohere/Qwen3/VibeVoice/Whisper
but breaks Parakeet and VAD because they look for files at the root
instead of in the per-backend subdirs.
The desktop app sidesteps this with `SettingsService.GetModelsDir()`
(root) plus per-backend `GetModelsDir()` (root + canonical subdir).
The CLI should match.
Scope
- Add `--models-dir ` as the canonical "where everything lives"
flag, mirroring the desktop app's models root.
- Make `--model` and `--models-dir` both optional. When neither is
passed, default to `DefaultModelsDir()` — which already exists in
Program.cs (line 957) and resolves to
`~/.local/share/Vernacula/models` on Linux. Today the CLI errors with
"--audio and --model are required"; that becomes "--audio is required"
and the models root falls back to the desktop app's location.
- Add subdir-fallback at flat-load sites. Same pattern Sortformer
already uses via `Config.GetSortformerModelPath`: when given a root
that contains a per-backend subdir, prefer the subdir; else fall back
to root for back-compat with users passing a bundle directly. Sites
to update:
- Parakeet construction (Program.cs around line 780):
`Directory.Exists(Path.Combine(modelDir, Config.ParakeetSubDir)) ? ... : modelDir`
- VadSegmenter (line 301): same treatment with `Config.VadSubDir`
("silero").
- DiariZen (line 312–313): already does this; verify it covers the
desktop app's layout.
- Update `PrintUsage()` to document the new flag, the default, and
the convention.
Out of scope
- Rewriting the per-backend `--cohere-model` / `--qwen3asr-model` /
`--vibevoice-model` / `--granite-model` overrides. Those stay as
per-backend escape hatches when someone wants to point at a non-canonical
bundle location.
- Changing `Vernacula.Base` constructor signatures (Parakeet, VadSegmenter)
to do their own subdir resolution. Keep the resolution in CLI; Base stays
bundle-path-agnostic. Sortformer's `Config.GetSortformerModelPath` is the
one already-existing exception; leaving it is fine.
Definition of done
- `dotnet run --project src/Vernacula.CLI -p:EP=Cuda -- --audio foo.wav --asr granite`
with no `--model` / `--models-dir` succeeds, picks up the desktop app's
`~/.local/share/Vernacula/models` automatically, and runs Granite.
- The same invocation with `--asr parakeet` (no `--model`) succeeds and
resolves Parakeet from `/parakeet/`.
- `--model ` (the existing pattern) still works
unchanged for users who have a non-canonical layout.
- `--help` documents the flag + default.
Context
Motivation
` as both the ParakeetVernacula.CLIcurrently overloads `--modelbundle path and the models root for sibling backends. That's a
historical artefact — Granite, Cohere, Qwen3, VibeVoice, and Whisper all
do `Path.Combine(modelDir, Config.SubDir)` and so silently treat
`--model` as the root. But Parakeet (`new ParakeetAsr(modelDir, ...)`)
and `VadSegmenter` load files flat from the directory you pass; they
need a bundle, not a root.
Practical consequence: pointing `--model` at the desktop app's
`~/.local/share/Vernacula/models` works for Granite/Cohere/Qwen3/VibeVoice/Whisper
but breaks Parakeet and VAD because they look for files at the root
instead of in the per-backend subdirs.
The desktop app sidesteps this with `SettingsService.GetModelsDir()`
(root) plus per-backend `GetModelsDir()` (root + canonical subdir).
The CLI should match.
Scope
flag, mirroring the desktop app's models root.
passed, default to `DefaultModelsDir()` — which already exists in
Program.cs (line 957) and resolves to
`~/.local/share/Vernacula/models` on Linux. Today the CLI errors with
"--audio and --model are required"; that becomes "--audio is required"
and the models root falls back to the desktop app's location.
already uses via `Config.GetSortformerModelPath`: when given a root
that contains a per-backend subdir, prefer the subdir; else fall back
to root for back-compat with users passing a bundle directly. Sites
to update:
`Directory.Exists(Path.Combine(modelDir, Config.ParakeetSubDir)) ? ... : modelDir`
("silero").
desktop app's layout.
the convention.
Out of scope
`--vibevoice-model` / `--granite-model` overrides. Those stay as
per-backend escape hatches when someone wants to point at a non-canonical
bundle location.
to do their own subdir resolution. Keep the resolution in CLI; Base stays
bundle-path-agnostic. Sortformer's `Config.GetSortformerModelPath` is the
one already-existing exception; leaving it is fine.
Definition of done
with no `--model` / `--models-dir` succeeds, picks up the desktop app's
`~/.local/share/Vernacula/models` automatically, and runs Granite.
resolves Parakeet from `/parakeet/`.
unchanged for users who have a non-canonical layout.
Context
`--granite-model ~/.local/share/Vernacula/models/granite_speech_4_1_2b_bf16`
on every command got old fast.
`src/Vernacula.CLI/Program.cs:957`.