Commit Graph

9 Commits

Author SHA1 Message Date
fa9b21856f feat: replace face pipeline with InsightFace, add content classifier
Face detection/recognition:
- Replace YuNet + SFace with InsightFace buffalo_l (RetinaFace + ArcFace)
- 512-d ArcFace embeddings (was 128-d SFace), migration 0006 resizes column
- Remove YOLO person-bbox workaround — RetinaFace is accurate enough
- Detection threshold 0.65 cleanly separates real faces (0.72+) from
  false positives on dogs/paintings (0.56-0.61)

Content-type classification:
- CLIP zero-shot classifier using native PyTorch text encoder + ONNX
  image encoder for high-quality text-image similarity
- Categories: photograph, screenshot, document, receipt, meme, artwork
- Writes Tag(kind=content_type) per photo via photo_tags
- Margin-based confidence: top-1 vs top-2 score difference
- New ClassifierSettings in config (enabled, min_confidence)
- Wired into vision_fanout pipeline

Tested: 6 real faces from 4 photos (zero false positives), 11/13 photos
classified (8 photograph, 2 artwork, 1 meme).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 13:49:02 +02:00
f48e099bd2 fix: verify faces against YOLO person detections for precision
Cross-reference face detections with YOLO 'person' bounding boxes —
only keep faces that overlap >= 50% with a detected human body. This
eliminates false positives on dogs, paintings, and cartoons without
needing an aggressive score threshold.

Lower face detection threshold back to 0.6 since the person-overlap
check is now the primary precision filter.

Tested: 6 verified faces from 4 photos, zero false positives.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 11:13:01 +02:00
229611b4c3 fix: face clusters write photo_tags, raise detection threshold to 0.7
- recluster_faces now writes photo_tags rows for each face cluster so
  the tag count and tag_ids filter work (previously count was always 0)
- Old cluster tags and photo_tags are cleaned up before re-clustering
- Raise face detection threshold from 0.4 to 0.7 to reduce false
  positives (was detecting dog faces as people)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 10:48:19 +02:00
db20cbb7d8 fix: face detection — use OpenCV FaceDetectorYN and full-res originals
- Rewrite faces.py to use cv2.FaceDetectorYN instead of raw ONNX
  (handles multi-scale anchor decoding and NMS internally)
- Load original photo files at up to 4000px for face detection instead
  of 240px thumbnails — faces were too small to detect at thumbnail res
- Falls back to thumbnail if original is unavailable

Tested: 33 faces extracted from 13 photos, clustered into 1 person.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 10:43:29 +02:00
7558aeb5e6 fix: sync DB sessions in Celery, letterbox YuNet, dedupe detections
- Rewrite all vision tasks to use sync psycopg2 sessions instead of
  asyncpg — fixes 'another operation in progress' and event loop errors
  when Celery forks workers sharing the async connection pool
- Letterbox-pad images to exactly 640x640 for YuNet face detector
  (was crashing on non-square thumbnails)
- Deduplicate object detections per label per photo — keep highest
  confidence only to avoid photo_tags PK violation on multiple
  detections of the same class
- Add all queues (-Q default,high,low,vision) to worker command

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 10:28:17 +02:00
ad007e4cd4 feat: add face detection, recognition, and clustering
- Create face_embeddings table with pgvector Vector(128) + HNSW index
- Implement extract_faces task (YuNet detection + SFace recognition)
- Implement recluster_faces task (DBSCAN clustering → Tag(kind=face_cluster))
- Clusters are named "Person N" and get representative_photo_id
- cluster_id FK → tags.id, SET NULL on delete for merge/rename support

Migration 0005 creates the face_embeddings table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:13:41 +02:00
1ebc4bfe73 feat: add YOLO object detection writing to unified Tag model
Implement detect_objects Celery task:
- Runs YOLOv8n on 640px thumbnail via ONNX Runtime
- Creates Tag(kind=object) rows for each COCO class detected
- Writes photo_tags associations with confidence, bbox, and source
- Wipes previous detections per source model on re-run

No new tables/migrations — uses the unified Tag model from PR3.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:11:26 +02:00
842a4fc864 feat: add OCR text extraction and Postgres full-text search
- Create ocr_text table for storing per-region OCR results
- Add tsvector search_vector column to photos with GIN index and
  auto-update trigger on filename/user_title/user_notes
- Implement ocr_photo Celery task using rapidocr-onnxruntime
- Add FTS leg to hybrid search: queries photos.search_vector and
  ocr_text via UNION, fused with semantic results via RRF (k=60)

Migration 0004 backfills search_vector for existing rows.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:10:14 +02:00
649437dc85 feat: add embeddings pipeline and semantic search endpoint
Wire the full embedding flow:
- Rewrite Embedding model to use pgvector Vector(512) with HNSW index
- Add embed_photo, vision_fanout, backfill_vision Celery tasks on
  dedicated `vision` queue
- Hook vision_fanout into generate_thumbnails completion
- Add POST /api/v1/photos/search with hybrid RRF ranking (semantic-only
  for now; FTS leg added in PR5)
- Stub ocr_photo, detect_objects, extract_faces tasks for later PRs

Migration 0003 drops/recreates the embeddings table (was never populated).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 09:07:32 +02:00