feat(whisper): add Distil-Whisper Small and Large v3 as first-class models
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) <noreply@anthropic.com>
This commit is contained in:
@@ -150,6 +150,23 @@ static ALL_MODELS: LazyLock<Vec<ModelEntry>> = LazyLock::new(|| {
|
|||||||
}],
|
}],
|
||||||
description: "Accuracy-first English transcription",
|
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 {
|
ModelEntry {
|
||||||
id: ModelId::new("whisper-medium-en"),
|
id: ModelId::new("whisper-medium-en"),
|
||||||
engine: Engine::Whisper,
|
engine: Engine::Whisper,
|
||||||
@@ -167,6 +184,23 @@ static ALL_MODELS: LazyLock<Vec<ModelEntry>> = LazyLock::new(|| {
|
|||||||
}],
|
}],
|
||||||
description: "Best Whisper accuracy — needs 4+ GB RAM",
|
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",
|
||||||
|
},
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,11 @@ fn whisper_model_id(size: &str) -> ModelId {
|
|||||||
"tiny" => ModelId::new("whisper-tiny-en"),
|
"tiny" => ModelId::new("whisper-tiny-en"),
|
||||||
"base" => ModelId::new("whisper-base-en"),
|
"base" => ModelId::new("whisper-base-en"),
|
||||||
"small" => ModelId::new("whisper-small-en"),
|
"small" => ModelId::new("whisper-small-en"),
|
||||||
|
"distil-small" | "distilsmall" => ModelId::new("whisper-distil-small-en"),
|
||||||
"medium" => ModelId::new("whisper-medium-en"),
|
"medium" => ModelId::new("whisper-medium-en"),
|
||||||
|
"distil-large" | "distil-large-v3" | "distillarge" => {
|
||||||
|
ModelId::new("whisper-distil-large-v3")
|
||||||
|
}
|
||||||
other => ModelId::new(other),
|
other => ModelId::new(other),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,7 +301,9 @@ pub fn list_models() -> Result<Vec<String>, String> {
|
|||||||
"whisper-tiny-en" => "Tiny".to_string(),
|
"whisper-tiny-en" => "Tiny".to_string(),
|
||||||
"whisper-base-en" => "Base".to_string(),
|
"whisper-base-en" => "Base".to_string(),
|
||||||
"whisper-small-en" => "Small".to_string(),
|
"whisper-small-en" => "Small".to_string(),
|
||||||
|
"whisper-distil-small-en" => "Distil-S".to_string(),
|
||||||
"whisper-medium-en" => "Medium".to_string(),
|
"whisper-medium-en" => "Medium".to_string(),
|
||||||
|
"whisper-distil-large-v3" => "Distil-L".to_string(),
|
||||||
other => other.to_string(),
|
other => other.to_string(),
|
||||||
})
|
})
|
||||||
.collect())
|
.collect())
|
||||||
|
|||||||
@@ -337,7 +337,9 @@
|
|||||||
Tiny: "whisper-tiny-en",
|
Tiny: "whisper-tiny-en",
|
||||||
Base: "whisper-base-en",
|
Base: "whisper-base-en",
|
||||||
Small: "whisper-small-en",
|
Small: "whisper-small-en",
|
||||||
|
"Distil-S": "whisper-distil-small-en",
|
||||||
Medium: "whisper-medium-en",
|
Medium: "whisper-medium-en",
|
||||||
|
"Distil-L": "whisper-distil-large-v3",
|
||||||
};
|
};
|
||||||
return map[size] || "whisper-base-en";
|
return map[size] || "whisper-base-en";
|
||||||
}
|
}
|
||||||
@@ -614,7 +616,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadSelectedModel() {
|
async function loadSelectedModel() {
|
||||||
const size = settings.modelSize.toLowerCase();
|
const size = whisperModelId(settings.modelSize);
|
||||||
engineStatus = "Loading...";
|
engineStatus = "Loading...";
|
||||||
engineOk = false;
|
engineOk = false;
|
||||||
try {
|
try {
|
||||||
@@ -650,7 +652,9 @@
|
|||||||
Tiny: "~75MB · fastest, lower accuracy",
|
Tiny: "~75MB · fastest, lower accuracy",
|
||||||
Base: "~150MB · balanced for most use",
|
Base: "~150MB · balanced for most use",
|
||||||
Small: "~500MB · noticeably more accurate",
|
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() {
|
async function downloadParakeet() {
|
||||||
@@ -1004,7 +1008,7 @@
|
|||||||
{#if settings.engine === "whisper"}
|
{#if settings.engine === "whisper"}
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<p class="text-[10px] font-medium text-text-tertiary uppercase tracking-wider mb-2">Whisper Model</p>
|
<p class="text-[10px] font-medium text-text-tertiary uppercase tracking-wider mb-2">Whisper Model</p>
|
||||||
<SegmentedButton options={["Tiny", "Base", "Small", "Medium"]} bind:value={settings.modelSize} />
|
<SegmentedButton options={["Tiny", "Base", "Small", "Distil-S", "Medium", "Distil-L"]} bind:value={settings.modelSize} />
|
||||||
<p class="text-[11px] text-text-tertiary mt-2">{modelDescriptions[settings.modelSize]}</p>
|
<p class="text-[11px] text-text-tertiary mt-2">{modelDescriptions[settings.modelSize]}</p>
|
||||||
|
|
||||||
<div class="flex items-center gap-2 mt-3">
|
<div class="flex items-center gap-2 mt-3">
|
||||||
@@ -1022,12 +1026,12 @@
|
|||||||
class="text-[11px] text-text-tertiary hover:text-accent"
|
class="text-[11px] text-text-tertiary hover:text-accent"
|
||||||
onclick={loadSelectedModel}
|
onclick={loadSelectedModel}
|
||||||
>Load model</button>
|
>Load model</button>
|
||||||
{:else if downloadingModel === settings.modelSize.toLowerCase()}
|
{:else if downloadingModel === whisperModelId(settings.modelSize)}
|
||||||
<span class="text-[11px] text-warning">{downloadProgress}% downloading...</span>
|
<span class="text-[11px] text-warning">{downloadProgress}% downloading...</span>
|
||||||
{:else}
|
{:else}
|
||||||
<button
|
<button
|
||||||
class="text-[11px] text-accent hover:text-accent-hover"
|
class="text-[11px] text-accent hover:text-accent-hover"
|
||||||
onclick={() => downloadModel(settings.modelSize.toLowerCase())}
|
onclick={() => downloadModel(whisperModelId(settings.modelSize))}
|
||||||
>Download {settings.modelSize}</button>
|
>Download {settings.modelSize}</button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,13 @@ export type FontFamily = "lexend" | "atkinson" | "opendyslexic";
|
|||||||
export type ReduceMotion = "system" | "on" | "off";
|
export type ReduceMotion = "system" | "on" | "off";
|
||||||
export type RecordingEngine = "whisper" | "parakeet";
|
export type RecordingEngine = "whisper" | "parakeet";
|
||||||
export type FormatMode = "Raw" | "Clean" | "Smart";
|
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 AiTier = "off" | "cleanup" | "tasks";
|
||||||
export type LlmModelIdStr = "qwen3_1_7b" | "qwen3_4b_instruct_2507" | "qwen3_14b";
|
export type LlmModelIdStr = "qwen3_1_7b" | "qwen3_4b_instruct_2507" | "qwen3_14b";
|
||||||
export type TaskBucket = "inbox" | "today" | "soon" | "later";
|
export type TaskBucket = "inbox" | "today" | "soon" | "later";
|
||||||
|
|||||||
Reference in New Issue
Block a user