From 36efcf232074e929e0544ce5cd18cba9e72382af Mon Sep 17 00:00:00 2001 From: Jake Date: Tue, 21 Apr 2026 07:41:22 +0100 Subject: [PATCH] feat(onboarding): parakeet-as-default pinned by test; FirstRunPage handles distil ids MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Parakeet-TDT scores 85 on any GPU-equipped English-capable system (Instant speed + Great accuracy + GPU boost + headroom) vs ~75 for the best distilled Whisper. A new test in recommendation.rs locks this in so future scoring tweaks don't silently regress it. FirstRunPage previously stored settings.modelSize by title-casing a lowercased alias — which worked for Tiny/Base/Small/Medium but produced "Whisper-distil-small-en" for the new distil ids. Swap to an id→label map and pass the raw model id through to download_model/load_model; the backend already accepts full ids via the whisper_model_id fallback. Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/core/src/recommendation.rs | 15 +++++++++++++++ src/lib/pages/FirstRunPage.svelte | 22 ++++++++++++++-------- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/crates/core/src/recommendation.rs b/crates/core/src/recommendation.rs index cce6dff..f4c3f49 100644 --- a/crates/core/src/recommendation.rs +++ b/crates/core/src/recommendation.rs @@ -177,4 +177,19 @@ mod tests { assert!(ranked.is_empty()); } + + #[test] + fn parakeet_is_top_recommendation_when_hardware_supports_it() { + // Any machine that fits Parakeet in RAM should see it ranked first — + // Parakeet-TDT is English-only but beats Whisper on English at lower + // latency, so it's Kon's default recommendation when eligible. + // (Users on non-English languages adjust manually — handled at the + // settings-UI level, not at the scoring level for now.) + let profile = profile_with_ram(Megabytes(16384)); + + let ranked = rank_recommendations(&profile); + let top = ranked.first().expect("at least one model ranks"); + + assert_eq!(top.entry.engine, Engine::Parakeet); + } } diff --git a/src/lib/pages/FirstRunPage.svelte b/src/lib/pages/FirstRunPage.svelte index eb470cf..ff07106 100644 --- a/src/lib/pages/FirstRunPage.svelte +++ b/src/lib/pages/FirstRunPage.svelte @@ -52,16 +52,22 @@ try { if (modelId.startsWith("whisper-")) { - const sizeMap = { - "whisper-tiny-en": "tiny", - "whisper-base-en": "base", - "whisper-small-en": "small", - "whisper-medium-en": "medium", + // backend's whisper_model_id accepts the full model id via its + // `other => ModelId::new(other)` fallback, so pass the id through + // unchanged rather than maintaining a fragile lowercased alias map. + await invoke("download_model", { size: modelId }); + await invoke("load_model", { size: modelId }); + + const idToLabel = { + "whisper-tiny-en": "Tiny", + "whisper-base-en": "Base", + "whisper-small-en": "Small", + "whisper-distil-small-en": "Distil-S", + "whisper-medium-en": "Medium", + "whisper-distil-large-v3": "Distil-L", }; - await invoke("download_model", { size: sizeMap[modelId] || modelId }); - await invoke("load_model", { size: sizeMap[modelId] || modelId }); settings.engine = "whisper"; - settings.modelSize = (sizeMap[modelId] || modelId).charAt(0).toUpperCase() + (sizeMap[modelId] || modelId).slice(1); + settings.modelSize = idToLabel[modelId] ?? "Base"; } else if (modelId.startsWith("parakeet-")) { await invoke("download_parakeet_model", { name: "ctc-int8" }); await invoke("load_parakeet_model", { name: "ctc-int8" });