Files
Lumotia/crates/core/src/model_registry.rs

248 lines
9.6 KiB
Rust

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<ModelFile>,
pub description: &'static str,
}
static ALL_MODELS: LazyLock<Vec<ModelEntry>> = 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
);
}
}
}
}