feat: backup architecture docs, source code, and scripts
This commit is contained in:
147
src/api/who.rs
Normal file
147
src/api/who.rs
Normal file
@@ -0,0 +1,147 @@
|
||||
//! Who API - 身份識別與 ID 映射接口 (Video-Scoped)
|
||||
|
||||
use axum::{
|
||||
extract::State,
|
||||
http::StatusCode,
|
||||
response::Json,
|
||||
routing::{get, post},
|
||||
Router,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::core::db::Database;
|
||||
|
||||
// --- Request / Response Structures ---
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct WhoQuery {
|
||||
pub face_id: Option<String>,
|
||||
pub speaker_id: Option<String>,
|
||||
pub uuid: Option<String>,
|
||||
pub chunk_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct WhoCandidatesRequest {
|
||||
pub query: String,
|
||||
pub video_uuid: Option<String>,
|
||||
pub limit: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct DefinePersonRequest {
|
||||
pub uuid: String,
|
||||
pub identity_id: Option<i32>,
|
||||
pub name: String,
|
||||
pub face_ids: Option<Vec<String>>,
|
||||
pub speaker_ids: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct WhoIdentity {
|
||||
pub identity_id: i32,
|
||||
pub uuid: String,
|
||||
pub name: String,
|
||||
pub tags: Option<Vec<String>>,
|
||||
pub face_ids: Vec<String>,
|
||||
pub speaker_ids: Vec<String>,
|
||||
}
|
||||
|
||||
// --- API Handlers ---
|
||||
|
||||
/// GET /api/v1/who
|
||||
pub async fn get_who_identity(
|
||||
State(state): State<crate::api::server::AppState>,
|
||||
axum::extract::Query(query): axum::extract::Query<WhoQuery>,
|
||||
) -> Result<Json<serde_json::Value>, (StatusCode, Json<serde_json::Value>)> {
|
||||
let db = &state.db;
|
||||
|
||||
// Priority 1: Query by Chunk (UUID + Chunk ID)
|
||||
if let (Some(uuid), Some(chunk_id)) = (&query.uuid, &query.chunk_id) {
|
||||
let info = db
|
||||
.get_who_info_by_chunk(uuid, chunk_id)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(serde_json::json!({ "error": e.to_string() })),
|
||||
)
|
||||
})?;
|
||||
return Ok(Json(info));
|
||||
}
|
||||
|
||||
// Priority 2: List all for a specific UUID
|
||||
if let Some(uuid) = &query.uuid {
|
||||
// TODO: Implement list_all_persons(uuid)
|
||||
return Ok(Json(serde_json::json!({ "message": "List all pending" })));
|
||||
}
|
||||
|
||||
Err((
|
||||
StatusCode::BAD_REQUEST,
|
||||
Json(serde_json::json!({ "error": "Missing uuid" })),
|
||||
))
|
||||
}
|
||||
|
||||
/// POST /api/v1/who/candidates
|
||||
/// Search person_identities table for n8n workflow
|
||||
pub async fn get_who_candidates(
|
||||
State(state): State<crate::api::server::AppState>,
|
||||
Json(req): Json<WhoCandidatesRequest>,
|
||||
) -> Result<Json<serde_json::Value>, (StatusCode, Json<serde_json::Value>)> {
|
||||
let db = &state.db;
|
||||
let limit = req.limit.unwrap_or(20);
|
||||
let query_str = format!("%{}%", req.query);
|
||||
|
||||
let results = db
|
||||
.search_person_candidates(&query_str, &req.video_uuid, limit)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(serde_json::json!({ "error": e.to_string() })),
|
||||
)
|
||||
})?;
|
||||
|
||||
// Format for n8n
|
||||
let response = serde_json::json!({
|
||||
"query": req.query,
|
||||
"items": results,
|
||||
"total": results.len()
|
||||
});
|
||||
|
||||
Ok(Json(response))
|
||||
}
|
||||
|
||||
/// POST /api/v1/who
|
||||
pub async fn define_person(
|
||||
State(state): State<crate::api::server::AppState>,
|
||||
Json(req): Json<DefinePersonRequest>,
|
||||
) -> Result<Json<WhoIdentity>, (StatusCode, Json<serde_json::Value>)> {
|
||||
let db = &state.db;
|
||||
|
||||
let identity = db
|
||||
.create_or_update_person(
|
||||
&req.uuid,
|
||||
req.identity_id,
|
||||
req.name.clone(),
|
||||
req.face_ids.unwrap_or_default(),
|
||||
req.speaker_ids.unwrap_or_default(),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(serde_json::json!({ "error": e.to_string() })),
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(Json(identity))
|
||||
}
|
||||
|
||||
// --- Router Setup ---
|
||||
|
||||
pub fn who_routes() -> Router<crate::api::server::AppState> {
|
||||
Router::new()
|
||||
.route("/api/v1/who", get(get_who_identity).post(define_person))
|
||||
.route("/api/v1/who/candidates", post(get_who_candidates))
|
||||
}
|
||||
Reference in New Issue
Block a user