use std::sync::LazyLock; use crate::types::{Megabytes, ModelId}; /// Which inference backend a model uses. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Engine { Whisper, Parakeet, Moonshine, } /// Qualitative speed classification. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SpeedTier { Instant, Fast, Moderate, Slow, } /// Qualitative accuracy classification. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum AccuracyTier { Excellent, Great, Good, } /// Language support scope. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum LanguageSupport { EnglishOnly, Multilingual(u16), } /// File required for a model download. #[derive(Debug, Clone)] pub struct ModelFile { pub filename: &'static str, pub url: &'static str, pub size: Megabytes, /// SHA256 hex digest for integrity verification. pub sha256: &'static str, } /// All metadata for a single downloadable model. /// This is pure data — no scoring logic lives here. #[derive(Debug, Clone)] pub struct ModelEntry { pub id: ModelId, pub engine: Engine, pub display_name: &'static str, pub disk_size: Megabytes, pub ram_required: Megabytes, pub speed_tier: SpeedTier, pub accuracy_tier: AccuracyTier, pub languages: LanguageSupport, pub files: Vec, pub description: &'static str, } static ALL_MODELS: LazyLock> = LazyLock::new(|| { vec![ ModelEntry { id: ModelId::new("parakeet-ctc-0.6b-int8"), engine: Engine::Parakeet, display_name: "Parakeet TDT 0.6B v2 (int8)", disk_size: Megabytes(650), ram_required: Megabytes(700), speed_tier: SpeedTier::Instant, accuracy_tier: AccuracyTier::Great, languages: LanguageSupport::EnglishOnly, files: vec![ ModelFile { filename: "encoder-model.int8.onnx", url: "https://huggingface.co/istupakov/parakeet-tdt-0.6b-v2-onnx/resolve/0bbb45a3365852604aef28b538a8f066f4ccaa85/encoder-model.int8.onnx", size: Megabytes(620), sha256: "3e0581fda6ab843888b51e56d7ee78b6d5bc3237ec113af1f732d1d5286aa155", }, ModelFile { filename: "decoder_joint-model.int8.onnx", url: "https://huggingface.co/istupakov/parakeet-tdt-0.6b-v2-onnx/resolve/0bbb45a3365852604aef28b538a8f066f4ccaa85/decoder_joint-model.int8.onnx", size: Megabytes(3), sha256: "a449f49acd68979d418651dd2dcb737cc0f1bf0225e009e29ee326354edbf7d3", }, ModelFile { filename: "nemo128.onnx", url: "https://huggingface.co/istupakov/parakeet-tdt-0.6b-v2-onnx/resolve/0bbb45a3365852604aef28b538a8f066f4ccaa85/nemo128.onnx", size: Megabytes(1), sha256: "a9fde1486ebfcc08f328d75ad4610c67835fea58c73ba57e3209a6f6cf019e9f", }, ModelFile { filename: "vocab.txt", url: "https://huggingface.co/istupakov/parakeet-tdt-0.6b-v2-onnx/resolve/0bbb45a3365852604aef28b538a8f066f4ccaa85/vocab.txt", size: Megabytes(1), sha256: "ec182b70dd42113aff6c5372c75cac58c952443eb22322f57bbd7f53977d497d", }, ], description: "Fastest local model — near-instant transcription", }, ModelEntry { id: ModelId::new("whisper-tiny-en"), engine: Engine::Whisper, display_name: "Whisper Tiny (English)", disk_size: Megabytes(75), ram_required: Megabytes(390), speed_tier: SpeedTier::Fast, accuracy_tier: AccuracyTier::Good, languages: LanguageSupport::EnglishOnly, files: vec![ModelFile { filename: "ggml-tiny.en.bin", url: "https://huggingface.co/ggerganov/whisper.cpp/resolve/5359861c739e955e79d9a303bcbc70fb988958b1/ggml-tiny.en.bin", size: Megabytes(75), sha256: "921e4cf8686fdd993dcd081a5da5b6c365bfde1162e72b08d75ac75289920b1f", }], description: "Bundled with app — works instantly", }, ModelEntry { id: ModelId::new("whisper-base-en"), engine: Engine::Whisper, display_name: "Whisper Base (English)", disk_size: Megabytes(142), ram_required: Megabytes(500), speed_tier: SpeedTier::Fast, accuracy_tier: AccuracyTier::Good, languages: LanguageSupport::EnglishOnly, files: vec![ModelFile { filename: "ggml-base.en.bin", url: "https://huggingface.co/ggerganov/whisper.cpp/resolve/5359861c739e955e79d9a303bcbc70fb988958b1/ggml-base.en.bin", size: Megabytes(142), sha256: "a03779c86df3323075f5e796cb2ce5029f00ec8869eee3fdfb897afe36c6d002", }], description: "Good balance of speed and accuracy", }, ModelEntry { id: ModelId::new("whisper-small-en"), engine: Engine::Whisper, display_name: "Whisper Small (English)", disk_size: Megabytes(466), ram_required: Megabytes(1024), speed_tier: SpeedTier::Moderate, accuracy_tier: AccuracyTier::Great, languages: LanguageSupport::EnglishOnly, files: vec![ModelFile { filename: "ggml-small.en.bin", url: "https://huggingface.co/ggerganov/whisper.cpp/resolve/5359861c739e955e79d9a303bcbc70fb988958b1/ggml-small.en.bin", size: Megabytes(466), sha256: "c6138d6d58ecc8322097e0f987c32f1be8bb0a18532a3f88f734d1bbf9c41e5d", }], 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/9e4a67ca4569c30be43a3fe7fba1621e504f0093/ggml-distil-small.en.bin", size: Megabytes(336), sha256: "7691eb11167ab7aaf6b3e05d8266f2fd9ad89c550e433f86ac266ebdee6c970a", }], description: "Small accuracy, ~6\u{00d7} faster — distilled variant", }, ModelEntry { id: ModelId::new("whisper-medium-en"), engine: Engine::Whisper, display_name: "Whisper Medium (English)", disk_size: Megabytes(1500), ram_required: Megabytes(2600), speed_tier: SpeedTier::Slow, accuracy_tier: AccuracyTier::Excellent, languages: LanguageSupport::EnglishOnly, files: vec![ModelFile { filename: "ggml-medium.en.bin", url: "https://huggingface.co/ggerganov/whisper.cpp/resolve/5359861c739e955e79d9a303bcbc70fb988958b1/ggml-medium.en.bin", size: Megabytes(1500), sha256: "cc37e93478338ec7700281a7ac30a10128929eb8f427dda2e865faa8f6da4356", }], 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/0d78dd96ed9fc152325f63b53788fec3b43de031/ggml-distil-large-v3.bin", size: Megabytes(1550), sha256: "2883a11b90fb10ed592d826edeaee7d2929bf1ab985109fe9e1e7b4d2b69a298", }], description: "Near large-v3 accuracy at ~6\u{00d7} the speed", }, ] }); /// Returns all known models. Pure data, no scoring. pub fn all_models() -> &'static [ModelEntry] { &ALL_MODELS } /// Find a model by its ID. pub fn find_model(id: &ModelId) -> Option<&'static ModelEntry> { ALL_MODELS.iter().find(|m| &m.id == id) } #[cfg(test)] mod tests { use super::all_models; #[test] fn every_model_file_has_sha256_and_pinned_url() { for model in all_models() { for file in &model.files { assert_eq!( file.sha256.len(), 64, "{} / {} must carry a SHA256 digest", model.id, file.filename ); assert!( file.sha256.chars().all(|c| c.is_ascii_hexdigit()), "{} / {} SHA256 must be hex", model.id, file.filename ); assert!( !file.url.contains("/resolve/main/"), "{} / {} must pin a Hugging Face revision", model.id, file.filename ); } } } }