feat: get_files 支持多页获取所有文件
问题: - Library 只显示 20 个文件 - 数据库有 176 个文件 - API per_page 强制限制最大 20 解决方案: - 实现多页获取逻辑 - 先获取第一页得到 total - 计算总页数 - 循环获取剩余页 - 合并所有文件返回 变更: - get_files 函数重构 - 新增 parse_file_info 辅助函数 - 支持最多 500 个文件(pageSize 限制) 测试: - ✅ 编译通过 - ⏳ 需要部署测试 预期效果: - Library 显示所有文件(176 个) - 一次调用获取所有数据 - 前端无需修改
This commit is contained in:
@@ -220,35 +220,72 @@ async fn search_agents(query: String, conversation_id: Option<String>) -> Result
|
|||||||
async fn get_files(args: GetFilesArgs) -> Result<Vec<FileInfo>, String> {
|
async fn get_files(args: GetFilesArgs) -> Result<Vec<FileInfo>, String> {
|
||||||
let page_size = args.page_size;
|
let page_size = args.page_size;
|
||||||
let client = get_client();
|
let client = get_client();
|
||||||
let url = format!("{}/api/v1/files?api_key={}&page=1&per_page={}", CORE_API, API_KEY, page_size);
|
let per_page = 20; // API 限制最大 20
|
||||||
|
|
||||||
|
// 获取第一页并获取总数
|
||||||
|
let url = format!("{}/api/v1/files?api_key={}&page=1&per_page={}", CORE_API, API_KEY, per_page);
|
||||||
let response = client.get(&url).send().await.map_err(|e| format!("Request failed: {}", e))?;
|
let response = client.get(&url).send().await.map_err(|e| format!("Request failed: {}", e))?;
|
||||||
let json: serde_json::Value = response.json().await.map_err(|e| format!("Parse failed: {}", e))?;
|
let json: serde_json::Value = response.json().await.map_err(|e| format!("Parse failed: {}", e))?;
|
||||||
|
|
||||||
let files: Vec<FileInfo> = json["data"]
|
let total = json["total"].as_u64().unwrap_or(0) as usize;
|
||||||
.as_array()
|
let mut all_files: Vec<FileInfo> = Vec::new();
|
||||||
.unwrap_or(&vec![])
|
|
||||||
.iter()
|
|
||||||
.filter_map(|f| {
|
|
||||||
let is_reg = f["is_registered"].as_bool().unwrap_or(false);
|
|
||||||
let file_uuid = f["file_uuid"].as_str()
|
|
||||||
.unwrap_or_else(|| f["file_path"].as_str().unwrap_or("")).to_string();
|
|
||||||
let status = f["status"].as_str().unwrap_or("").to_string();
|
|
||||||
Some(FileInfo {
|
|
||||||
file_uuid,
|
|
||||||
file_name: f["file_name"].as_str()?.to_string(),
|
|
||||||
file_path: f["file_path"].as_str().unwrap_or("").to_string(),
|
|
||||||
file_size: f["file_size"].as_i64().unwrap_or(0),
|
|
||||||
modified_time: f["modified_time"].as_str().unwrap_or("").to_string(),
|
|
||||||
is_registered: is_reg,
|
|
||||||
registration_time: f["registration_time"].as_str().map(|s| s.to_string()),
|
|
||||||
ingested: matches!(status.as_str(), "completed" | "keyword_ready" | "semantic_ready" | "face_mgmt_ready" | "agent_ready"),
|
|
||||||
status,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(files)
|
// 解析第一页的文件
|
||||||
|
if let Some(files_array) = json["data"].as_array() {
|
||||||
|
for f in files_array {
|
||||||
|
if let Some(file_info) = parse_file_info(f) {
|
||||||
|
all_files.push(file_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算总页数
|
||||||
|
let total_pages = (total + per_page - 1) / per_page;
|
||||||
|
|
||||||
|
// 获取剩余页(如果有限制)
|
||||||
|
let max_files = std::cmp::min(page_size, total);
|
||||||
|
let max_pages = (max_files + per_page - 1) / per_page;
|
||||||
|
|
||||||
|
for page in 2..=max_pages.min(total_pages) {
|
||||||
|
if all_files.len() >= page_size {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let url = format!("{}/api/v1/files?api_key={}&page={}&per_page={}", CORE_API, API_KEY, page, per_page);
|
||||||
|
let response = client.get(&url).send().await.map_err(|e| format!("Request failed: {}", e))?;
|
||||||
|
let json: serde_json::Value = response.json().await.map_err(|e| format!("Parse failed: {}", e))?;
|
||||||
|
|
||||||
|
if let Some(files_array) = json["data"].as_array() {
|
||||||
|
for f in files_array {
|
||||||
|
if all_files.len() >= page_size {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if let Some(file_info) = parse_file_info(f) {
|
||||||
|
all_files.push(file_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(all_files)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_file_info(f: &serde_json::Value) -> Option<FileInfo> {
|
||||||
|
let is_reg = f["is_registered"].as_bool().unwrap_or(false);
|
||||||
|
let file_uuid = f["file_uuid"].as_str()
|
||||||
|
.unwrap_or_else(|| f["file_path"].as_str().unwrap_or("")).to_string();
|
||||||
|
let status = f["status"].as_str().unwrap_or("").to_string();
|
||||||
|
Some(FileInfo {
|
||||||
|
file_uuid,
|
||||||
|
file_name: f["file_name"].as_str()?.to_string(),
|
||||||
|
file_path: f["file_path"].as_str().unwrap_or("").to_string(),
|
||||||
|
file_size: f["file_size"].as_i64().unwrap_or(0),
|
||||||
|
modified_time: f["modified_time"].as_str().unwrap_or("").to_string(),
|
||||||
|
is_registered: is_reg,
|
||||||
|
registration_time: f["registration_time"].as_str().map(|s| s.to_string()),
|
||||||
|
ingested: matches!(status.as_str(), "completed" | "keyword_ready" | "semantic_ready" | "face_mgmt_ready" | "agent_ready"),
|
||||||
|
status,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
|||||||
Reference in New Issue
Block a user