Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
412 changes: 393 additions & 19 deletions src-tauri/Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ crossterm = "0.28"
tui-input = "0.11"

dirs = "5"
hf-hub = "0.5"
zip = "0.6"
tar = "0.4"
flate2 = "1"
Expand Down
12 changes: 12 additions & 0 deletions src-tauri/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,18 @@ pub struct AppConfig {
/// Preferred GGUF source owners on HuggingFace, in priority order.
#[serde(default)]
pub preferred_owners: Vec<String>,
/// When enabled, model downloads are written to the HuggingFace Hub cache
/// (HF_HOME or ~/.cache/huggingface/) instead of the configured download_dir.
#[serde(default)]
pub hf_cache_enabled: bool,
/// When enabled, deletes remove orphaned blobs from the HF cache after
/// removing the snapshot symlink. Defaults to true.
#[serde(default = "default_hf_cache_prune_on_delete")]
pub hf_cache_prune_on_delete: bool,
}

fn default_hf_cache_prune_on_delete() -> bool {
true
}

impl AppConfig {
Expand Down
27 changes: 23 additions & 4 deletions src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,20 @@ async fn set_preferred_owners(
config.save().map_err(|e| e.to_string())
}

#[tauri::command]
async fn set_hf_cache_enabled(enabled: bool, state: State<'_, AppState>) -> Result<(), String> {
let mut config = state.config.lock().unwrap();
config.hf_cache_enabled = enabled;
config.save().map_err(|e| e.to_string())
}

#[tauri::command]
async fn set_hf_cache_prune_on_delete(enabled: bool, state: State<'_, AppState>) -> Result<(), String> {
let mut config = state.config.lock().unwrap();
config.hf_cache_prune_on_delete = enabled;
config.save().map_err(|e| e.to_string())
}

#[tauri::command]
async fn validate_hf_owner(
owner: String,
Expand Down Expand Up @@ -347,9 +361,11 @@ async fn download_model(
_ => (false, vec![]),
};

// If downloading an mmproj alongside a model, prefix the filename
// If downloading an mmproj alongside a model, prefix the filename.
// When HF cache is enabled, skip prefixing — hf_hub stores files by
// their original repo path, so we pass the un-prefixed name through.
let is_mmproj = huggingface::is_mmproj_file(&filename);
let save_filename = if is_mmproj {
let save_filename = if is_mmproj && !config.hf_cache_enabled {
if let Some(ref model_name) = companion_model {
models::prefixed_mmproj_filename(model_name, &filename)
} else {
Expand Down Expand Up @@ -408,8 +424,9 @@ async fn download_model(
}

#[tauri::command]
async fn delete_model(path: String, _state: State<'_, AppState>) -> Result<(), String> {
models::delete_model(&std::path::PathBuf::from(path)).map_err(|e| e.to_string())
async fn delete_model(path: String, state: State<'_, AppState>) -> Result<(), String> {
let prune = state.config.lock().unwrap().hf_cache_prune_on_delete;
models::delete_model(&std::path::PathBuf::from(path), prune).map_err(|e| e.to_string())
}

#[tauri::command]
Expand Down Expand Up @@ -744,6 +761,8 @@ pub fn run() {
get_known_owners,
get_preferred_owners,
set_preferred_owners,
set_hf_cache_enabled,
set_hf_cache_prune_on_delete,
validate_hf_owner,
search_hf_models,
get_hf_repo_files,
Expand Down
Loading
Loading