Commit Graph

224 Commits

Author SHA1 Message Date
Accusys
3067896b0f fix: comprehensive fixes for ingestion and TKG
1. Add Redis PipelineProgress cleanup in unregister_internal
   - Deletes progress key when file is unregistered

2. Fix ingestion_complete asr_status query
   - Query ASRX first, then ASR
   - Filter out NULL values to avoid false negatives

3. Fix TKG 0 nodes/edges support
   - TKG is considered done if face traces are complete
   - TKG may create 0 nodes/edges for videos with minimal content

4. Add ASRX fallback to ASR segments
   - When ASRX has 0 segments but ASR has segments, use ASR segments
   - Ensures at least one ASRX output when ASR has content
2026-07-06 21:14:08 +08:00
Accusys
146d3cedb2 fix: update PipelineProgress when job completes via essential_completed path
When a job completes via the essential_completed branch (all essential
processors done but some non-essential failed), the PipelineProgress
was not being updated to 100%, causing a discrepancy where the status
showed 'completed' but progress showed <100%.

Now PipelineProgress.mark_completed() is called in both completion paths.
2026-07-06 19:08:56 +08:00
Accusys
765db8ae9f fix: TKG FPS calculation for ASRX fallback segments
When ASRX falls back to ASR segments, end_frame may be 0.
The FPS calculation now handles this case correctly by checking
both end_frame > 0 and end_time > 0 before dividing.

This prevents division by zero and incorrect FPS values when
processing videos with ASRX fallback segments.
2026-07-06 16:08:32 +08:00
Accusys
dd63dbff9b fix: support videos with no audio or no faces
1. trace_done now checks for 'no_faces' status in face_traced.json
   - Videos with no detected faces now complete correctly
   - Previously stuck because trace_count=0 returned false

2. ASRX fallback to ASR segments includes start_frame/end_frame
   - Added _convert_asr_segments_to_asrx helper function
   - TKG can now process fallback segments correctly

This allows processing of:
- Videos with no audio track (ASR: no_audio_track)
- Videos with no faces (face_traced.json: no_faces)
2026-07-06 15:54:14 +08:00
Accusys
e4fdbbc18a fix: clear stale PipelineProgress when new job starts
When a file is re-registered, the old PipelineProgress in Redis
was not cleared, causing the Portal to show 'completed' status
even though the new job was still running.

Now PipelineProgress is deleted when a new job starts processing.
2026-07-06 13:07:53 +08:00
Accusys
004ff9ad48 fix: ingestion_complete now checks TKG nodes before completing job
Previously, ingestion_complete only checked ASR and face traces,
causing jobs to complete before TKG was triggered. This resulted in
TKG nodes being 0 even after job completion.

Now ingestion_complete also checks if TKG nodes exist for the file.
The job stays in 'running' status until TKG completes.
2026-07-06 12:24:25 +08:00
Accusys
552f539bdf fix: remove TKG guard to prevent deadlock
The TKG guard was checking if nodes exist before spawning TKG build.
This caused a deadlock when:
1. TKG spawns (async)
2. ingestion_complete checks → false (nodes not yet created)
3. Returns Ok(false), job stays running
4. Next poll: guard checks nodes → no nodes yet (TKG still running)
5. Skips TKG → deadlock!

Since build_tkg uses ON CONFLICT (idempotent), it's safe to call
multiple times. Removed the guard to fix the deadlock.
2026-07-06 11:28:40 +08:00
Accusys
221aa4c4cc fix: worker detects deleted jobs and skips them
When a job is deleted from the database (e.g., by unregister),
the worker now checks if the job still exists before processing.
If the job no longer exists, it skips it instead of getting stuck.

This fixes the issue where unregistering a file would leave the
worker stuck trying to process a non-existent job.
2026-07-06 10:28:11 +08:00
Accusys
799ede5a0e feat: OCR independent chunks + TMDb seed with file_uuid
- Rule 1 now creates OCR-only chunks instead of merging into ASRX
- generate_seed_embeddings.py supports --file-uuid parameter
- get_seeds() filters by file_uuid
- identity_matcher.py uses file_uuid for seed matching
- Push QDRANT_API_KEY to Python subprocesses
- Face clustering uses frame+bbox matching instead of face_id
- Portal uses JWT authentication
- FilesView filter logic fixed
2026-07-06 08:56:56 +08:00
Accusys
e91d51cc5e feat: OCR independent chunks (方案 A) + stats API
Rule 1 now creates OCR chunks separately from ASRX segments:
- Phase 1: ASRX segments (pure speech, NO OCR merge)
- Phase 2: OCR-only chunks (all OCR frames grouped by proximity)

