From 4561810751af4088d9aa99492184aa0ae9f362d9 Mon Sep 17 00:00:00 2001 From: Jake Date: Tue, 21 Apr 2026 07:39:03 +0100 Subject: [PATCH] feat(whisper): add Distil-Whisper Small and Large v3 as first-class models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two new registry entries (crates/core/src/model_registry.rs): - whisper-distil-small-en — 336 MB, ~6× faster than whisper-small-en - whisper-distil-large-v3 — 1.55 GB, near large-v3 accuracy at medium size Both are whisper.cpp-compatible GGML binaries hosted on HF by the distil-whisper org; no runtime change, just wider model choice. English-only by design (matches upstream Distil-Whisper). The Settings model picker widens to six options — Tiny, Base, Small, Distil-S, Medium, Distil-L — ordered roughly by accuracy. Download/load commands now take the resolved model id (whisper-distil-*) instead of the lowercased label, so the frontend owns the label↔id mapping. Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/core/src/model_registry.rs | 34 +++++++++++++++++++++++++++++++ src-tauri/src/commands/models.rs | 6 ++++++ src/lib/pages/SettingsPage.svelte | 14 ++++++++----- src/lib/types/app.ts | 8 +++++++- 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/crates/core/src/model_registry.rs b/crates/core/src/model_registry.rs index ebb6a9c..41abba3 100644 --- a/crates/core/src/model_registry.rs +++ b/crates/core/src/model_registry.rs @@ -150,6 +150,23 @@ static ALL_MODELS: LazyLock> = LazyLock::new(|| { }], description: "Accuracy-first English transcription", }, + ModelEntry { + id: ModelId::new("whisper-distil-small-en"), + engine: Engine::Whisper, + display_name: "Distil-Whisper Small (English)", + disk_size: Megabytes(336), + ram_required: Megabytes(900), + speed_tier: SpeedTier::Fast, + accuracy_tier: AccuracyTier::Great, + languages: LanguageSupport::EnglishOnly, + files: vec![ModelFile { + filename: "ggml-distil-small.en.bin", + url: "https://huggingface.co/distil-whisper/distil-small.en/resolve/main/ggml-distil-small.en.bin", + size: Megabytes(336), + sha256: None, + }], + description: "Small accuracy, ~6\u{00d7} faster — distilled variant", + }, ModelEntry { id: ModelId::new("whisper-medium-en"), engine: Engine::Whisper, @@ -167,6 +184,23 @@ static ALL_MODELS: LazyLock> = LazyLock::new(|| { }], description: "Best Whisper accuracy — needs 4+ GB RAM", }, + ModelEntry { + id: ModelId::new("whisper-distil-large-v3"), + engine: Engine::Whisper, + display_name: "Distil-Whisper Large v3 (English)", + disk_size: Megabytes(1550), + ram_required: Megabytes(2800), + speed_tier: SpeedTier::Moderate, + accuracy_tier: AccuracyTier::Excellent, + languages: LanguageSupport::EnglishOnly, + files: vec![ModelFile { + filename: "ggml-distil-large-v3.bin", + url: "https://huggingface.co/distil-whisper/distil-large-v3-ggml/resolve/main/ggml-distil-large-v3.bin", + size: Megabytes(1550), + sha256: None, + }], + description: "Near large-v3 accuracy at ~6\u{00d7} the speed", + }, ] }); diff --git a/src-tauri/src/commands/models.rs b/src-tauri/src/commands/models.rs index 0e9d1c5..dc1e636 100644 --- a/src-tauri/src/commands/models.rs +++ b/src-tauri/src/commands/models.rs @@ -15,7 +15,11 @@ fn whisper_model_id(size: &str) -> ModelId { "tiny" => ModelId::new("whisper-tiny-en"), "base" => ModelId::new("whisper-base-en"), "small" => ModelId::new("whisper-small-en"), + "distil-small" | "distilsmall" => ModelId::new("whisper-distil-small-en"), "medium" => ModelId::new("whisper-medium-en"), + "distil-large" | "distil-large-v3" | "distillarge" => { + ModelId::new("whisper-distil-large-v3") + } other => ModelId::new(other), } } @@ -297,7 +301,9 @@ pub fn list_models() -> Result, String> { "whisper-tiny-en" => "Tiny".to_string(), "whisper-base-en" => "Base".to_string(), "whisper-small-en" => "Small".to_string(), + "whisper-distil-small-en" => "Distil-S".to_string(), "whisper-medium-en" => "Medium".to_string(), + "whisper-distil-large-v3" => "Distil-L".to_string(), other => other.to_string(), }) .collect()) diff --git a/src/lib/pages/SettingsPage.svelte b/src/lib/pages/SettingsPage.svelte index 7ffa4fb..b2c1bb9 100644 --- a/src/lib/pages/SettingsPage.svelte +++ b/src/lib/pages/SettingsPage.svelte @@ -337,7 +337,9 @@ Tiny: "whisper-tiny-en", Base: "whisper-base-en", Small: "whisper-small-en", + "Distil-S": "whisper-distil-small-en", Medium: "whisper-medium-en", + "Distil-L": "whisper-distil-large-v3", }; return map[size] || "whisper-base-en"; } @@ -614,7 +616,7 @@ } async function loadSelectedModel() { - const size = settings.modelSize.toLowerCase(); + const size = whisperModelId(settings.modelSize); engineStatus = "Loading..."; engineOk = false; try { @@ -650,7 +652,9 @@ Tiny: "~75MB · fastest, lower accuracy", Base: "~150MB · balanced for most use", Small: "~500MB · noticeably more accurate", - Medium: "~1.5GB · best quality, slower", + "Distil-S": "~336MB · small-level accuracy at ~6× the speed", + Medium: "~1.5GB · best Whisper accuracy, slower", + "Distil-L": "~1.55GB · near-large accuracy at ~6× the speed", }; async function downloadParakeet() { @@ -1004,7 +1008,7 @@ {#if settings.engine === "whisper"}

Whisper Model

- +

{modelDescriptions[settings.modelSize]}

@@ -1022,12 +1026,12 @@ class="text-[11px] text-text-tertiary hover:text-accent" onclick={loadSelectedModel} >Load model - {:else if downloadingModel === settings.modelSize.toLowerCase()} + {:else if downloadingModel === whisperModelId(settings.modelSize)} {downloadProgress}% downloading... {:else} {/if}
diff --git a/src/lib/types/app.ts b/src/lib/types/app.ts index ec1be21..80f591e 100644 --- a/src/lib/types/app.ts +++ b/src/lib/types/app.ts @@ -3,7 +3,13 @@ export type FontFamily = "lexend" | "atkinson" | "opendyslexic"; export type ReduceMotion = "system" | "on" | "off"; export type RecordingEngine = "whisper" | "parakeet"; export type FormatMode = "Raw" | "Clean" | "Smart"; -export type WhisperModelSize = "Tiny" | "Base" | "Small" | "Medium"; +export type WhisperModelSize = + | "Tiny" + | "Base" + | "Small" + | "Distil-S" + | "Medium" + | "Distil-L"; export type AiTier = "off" | "cleanup" | "tasks"; export type LlmModelIdStr = "qwen3_1_7b" | "qwen3_4b_instruct_2507" | "qwen3_14b"; export type TaskBucket = "inbox" | "today" | "soon" | "later";