6.3 KiB
Unified Binary + Startup Dialog Plan
Summary
Merge the CLI and GUI into a single voice_linux binary that always opens the GTK3 window. On launch, a startup dialog appears letting the user choose CPU vs GPU and select which whisper model to use. All available ggml models are downloaded to ./models/ so the user can test them.
Current State
| Item | Status |
|---|---|
Two binaries: voice_linux (CLI) and voice_linux_gui (GTK3) |
Active |
| GPU passthrough + NVIDIA driver + CUDA toolkit | Working |
whisper.cpp built with GGML_CUDA=ON |
Working |
--gpu / --cpu flags parsed in both binaries |
Working |
Model path hardcoded in config.ini as model_path= |
Working |
transcribe_init() called once at startup before GTK loop |
Working |
Architecture Changes
flowchart TD
A[./voice_linux launched] --> B[Load config.ini]
B --> C[audio_init]
C --> D{Show Startup Dialog}
D --> |User picks CPU/GPU + model| E[transcribe_init with selections]
E --> F[typer_init]
F --> G[Main GTK window + event loop]
G --> H[On window close: cleanup]
Key change: transcribe_init() is deferred until after the startup dialog returns the user's selections. Audio init happens first so the mic meter can work, but model loading waits for the dialog.
Whisper Models to Download
All English-optimized ggml models from the whisper.cpp HuggingFace repo. The GTX 1080 Ti has 11 GB VRAM, so all models up to large-v3 fit comfortably.
| Model | File | Size | VRAM est. |
|---|---|---|---|
| tiny.en | ggml-tiny.en.bin |
~75 MB | ~200 MB |
| base.en | ggml-base.en.bin |
~142 MB | ~350 MB |
| small.en | ggml-small.en.bin |
~466 MB | ~1 GB |
| medium.en | ggml-medium.en.bin |
~1.5 GB | ~3 GB |
| large-v3-turbo | ggml-large-v3-turbo.bin |
~1.6 GB | ~3.5 GB |
| large-v3 | ggml-large-v3.bin |
~3.1 GB | ~6 GB |
Base URL: https://huggingface.co/ggerganov/whisper.cpp/resolve/main/
Detailed Steps
Step 1: Download all whisper models
Create a scripts/download_models.sh that downloads each model to ./models/ if not already present. Also callable from build.sh.
Step 2: Add startup dialog to gui_main.c
Insert a modal GtkDialog that runs before transcribe_init():
- GPU toggle:
GtkComboBoxTextwith entriesCPUandGPU. Default toGPUif CUDA device is detected at runtime, otherwiseCPU. - Model picker:
GtkComboBoxTextpopulated by scanning./models/ggml-*.binfiles. Display friendly names derived from filenames. Pre-select the model fromconfig.ini. - OK button: closes dialog, returns selections to
main().
The dialog is a transient child of a hidden parent window so it appears centered on screen.
GPU detection at dialog time: check if nvidia-smi exits 0, or check if the whisper.cpp CUDA backend reports a device. Simplest approach: try access /dev/nvidia0 — if it exists, default to GPU.
Step 3: Defer transcribe_init
Current flow in gui_main.c main():
config_load -> use_gpu from argv -> audio_init -> transcribe_init -> typer_init -> gtk loop
New flow:
config_load -> audio_init -> show_startup_dialog -> transcribe_init(dialog selections) -> typer_init -> gtk loop
The startup dialog returns:
int use_gpu— 0 or 1char model_path[512]— full path to selected model file
These override whatever was in config.ini / argv.
Step 4: Remove CLI binary from default build
- Keep
src/main.cin the repo for reference or future headless use, but do not build it by default. - In
build.sh: remove the separate CLI gcc invocation. The GUI gcc line outputs./voice_linuxinstead of./voice_linux_gui. - In
Makefile: changeTARGETto build fromgui_main.csources. Removevoice_linux_guitarget. Optionally add aclitarget for headless builds. - The
BUILD_GUIenv var is no longer needed; remove it.
Step 5: Add use_gpu to config.ini and config.c
Add a use_gpu=1 line to config.ini. Parse it in config_load_file(). This becomes the default for the startup dialog, overridable by the dialog selection. The --gpu / --cpu CLI flags still work as overrides.
Add int use_gpu; to voice_config_t.
Step 6: Update README.md
Simplify run instructions to just ./voice_linux. Remove voice_linux_gui references. Document the startup dialog behavior.
Step 7: Build and test
bash ./build.sh
./voice_linux
Verify:
- Startup dialog appears with CPU/GPU toggle and model list
- Selecting GPU + medium.en loads correctly with CUDA backend
- Main window works as before after dialog closes
Files Modified
| File | Change |
|---|---|
src/gui_main.c |
Add startup dialog function; defer transcribe_init; update main() flow |
src/config.h |
Add use_gpu field to voice_config_t |
src/config.c |
Parse use_gpu from config file |
config.ini |
Add use_gpu=1 |
build.sh |
Single binary output ./voice_linux; remove BUILD_GUI toggle; remove CLI build |
Makefile |
Single target ./voice_linux from gui sources |
README.md |
Update run instructions |
scripts/download_models.sh |
New script to download all models |
Files NOT Modified
| File | Reason |
|---|---|
src/main.c |
Kept for optional headless builds; not built by default |
src/transcribe.c |
API unchanged — transcribe_init / transcribe_cleanup already support the needed flow |
src/transcribe.h |
No changes needed |
src/audio.c / src/audio.h |
No changes needed |
src/hotkey.c / src/hotkey.h |
Only used by CLI; not linked into GUI binary |
Risk Notes
- The startup dialog adds a brief pause before the main window. Model loading (especially large-v3 at 3 GB) takes several seconds — a progress indicator or status label in the main window info area will show loading state.
- If no models are found in
./models/, the dialog should show an error message and offer to run the download script. - The
transcribe_initcall blocks the GTK main thread during model load. For large models this could be 5-10 seconds. An improvement would be async loading with a progress bar, but for v1 a simple "Loading model..." label update before the blocking call is sufficient.