Added OCR statistics to ingestion status API:
- rule1_ocr: shows OCR pre_chunks count
- rule1_ocr_chunks: shows OCR-only chunks count

Example: FilmRiot_test now has 32 ASRX + 3 OCR-only = 35 chunks
Stats: rule1_sentence: 35, rule1_ocr: 30, rule1_ocr_chunks: 3
2026-07-05 23:31:06 +08:00
Accusys
5a3f791ecd feat: only run identity agent if file has seed identities
Identity agent now checks Qdrant _seeds collection for the file's
seed identity photos before running. If no seeds exist, the agent
is skipped to avoid unnecessary processing.

Flow:
1. Job completes (Face + ASRX done)
2. Check Qdrant _seeds for file_uuid
3. If seeds exist → run identity agent
4. If no seeds → skip identity agent
2026-07-05 22:22:22 +08:00
Accusys
0b82aa875c feat: Rule 1 now creates chunks for OCR-only text
Previously Rule 1 only created chunks from ASRX segments, merging OCR
text where frame ranges overlapped. OCR text that didn't overlap with
any ASRX segment was ignored.

Now Rule 1 has two phases:
1. Process ASRX segments (merge OCR where overlapping) - existing behavior
2. Create chunks for OCR-only text (frames not covered by ASRX)

OCR-only chunks are grouped by consecutive frames (within 5 frames)
to avoid creating too many single-frame chunks.

Example: ASRX 819 + OCR-only 4 = 823 sentence chunks
2026-07-05 22:06:35 +08:00
Accusys
465552f8b2 fix: remove duplicate 'asr' pre_chunks storage in ASRX handler
Bug: ASRX handler stored pre_chunks as BOTH 'asrx' and 'asr' types.
This caused confusion because Rule 1 queries 'asrx' type, but only
'asr' type existed in the database (asrx type was deleted or never stored).

Fix: Remove the duplicate 'asr' storage (lines 530-542).
ASRX handler now only stores 'asrx' type pre_chunks to workspace SQLite.
PostgreSQL pre_chunks are stored by processor.rs with correct 'asrx' type.

This ensures Rule 1 can find ASRX pre_chunks correctly.
2026-07-05 19:49:03 +08:00
Accusys
7fc4dcbddb feat: add media type and indexed status filters to FilesView
Frontend:
- Add media type filter (全部/影片/照片)
- Add indexed status filter (未入庫/已入庫)
- Show media type column with icons
- Fix status filter to handle indexed/unindexed correctly
- Determine media type from file extension

Backend:
- Add total_chunks field to FileItem API response
- Query chunk counts efficiently in batch with IN clause
- Frontend uses total_chunks to determine is_indexed status
2026-07-04 22:41:51 +08:00
Accusys
96e13e40cb fix: all_completed now checks ALL expected processors have results
Bug: all_completed only checked existing results, not missing processors.
If a processor (like pose) never created a result row, all_completed would
still return true and mark the job as completed.

Fix: all_completed now checks that every processor in job_processors has
a corresponding completed result. Added logging for missing processors.

