pub use nika_core::catalogs::models::*;
use std::path::PathBuf;
#[derive(Debug, Clone)]
pub struct ResolvedModel {
pub model: &'static KnownModel,
pub quantization: Quantization,
pub path: PathBuf,
}
#[must_use]
pub fn detect_available_ram_gb() -> u32 {
crate::util::system::get_available_ram_gb()
}
pub fn resolve_model(
id: &str,
quantization: Option<Quantization>,
) -> Result<ResolvedModel, ModelResolveError> {
let model =
find_model(id).ok_or_else(|| ModelResolveError::UnknownModel { id: id.to_string() })?;
let quant =
quantization.unwrap_or_else(|| auto_select_quantization(model, detect_available_ram_gb()));
let filename = model
.quantizations
.iter()
.find(|(q, _)| *q == quant)
.map(|(_, f)| *f)
.ok_or_else(|| ModelResolveError::QuantizationNotAvailable {
quantization: quant,
model_id: id.to_string(),
})?;
let cache_dir = dirs::home_dir()
.ok_or(ModelResolveError::HomeDirectoryNotFound)?
.join(".cache/huggingface/hub");
let repo_dir_name = format!("models--{}", model.hf_repo.replace('/', "--"));
let snapshots_dir = cache_dir.join(&repo_dir_name).join("snapshots");
if !snapshots_dir.exists() {
return Err(ModelResolveError::ModelNotDownloaded {
model_id: id.to_string(),
});
}
let snapshot = std::fs::read_dir(&snapshots_dir)
.map_err(|e| ModelResolveError::SnapshotsDirReadError {
path: snapshots_dir.clone(),
message: e.to_string(),
})?
.filter_map(|e| e.ok())
.filter(|e| e.file_type().map(|t| t.is_dir()).unwrap_or(false))
.max_by_key(|e| e.metadata().and_then(|m| m.modified()).ok());
let snapshot_dir = snapshot.ok_or_else(|| ModelResolveError::NoSnapshotsFound {
model_id: id.to_string(),
})?;
let model_path = snapshot_dir.path().join(filename);
if !model_path.exists() {
return Err(ModelResolveError::ModelFileNotFound {
path: model_path,
model_id: id.to_string(),
});
}
Ok(ResolvedModel {
model,
quantization: quant,
path: model_path,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_resolve_model_unknown_id() {
let err = resolve_model("nonexistent:model", None).unwrap_err();
match err {
ModelResolveError::UnknownModel { id } => {
assert_eq!(id, "nonexistent:model");
}
other => panic!("Expected UnknownModel, got: {:?}", other),
}
}
#[test]
fn test_resolve_model_unavailable_quantization() {
let err = resolve_model("qwen3:1.7b", Some(Quantization::F16)).unwrap_err();
match err {
ModelResolveError::QuantizationNotAvailable {
quantization,
model_id,
} => {
assert_eq!(quantization, Quantization::F16);
assert_eq!(model_id, "qwen3:1.7b");
}
other => panic!("Expected QuantizationNotAvailable, got: {:?}", other),
}
}
}