use crate::catalog::CatalogModel;
use crate::host::{LoadedModel, ModelRuntime};
use std::path::PathBuf;
use std::sync::Arc;
pub struct Loaders {
models_root: PathBuf,
}
impl Loaders {
pub fn new(models_root: PathBuf) -> Self {
Self { models_root }
}
}
impl ModelRuntime for Loaders {
fn can_load(&self, model: &CatalogModel) -> bool {
match model.source.engine {
#[cfg(all(feature = "llama", not(target_os = "windows")))]
crate::types::ModelEngine::LlamaCpp => true,
#[cfg(feature = "stt-stream")]
crate::types::ModelEngine::Parakeet => true,
_ => false,
}
}
fn load(&self, model: &CatalogModel) -> anyhow::Result<Arc<dyn LoadedModel>> {
match &model.source.engine {
#[cfg(all(feature = "llama", not(target_os = "windows")))]
crate::types::ModelEngine::LlamaCpp => Ok(Arc::new(
crate::engine::llama::load_resident(&self.models_root, model)?,
)),
#[cfg(feature = "stt-stream")]
crate::types::ModelEngine::Parakeet => Ok(Arc::new(
crate::engine::parakeet::load_resident(&self.models_root, model)?,
)),
engine => {
let _ = &self.models_root;
anyhow::bail!(
"no in-process loader for engine {engine:?} (model {})",
model.id
)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::{ModelEngine, ModelSource, TaskKind};
#[test]
fn an_engine_without_a_loader_is_refused_by_name() {
let model = CatalogModel {
id: "m".into(),
display_name: "m".into(),
kind: TaskKind::Image,
vram_gb_estimate: 1.0,
description: None,
source: ModelSource {
engine: ModelEngine::SdCpp,
files: vec![],
cli_defaults: Default::default(),
},
enabled: true,
origin: "local".into(),
exclusive_group: None,
};
let loaders = Loaders::new(PathBuf::from("/nonexistent"));
assert!(!loaders.can_load(&model));
let err = loaders.load(&model).err().expect("refused");
assert!(
err.to_string()
.contains("no in-process loader for engine SdCpp"),
"{err}"
);
}
#[cfg(all(feature = "llama", not(target_os = "windows")))]
#[test]
fn an_llm_can_be_loaded() {
let model = CatalogModel {
id: "m".into(),
display_name: "m".into(),
kind: TaskKind::Llm,
vram_gb_estimate: 1.0,
description: None,
source: ModelSource {
engine: ModelEngine::LlamaCpp,
files: vec![],
cli_defaults: Default::default(),
},
enabled: true,
origin: "local".into(),
exclusive_group: None,
};
assert!(Loaders::new(PathBuf::from("/nonexistent")).can_load(&model));
}
}