Skip to content

Commit 31f91e5

Browse files
committed
feat(kb): bge 模型下载命令(hf-mirror 双源,REQ-262 余项)
1 parent 6a10ba0 commit 31f91e5

2 files changed

Lines changed: 48 additions & 0 deletions

File tree

‎app/src-tauri/src/commands_kb.rs‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,53 @@ pub fn kb_index_stats(state: State<'_, AppState>) -> Result<KbIndexStats, String
6868
/// kb embedding 模型相对目录(model_dir 下;与 speaker 下载器同约定)
6969
const EMBEDDING_MODEL_REL: &str = "embedding/bge-small-zh-v1.5";
7070

71+
/// 下载 kb embedding 模型(bge-small-zh-v1.5 int8 ONNX + BERT 词表)。
72+
///
73+
/// @ai-context: 模型文件不入库、不打包(约 25MB 按需下载——REQ-262 口径);
74+
/// 源:ONNX 量化模型走 Xenova(社区导出),vocab.txt 走 BAAI
75+
/// 官方仓库;下载写 .part 后原子改名(中断残留可重下覆盖)。
76+
/// 下载完成 ≠ 就绪——需 kb_embedding_load 换槽 + 「学习库」段
77+
/// 重建索引回填向量(命令返回值给前端引导文案)。
78+
#[tauri::command]
79+
pub async fn kb_embedding_download(state: State<'_, AppState>) -> Result<String, String> {
80+
let dir = state.model_dir.join(EMBEDDING_MODEL_REL);
81+
let files: [(&str, &str); 2] = [
82+
(
83+
"model_quantized.onnx",
84+
"https://hf-mirror.com/Xenova/bge-small-zh-v1.5/resolve/main/onnx/model_quantized.onnx",
85+
),
86+
(
87+
"vocab.txt",
88+
"https://hf-mirror.com/BAAI/bge-small-zh-v1.5/resolve/main/vocab.txt",
89+
),
90+
];
91+
tauri::async_runtime::spawn_blocking(move || -> Result<String, String> {
92+
std::fs::create_dir_all(&dir).map_err(|e| format!("创建模型目录失败: {e}"))?;
93+
let mut downloaded = Vec::new();
94+
for (name, url) in files {
95+
let part = dir.join(format!("{name}.part"));
96+
let target = dir.join(name);
97+
let resp = ureq::get(url)
98+
.timeout(std::time::Duration::from_secs(600))
99+
.call()
100+
.map_err(|e| format!("下载 {name} 失败: {e}"))?;
101+
let mut reader = resp.into_reader();
102+
let mut out = std::fs::File::create(&part).map_err(|e| format!("写临时文件失败: {e}"))?;
103+
std::io::copy(&mut reader, &mut out).map_err(|e| format!("写 {name} 失败: {e}"))?;
104+
drop(out);
105+
std::fs::rename(&part, &target).map_err(|e| format!("落位 {name} 失败: {e}"))?;
106+
downloaded.push(name.to_string());
107+
}
108+
Ok(format!(
109+
"已下载:{}({})——请在「学习库」段点击加载引擎并重建索引以回填向量",
110+
downloaded.join("、"),
111+
dir.to_string_lossy()
112+
))
113+
})
114+
.await
115+
.map_err(|e| format!("下载任务调度失败: {e}"))?
116+
}
117+
71118
/// 引擎状态视图(设置页「学习库」段数据源——无模型如实显示 noop 与原因)。
72119
#[derive(Serialize)]
73120
#[serde(rename_all = "camelCase")]

‎app/src-tauri/src/lib.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,7 @@ pub fn run() {
605605
commands_kb::kb_reindex_all,
606606
commands_kb::kb_embedding_status,
607607
commands_kb::kb_embedding_load,
608+
commands_kb::kb_embedding_download,
608609
// v0.19.1(REQ-260):学习库问答生成开关与预算档位(设置段读写)
609610
commands_ai_settings::ai_set_kb_qa,
610611
// v0.19.3(REQ-261):检索建议(发现路径——默认关,建议制)

0 commit comments

Comments
 (0)