cleanup: remove dead code and duplicate docs

- Remove session-ses_2f27.md (161KB raw session log)
- Remove 49 ROOT_* duplicate files across REFERENCE/
- Remove 14 duplicate files between REFERENCE/ root and history/
- Remove asr_legacy.rs (dead code, replaced by asr.rs)
- Remove src/core/worker/ (duplicate JobWorker)
- Remove src/core/layers/ (empty directory)
- Remove 4 .bak files in src/
- Remove 7 dead private methods in worker/processor.rs
- Remove backup directory from git tracking
This commit is contained in:
Warren
2026-05-04 01:31:21 +08:00
parent ee81e343ce
commit e75c4d6f07
3270 changed files with 35190 additions and 53367 deletions

View File

@@ -103,8 +103,14 @@ pub fn face_recognition_routes() -> Router<crate::api::server::AppState> {
.route("/api/v1/face/register", post(register_face_api))
.route("/api/v1/face/search", post(search_faces))
.route("/api/v1/face/list", get(list_faces))
.route("/api/v1/face/:face_id", get(get_face_details))
.route("/api/v1/face/:face_id", axum::routing::delete(delete_face))
.route(
"/api/v1/files/:file_uuid/faces/:face_id",
get(get_face_details),
)
.route(
"/api/v1/files/:file_uuid/faces/:face_id",
axum::routing::delete(delete_face),
)
.route(
"/api/v1/face/results/:file_uuid",
get(get_recognition_results),
@@ -550,7 +556,7 @@ async fn list_faces(
async fn get_face_details(
State(_state): State<crate::api::server::AppState>,
Path(face_id): Path<String>,
Path((file_uuid, face_id)): Path<(String, String)>,
) -> Result<Json<serde_json::Value>, (StatusCode, String)> {
let db = match PostgresDb::init().await {
Ok(db) => db,
@@ -575,7 +581,7 @@ async fn get_face_details(
updated_at,
is_active
FROM {}
WHERE face_id = $1
WHERE face_id = $1 AND file_uuid = $2
"#,
face_identities_table
);
@@ -591,6 +597,7 @@ async fn get_face_details(
bool,
)> = match sqlx::query_as(&query)
.bind(&face_id)
.bind(&file_uuid)
.fetch_optional(db.pool())
.await
{
@@ -637,7 +644,7 @@ async fn get_face_details(
async fn delete_face(
State(_state): State<crate::api::server::AppState>,
Path(face_id): Path<String>,
Path((file_uuid, face_id)): Path<(String, String)>,
) -> Result<Json<serde_json::Value>, (StatusCode, String)> {
let db = match PostgresDb::init().await {
Ok(db) => db,
@@ -655,7 +662,7 @@ async fn delete_face(
r#"
UPDATE {}
SET is_active = FALSE, updated_at = CURRENT_TIMESTAMP
WHERE face_id = $1 AND is_active = TRUE
WHERE face_id = $1 AND file_uuid = $2 AND is_active = TRUE
RETURNING face_id, name
"#,
face_identities_table
@@ -663,6 +670,7 @@ async fn delete_face(
let deleted: Option<(String, Option<String>)> = match sqlx::query_as(&query)
.bind(&face_id)
.bind(&file_uuid)
.fetch_optional(db.pool())
.await
{

View File

@@ -56,7 +56,10 @@ pub fn identity_routes() -> Router<crate::api::server::AppState> {
"/api/v1/identities/:identity_id/faces",
get(get_identity_faces),
)
.route("/api/v1/faces/:face_id/thumbnail", get(get_face_thumbnail))
.route(
"/api/v1/files/:file_uuid/faces/:face_id/thumbnail",
get(get_face_thumbnail),
)
}
/// Register a Global Identity from face.json with multi-angle reference vectors.
@@ -719,7 +722,7 @@ async fn get_identity_faces(
}
async fn get_face_thumbnail(
Path(face_id): Path<i32>,
Path((file_uuid, face_id)): Path<(String, i32)>,
) -> Result<impl IntoResponse, (StatusCode, String)> {
let db = match PostgresDb::init().await {
Ok(db) => db,
@@ -738,12 +741,13 @@ async fn get_face_thumbnail(
"SELECT fd.frame_number, fd.bbox, v.file_path, v.fps
FROM {} fd
JOIN {} v ON fd.file_uuid = v.uuid
WHERE fd.id = $1",
WHERE fd.id = $1 AND fd.file_uuid = $2",
table_fd, table_v
);
let row: Option<(i64, Option<serde_json::Value>, String, f64)> = match sqlx::query_as(&sql)
.bind(face_id)
.bind(&file_uuid)
.fetch_optional(db.pool())
.await
{

View File

@@ -29,6 +29,70 @@ pub fn identity_routes() -> Router<crate::api::server::AppState> {
pub struct FilesQuery {
page: Option<usize>,
page_size: Option<usize>,
uuid: Option<String>, // Add uuid filter
}
async fn list_files(
State(state): State<crate::api::server::AppState>,
Query(params): Query<FilesQuery>,
) -> Result<Json<FilesResponse>, (StatusCode, String)> {
let page = params.page.unwrap_or(1);
let page_size = params.page_size.unwrap_or(20);
// If UUID is provided, fetch that specific file and return it as a list item
if let Some(ref uuid) = params.uuid {
let video = state
.db
.get_video_by_uuid(uuid)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
let data = if let Some(v) = video {
vec![FileItem {
file_uuid: v.file_uuid,
file_name: v.file_name,
file_path: v.file_path,
status: v.status.as_str().to_string(),
}]
} else {
vec![]
};
return Ok(Json(FilesResponse {
success: true,
total: data.len() as i64,
page,
page_size,
data,
}));
}
// Default: List files with pagination
let offset = ((page - 1) as i64) * (page_size as i64);
let records = state
.db
.list_files(page_size as i32, offset)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
let data = records
.into_iter()
.map(|r| FileItem {
file_uuid: r.file_uuid,
file_name: r.file_name,
file_path: r.file_path,
status: "ready".to_string(), // Hardcoded for now
})
.collect();
Ok(Json(FilesResponse {
success: true,
total: 0, // TODO: Implement count query
page,
page_size,
data,
}))
}
#[derive(Debug, Serialize)]
@@ -45,40 +109,7 @@ pub struct FileItem {
pub file_uuid: String,
pub file_name: String,
pub file_path: String,
pub status: String, // From probe or processing status
}
async fn list_files(
State(state): State<crate::api::server::AppState>,
Query(params): Query<FilesQuery>,
) -> Result<Json<FilesResponse>, (StatusCode, String)> {
let page = params.page.unwrap_or(1);
let page_size = params.page_size.unwrap_or(20);
let offset = ((page - 1) as i64) * (page_size as i64);
let records = state
.db
.list_files(page_size as i32, offset)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
let data = records
.into_iter()
.map(|r| FileItem {
file_uuid: r.file_uuid,
file_name: r.file_name,
file_path: r.file_path,
status: "ready".to_string(),
})
.collect();
Ok(Json(FilesResponse {
success: true,
total: 0, // TODO
page,
page_size,
data,
}))
pub status: String,
}
#[derive(Debug, Serialize)]

View File

@@ -1,195 +0,0 @@
//! Smart Search API
//! Implements the 5W1H search capability using semantic vectors.
use axum::{extract::State, http::StatusCode, response::Json, routing::post, Router};
use serde::{Deserialize, Serialize};
use serde_json;
use tracing;
use crate::core::db::PostgresDb;
// --- Request / Response Structures ---
#[derive(Debug, Deserialize)]
pub struct SmartSearchRequest {
pub uuid: String,
pub query: String,
pub limit: Option<usize>,
}
#[derive(Debug, Serialize)]
pub struct SearchResult {
pub id: i32,
pub parent_id: i32,
pub scene_order: Option<i32>,
// Primary: frame-accurate position (authoritative unit)
pub start_frame: i64,
pub end_frame: i64,
pub fps: f64,
// Reference: time derived from frames (subject to FPS variation, not precise)
pub start_time: f64,
pub end_time: f64,
pub raw_text: Option<String>, // Text content of the child chunk
pub summary: Option<String>, // Summary from parent context
pub metadata: Option<serde_json::Value>,
pub similarity: Option<f64>,
}
#[derive(Debug, Serialize)]
pub struct SmartSearchResponse {
pub query: String,
pub results: Vec<SearchResult>,
pub strategy: String,
}
// --- API Handler ---
pub async fn smart_search(
State(state): State<crate::api::server::AppState>,
Json(req): Json<SmartSearchRequest>,
) -> Result<Json<SmartSearchResponse>, (StatusCode, Json<serde_json::Value>)> {
let db = &state.db;
let limit = req.limit.unwrap_or(5);
// 1. Generate Embedding using Ollama
let embedding = get_ollama_embedding(&req.query).await.map_err(
|e| -> (StatusCode, Json<serde_json::Value>) {
tracing::error!("Embedding failed: {}", e);
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(serde_json::json!({ "error": e.to_string() })),
)
},
)?;
// 2. Search Database (Drill-Down: Find Parents First)
let db_parents: Vec<crate::core::db::postgres_db::SemanticSearchResult> = db
.search_parent_chunks_semantic(&req.uuid, &embedding, limit)
.await
.map_err(
|e: anyhow::Error| -> (StatusCode, Json<serde_json::Value>) {
tracing::error!("DB search failed: {}", e);
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(serde_json::json!({ "error": e.to_string() })),
)
},
)?;
if db_parents.is_empty() {
return Ok(Json(SmartSearchResponse {
query: req.query,
results: vec![],
strategy: "semantic_vector_search".to_string(),
}));
}
// Collect Parent IDs
let parent_ids: Vec<i32> = db_parents.iter().map(|p| p.id).collect();
// 3. Fetch Children for these Parents (Drill Down)
// We fetch all children for these parents (limit can be adjusted)
let children: Vec<crate::core::db::postgres_db::ChildChunkResult> = db
.get_children_for_parents(&parent_ids, 10) // Fetch top 10 children per parent
.await
.map_err(
|e: anyhow::Error| -> (StatusCode, Json<serde_json::Value>) {
tracing::error!("Fetching children failed: {}", e);
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(serde_json::json!({ "error": e.to_string() })),
)
},
)?;
// 4. Map Parents to a lookup table
let parent_map: std::collections::HashMap<
i32,
&crate::core::db::postgres_db::SemanticSearchResult,
> = db_parents.iter().map(|p| (p.id, p)).collect();
// Map Children to API response struct
let results: Vec<SearchResult> = children
.into_iter()
.map(|c| {
let parent = parent_map.get(&c.parent_id);
SearchResult {
id: c.id,
parent_id: c.parent_id,
scene_order: parent.map(|p| p.scene_order),
start_frame: c.start_frame,
end_frame: c.end_frame,
fps: c.fps,
start_time: c.start_time,
end_time: c.end_time,
raw_text: Some(c.raw_text),
summary: parent.map(|p| p.summary.clone()),
metadata: parent.map(|p| p.metadata.clone()),
similarity: parent.and_then(|p| p.similarity),
}
})
.collect();
// 6. Sort results by similarity (descending)
// Since all children of a parent have the same parent similarity, this groups relevant chunks together
let mut results = results;
results.sort_by(|a, b| {
b.similarity
.partial_cmp(&a.similarity)
.unwrap_or(std::cmp::Ordering::Equal)
});
// 7. Limit the final results (optional, but good for API consistency)
let limit = req.limit.unwrap_or(5) * 5; // Allow more children per parent context
results.truncate(limit);
// 8. Format Response
let response = SmartSearchResponse {
query: req.query,
results,
strategy: "drill_down_semantic_search".to_string(),
};
Ok(Json(response))
}
// --- Helper: Ollama Embedding ---
async fn get_ollama_embedding(
text: &str,
) -> Result<Vec<f32>, Box<dyn std::error::Error + Send + Sync>> {
let client = reqwest::Client::new();
let payload = serde_json::json!({
"model": "nomic-embed-text",
"prompt": text
});
let res = client
.post("http://localhost:11434/api/embeddings")
.json(&payload)
.send()
.await?
.json::<serde_json::Value>()
.await?;
// Parse embedding array from response
let embedding = res["embedding"]
.as_array()
.ok_or("No embedding found in Ollama response")?
.iter()
.map(|v| v.as_f64().unwrap_or(0.0) as f32)
.collect();
Ok(embedding)
}
// --- Router Setup ---
pub fn search_routes() -> Router<crate::api::server::AppState> {
Router::new().route("/smart", post(smart_search))
}

File diff suppressed because it is too large Load Diff