From a880c80556f995d158adc109a5d1b6b84960f80d Mon Sep 17 00:00:00 2001 From: Accusys Date: Sun, 17 May 2026 22:16:20 +0800 Subject: [PATCH] fix: face_detections INSERT in pipeline, add dependency graph doc --- .../API_WORKSPACE/modules/10_pipeline.md | 69 ++++++++++++++--- docs_v1.0/doc/10_pipeline.html | 74 ++++++++++++++++--- src/core/db/postgres_db.rs | 15 ++++ src/worker/processor.rs | 15 +++- 4 files changed, 149 insertions(+), 24 deletions(-) diff --git a/docs_v1.0/API_WORKSPACE/modules/10_pipeline.md b/docs_v1.0/API_WORKSPACE/modules/10_pipeline.md index 73b3bc8..20f2e04 100644 --- a/docs_v1.0/API_WORKSPACE/modules/10_pipeline.md +++ b/docs_v1.0/API_WORKSPACE/modules/10_pipeline.md @@ -4,6 +4,52 @@ ## Pipeline +### Dependency Graph + +```mermaid +flowchart TB + subgraph Processors["10 Processors"] + Cut[Cut] --> ASR[ASR] + ASR --> ASRX[ASRX] + ASRX --> Story[Story] + Cut --> Story + YOLO[YOLO] --> VisualChunk[VisualChunk] + VisualChunk --> Story + Face[Face] --> Story + Story --> FiveW1H[5W1H] + OCR[OCR] + Pose[Pose] + end + + subgraph Ingestion["入庫 (Post-Processing)"] + ASR --> Rule1[Rule 1 Sentence] + ASRX --> Rule1 + Rule1 --> Vectorize[Auto-Vectorize] + Rule1 --> Phase1[Phase 1 Pack] + + Cut --> Rule3[Rule 3 Scene] + ASR --> Rule3 + + Face --> Trace[Face Trace] + Trace --> Qdrant[Qdrant Sync] + Trace --> TraceChunks[Trace Chunks] + Trace --> TKG[TKG Builder] + + Face --> TMDbMatch[TMDb Match] + Face --> SceneMeta[Scene Metadata] + YOLO --> SceneMeta + Face --> IdentityAgent[Identity Agent] + ASRX --> IdentityAgent + + Cut --> Agent5W1H[5W1H Agent] + ASR --> Agent5W1H + Agent5W1H --> Phase2[Phase 2 Pack] + end + + style Processors fill:#1a1a2e,stroke:#e94560 + style Ingestion fill:#16213e,stroke:#0f3460 +``` + ### 10 Processor Stages | # | Processor | Depends On | Description | @@ -16,7 +62,7 @@ | 6 | `Face` | — | Face detection + recognition (InsightFace + CoreML) | | 7 | `Pose` | — | Pose estimation | | 8 | `VisualChunk` | YOLO | Visual object chunking | -| 9 | `Story` | ASRX + Cut | Narrative scene summarization (LLM, with embedding) | +| 9 | `Story` | ASRX + Cut + YOLO + Face | Narrative scene summarization (LLM, with embedding) | | 10 | `5W1H` | Story | Who/What/When/Where/Why extraction (LLM, with embedding) | ### Post-Processing (入庫) @@ -27,16 +73,17 @@ After all 10 processors complete, the pipeline runs the following storage & enri |---|------|----------|----------| | 1 | **Rule 1 Sentence Chunking** | ASR + ASRX | `chunk` table, `chunk_type = 'sentence'` | | 2 | **Auto-Vectorize** | Rule 1 | `chunk.embedding` IS NOT NULL (pgvector) | -| 3 | **Rule 3 Scene Chunking** | Cut + ASR | `chunk` table, `chunk_type = 'cut'` | -| 4 | **Face Trace + DB Store** | Face | `face_detections.trace_id` IS NOT NULL | -| 5 | **Qdrant Face Sync** | Face Trace | Qdrant collection (face embeddings) | -| 6 | **Trace Chunks** | Face Trace | `chunk` table, `chunk_type = 'trace'` | -| 7 | **TKG Builder** | Face Trace | `tkg_nodes` + `tkg_edges` tables | -| 8 | **TMDb Face Matching** | Face + TMDb enabled | `face_detections.identity_id` IS NOT NULL | -| 9 | **Heuristic Scene Metadata** | Face + YOLO | `{file_uuid}.scene_meta.json` on disk | -| 10 | **Identity Agent** | Face + ASRX | `identities` with `source = 'identity_agent'` | -| 11 | **5W1H Agent** | Cut + ASR | `chunk.summary_text` IS NOT NULL (chunk_type = 'cut') | -| 12 | **Release Pack** | 5W1H Agent | `release_pack.py --phase 2` output | +| 3 | **Phase 1 Pack** | Rule 1 | `release_pack.py --phase 1` | +| 4 | **Rule 3 Scene Chunking** | Cut + ASR | `chunk` table, `chunk_type = 'cut'` | +| 5 | **Face Trace** | Face | `face_detections.trace_id` IS NOT NULL | +| 6 | **Qdrant Face Sync** | Face Trace | Qdrant face_embedding collection | +| 7 | **Trace Chunks** | Face Trace | `chunk` table, `chunk_type = 'trace'` | +| 8 | **TKG Builder** | Face Trace | `tkg_nodes` + `tkg_edges` tables | +| 9 | **TMDb Face Matching** | Face + TMDb enabled | `face_detections.identity_id` IS NOT NULL | +| 10 | **Heuristic Scene Metadata** | Face + YOLO | `{file_uuid}.scene_meta.json` on disk | +| 11 | **Identity Agent** | Face + ASRX | `identities` with `source = 'identity_agent'` | +| 12 | **5W1H Agent** | Cut + ASR | `chunk.summary_text` IS NOT NULL (chunk_type = 'cut') | +| 13 | **Release Pack** | 5W1H Agent | `release_pack.py --phase 2` output | ### Ingestion Status diff --git a/docs_v1.0/doc/10_pipeline.html b/docs_v1.0/doc/10_pipeline.html index cfda8a3..937c7cb 100644 --- a/docs_v1.0/doc/10_pipeline.html +++ b/docs_v1.0/doc/10_pipeline.html @@ -30,6 +30,50 @@ a { color: #0066cc; }

