#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ModelArch {
Qwen2,
Llama,
Gemma2,
}
#[derive(Debug, Clone, Copy)]
pub struct MiniModel {
pub name: &'static str,
pub params: &'static str,
pub quant: &'static str,
pub approx_ram_gb: f32,
pub hf_repo: &'static str,
pub gguf_file: &'static str,
pub arch: ModelArch,
pub note: &'static str,
}
pub const PALETTE: &[MiniModel] = &[
MiniModel {
name: "qwen2.5-0.5b",
params: "0.5B",
quant: "Q4_K_M",
approx_ram_gb: 0.5,
hf_repo: "Qwen/Qwen2.5-0.5B-Instruct-GGUF",
gguf_file: "qwen2.5-0.5b-instruct-q4_k_m.gguf",
arch: ModelArch::Qwen2,
note: "tiniest; fast summarizer/classifier, lowest RAM",
},
MiniModel {
name: "llama-3.2-1b",
params: "1B",
quant: "Q4_K_M",
approx_ram_gb: 0.8,
hf_repo: "bartowski/Llama-3.2-1B-Instruct-GGUF",
gguf_file: "Llama-3.2-1B-Instruct-Q4_K_M.gguf",
arch: ModelArch::Llama,
note: "strong 1B; good summaries with tiny footprint",
},
MiniModel {
name: "smollm2-1.7b",
params: "1.7B",
quant: "Q4_K_M",
approx_ram_gb: 1.0,
hf_repo: "bartowski/SmolLM2-1.7B-Instruct-GGUF",
gguf_file: "SmolLM2-1.7B-Instruct-Q4_K_M.gguf",
arch: ModelArch::Llama,
note: "instruction-tuned small; concise summarizer",
},
MiniModel {
name: "qwen2.5-1.5b",
params: "1.5B",
quant: "Q4_K_M",
approx_ram_gb: 1.0,
hf_repo: "Qwen/Qwen2.5-1.5B-Instruct-GGUF",
gguf_file: "qwen2.5-1.5b-instruct-q4_k_m.gguf",
arch: ModelArch::Qwen2,
note: "balanced default summarizer pick on 16 GB",
},
MiniModel {
name: "gemma-2-2b",
params: "2B",
quant: "Q4_K_M",
approx_ram_gb: 1.7,
hf_repo: "bartowski/gemma-2-2b-it-GGUF",
gguf_file: "gemma-2-2b-it-Q4_K_M.gguf",
arch: ModelArch::Gemma2,
note: "fluent 2B; nicer prose, more RAM",
},
MiniModel {
name: "qwen2.5-3b",
params: "3B",
quant: "Q4_K_M",
approx_ram_gb: 2.0,
hf_repo: "Qwen/Qwen2.5-3B-Instruct-GGUF",
gguf_file: "qwen2.5-3b-instruct-q4_k_m.gguf",
arch: ModelArch::Qwen2,
note: "strongest small; upper bound for a 16 GB box",
},
MiniModel {
name: "llama-3.2-3b",
params: "3B",
quant: "Q4_K_M",
approx_ram_gb: 2.0,
hf_repo: "bartowski/Llama-3.2-3B-Instruct-GGUF",
gguf_file: "Llama-3.2-3B-Instruct-Q4_K_M.gguf",
arch: ModelArch::Llama,
note: "capable 3B; upper bound on a 16 GB box",
},
];
#[must_use]
pub fn palette() -> &'static [MiniModel] {
PALETTE
}
#[must_use]
pub fn find(name: &str) -> Option<&'static MiniModel> {
PALETTE.iter().find(|m| m.name == name)
}
#[must_use]
pub fn fitting(ram_budget_gb: f32) -> Vec<&'static MiniModel> {
PALETTE
.iter()
.filter(|m| m.approx_ram_gb <= ram_budget_gb)
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn palette_is_nonempty_and_well_formed() {
assert!(!PALETTE.is_empty());
for m in PALETTE {
assert!(!m.name.is_empty());
assert!(!m.hf_repo.is_empty() && m.gguf_file.ends_with(".gguf"));
assert!(
m.approx_ram_gb > 0.0 && m.approx_ram_gb <= 3.0,
"{} is too large for the mini palette: {} GB",
m.name,
m.approx_ram_gb
);
}
}
#[test]
fn palette_is_smallest_first_and_names_unique() {
let mut seen = std::collections::HashSet::new();
let mut last = 0.0f32;
for m in PALETTE {
assert!(seen.insert(m.name), "duplicate palette name: {}", m.name);
assert!(m.approx_ram_gb >= last, "palette must be smallest-first");
last = m.approx_ram_gb;
}
}
#[test]
fn find_resolves_by_alias() {
assert_eq!(find("qwen2.5-1.5b").unwrap().arch, ModelArch::Qwen2);
assert_eq!(find("llama-3.2-1b").unwrap().arch, ModelArch::Llama);
assert!(find("does-not-exist").is_none());
}
#[test]
fn fitting_respects_a_ram_budget() {
let small = fitting(1.0);
assert!(small.iter().all(|m| m.approx_ram_gb <= 1.0));
assert!(
small.len() < PALETTE.len(),
"a 1 GB budget should exclude the larger entries"
);
assert!(fitting(0.5).iter().any(|m| m.name == "qwen2.5-0.5b"));
}
}