polishing

This commit is contained in:
2026-05-06 10:53:27 -06:00
parent 09ebcbc9ec
commit fd6697b48e
18 changed files with 889 additions and 145 deletions

141
src-tauri/src/models.rs Normal file
View File

@ -0,0 +1,141 @@
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Serialize, Deserialize)]
pub struct ModelInfo {
pub name: String,
pub path: String,
pub size_bytes: u64,
pub kind: String,
}
fn huggingface_cache_dir() -> PathBuf {
// Follows huggingface_hub default cache location
if let Ok(custom) = std::env::var("HF_HOME") {
return PathBuf::from(custom).join("hub");
}
if let Ok(custom) = std::env::var("XDG_CACHE_HOME") {
return PathBuf::from(custom).join("huggingface").join("hub");
}
dirs::home_dir()
.unwrap_or_default()
.join(".cache")
.join("huggingface")
.join("hub")
}
fn scan_whisper_models() -> Vec<ModelInfo> {
let cache_dir = huggingface_cache_dir();
if !cache_dir.exists() {
return vec![];
}
let mut models = vec![];
let pattern = "models--Systran--faster-whisper-";
let Ok(entries) = std::fs::read_dir(&cache_dir) else {
return vec![];
};
for entry in entries.flatten() {
let name = entry.file_name();
let name_str = name.to_string_lossy();
if !name_str.starts_with(pattern) {
continue;
}
let model_name = name_str
.strip_prefix(pattern)
.unwrap_or(&name_str)
.to_string();
// The actual model files are in snapshots/ subdirectory
let snapshots_dir = entry.path().join("snapshots");
let mut total_size = 0u64;
if let Ok(snap_entries) = std::fs::read_dir(&snapshots_dir) {
for snap in snap_entries.flatten() {
total_size += dir_size(&snap.path());
}
}
// If no snapshots dir, try blobs/
if total_size == 0 {
let blobs_dir = entry.path().join("blobs");
if blobs_dir.exists() {
total_size = dir_size(&blobs_dir);
}
}
models.push(ModelInfo {
name: model_name,
path: entry.path().to_string_lossy().to_string(),
size_bytes: total_size,
kind: "whisper".to_string(),
});
}
models
}
fn scan_llm_models(app_data_dir: &PathBuf) -> Vec<ModelInfo> {
let models_dir = app_data_dir.join("models");
if !models_dir.exists() {
return vec![];
}
let mut models = vec![];
let Ok(entries) = std::fs::read_dir(&models_dir) else {
return vec![];
};
for entry in entries.flatten() {
let path = entry.path();
if path.extension().map(|e| e == "gguf").unwrap_or(false) {
let meta = std::fs::metadata(&path).ok();
models.push(ModelInfo {
name: entry.file_name().to_string_lossy().to_string(),
path: path.to_string_lossy().to_string(),
size_bytes: meta.map(|m| m.len()).unwrap_or(0),
kind: "llm".to_string(),
});
}
}
models
}
fn dir_size(path: &std::path::Path) -> u64 {
let mut total = 0u64;
if let Ok(entries) = std::fs::read_dir(path) {
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
total += dir_size(&path);
} else if let Ok(meta) = std::fs::metadata(&path) {
total += meta.len();
}
}
}
total
}
pub fn list_models(app_data_dir: &PathBuf) -> Vec<ModelInfo> {
let mut models = scan_whisper_models();
models.extend(scan_llm_models(app_data_dir));
models
}
pub fn delete_model(path: &str) -> Result<(), String> {
let path = std::path::Path::new(path);
if !path.exists() {
return Err("Model path not found".to_string());
}
if path.is_dir() {
std::fs::remove_dir_all(path)
.map_err(|e| format!("Failed to delete model: {e}"))?;
} else {
std::fs::remove_file(path)
.map_err(|e| format!("Failed to delete model: {e}"))?;
}
Ok(())
}