fix: ensure_default_models 每次启动重新检查模型文件存在性

This commit is contained in:
2026-07-04 16:02:42 +08:00
parent 6810d1ca13
commit 8fc82813d3
2 changed files with 173 additions and 73 deletions

View File

@@ -148,82 +148,87 @@ impl ModelManager {
}
/// 初始化默认模型清单(首次启动或清单缺失时)
/// 每次启动都重新检查文件存在性,更新 downloaded 状态(符号链接可能后建)
pub fn ensure_default_models(&mut self) -> Result<()> {
if !self.registry.models.is_empty() {
return Ok(());
// 首次:注册表为空,填充默认清单
if self.registry.models.is_empty() {
let defaults = vec![
ModelInfo {
id: "qwen2.5-0.5b-q4_k_m".to_string(),
kind: ModelKind::Llm,
name: "Qwen2.5 0.5B Q4 (推荐默认)".to_string(),
version: "0.5b".to_string(),
size: 469 * 1024 * 1024,
memory_required: 1024 * 1024 * 1024,
recommended_tier: "4G 内存档可用".to_string(),
url: "https://hf-mirror.com/Qwen/Qwen2.5-0.5B-Instruct-GGUF/resolve/main/qwen2.5-0.5b-instruct-q4_k_m.gguf".to_string(),
sha256: String::new(),
filename: "qwen2.5-0.5b-q4_k_m.gguf".to_string(),
},
ModelInfo {
id: "gemma3-1b-q4_k_m".to_string(),
kind: ModelKind::Llm,
name: "Gemma3 1B Q4 (可选档)".to_string(),
version: "1b".to_string(),
size: 800 * 1024 * 1024,
memory_required: 2 * 1024 * 1024 * 1024,
recommended_tier: "建议 8G 以上".to_string(),
url: "https://hf-mirror.com/google/gemma-3-1b-it-GGUF/resolve/main/gemma-3-1b-it-q4_k_m.gguf".to_string(),
sha256: String::new(),
filename: "gemma3-1b-q4_k_m.gguf".to_string(),
},
ModelInfo {
id: "whisper-tiny".to_string(),
kind: ModelKind::Asr,
name: "Whisper Tiny (中文)".to_string(),
version: "tiny".to_string(),
size: 75 * 1024 * 1024,
memory_required: 200 * 1024 * 1024,
recommended_tier: "4G 内存档可用".to_string(),
url: "https://hf-mirror.com/ggerganov/whisper.cpp/resolve/main/ggml-tiny.bin".to_string(),
sha256: String::new(),
filename: "ggml-tiny.bin".to_string(),
},
ModelInfo {
id: "piper-zh-huayan".to_string(),
kind: ModelKind::Tts,
name: "Piper zh_CN huayan (中文女声)".to_string(),
version: "medium".to_string(),
size: 63 * 1024 * 1024,
memory_required: 150 * 1024 * 1024,
recommended_tier: "4G 内存档可用".to_string(),
url: "https://hf-mirror.com/rhasspy/piper-voices/resolve/main/zh/zh_CN/huayan/medium/zh_CN-huayan-medium.onnx".to_string(),
sha256: String::new(),
filename: "zh_CN-huayan-medium.onnx".to_string(),
},
];
for info in defaults {
self.registry.models.push(LocalModelEntry {
info,
downloaded: false,
download_progress: 0,
});
}
// 设置默认 active 模型
if !self.registry.active.contains_key(&ModelKind::Llm) {
self.registry.active.insert(ModelKind::Llm, "qwen2.5-0.5b-q4_k_m".to_string());
}
if !self.registry.active.contains_key(&ModelKind::Asr) {
self.registry.active.insert(ModelKind::Asr, "whisper-tiny".to_string());
}
if !self.registry.active.contains_key(&ModelKind::Tts) {
self.registry.active.insert(ModelKind::Tts, "piper-zh-huayan".to_string());
}
}
// Spike 推荐的默认模型清单
let defaults = vec![
ModelInfo {
id: "qwen2.5-0.5b-q4_k_m".to_string(),
kind: ModelKind::Llm,
name: "Qwen2.5 0.5B Q4 (推荐默认)".to_string(),
version: "0.5b".to_string(),
size: 469 * 1024 * 1024,
memory_required: 1024 * 1024 * 1024,
recommended_tier: "4G 内存档可用".to_string(),
url: "https://hf-mirror.com/Qwen/Qwen2.5-0.5B-Instruct-GGUF/resolve/main/qwen2.5-0.5b-instruct-q4_k_m.gguf".to_string(),
sha256: String::new(), // 实际部署时填充
filename: "qwen2.5-0.5b-q4_k_m.gguf".to_string(),
},
ModelInfo {
id: "gemma3-1b-q4_k_m".to_string(),
kind: ModelKind::Llm,
name: "Gemma3 1B Q4 (可选档)".to_string(),
version: "1b".to_string(),
size: 800 * 1024 * 1024,
memory_required: 2 * 1024 * 1024 * 1024,
recommended_tier: "建议 8G 以上".to_string(),
url: "https://hf-mirror.com/google/gemma-3-1b-it-GGUF/resolve/main/gemma-3-1b-it-q4_k_m.gguf".to_string(),
sha256: String::new(),
filename: "gemma3-1b-q4_k_m.gguf".to_string(),
},
ModelInfo {
id: "whisper-tiny".to_string(),
kind: ModelKind::Asr,
name: "Whisper Tiny (中文)".to_string(),
version: "tiny".to_string(),
size: 75 * 1024 * 1024,
memory_required: 200 * 1024 * 1024,
recommended_tier: "4G 内存档可用".to_string(),
url: "https://hf-mirror.com/ggerganov/whisper.cpp/resolve/main/ggml-tiny.bin".to_string(),
sha256: String::new(),
filename: "ggml-tiny.bin".to_string(),
},
ModelInfo {
id: "piper-zh-huayan".to_string(),
kind: ModelKind::Tts,
name: "Piper zh_CN huayan (中文女声)".to_string(),
version: "medium".to_string(),
size: 63 * 1024 * 1024,
memory_required: 150 * 1024 * 1024,
recommended_tier: "4G 内存档可用".to_string(),
url: "https://hf-mirror.com/rhasspy/piper-voices/resolve/main/zh/zh_CN/huayan/medium/zh_CN-huayan-medium.onnx".to_string(),
sha256: String::new(),
filename: "zh_CN-huayan-medium.onnx".to_string(),
},
];
for info in defaults {
let filename = info.filename.clone();
let downloaded = self.store_dir.join(info.kind.dir_name()).join(&filename).exists();
self.registry.models.push(LocalModelEntry {
info,
downloaded,
download_progress: if downloaded { 100 } else { 0 },
});
}
// 设置默认 active 模型
if !self.registry.active.contains_key(&ModelKind::Llm) {
self.registry.active.insert(ModelKind::Llm, "qwen2.5-0.5b-q4_k_m".to_string());
}
if !self.registry.active.contains_key(&ModelKind::Asr) {
self.registry.active.insert(ModelKind::Asr, "whisper-tiny".to_string());
}
if !self.registry.active.contains_key(&ModelKind::Tts) {
self.registry.active.insert(ModelKind::Tts, "piper-zh-huayan".to_string());
// 每次启动都重新检查文件存在性(符号链接可能后建,或文件被手动删除)
for entry in &mut self.registry.models {
let path = self.store_dir.join(entry.info.kind.dir_name()).join(&entry.info.filename);
let exists = path.exists();
entry.downloaded = exists;
entry.download_progress = if exists { 100 } else { 0 };
}
self.save_registry()?;