use super::catalog::ModelCatalogEntry;
use super::ModelService;
use anyhow::{Context, Result};
use indicatif::ProgressBar;
use std::path::PathBuf;
use tokio::fs;
impl ModelService {
#[cfg(feature = "model-download")]
pub(super) async fn pull_labels_file(
&self,
model_name: &str,
filename: &str,
progress: Option<&ProgressBar>,
) -> Result<PathBuf> {
let model_dir = self.models_dir.join(model_name);
let output_path = model_dir.join("labels.txt");
if output_path.exists() {
if let Some(pb) = progress {
pb.set_message("Labels file already cached".to_string());
}
return Ok(output_path);
}
let url = match filename {
"imagenet-labels.txt" => "https://raw.githubusercontent.com/pytorch/hub/master/imagenet_classes.txt",
_ => {
if let Some(pb) = progress {
pb.set_message(format!("⚠️ Unknown labels file: {}, skipping", filename));
}
return Ok(output_path); }
};
if let Some(pb) = progress {
pb.set_message(format!("Downloading labels: {}", filename));
}
let client = reqwest::Client::new();
let response = client
.get(url)
.send()
.await
.context(format!("Failed to download labels from {}", url))?;
if !response.status().is_success() {
anyhow::bail!("Failed to download labels: HTTP {}", response.status());
}
let content = response.text().await.context("Failed to read labels content")?;
fs::write(&output_path, content)
.await
.context("Failed to write labels file")?;
if let Some(pb) = progress {
pb.set_message(format!("Downloaded labels: {}", filename));
}
Ok(output_path)
}
#[cfg(feature = "model-download")]
pub(super) async fn write_inline_labels(&self, model_name: &str, classes: &[String]) -> Result<()> {
let model_dir = self.models_dir.join(model_name);
let labels_path = model_dir.join("labels.txt");
let content = classes.join("\n");
fs::write(&labels_path, content)
.await
.context("Failed to write inline labels to labels.txt")?;
Ok(())
}
#[cfg(feature = "model-download")]
pub(super) async fn pull_labels_from_repo(
&self,
entry: &ModelCatalogEntry,
model_name: &str,
progress: Option<&ProgressBar>,
) -> Result<()> {
let model_dir = self.models_dir.join(model_name);
let labels_path = model_dir.join("labels.txt");
if labels_path.exists() {
if let Some(pb) = progress {
pb.set_message("Labels file already cached".to_string());
}
return Ok(());
}
let model_dir_in_repo = entry.filename.rsplit_once('/').map(|(dir, _)| dir).unwrap_or("");
if model_dir_in_repo.is_empty() {
return Ok(());
}
let labels_filename = format!("{}/labels.json", model_dir_in_repo);
if let Some(pb) = progress {
pb.set_message(format!("Downloading labels from {}", entry.repo));
}
let url = format!("https://huggingface.co/{}/raw/main/{}", entry.repo, labels_filename);
let client = reqwest::Client::new();
let response = match client.get(&url).send().await {
Ok(resp) if resp.status().is_success() => resp,
_ => {
return Ok(());
}
};
let json_content = response.text().await.context("Failed to read labels.json response")?;
let labels: Vec<String> = serde_json::from_str(&json_content).context("Failed to parse labels.json")?;
let content = labels.join("\n");
fs::write(&labels_path, content)
.await
.context("Failed to write labels.txt")?;
if let Some(pb) = progress {
pb.set_message(format!("Downloaded {} class labels", labels.len()));
}
Ok(())
}
}