use anyhow::{Context, Result};
use serde_json::json;
use std::path::PathBuf;
use crate::{WireFormat, style};
#[allow(dead_code)]
pub fn download_command(
ner: bool,
models: Vec<String>,
all: bool,
cache_dir: Option<PathBuf>,
format: WireFormat,
) -> Result<()> {
let to_download = select_models(ner, models, all)?;
let downloaded = download_models(&to_download, cache_dir)?;
match format {
WireFormat::Text => {
println!("{}", style::header("NER Model Download"));
println!("{}", style::dim("=================="));
for d in &downloaded {
println!(" {}", style::success(d));
}
println!("{}", style::success("Done"));
}
WireFormat::Json => {
let output = json!({
"downloaded": downloaded,
});
println!(
"{}",
serde_json::to_string_pretty(&output).context("Failed to serialize NER download results to JSON")?
);
}
WireFormat::Toon => {
let output = json!({
"downloaded": downloaded,
});
println!(
"{}",
serde_toon::to_string(&output).context("Failed to serialize NER download results to TOON")?
);
}
}
Ok(())
}
pub fn select_models(ner: bool, models: Vec<String>, all: bool) -> Result<Vec<String>> {
for model in &models {
if model.trim().is_empty() {
anyhow::bail!("Field 'ner_model' must not be empty. Omit the field or provide a valid model name.");
}
}
let mut to_download: Vec<String> = Vec::new();
if all {
to_download.extend(xberg::text::ner::known_models().iter().map(|s| s.to_string()));
} else if !models.is_empty() {
to_download.extend(models);
} else if ner {
to_download.push(xberg::text::ner::default_model_name().to_string());
} else {
anyhow::bail!("No NER model specified. Use --ner, --ner-model <MODEL>, or --all-ner-models.");
}
Ok(to_download)
}
pub fn download_models(models: &[String], cache_dir: Option<PathBuf>) -> Result<Vec<String>> {
let mut downloaded: Vec<String> = Vec::with_capacity(models.len());
for repo in models {
let path = xberg::text::ner::download_model(repo, cache_dir.clone())
.with_context(|| format!("Failed to download NER model '{repo}'"))?;
downloaded.push(format!("{repo} -> {}", path.display()));
}
Ok(downloaded)
}
#[cfg(test)]
mod tests {
use super::select_models;
#[test]
fn select_models_uses_default_when_ner_flag_is_set() {
let models = select_models(true, Vec::new(), false).unwrap();
assert_eq!(models, vec![xberg::text::ner::default_model_name()]);
}
#[test]
fn select_models_uses_explicit_models() {
let models = select_models(false, vec!["gliner_small-v2.5".to_string()], false).unwrap();
assert_eq!(models, vec!["gliner_small-v2.5"]);
}
#[test]
fn select_models_rejects_blank_model() {
let error = select_models(false, vec![" ".to_string()], false).unwrap_err();
assert!(error.to_string().contains("must not be empty"));
}
}