refactor(tkg): remove dead code - FaceTraceRow, FaceDetectionRow, build_face_track_nodes_from_face_json
This commit is contained in:
@@ -613,34 +613,6 @@ struct AsrxSpeakerStat {
|
||||
count: i64,
|
||||
}
|
||||
|
||||
// ── Face detection trace ──────────────────────────────────────────
|
||||
|
||||
#[derive(Debug, sqlx::FromRow)]
|
||||
struct FaceTraceRow {
|
||||
trace_id: i64,
|
||||
frame_count: i64,
|
||||
start_f: i64,
|
||||
end_f: i64,
|
||||
avg_x: Option<f64>,
|
||||
avg_y: Option<f64>,
|
||||
avg_w: Option<f64>,
|
||||
avg_h: Option<f64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, sqlx::FromRow)]
|
||||
struct FaceDetectionRow {
|
||||
trace_id: i64,
|
||||
frame_number: i64,
|
||||
#[allow(dead_code)]
|
||||
x: Option<f64>,
|
||||
#[allow(dead_code)]
|
||||
y: Option<f64>,
|
||||
#[allow(dead_code)]
|
||||
width: Option<f64>,
|
||||
#[allow(dead_code)]
|
||||
height: Option<f64>,
|
||||
}
|
||||
|
||||
// ── Public API ────────────────────────────────────────────────────
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
@@ -1193,135 +1165,6 @@ async fn build_face_track_nodes_from_qdrant(
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
async fn build_face_track_nodes_from_face_json(
|
||||
pool: &PgPool,
|
||||
file_uuid: &str,
|
||||
pose_data: &[FacePose],
|
||||
) -> Result<usize> {
|
||||
let face_json_path =
|
||||
Path::new(&*crate::core::config::OUTPUT_DIR).join(format!("{}.face.json", file_uuid));
|
||||
|
||||
if !face_json_path.exists() {
|
||||
tracing::info!("[TKG-Phase2.5] No face.json for {}", file_uuid);
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let content = std::fs::read_to_string(&face_json_path)
|
||||
.with_context(|| format!("Failed to read {:?}", face_json_path))?;
|
||||
let face_result: crate::core::processor::face::FaceResult = serde_json::from_str(&content)
|
||||
.with_context(|| format!("Failed to parse {:?}", face_json_path))?;
|
||||
|
||||
// Extract faces with embeddings
|
||||
let faces_with_embeddings: Vec<(u64, f64, crate::core::processor::face::Face)> = face_result
|
||||
.frames
|
||||
.iter()
|
||||
.flat_map(|frame| {
|
||||
frame.faces.iter().filter_map(|face| {
|
||||
if let Some(ref embedding) = face.embedding {
|
||||
Some((frame.frame, frame.timestamp, face.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
if faces_with_embeddings.is_empty() {
|
||||
tracing::info!(
|
||||
"[TKG-Phase2.5] No embeddings in face.json for {}",
|
||||
file_uuid
|
||||
);
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
tracing::info!(
|
||||
"[TKG-Phase2.5] Found {} faces with embeddings in face.json",
|
||||
faces_with_embeddings.len()
|
||||
);
|
||||
|
||||
// Simple clustering: assign trace_id based on consecutive similar embeddings
|
||||
let nodes_table = t("tkg_nodes");
|
||||
let mut trace_id = 1_i64;
|
||||
let mut traces: Vec<(i64, Vec<(u64, f64, f64, f64, f64, f64)>)> = vec![];
|
||||
|
||||
for (frame, timestamp, face) in &faces_with_embeddings {
|
||||
// For simplicity, assign all faces to one trace (proper clustering requires DBSCAN)
|
||||
if traces.is_empty() {
|
||||
traces.push((trace_id, vec![]));
|
||||
}
|
||||
traces[0].1.push((
|
||||
*frame,
|
||||
*timestamp,
|
||||
face.x as f64,
|
||||
face.y as f64,
|
||||
face.width as f64,
|
||||
face.height as f64,
|
||||
));
|
||||
}
|
||||
|
||||
let mut count = 0;
|
||||
for (tid, frames) in &traces {
|
||||
let external_id = format!("face_track_{}", tid);
|
||||
let label = format!("Face Trace {}", tid);
|
||||
|
||||
let frame_count = frames.len() as i64;
|
||||
let start_f = frames
|
||||
.iter()
|
||||
.map(|(f, _, _, _, _, _)| *f as i64)
|
||||
.min()
|
||||
.unwrap_or(0);
|
||||
let end_f = frames
|
||||
.iter()
|
||||
.map(|(f, _, _, _, _, _)| *f as i64)
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
let avg_x = frames.iter().map(|(_, _, x, _, _, _)| *x).sum::<f64>() / frame_count as f64;
|
||||
let avg_y = frames.iter().map(|(_, _, _, y, _, _)| *y).sum::<f64>() / frame_count as f64;
|
||||
let avg_w = frames.iter().map(|(_, _, _, _, w, _)| *w).sum::<f64>() / frame_count as f64;
|
||||
let avg_h = frames.iter().map(|(_, _, _, _, _, h)| *h).sum::<f64>() / frame_count as f64;
|
||||
|
||||
let props = serde_json::json!({
|
||||
"trace_id": tid,
|
||||
"frame_count": frame_count,
|
||||
"start_frame": start_f,
|
||||
"end_frame": end_f,
|
||||
"avg_bbox": {
|
||||
"x": avg_x.round() as i64,
|
||||
"y": avg_y.round() as i64,
|
||||
"width": avg_w.round() as i64,
|
||||
"height": avg_h.round() as i64,
|
||||
},
|
||||
});
|
||||
|
||||
sqlx::query(&format!(
|
||||
r#"
|
||||
INSERT INTO {} (node_type, external_id, file_uuid, label, properties)
|
||||
VALUES ($1, $2, $3, $4, $5::jsonb)
|
||||
ON CONFLICT (file_uuid, node_type, external_id)
|
||||
DO UPDATE SET
|
||||
properties = COALESCE(EXCLUDED.properties, tkg_nodes.properties),
|
||||
label = COALESCE(NULLIF(EXCLUDED.label, ''), tkg_nodes.label)
|
||||
"#,
|
||||
nodes_table
|
||||
))
|
||||
.bind("face_track")
|
||||
.bind(&external_id)
|
||||
.bind(file_uuid)
|
||||
.bind(&label)
|
||||
.bind(serde_json::to_string(&props)?)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
count += 1;
|
||||
}
|
||||
|
||||
tracing::info!(
|
||||
"[TKG-Phase2.5] Built {} face_track nodes from face.json",
|
||||
count
|
||||
);
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
async fn build_yolo_object_nodes(
|
||||
pool: &PgPool,
|
||||
file_uuid: &str,
|
||||
|
||||
Reference in New Issue
Block a user