Pipeline

+

Dependency Graph

+
flowchart TB
+    subgraph Processors["10 Processors"]
+        Cut[Cut] --> ASR[ASR]
+        ASR --> ASRX[ASRX]
+        ASRX --> Story[Story]
+        Cut --> Story
+        YOLO[YOLO] --> VisualChunk[VisualChunk]
+        VisualChunk --> Story
+        Face[Face] --> Story
+        Story --> FiveW1H[5W1H]
+        OCR[OCR]
+        Pose[Pose]
+    end
+
+    subgraph Ingestion["入庫 (Post-Processing)"]
+        ASR --> Rule1[Rule 1 Sentence]
+        ASRX --> Rule1
+        Rule1 --> Vectorize[Auto-Vectorize]
+        Rule1 --> Phase1[Phase 1 Pack]
+
+        Cut --> Rule3[Rule 3 Scene]
+        ASR --> Rule3
+
+        Face --> Trace[Face Trace]
+        Trace --> Qdrant[Qdrant Sync]
+        Trace --> TraceChunks[Trace Chunks]
+        Trace --> TKG[TKG Builder]
+
+        Face --> TMDbMatch[TMDb Match]
+        Face --> SceneMeta[Scene Metadata]
+        YOLO --> SceneMeta
+        Face --> IdentityAgent[Identity Agent]
+        ASRX --> IdentityAgent
+
+        Cut --> Agent5W1H[5W1H Agent]
+        ASR --> Agent5W1H
+        Agent5W1H --> Phase2[Phase 2 Pack]
+    end
+
+    style Processors fill:#1a1a2e,stroke:#e94560
+    style Ingestion fill:#16213e,stroke:#0f3460
+
+

