All API through Rust proxy, fix unregistered files null uuid, People enhancements

This commit is contained in:
2026-06-14 11:05:23 +08:00
parent a700cc983e
commit 3ba2120c8e
8 changed files with 265 additions and 45 deletions

View File

@@ -16,6 +16,7 @@ serde_json = "1"
sqlx = { version = "0.7", features = ["runtime-tokio", "postgres", "json"] }
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }
base64 = "0.22"
[build-dependencies]
tauri-build = { version = "2", features = [] }

View File

@@ -1,6 +1,7 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use serde::Serialize;
use base64::{Engine as _, engine::general_purpose::STANDARD};
#[derive(Serialize)]
struct SearchResult {
@@ -18,6 +19,7 @@ struct FileInfo {
file_name: String,
file_size: i64,
modified_time: String,
#[serde(rename = "isRegistered")]
is_registered: bool,
}
@@ -84,8 +86,15 @@ async fn search_llm_smart(query: String, limit: usize) -> Result<Vec<SearchResul
Ok(results)
}
#[derive(serde::Deserialize)]
struct GetFilesArgs {
#[serde(rename = "pageSize")]
page_size: usize,
}
#[tauri::command]
async fn get_files(page_size: usize) -> Result<Vec<FileInfo>, String> {
async fn get_files(args: GetFilesArgs) -> Result<Vec<FileInfo>, String> {
let page_size = args.page_size;
let client = reqwest::Client::new();
let url = format!("{}/api/v1/files/scan?api_key={}&page_size={}", CORE_API, API_KEY, page_size);
@@ -97,12 +106,15 @@ async fn get_files(page_size: usize) -> Result<Vec<FileInfo>, String> {
.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();
Some(FileInfo {
file_uuid: f["file_uuid"].as_str()?.to_string(),
file_uuid,
file_name: f["file_name"].as_str()?.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: f["is_registered"].as_bool().unwrap_or(false),
is_registered: is_reg,
})
})
.collect();
@@ -112,8 +124,14 @@ async fn get_files(page_size: usize) -> Result<Vec<FileInfo>, String> {
#[tauri::command]
async fn get_people(page: usize, per_page: usize) -> Result<Vec<PersonInfo>, String> {
eprintln!("[get_people] page={} per_page={}", page, per_page);
let client = reqwest::Client::new();
let url = format!("{}/api/v1/identities?api_key={}&page={}&per_page={}", CORE_API, API_KEY, page, per_page);
eprintln!("[get_people] url={}", url);
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))?;
eprintln!("[get_people] identities count: {}", json["identities"].as_array().map(|a| a.len()).unwrap_or(0));
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))?;
@@ -130,6 +148,7 @@ async fn get_people(page: usize, per_page: usize) -> Result<Vec<PersonInfo>, Str
})
.collect();
eprintln!("[get_people] returning {} people", people.len());
Ok(people)
}
@@ -185,6 +204,76 @@ async fn get_traces(uuid: String, per_page: usize) -> Result<Vec<TraceInfo>, Str
Ok(traces)
}
#[tauri::command]
async fn get_thumbnail(uuid: String, frame: u32) -> Result<String, String> {
let url = format!("{}/api/v1/file/{}/thumbnail?api_key={}&frame={}", CORE_API, uuid, API_KEY, frame);
let bytes = reqwest::get(&url).await
.map_err(|e| format!("Thumbnail request failed: {}", e))?
.bytes().await
.map_err(|e| format!("Thumbnail read failed: {}", e))?;
Ok(format!("data:image/jpeg;base64,{}", STANDARD.encode(&bytes)))
}
#[tauri::command]
async fn get_video_stream(uuid: String, start_time: f64, end_time: f64) -> Result<String, String> {
let url = format!("{}/api/v1/file/{}/video?api_key={}&start_time={}&end_time={}", CORE_API, uuid, API_KEY, start_time, end_time);
let bytes = reqwest::get(&url).await
.map_err(|e| format!("Video request failed: {}", e))?
.bytes().await
.map_err(|e| format!("Video read failed: {}", e))?;
Ok(format!("data:video/mp4;base64,{}", STANDARD.encode(&bytes)))
}
const PROFILE_DIRS: &[&str] = &[
"/Users/accusys/momentry/output/identities",
"/Users/accusys/momentry/output_dev/identities",
];
#[tauri::command]
async fn get_identity_profile(uuid: String) -> Result<String, String> {
let no_dash = uuid.replace('-', "");
for dir in PROFILE_DIRS {
let path = format!("{}/{}/profile.jpg", dir, no_dash);
if std::path::Path::new(&path).exists() {
let bytes = std::fs::read(&path).map_err(|e| format!("Read failed: {}", e))?;
return Ok(format!("data:image/jpeg;base64,{}", STANDARD.encode(&bytes)));
}
let path = format!("{}/{}/profile.jpg", dir, uuid);
if std::path::Path::new(&path).exists() {
let bytes = std::fs::read(&path).map_err(|e| format!("Read failed: {}", e))?;
return Ok(format!("data:image/jpeg;base64,{}", STANDARD.encode(&bytes)));
}
}
Err("Profile image not found".to_string())
}
#[tauri::command]
async fn update_identity_name(uuid: String, name: String) -> Result<(), String> {
let client = reqwest::Client::new();
let url = format!("{}/api/v1/identity/{}?api_key={}", CORE_API, uuid, API_KEY);
let resp = client.patch(&url)
.json(&serde_json::json!({"name": name}))
.send().await
.map_err(|e| format!("Request failed: {}", e))?;
if !resp.status().is_success() {
return Err(format!("Update failed: {}", resp.status()));
}
Ok(())
}
#[tauri::command]
async fn delete_identity(uuid: String) -> Result<(), String> {
let client = reqwest::Client::new();
let url = format!("{}/api/v1/identity/{}?api_key={}", CORE_API, uuid, API_KEY);
let resp = client.delete(&url)
.send().await
.map_err(|e| format!("Request failed: {}", e))?;
if !resp.status().is_success() && resp.status() != 204 {
return Err(format!("Delete failed: {}", resp.status()));
}
Ok(())
}
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_shell::init())
@@ -193,7 +282,12 @@ fn main() {
get_files,
get_people,
get_faces,
get_traces
get_traces,
get_thumbnail,
get_video_stream,
get_identity_profile,
update_identity_name,
delete_identity
])
.run(tauri::generate_context!())
.expect("error while running tauri application");