Also fixed:
- any_pending now checks all expected processors, not just existing results
- Added missing_processors detection and logging
2026-07-04 22:09:38 +08:00
Accusys
4e8c0ea5b9 fix: skip empty ASRX segments in Rule 1, fix chunk_id numbering
- Skip chunks where both ASRX text and OCR text are empty
- Use count-based chunk_id instead of index to avoid gaps
- This ensures PostgreSQL and Qdrant chunk counts match
2026-07-04 12:41:40 +08:00
Accusys
e4d6fbac50 feat: add search_by_appearance agent tool for clothing color search
- New Python script: clothing_color_search.py
- New agent tool: search_by_appearance (red, blue, green, etc.)
- Uses appearance.json person bboxes + HSV color analysis
- Returns matched frames with confidence scores
2026-07-02 22:22:07 +08:00
Accusys
78364afc51 fix: keyword search - add text_content field and CJK support
- Added text_content field to SearchResult and SemanticSearchResult
- Added get_chunk_by_id_no_embedding for keyword results without embedding requirement
- Fixed search_bm25 to use position-based ranking for CJK/Korean content
- Fixed sqlx column mapping with explicit alias
- Skip text_match filter for keyword-only results
- Use text_content as fallback when summary is empty
2026-07-02 21:16:38 +08:00
Accusys
5a9d4325d8 fix: face thumbnail crop using bbox parameters
- Added bbox_x, bbox_y, bbox_w, bbox_h fields to ThumbQuery
- face_thumbnail now uses bbox params for ffmpeg crop filter
- Frontend passes bboxX/Y/Width/Height which maps to bbox_x/y/w/h
2026-07-02 18:31:54 +08:00
Accusys
3035c6db5d fix: add /api/v1/face-thumbnail route for People view thumbnails
- Frontend calls /api/v1/face-thumbnail?uuid=...&frame=...
- Backend only had /api/v1/file/:file_uuid/thumbnail
- Added compat route and uuid field to ThumbQuery
2026-07-02 18:13:38 +08:00
Accusys
28a4e9b1b8 fix: worker/processor.rs ASRX 使用正確的 start_frame
- 使用 segment.start_frame 取代 i (sequential index)
- data JSON 加入 start_frame, end_frame
2026-07-02 17:10:24 +08:00
Accusys
3943075a9b fix: ASRX pre_chunks 使用正確的 start_frame
- pipeline/mod.rs: 使用 segment.start_frame 取代 i (sequential index)
- data JSON 加入 end_time, start_frame, end_frame 供 rule1_ingest 使用
- 確保 ASRX pre_chunks 有正確的 frame 資訊
2026-07-02 17:08:50 +08:00
Accusys
e2b3858b67 fix: job never completes - processor_results.file_uuid is NULL
- ingestion_complete query used file_uuid column which is always NULL
- Changed to JOIN processor_results with monitor_jobs on job_id
- All stuck jobs now complete successfully
2026-07-02 16:42:24 +08:00
Accusys
bd6d108ade fix: remove trace_chunks from API + fix OCR frame calculation
- Removed trace_chunks field from PostgresStats struct
- Removed trace_chunks query from get_file_stats and get_ingestion_status
- Fixed OCR fetch_ocr_texts to compute frames from start_time*FPS
- Updated scan.rs to use separate count_nodes/count_edges functions
2026-07-02 16:23:25 +08:00
Accusys
d4c26deae2 fix: pipeline progress computed from DB state instead of Redis
- get_pipeline_progress_handler now queries actual DB counts
- Fixed processor_results query (requires JOIN with monitor_jobs)
- Card progress bar and right-click content now consistent
2026-07-02 15:11:25 +08:00
Accusys
619b056ada fix: TKG stats API returning 0 - count_by_type used wrong column
- tkg_nodes has no edge_type column, query was failing silently
- Split into count_nodes(node_type) and count_edges(edge_type)
- Fixed text_region → text_trace node type name
- Also: OCR frame fix in rule1 (end_frame computed from end_time+FPS)
2026-07-02 14:53:47 +08:00
Accusys
6507766ea2 fix: Qdrant collection name + PipelineProgress accumulation
- scan.rs: rule1 collection 'momentry_public_rule1_v2' → 'momentry_rule1'
- progress.rs: publish_pipeline_progress now reads existing progress and merges stages
2026-07-02 13:44:45 +08:00
Accusys
64f29d614b fix: Rule 1/TKG trigger conditions + essential_failed guard
- Rule 1 trigger: has_asr_or_asrx → has_asrx (wait for ASRX pre_chunks)
- P3/P4 triggers: has_asr_or_asrx → has_asrx (need ASRX data)
- Add essential_failed check: job only fails if essential processor fails
- P2/P3/P4 triggers: all_completed → has_face && has_asrx
- Add publish_pipeline_progress calls at each pipeline stage
2026-07-02 13:31:38 +08:00
Accusys
3eabd45882 fix: ASRX duplication, TKG edges, trace ingest, and add pipeline progress publishing
- ASRX handler no longer stores duplicate 'asr' pre_chunks
- Pre_chunks storage made idempotent (delete-before-insert)
- Rule 1 + trace_ingest changed to query 'asrx' not 'asr'
- Trace chunks removed (dynamic from TKG/Qdrant)
- TKG scroll_face_points fixed: trace_id >= 1 (not == 1)
- TKG AsrxSegmentEntry: start/end -> start_time/end_time (match ASRX JSON)
- Unregister error handling: log instead of silent discard
- Add publish_pipeline_progress calls at each pipeline stage
  (processors, rule1, face_trace, identity_agent, TKG, rule2, completion)
2026-07-02 10:43:46 +08:00
Accusys
d791d138f2 fix: API endpoints for file_uuid filtering of pending identities
- get_file_identities: UNION face_detections + file_identities
- list_identities: add file_bindings from file_identities table
- Add back /api/v1/traces/unassigned route
- Total count query now includes file_identities