10 Processor Stages

@@ -92,7 +136,7 @@ a { color: #0066cc; } - + @@ -129,60 +173,66 @@ a { color: #0066cc; } + + + + + + - - + + - + - + - + - + - + - + - + - + - + diff --git a/src/core/db/postgres_db.rs b/src/core/db/postgres_db.rs index ce03dfc..3dc9120 100644 --- a/src/core/db/postgres_db.rs +++ b/src/core/db/postgres_db.rs @@ -2193,6 +2193,21 @@ impl PostgresDb { Ok(()) } + pub async fn store_face_detections_batch( + &self, uuid: &str, detections: &[(i64, f64, i32, i32, i32, i32, f32)] + ) -> Result<()> { + let table = schema::table_name("face_detections"); + for (frame, ts, x, y, w, h, conf) in detections { + sqlx::query(&format!( + "INSERT INTO {} (file_uuid, frame_number, timestamp_secs, x, y, width, height, confidence) \ + VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT DO NOTHING", table + )) + .bind(uuid).bind(frame).bind(ts).bind(x).bind(y).bind(w).bind(h).bind(conf) + .execute(&self.pool).await?; + } + Ok(()) + } + pub async fn store_scene_pre_chunks_batch(&self, uuid: &str, scenes: &[(i64, i64, i64, f64, f64, serde_json::Value)]) -> Result<()> { let table = schema::table_name("pre_chunks"); for (_i, _sf, _ef, start, end, data) in scenes { diff --git a/src/worker/processor.rs b/src/worker/processor.rs index 0a7c6c0..1631914 100644 --- a/src/worker/processor.rs +++ b/src/worker/processor.rs @@ -887,12 +887,14 @@ impl ProcessorPool { ) -> Result<()> { let frames_count = face_result.frames.len(); tracing::info!( - "Storing {} Face pre-chunks for video {}", + "Storing {} Face pre-chunks + {} detections for video {}", frames_count, + face_result.frames.iter().map(|f| f.faces.len()).sum::(), uuid ); let mut pre_chunks_to_store = Vec::new(); + let mut detections_to_store = Vec::new(); for frame in face_result.frames.iter() { let data = serde_json::json!({ @@ -901,10 +903,21 @@ impl ProcessorPool { }); pre_chunks_to_store.push((frame.frame as i64, Some(frame.timestamp), data, None, None)); + + for face in frame.faces.iter() { + detections_to_store.push(( + frame.frame as i64, + frame.timestamp, + face.x, face.y, face.width, face.height, + face.confidence, + )); + } } db.store_raw_pre_chunks_batch(uuid, "face", &pre_chunks_to_store) .await?; + db.store_face_detections_batch(uuid, &detections_to_store) + .await?; Ok(()) }
9 StoryASRX + CutASRX + Cut + YOLO + Face Narrative scene summarization (LLM, with embedding)
3Phase 1 PackRule 1release_pack.py --phase 1
4 Rule 3 Scene Chunking Cut + ASR chunk table, chunk_type = 'cut'
4Face Trace + DB Store5Face Trace Face face_detections.trace_id IS NOT NULL
56 Qdrant Face Sync Face TraceQdrant collection (face embeddings)Qdrant face_embedding collection
67 Trace Chunks Face Trace chunk table, chunk_type = 'trace'
78 TKG Builder Face Trace tkg_nodes + tkg_edges tables
89 TMDb Face Matching Face + TMDb enabled face_detections.identity_id IS NOT NULL
910 Heuristic Scene Metadata Face + YOLO {file_uuid}.scene_meta.json on disk
1011 Identity Agent Face + ASRX identities with source = 'identity_agent'
1112 5W1H Agent Cut + ASR chunk.summary_text IS NOT NULL (chunk_type = 'cut')
1213 Release Pack 5W1H Agent release_pack.py --phase 2 output