use crate::backends::gguf::types::MetaValue;
use std::path::Path;
#[derive(Debug, Clone, Default, PartialEq)]
pub struct SamplingConfig {
pub top_k: Option<i32>,
pub top_p: Option<f32>,
pub temperature: Option<f32>,
}
impl SamplingConfig {
pub fn is_empty(&self) -> bool {
self.top_k.is_none() && self.top_p.is_none() && self.temperature.is_none()
}
}
pub fn parse_generation_config(dir: &Path) -> Option<SamplingConfig> {
let path = dir.join("generation_config.json");
let s = std::fs::read_to_string(&path).ok()?;
let v: serde_json::Value = serde_json::from_str(&s).ok()?;
let mut cfg = SamplingConfig::default();
if let Some(n) = v.get("top_k").and_then(|x| x.as_i64()) {
cfg.top_k = Some(n as i32);
}
if let Some(n) = v.get("top_p").and_then(|x| x.as_f64()) {
cfg.top_p = Some(n as f32);
}
if let Some(n) = v.get("temperature").and_then(|x| x.as_f64()) {
cfg.temperature = Some(n as f32);
}
if cfg.is_empty() {
None
} else {
Some(cfg)
}
}
pub fn emit_general_prelude(
arch_name: &str,
name: String,
id_components: &ModelIdComponents,
size_label_override: Option<&str>,
model_card: Option<&ModelCard>,
sampling: Option<&SamplingConfig>,
) -> Vec<(String, MetaValue)> {
let mut kv: Vec<(String, MetaValue)> = Vec::with_capacity(32);
kv.push((
"general.architecture".into(),
MetaValue::String(arch_name.into()),
));
kv.push(("general.type".into(), MetaValue::String("model".into())));
if let Some(s) = sampling {
if let Some(v) = s.top_k {
kv.push(("general.sampling.top_k".into(), MetaValue::I32(v)));
}
if let Some(v) = s.top_p {
kv.push(("general.sampling.top_p".into(), MetaValue::F32(v)));
}
if let Some(v) = s.temperature {
kv.push(("general.sampling.temp".into(), MetaValue::F32(v)));
}
}
kv.push(("general.name".into(), MetaValue::String(name)));
if let Some(v) = &id_components.version {
kv.push(("general.version".into(), MetaValue::String(v.clone())));
}
if let Some(o) = &id_components.organization {
kv.push(("general.organization".into(), MetaValue::String(o.clone())));
}
if let Some(f) = &id_components.finetune {
kv.push(("general.finetune".into(), MetaValue::String(f.clone())));
}
if let Some(b) = &id_components.basename {
kv.push(("general.basename".into(), MetaValue::String(b.clone())));
}
let size_label_final: Option<String> = size_label_override
.map(String::from)
.or_else(|| id_components.size_label.clone());
if let Some(sl) = size_label_final {
kv.push(("general.size_label".into(), MetaValue::String(sl)));
}
if let Some(card) = model_card {
if let Some(license) = &card.license {
kv.push(("general.license".into(), MetaValue::String(license.clone())));
}
if let Some(license_name) = &card.license_name {
kv.push((
"general.license.name".into(),
MetaValue::String(license_name.clone()),
));
}
if let Some(license_link) = &card.license_link {
kv.push((
"general.license.link".into(),
MetaValue::String(license_link.clone()),
));
}
if !card.base_models.is_empty() {
kv.push((
"general.base_model.count".into(),
MetaValue::U32(card.base_models.len() as u32),
));
for (i, entry) in card.base_models.iter().enumerate() {
let (name, org, url) = split_base_model(&entry.raw);
if let Some(name) = name {
kv.push((
format!("general.base_model.{i}.name"),
MetaValue::String(name),
));
}
if let Some(org) = org {
kv.push((
format!("general.base_model.{i}.organization"),
MetaValue::String(org),
));
}
if let Some(url) = url {
kv.push((
format!("general.base_model.{i}.repo_url"),
MetaValue::String(url),
));
}
}
}
if !card.tags.is_empty() {
kv.push((
"general.tags".into(),
MetaValue::ArrayString(card.tags.clone()),
));
}
if !card.languages.is_empty() {
kv.push((
"general.languages".into(),
MetaValue::ArrayString(card.languages.clone()),
));
}
}
kv
}
pub fn emit_general_postlude(file_type: u32) -> Vec<(String, MetaValue)> {
vec![
("general.quantization_version".into(), MetaValue::U32(2)),
("general.file_type".into(), MetaValue::U32(file_type)),
]
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BaseModelEntry {
pub raw: String,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ModelCard {
pub license: Option<String>,
pub license_name: Option<String>,
pub license_link: Option<String>,
pub tags: Vec<String>,
pub languages: Vec<String>,
pub base_models: Vec<BaseModelEntry>,
}
impl ModelCard {
pub fn is_empty(&self) -> bool {
self.license.is_none()
&& self.license_name.is_none()
&& self.license_link.is_none()
&& self.tags.is_empty()
&& self.languages.is_empty()
&& self.base_models.is_empty()
}
}
pub fn parse_readme_frontmatter(dir: &Path) -> Option<ModelCard> {
let readme_path = dir.join("README.md");
let contents = std::fs::read_to_string(&readme_path).ok()?;
let frontmatter = extract_frontmatter_block(&contents)?;
Some(parse_yaml_frontmatter(frontmatter))
}
fn extract_frontmatter_block(contents: &str) -> Option<&str> {
let trimmed_start = contents.trim_start_matches('\u{FEFF}'); let after_first = trimmed_start.strip_prefix("---\n").or_else(|| {
trimmed_start.strip_prefix("---\r\n")
})?;
let close_idx = after_first
.find("\n---\n")
.or_else(|| after_first.find("\n---\r\n"))?;
Some(&after_first[..close_idx])
}
fn parse_yaml_frontmatter(text: &str) -> ModelCard {
let mut card = ModelCard::default();
let mut lines = text.lines().peekable();
let mut pipeline_tag: Option<String> = None;
while let Some(line) = lines.next() {
if line.is_empty() || line.trim_start().starts_with('#') {
continue;
}
if line.starts_with(char::is_whitespace) {
continue;
}
let Some(colon) = line.find(':') else {
continue;
};
let key = line[..colon].trim();
let after_colon = line[colon + 1..].trim();
match key {
"license" => {
if !after_colon.is_empty() {
card.license = Some(unquote_scalar(after_colon).to_string());
}
}
"license_name" => {
if !after_colon.is_empty() {
card.license_name = Some(unquote_scalar(after_colon).to_string());
}
}
"license_link" => {
if !after_colon.is_empty() {
card.license_link = Some(unquote_scalar(after_colon).to_string());
}
}
"tags" => {
card.tags = read_block_list(&mut lines);
}
"pipeline_tag" => {
if !after_colon.is_empty() {
pipeline_tag = Some(unquote_scalar(after_colon).to_string());
}
}
"language" => {
card.languages = read_block_list(&mut lines);
}
"base_model" => {
card.base_models = read_block_list(&mut lines)
.into_iter()
.map(|raw| BaseModelEntry { raw })
.collect();
}
_ => {
if after_colon.is_empty() {
let _ = read_block_list(&mut lines);
}
}
}
}
if let Some(pt) = pipeline_tag {
card.tags.push(pt);
}
card
}
fn read_block_list<'a, I>(lines: &mut std::iter::Peekable<I>) -> Vec<String>
where
I: Iterator<Item = &'a str>,
{
let mut out = Vec::new();
while let Some(&peek) = lines.peek() {
let trimmed = peek.trim_start();
if let Some(item) = trimmed.strip_prefix("- ") {
let _ = lines.next();
out.push(unquote_scalar(item.trim()).to_string());
continue;
}
if let Some(item) = trimmed.strip_prefix('-') {
if item.starts_with(' ') {
let _ = lines.next();
out.push(unquote_scalar(item.trim()).to_string());
continue;
}
}
break;
}
out
}
fn unquote_scalar(s: &str) -> &str {
let s = s.trim();
if s.len() >= 2 {
let bytes = s.as_bytes();
let first = bytes[0];
let last = bytes[bytes.len() - 1];
if (first == b'\'' && last == b'\'') || (first == b'"' && last == b'"') {
return &s[1..s.len() - 1];
}
}
s
}
pub fn split_base_model(raw: &str) -> (Option<String>, Option<String>, Option<String>) {
let Some((org, name)) = raw.split_once('/') else {
return (None, None, None);
};
let pretty_org = title_case_hyphenated(org);
let pretty_name = title_case_hyphenated(name);
let repo_url = format!("https://huggingface.co/{org}/{name}");
(Some(pretty_name), Some(pretty_org), Some(repo_url))
}
pub fn format_param_count_rounded(n: u64, min_digits: usize) -> String {
let n_abs = n as f64;
let (scaled, suffix) = if n_abs > 1e12 {
(n_abs * 1e-12, 'T')
} else if n_abs > 1e9 {
(n_abs * 1e-9, 'B')
} else if n_abs > 1e6 {
(n_abs * 1e-6, 'M')
} else {
(n_abs * 1e-3, 'K')
};
let rounded_int = scaled.round() as i64;
let int_str_len = rounded_int.abs().to_string().trim_start_matches('0').len();
let fix = min_digits.saturating_sub(int_str_len);
format!("{scaled:.*}{suffix}", fix)
}
pub fn compute_size_label(
tensors: impl IntoIterator<Item = (u64, bool)>,
expert_count: u32,
) -> String {
let mut shared_params: u64 = 0;
let mut expert_params: u64 = 0;
let mut total: u64 = 0;
for (size, is_expert) in tensors {
total += size;
if is_expert && expert_count > 0 {
expert_params += size / (expert_count as u64);
} else {
shared_params += size;
}
}
if expert_count > 0 {
let pretty = format_param_count_rounded(shared_params + expert_params, 2);
format!("{expert_count}x{pretty}")
} else {
format_param_count_rounded(total, 2)
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ModelIdComponents {
pub name: Option<String>,
pub organization: Option<String>,
pub basename: Option<String>,
pub finetune: Option<String>,
pub version: Option<String>,
pub size_label: Option<String>,
}
pub fn get_model_id_components(model_id: &str) -> ModelIdComponents {
let mut out = ModelIdComponents::default();
if model_id.contains(' ') {
out.name = Some(model_id.to_string());
return out;
}
let (org_component, full_name) = match model_id.split_once('/') {
Some((org, name)) if !org.starts_with('.') => (Some(org), name),
_ => (None, model_id),
};
if full_name.is_empty() {
return out;
}
let mut name_parts: Vec<String> = full_name
.split('-')
.filter(|s| !s.is_empty())
.map(str::to_string)
.collect();
let n = name_parts.len();
let mut tags: Vec<NameTagSet> = (0..n).map(|_| NameTagSet::default()).collect();
for (i, part) in name_parts.iter_mut().enumerate() {
if is_version_marker(part) {
tags[i].version = true;
} else if let Some(upper) = quant_type_uppercased(part) {
tags[i].kind = true;
*part = upper;
} else if i > 0 {
if let Some(normalized) = normalize_size_label(part) {
tags[i].size_label = true;
*part = normalized;
} else if matches!(
part.to_ascii_lowercase().as_str(),
"chat" | "instruct" | "vision" | "lora"
) {
tags[i].finetune = true;
}
}
}
let has_numeric_size_label = name_parts
.iter()
.zip(tags.iter())
.filter(|(_, t)| t.size_label)
.any(|(n, _)| n.chars().any(|c| c.is_ascii_digit()));
if has_numeric_size_label {
for (part, t) in name_parts.iter().zip(tags.iter_mut()) {
if t.size_label && part.chars().all(|c| c.is_alphabetic()) {
t.size_label = false;
}
}
}
let mut at_start = true;
for (part, t) in name_parts.iter().zip(tags.iter_mut()) {
let untagged = !t.has_any();
if at_start
&& ((untagged && part.chars().next().is_some_and(|c| c.is_alphabetic())) || t.version)
{
t.basename = true;
} else {
at_start = false;
if !t.has_any() {
t.finetune = true;
}
}
}
for t in tags.iter_mut().rev() {
if t.basename && t.count() > 1 {
t.basename = false;
} else {
break;
}
}
let basename = collect_joined(&name_parts, &tags, |t| t.basename);
let size_label = collect_joined_dedup(&name_parts, &tags, |t| t.size_label);
let finetune = collect_joined(&name_parts, &tags, |t| t.finetune);
let version = collect_joined(&name_parts, &tags, |t| t.version && !t.basename);
let too_ambiguous = size_label.is_none() && finetune.is_none() && version.is_none();
let final_basename = if too_ambiguous { None } else { basename };
out.name = Some(title_case_hyphenated(full_name));
out.organization = org_component.map(title_case_hyphenated);
out.basename = final_basename;
out.finetune = finetune;
out.version = version;
out.size_label = size_label;
out
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
struct NameTagSet {
basename: bool,
size_label: bool,
finetune: bool,
version: bool,
kind: bool,
}
impl NameTagSet {
fn has_any(&self) -> bool {
self.basename || self.size_label || self.finetune || self.version || self.kind
}
fn count(&self) -> usize {
(self.basename as usize)
+ (self.size_label as usize)
+ (self.finetune as usize)
+ (self.version as usize)
+ (self.kind as usize)
}
}
fn collect_joined<F>(parts: &[String], tags: &[NameTagSet], pred: F) -> Option<String>
where
F: Fn(&NameTagSet) -> bool,
{
let joined: String = parts
.iter()
.zip(tags.iter())
.filter(|(_, t)| pred(t))
.map(|(p, _)| p.as_str())
.collect::<Vec<_>>()
.join("-");
if joined.is_empty() {
None
} else {
Some(joined)
}
}
fn collect_joined_dedup<F>(parts: &[String], tags: &[NameTagSet], pred: F) -> Option<String>
where
F: Fn(&NameTagSet) -> bool,
{
let mut seen = std::collections::HashSet::new();
let mut out = Vec::new();
for (part, t) in parts.iter().zip(tags.iter()) {
if pred(t) && seen.insert(part.clone()) {
out.push(part.as_str());
}
}
if out.is_empty() {
None
} else {
Some(out.join("-"))
}
}
fn is_version_marker(part: &str) -> bool {
let lower = part.to_ascii_lowercase();
let rest = lower
.strip_prefix('v')
.or_else(|| lower.strip_prefix("iter"))
.unwrap_or(&lower);
if rest.is_empty() {
return false;
}
let mut chars = rest.chars().peekable();
if !chars.peek().is_some_and(|c| c.is_ascii_digit()) {
return false;
}
while let Some(&c) = chars.peek() {
if c.is_ascii_digit() {
chars.next();
} else {
break;
}
}
while let Some(&c) = chars.peek() {
if c != '.' {
return false;
}
chars.next();
if !chars.peek().is_some_and(|c| c.is_ascii_digit()) {
return false;
}
while let Some(&c) = chars.peek() {
if c.is_ascii_digit() {
chars.next();
} else {
break;
}
}
}
true
}
fn quant_type_uppercased(part: &str) -> Option<String> {
let lower = part.to_ascii_lowercase();
let bytes = lower.as_bytes();
if matches!(
lower.as_str(),
"fp16" | "fp32" | "bfp16" | "bfp32" | "f16" | "f32" | "bf16" | "bf32"
) {
return Some(part.to_ascii_uppercase());
}
let mut idx = 0;
if bytes.get(idx) == Some(&b'i') {
idx += 1;
}
if bytes.get(idx) != Some(&b'q') {
return None;
}
idx += 1;
if !bytes.get(idx).is_some_and(|b| b.is_ascii_digit()) {
return None;
}
idx += 1;
while idx < bytes.len() {
if bytes[idx] != b'_' {
return None;
}
idx += 1;
if idx >= bytes.len() || !(bytes[idx].is_ascii_alphanumeric()) {
return None;
}
while idx < bytes.len() && bytes[idx].is_ascii_alphanumeric() {
idx += 1;
}
}
Some(part.to_ascii_uppercase())
}
fn normalize_size_label(part: &str) -> Option<String> {
let lower = part.to_ascii_lowercase();
if matches!(
lower.as_str(),
"small" | "mini" | "medium" | "large" | "xl" | "xxl"
) {
return Some(part.to_string());
}
let bytes = lower.as_bytes();
let mut idx = 0;
if bytes.get(idx) == Some(&b'a') {
idx += 1;
} else {
let start = idx;
while idx < bytes.len() && bytes[idx].is_ascii_digit() {
idx += 1;
}
if idx > start && bytes.get(idx) == Some(&b'x') {
idx += 1;
} else {
idx = 0;
}
}
let core_start = idx;
while idx < bytes.len() && bytes[idx].is_ascii_digit() {
idx += 1;
}
if idx == core_start {
return None;
}
if let Some(&b) = bytes.get(idx) {
if b == b'.' || b == b'_' {
idx += 1;
let frac_start = idx;
while idx < bytes.len() && bytes[idx].is_ascii_digit() {
idx += 1;
}
if idx == frac_start {
return None;
}
}
}
let suffix_idx = idx;
let suffix_char = bytes.get(idx)?;
if !matches!(*suffix_char, b'k' | b'm' | b'b' | b't') {
return None;
}
idx += 1;
if let Some(b) = bytes.get(idx) {
if b.is_ascii_digit() {
idx += 1;
}
}
if idx != bytes.len() {
return None;
}
let mut out: Vec<u8> = part.bytes().collect();
for b in out.iter_mut() {
if *b == b'_' {
*b = b'.';
}
}
if let Some(b) = out.get_mut(suffix_idx) {
b.make_ascii_uppercase();
}
Some(String::from_utf8(out).expect("ASCII-only"))
}
fn title_case_hyphenated(s: &str) -> String {
s.split('-')
.filter(|p| !p.is_empty())
.map(|part| {
if should_title_case(part) {
python_str_title(part)
} else {
part.to_string()
}
})
.collect::<Vec<_>>()
.join(" ")
}
fn is_python_islower(s: &str) -> bool {
let mut has_cased = false;
for c in s.chars() {
if c.is_alphabetic() {
has_cased = true;
if !c.is_lowercase() {
return false;
}
}
}
has_cased
}
fn is_version_or_digit_start(s: &str) -> bool {
if let Some(rest) = s.strip_prefix('v') {
if !rest.is_empty() && rest.chars().next().is_some_and(|c| c.is_ascii_digit()) {
let mut chars = rest.chars().peekable();
while let Some(&c) = chars.peek() {
if c.is_ascii_digit() {
chars.next();
} else {
break;
}
}
let mut all_match = true;
while let Some(&c) = chars.peek() {
if c != '.' {
all_match = false;
break;
}
chars.next();
if !chars.peek().is_some_and(|c| c.is_ascii_digit()) {
all_match = false;
break;
}
while let Some(&c) = chars.peek() {
if c.is_ascii_digit() {
chars.next();
} else {
break;
}
}
}
if all_match && chars.peek().is_none() {
return true;
}
}
}
s.chars().next().is_some_and(|c| c.is_ascii_digit())
}
fn should_title_case(s: &str) -> bool {
is_python_islower(s) && !is_version_or_digit_start(s)
}
fn python_str_title(s: &str) -> String {
let mut out = String::with_capacity(s.len());
let mut prev_is_alpha = false;
for c in s.chars() {
if c.is_alphabetic() {
if !prev_is_alpha {
out.extend(c.to_uppercase());
} else {
out.extend(c.to_lowercase());
}
prev_is_alpha = true;
} else {
out.push(c);
prev_is_alpha = false;
}
}
out
}
#[allow(dead_code)]
fn is_version_part(part: &str) -> bool {
let lower = part.to_ascii_lowercase();
let rest = if let Some(r) = lower.strip_prefix('v') {
r
} else if let Some(r) = lower.strip_prefix("iter") {
r
} else {
return false;
};
if rest.is_empty() {
return false;
}
let mut chars = rest.chars().peekable();
if !chars.peek().is_some_and(|c| c.is_ascii_digit()) {
return false;
}
while let Some(&c) = chars.peek() {
if c.is_ascii_digit() {
chars.next();
} else {
break;
}
}
while let Some(&c) = chars.peek() {
if c != '.' {
return false;
}
chars.next();
if !chars.peek().is_some_and(|c| c.is_ascii_digit()) {
return false;
}
while let Some(&c) = chars.peek() {
if c.is_ascii_digit() {
chars.next();
} else {
break;
}
}
}
true
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn extract_frontmatter_block_handles_lf() {
let contents = "---\nfoo: bar\nbaz: qux\n---\nbody text\n";
assert_eq!(
extract_frontmatter_block(contents),
Some("foo: bar\nbaz: qux")
);
}
#[test]
fn extract_frontmatter_block_returns_none_without_sentinel() {
let contents = "# Just markdown\nno frontmatter\n";
assert_eq!(extract_frontmatter_block(contents), None);
}
#[test]
fn parse_license_scalar() {
let card = parse_yaml_frontmatter("license: apache-2.0\n");
assert_eq!(card.license.as_deref(), Some("apache-2.0"));
}
#[test]
fn parse_quoted_norwegian_language_code() {
let frontmatter = "language:\n- en\n- 'no'\n- fr\n";
let card = parse_yaml_frontmatter(frontmatter);
assert_eq!(card.languages, vec!["en", "no", "fr"]);
}
#[test]
fn parse_base_model_list() {
let frontmatter = "base_model:\n- nomic-ai/nomic-embed-text-v2-moe-unsupervised\n";
let card = parse_yaml_frontmatter(frontmatter);
assert_eq!(card.base_models.len(), 1);
assert_eq!(
card.base_models[0].raw,
"nomic-ai/nomic-embed-text-v2-moe-unsupervised"
);
}
#[test]
fn parse_full_nomic_v2_moe_frontmatter() {
let frontmatter = "\
base_model:
- nomic-ai/nomic-embed-text-v2-moe-unsupervised
library_name: sentence-transformers
pipeline_tag: sentence-similarity
tags:
- sentence-transformers
- sentence-similarity
- feature-extraction
license: apache-2.0
language:
- en
- es
- 'no'
";
let card = parse_yaml_frontmatter(frontmatter);
assert_eq!(card.license.as_deref(), Some("apache-2.0"));
assert_eq!(
card.tags,
vec![
"sentence-transformers",
"sentence-similarity",
"feature-extraction",
"sentence-similarity"
]
);
assert_eq!(card.languages, vec!["en", "es", "no"]);
assert_eq!(card.base_models.len(), 1);
assert_eq!(
card.base_models[0].raw,
"nomic-ai/nomic-embed-text-v2-moe-unsupervised"
);
}
#[test]
fn split_base_model_title_cases() {
let (name, org, url) = split_base_model("nomic-ai/nomic-embed-text-v2-moe-unsupervised");
assert_eq!(
name.as_deref(),
Some("Nomic Embed Text v2 Moe Unsupervised")
);
assert_eq!(org.as_deref(), Some("Nomic Ai"));
assert_eq!(
url.as_deref(),
Some("https://huggingface.co/nomic-ai/nomic-embed-text-v2-moe-unsupervised")
);
}
#[test]
fn split_base_model_without_slash_returns_none() {
let (name, org, url) = split_base_model("not-an-org-slash-name");
assert_eq!(name, None);
assert_eq!(org, None);
assert_eq!(url, None);
}
#[test]
fn empty_modelcard_is_empty() {
let card = ModelCard::default();
assert!(card.is_empty());
}
#[test]
fn unknown_top_level_keys_are_silently_ignored() {
let frontmatter = "license: apache-2.0\nmystery_key: foo\nbase_model:\n- a/b\n";
let card = parse_yaml_frontmatter(frontmatter);
assert_eq!(card.license.as_deref(), Some("apache-2.0"));
assert_eq!(card.base_models.len(), 1);
}
#[test]
fn get_model_id_components_nomic_v2_moe() {
let c = get_model_id_components("nomic-ai/nomic-xlm-2048");
assert_eq!(c.name.as_deref(), Some("Nomic Xlm 2048"));
assert_eq!(c.organization.as_deref(), Some("Nomic Ai"));
assert_eq!(c.basename.as_deref(), Some("nomic-xlm"));
assert_eq!(c.version.as_deref(), Some("2048"));
assert_eq!(c.finetune, None);
assert_eq!(c.size_label, None);
}
#[test]
fn get_model_id_components_llama_3_8b_instruct() {
let c = get_model_id_components("meta-llama/Meta-Llama-3-8B-Instruct");
assert_eq!(c.name.as_deref(), Some("Meta Llama 3 8B Instruct"));
assert_eq!(c.organization.as_deref(), Some("Meta Llama"));
assert_eq!(c.basename.as_deref(), Some("Meta-Llama-3"));
assert_eq!(c.version, None);
assert_eq!(c.size_label.as_deref(), Some("8B"));
assert_eq!(c.finetune.as_deref(), Some("Instruct"));
}
#[test]
fn get_model_id_components_trailing_version_strips_basename() {
let c = get_model_id_components("nomic-ai/nomic-xlm-v2");
assert_eq!(c.basename.as_deref(), Some("nomic-xlm"));
assert_eq!(c.version.as_deref(), Some("v2"));
}
#[test]
fn get_model_id_components_no_org_slash() {
let c = get_model_id_components("orphan-model-7B");
assert_eq!(c.organization, None);
assert_eq!(c.basename.as_deref(), Some("orphan-model"));
assert_eq!(c.size_label.as_deref(), Some("7B"));
}
#[test]
fn get_model_id_components_human_sentence() {
let c = get_model_id_components("Some Long Display Name");
assert_eq!(c.name.as_deref(), Some("Some Long Display Name"));
assert_eq!(c.organization, None);
assert_eq!(c.basename, None);
}
#[test]
fn get_model_id_components_too_ambiguous_drops_basename() {
let c = get_model_id_components("acme/widget");
assert_eq!(c.name.as_deref(), Some("Widget"));
assert_eq!(c.organization.as_deref(), Some("Acme"));
assert_eq!(c.basename, None); assert_eq!(c.size_label, None);
assert_eq!(c.finetune, None);
assert_eq!(c.version, None);
}
#[test]
fn normalize_size_label_moe_form() {
assert_eq!(normalize_size_label("8x7B"), Some("8x7B".to_string()));
assert_eq!(normalize_size_label("8x7b"), Some("8x7B".to_string()));
}
#[test]
fn normalize_size_label_with_decimal() {
assert_eq!(normalize_size_label("1.5B"), Some("1.5B".to_string()));
assert_eq!(normalize_size_label("1_5b"), Some("1.5B".to_string()));
}
#[test]
fn normalize_size_label_rejects_non_size() {
assert_eq!(normalize_size_label("foo"), None);
assert_eq!(normalize_size_label("2048"), None); assert_eq!(normalize_size_label("XYZ"), None);
}
#[test]
fn is_version_marker_matches_pure_numeric() {
assert!(is_version_marker("2048"));
assert!(is_version_marker("v2"));
assert!(is_version_marker("V1"));
assert!(is_version_marker("iter3"));
assert!(is_version_marker("1.5"));
}
#[test]
fn is_version_marker_rejects_alpha_suffix() {
assert!(!is_version_marker("v2a"));
assert!(!is_version_marker("v"));
}
#[test]
fn title_case_hyphenated_matches_canonical_id_to_title() {
assert_eq!(
title_case_hyphenated("google-gemma-4-26b-a4b-it"),
"Google Gemma 4 26b A4B It"
);
assert_eq!(title_case_hyphenated("nomic-xlm-2048"), "Nomic Xlm 2048");
assert_eq!(
title_case_hyphenated("nomic-embed-text-v2-moe-unsupervised"),
"Nomic Embed Text v2 Moe Unsupervised"
);
assert_eq!(
title_case_hyphenated("Meta-Llama-3-8B-Instruct"),
"Meta Llama 3 8B Instruct"
);
}
#[test]
fn python_str_title_matches_python_semantics() {
assert_eq!(python_str_title("a4b"), "A4B");
assert_eq!(python_str_title("abc"), "Abc");
assert_eq!(python_str_title("hello world"), "Hello World");
assert_eq!(python_str_title("aBc"), "Abc"); assert_eq!(python_str_title("123"), "123");
}
#[test]
fn is_python_islower_matches_python_semantics() {
assert!(is_python_islower("abc")); assert!(is_python_islower("a4b")); assert!(!is_python_islower("ABC")); assert!(!is_python_islower("aBc")); assert!(!is_python_islower("123")); assert!(!is_python_islower("4")); }
#[test]
fn emit_general_prelude_gemma_layout() {
let id_components = get_model_id_components("google-gemma-4-26b-a4b-it");
let sampling = SamplingConfig {
top_k: Some(64),
top_p: Some(0.95),
temperature: Some(1.0),
};
let kv = emit_general_prelude(
"gemma4",
"Google Gemma 4 26b A4B It".to_string(),
&id_components,
None,
None,
Some(&sampling),
);
let keys: Vec<&str> = kv.iter().map(|(k, _)| k.as_str()).collect();
assert_eq!(
keys,
vec![
"general.architecture",
"general.type",
"general.sampling.top_k",
"general.sampling.top_p",
"general.sampling.temp",
"general.name",
"general.finetune",
"general.basename",
"general.size_label",
]
);
let by_key: std::collections::HashMap<_, _> =
kv.iter().map(|(k, v)| (k.as_str(), v.clone())).collect();
assert_eq!(
by_key["general.architecture"],
MetaValue::String("gemma4".into())
);
assert_eq!(by_key["general.type"], MetaValue::String("model".into()));
assert_eq!(by_key["general.sampling.top_k"], MetaValue::I32(64));
assert_eq!(
by_key["general.name"],
MetaValue::String("Google Gemma 4 26b A4B It".into())
);
assert_eq!(by_key["general.finetune"], MetaValue::String("it".into()));
assert_eq!(
by_key["general.basename"],
MetaValue::String("google-gemma-4".into())
);
assert_eq!(
by_key["general.size_label"],
MetaValue::String("26B-a4B".into())
);
}
#[test]
fn emit_general_prelude_nomic_v2moe_layout() {
let id_components = get_model_id_components("nomic-ai/nomic-xlm-2048");
let card = ModelCard {
license: Some("apache-2.0".into()),
license_name: None,
license_link: None,
tags: vec!["sentence-transformers".into(), "sentence-similarity".into()],
languages: vec!["en".into(), "es".into()],
base_models: vec![BaseModelEntry {
raw: "nomic-ai/nomic-embed-text-v2-moe-unsupervised".into(),
}],
};
let kv = emit_general_prelude(
"nomic-bert-moe",
"Nomic Xlm 2048".to_string(),
&id_components,
Some("8x277M"), Some(&card),
None, );
let keys: Vec<&str> = kv.iter().map(|(k, _)| k.as_str()).collect();
assert_eq!(
keys,
vec![
"general.architecture",
"general.type",
"general.name",
"general.version",
"general.organization",
"general.basename",
"general.size_label",
"general.license",
"general.base_model.count",
"general.base_model.0.name",
"general.base_model.0.organization",
"general.base_model.0.repo_url",
"general.tags",
"general.languages",
]
);
let by_key: std::collections::HashMap<_, _> =
kv.iter().map(|(k, v)| (k.as_str(), v.clone())).collect();
assert_eq!(
by_key["general.architecture"],
MetaValue::String("nomic-bert-moe".into())
);
assert_eq!(
by_key["general.size_label"],
MetaValue::String("8x277M".into())
);
assert_eq!(
by_key["general.organization"],
MetaValue::String("Nomic Ai".into())
);
}
#[test]
fn is_version_or_digit_start_canonical_regex() {
assert!(is_version_or_digit_start("v2"));
assert!(is_version_or_digit_start("v1.5"));
assert!(is_version_or_digit_start("26b")); assert!(is_version_or_digit_start("7B"));
assert!(is_version_or_digit_start("4"));
assert!(!is_version_or_digit_start("google"));
assert!(!is_version_or_digit_start("v")); assert!(!is_version_or_digit_start("a4b")); }
#[test]
fn format_param_count_rounded_matches_canonical() {
assert_eq!(format_param_count_rounded(277_036_864, 2), "277M");
assert_eq!(format_param_count_rounded(1_500_000_000, 2), "1.5B");
assert_eq!(format_param_count_rounded(27_000_000, 2), "27M");
assert_eq!(format_param_count_rounded(27_500_000, 2), "28M");
assert_eq!(format_param_count_rounded(500_000, 2), "500K");
assert_eq!(format_param_count_rounded(1_200_000_000_000, 2), "1.2T");
}
#[test]
fn compute_size_label_moe_8_experts() {
let tensors = vec![
(192_036_864_u64, false), (28_000_000, false), (28_320_000, false), (8 * 4_720_000, true), ];
let label = compute_size_label(tensors, 8);
assert!(label.starts_with("8x"), "got {label}");
assert!(label.ends_with('M') || label.ends_with('B'), "got {label}");
}
#[test]
fn compute_size_label_dense_no_experts() {
let tensors = vec![(192_000_000, false), (100_000_000, false)];
let label = compute_size_label(tensors, 0);
assert_eq!(label, "292M");
}
#[test]
fn compute_size_label_zero_experts_falls_back_to_total() {
let tensors = vec![(7_000_000_000_u64, false)];
let label = compute_size_label(tensors, 0);
assert_eq!(label, "7.0B");
}
#[test]
fn unknown_block_list_keys_consume_their_items() {
let frontmatter = "\
unknown_list:
- skip_me_1
- skip_me_2
tags:
- real_tag
";
let card = parse_yaml_frontmatter(frontmatter);
assert_eq!(card.tags, vec!["real_tag"]);
}
}