Repository navigation
feat: Model Settings — whisper selection, download/delete, dedicated page - #21
Conversation
…el management
Add a dedicated Models tab to Settings where users can browse, download,
delete, and select ML models. Users on M1 Macs can now choose smaller
Whisper variants (small, medium) instead of the default large-v3-turbo.
- Add whisper_model config field (Rust + TS) with backward-compatible default
- Expand sidecar MODEL_REGISTRY with 3 whisper variants, categories, and
recommended flags
- Make transcribe() accept configurable model_name with hot-swap support
- Add DELETE /models/{name} endpoint using HF cache deletion API
- Add delete_model Tauri command and whisper model passthrough in pipeline
- Add Models tab UI with grouped display, download/delete/select controls
- Replace "+ Create Voice" with smart button detecting model setup state
- Update Create Voice wizard to only require mode-specific models
- Add tests across all layers (94 frontend, 127 Rust, 77 Python)
The sidecar returns these fields but Rust's ModelInfo was silently dropping them during deserialization, causing the frontend to render empty model lists (filter by category found no matches).
Move model management from a Settings tab to its own /models route with a sidebar nav item nested under Settings. This prepares for the upcoming expansion to 8+ TTS and STS model variants that would overwhelm a tab. - Create src/routes/(app)/models/+page.svelte with full model UI - Add "Models" as indented sidebar item under Settings - Remove Models tab and model UI code from settings page - Smart button in Voice section now navigates to /models
The _model_cache had a 30s TTL that kept stale False results after a model was downloaded, causing /models/status to still report "Not downloaded" until the cache expired.
The test was flaky due to parallel test threads sharing the same temp directory. Fixed by using thread-unique entry names, creating all entries before backdating mtime, setting both atime+mtime, and adding a verification step that the filesystem honored the backdate.
Critical: fix $derived.by reactivity (BUG-1), health endpoint hardcoded model (BUG-3), silent model name fallback (BUG-4). High: add memory cleanup on model hot-swap/delete (BUG-5/17), use shared HttpClient (BUG-6), remove duplicate check_models_downloaded (BUG-7), don't cache transient errors (BUG-8), log swallowed errors (BUG-9), split delete try/except (BUG-10). Medium: extract getRequiredModelNames utility (BUG-11), extract ModelCard component (BUG-12), async transcription (BUG-13), single scan_cache_dir call (BUG-14), selectWhisperModel error handling (BUG-15), fix stale fallback after delete (BUG-16), WHISPER_MODELS sync test (BUG-18). Low: add logger.error calls (BUG-19), SSE parsing tests (BUG-20), dir_size tests (BUG-21), DELETE endpoint tests (BUG-22). Pre-existing: stream SSE via bytes_stream instead of buffering (BUG-2).
📝 WalkthroughWalkthroughThis pull request introduces comprehensive model management features across the full stack: adds a model registry with legacy aliases in the Python sidecar, implements model selection for transcription and model deletion endpoints, updates the Rust backend to support whisper model configuration and deletion, and adds a new Models UI page with model card component for browsing, selecting, and managing downloaded TTS/transcription/voice-conversion models. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User<br/>(Frontend)
participant UI as Models Page
participant Tauri as Tauri Runtime
participant Rust as Rust Backend
participant Sidecar as Python Sidecar
participant HF as HuggingFace Cache
participant Memory as In-Memory<br/>Model State
User->>UI: Click delete model button
UI->>UI: Set confirmingDelete state
User->>UI: Confirm deletion
UI->>Tauri: delete_model(model_name)
activate Tauri
Tauri->>Rust: Call delete_model command
activate Rust
Rust->>Sidecar: DELETE /models/{model_name}
activate Sidecar
Sidecar->>Sidecar: Resolve legacy alias
Sidecar->>HF: scan_cache_dir() for repo_id
HF-->>Sidecar: Cache entries
Sidecar->>HF: Delete matching revisions
Sidecar->>Memory: Clear in-memory model globals<br/>(per category)
Sidecar->>Sidecar: Invalidate _model_cache[repo_id]
Sidecar-->>Rust: Return JSON success
deactivate Sidecar
Rust-->>Tauri: Return response
deactivate Rust
Tauri-->>UI: Success callback
deactivate Tauri
UI->>Tauri: getModelStatus() [refresh]
UI-->>User: Update model list, clear delete state
alt Deleted model was active whisper model
UI->>UI: Select fallback downloaded model
UI->>Tauri: Update config.whisper_model
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
/models) accessible from sidebar under SettingsChanges across all 3 layers
Python sidecar:
MODEL_REGISTRYwith categories,DELETE /models/{name}endpoint, configurabletranscribe()with model hot-swap + memory cleanup, exact repo_id matchingRust backend:
delete_modelcommand,whisper_modelconfig field, model name passthrough in pipeline,ModelInfowith category/recommended fieldsSvelte frontend: Models page with
ModelCardcomponent, sidebar nav item, sharedgetRequiredModelNames()utility,$derived.byfor reactive model status