Frontend can now:
- Filter pending identities by file_uuid
- Filter pending faces (unassigned traces) by file_uuid
2026-06-26 14:26:36 +08:00
Accusys
6f1a560d06 fix: add script_dir() method to PythonExecutor 2026-06-26 13:46:23 +08:00
Accusys
6cbc11efda feat: add confirm_identity API endpoint
- Add POST /api/v1/agents/identity/confirm endpoint
- Calls confirm_identity.py to bind trace to identity
- Updates TKG, Qdrant _faces, PG face_detections, _seeds
- Optional Round 2 propagation after confirmation
- Fix trace_id=0 check in confirm_identity.py (use 'is not None')
- Document API endpoint in 08_identity_agent.md
2026-06-26 08:30:03 +08:00
Accusys
615f9da2df fix: identity status - TMDb and user_defined identities start as 'pending' (確認制) 2026-06-26 02:16:46 +08:00
Accusys
a2f2b7918a fix: add trace_id and status to face_track nodes, force update properties on rebuild 2026-06-26 00:19:00 +08:00
Accusys
0c3f385b1f remove: skin_tone_trace node type
- skin_tone is a person attribute (like height), not trace attribute
- Remove build_skin_tone_trace_nodes function
- Remove skin_tone_trace_nodes from TkgResult and API response
- Remove skin_tone_trace from documentation tables
2026-06-25 19:21:05 +08:00
Accusys
fd2edd5736 fix: TKG rebuild type mismatch and face_track nodes
- Fix trace_id type mismatch (INT4 vs i64) with explicit ::bigint cast
- Change build_face_track_nodes to use from_pg version
- Add skin_tone_trace_nodes to API response
- Add #[derive(Serialize)] to TkgResult
- Fix Unicode panic in text label truncation
- Add push_existing_embeddings.py script
2026-06-25 11:23:53 +08:00
Accusys
ecb0e9c7d0 feat: add /api/v1/health public endpoint
- Add public health routes at /api/v1/health, /api/v1/health/detailed, /api/v1/health/consistency
- Make health functions and response types public
- Public routes bypass auth middleware (unlike protected /api/v1/* routes)
2026-06-25 10:05:33 +08:00
Accusys
4273576612 feat: implement skin_tone_trace node builder and standardize TKG node naming
- Add build_skin_tone_trace_nodes() to tkg.rs (Fitzpatrick I-VI classification)
- Add skin_tone_trace_nodes field to TkgResult
- Standardize node naming: _trace -> _track (text uses _region)
- Add external_id format column to Node Types table
- Add storage names to Edge Types table
- Create TKG_FORMATION_V1.0.md with Phase 0-4 definition, flow diagram, queries
- Add cross-reference from identity_agent_v4.0.md to TKG Formation
- Update Python scripts to executable mode
2026-06-25 03:09:16 +08:00
Accusys
074cdcdbed refactor: remove face embedding architecture - single Qdrant _faces collection
- Delete FaceEmbeddingDb module (face_embedding_db.rs)
- Stub match_faces_iterative, generate_seed_embeddings, tmdb_match_handler
- Remove sync_trace_embeddings, populate_face_embeddings_to_qdrant
- Remove embedding from face.json output (face_processor.py)
- Remove embedding from PG UPDATE (store_traced_faces.py)
- Remove workspace traces staging (checkin.rs, qdrant_workspace.rs)
- Fix tests: add pose_angle to Face, hand_nodes to TkgResult

Disabled functions (need reimplement with _faces):
- match_faces_iterative (identity agent)
- generate_seed_embeddings (TMDb seeds)
- tmdb_match_handler (TMDb matching)
- cluster_face_embeddings, search_similar_faces
- merge_traces_within_cuts
2026-06-24 22:27:09 +08:00
Accusys
360cb991e1 feat: add queued status + FIFO queue ordering
- Add Queued variant to VideoStatus enum
- Trigger sets videos.status='queued' instead of staying 'pending'
- Worker sets videos.status='processing' on pickup
- list_monitor_jobs_by_status ORDER BY created_at ASC (FIFO)
- queue_position counts both 'pending' and 'queued' jobs
2026-06-24 05:18:40 +08:00
Accusys
14e886cc08 feat: progressive multi-round face matching + pending person API
- Identity agent: per-face max matching, multi-round with derived
  seeds from high-confidence faces, angle diversity filter (cosine sim < 0.90)
- Pending person API: POST /file/:file_uuid/pending-person
  + GET /file/:file_uuid/pending-persons with status=pending, source=manual
- Update API docs (07_identity.md)
2026-06-24 03:42:04 +08:00
Accusys
766a1d9a6d feat: Swift Face Pose integration + TKG 方案 B
Major Changes:
- swift_face_pose: output pose angles (yaw/pitch/roll) in face.json
- face_processor.py: call swift_face_pose (dual output: face.json + pose.json)
- Face struct: add pose_angle field
- TKG 方案 B: gaze/lip_track nodes from face.json (no face_detections dependency)
- Chunk cleanup: delete old data before rebuild (avoid duplicate key)
- Hand nodes: classify by hand_type + gesture (15 combinations)
- HAND_OBJECT edges: bbox spatial matching (174 matches)

Test Results:
- Blake Jones: 8 faces, pose_angle ✓, 66 nodes, 174 edges
- FilmRiot: 394 faces, pose_angle ✓, 35 nodes, 39 edges
- Left hands: 132, Right hands: 2

Architecture:
- All TKG nodes built from JSON files (face.json, hand.json, yolo.json)
- Swift processors: sample_interval=3 (Face/Pose/Hand sync)
- Cleanup functions: delete_tkg_nodes_by_uuid, delete_tkg_edges_by_uuid
2026-06-23 05:47:24 +08:00
Accusys
e1e2da2140 fix: processor-counts API + ASRX field name conversion
- Fix processor-counts API to correctly read JSON counts:
  - YOLO: use frames.length (was returning null)
  - CUT: prioritize scenes.length over frame_count
  - Result: YOLO 1963 frames, CUT 25 scenes (correct)

- Fix ASRX field name conversion:
  - Convert start_time/end_time → start/end for ASRX compatibility
  - Prefer frame-based positioning over time-based

- Document issues in issues_2026-06-21.md:
  - Issue 6: ASRX field name mismatch
  - Issue 7: processor-counts API null values
2026-06-22 23:33:39 +08:00
Accusys
db8bb8fa95 fix(tkg): handle null identity_id + remove skin_tone nodes
- Fix Phase 2.5 null handling in build_gaze/lip_track_nodes
  - Use query_scalar::<_, Option<i64>> + flatten() for nullable fields
  - Prevents 'unexpected null' decoding errors

- Remove skin_tone_trace_nodes from TKG build
  - Delete build_skin_tone_trace_nodes function (110 lines)
  - Remove from TkgResult struct and API response
  - Skin tone should be independent function, not in TKG

Result: TKG rebuild now completes successfully
- Nodes: 40 (face_track, gaze_track, text_region, appearance)
- Edges: 2967 (co_occurrence edges increased from 21 → 2964)
2026-06-22 16:39:47 +08:00
Accusys
70e849d3ae refactor: remove Rule 3, Story, and Caption processors
- Remove Rule 3 (Scene Chunking) from worker auto-trigger
- Remove rule3_ingest.rs and related imports
- Remove Story/Caption from playground module parsing
- Clean up scan.rs Rule 3 display
- Fix ASRX field name conversion (start_time -> start)

Reason: Story/5W1H/Scene accuracy too poor - will redesign later
2026-06-22 15:34:02 +08:00
Accusys
22f13eca4b fix(cut): change ffprobe output format to default=nk=0
- Problem: compact=p=0:nk=1 outputs pipe-delimited format without pts_time=
- Fix: default=nk=0 outputs pts_time=XXX format that parser can match
- Result: Charade scene detection from 1 scene -> 833 scenes (correct)
2026-06-22 13:25:16 +08:00
Accusys
30b252ac95 fix: pre_chunks schema + TMDb movie name extraction
- pre_chunks: add chunk_type, text_content columns; drop NOT NULL on
  coordinate_type/coordinate_index (INSERT statements reference these
  columns but CREATE TABLE was missing them)
- run_migrations: add ALTER TABLE for existing databases
- extract_movie_name: filter noise words (youtube, fps, 24fps, 1080p,
  pure digits) so 'Charade_YouTube_24fps' → 'Charade'
- run-server-3002.sh: add companion worker startup (matching 3003 script)
2026-06-22 11:55:12 +08:00
Accusys
f4de741d5b fix: add appearance back to processor list, keep mediapipe/story filtered out 2026-06-22 09:20:16 +08:00
Accusys
c93b54efeb fix: filter deprecated processors from trigger API requests 2026-06-22 09:15:02 +08:00
Accusys
4ba248513e fix: correct processor list - remove deprecated mediapipe/appearance/story, fix auto-pipeline order
- ProcessorType::all(): remove MediaPipe, Appearance, Story (mediapipe replaced by Swift)
- files.rs auto-pipeline: fix order to cut,asr,asrx,yolo,ocr,face,pose (was missing asr)
- postgres_db.rs run_migrations(): rewrite to auto-create all 38 tables idempotently
2026-06-22 08:49:41 +08:00