Implement quality score tracking and batch Frigate file mapping

- Track laplacian blur score through quality filtering pipeline
  (quality.py: blur_score on QualityResult; diversity.py: store on asset;
   executor.py: read via quality_score key)
- Replace per-file polling with post-person batch reconciliation:
  after all uploads for a person complete, poll Frigate (up to 15s)
  until the expected number of new files appear, then map by filename
  timestamp order (Frigate FIFO queue = upload order = timestamp order)
- Document race condition limitation: concurrent external uploads cause
  the batch to be skipped entirely (safe but files go unmapped); noted
  in code as requiring a Frigate API fix (return filename on upload)
- Add two assess_quality integration tests for blur_score

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-13 04:59:12 +00:00
co-authored by Claude Sonnet 4.6
parent 9f92e1c919
commit 11e7d4aad7
4 changed files with 93 additions and 30 deletions
+7 -3
View File
@@ -20,6 +20,7 @@ class QualityResult:
passed: bool
reasons: list[str] = field(default_factory=list)
blur_score: float | None = None
@property
def reason(self) -> str:
@@ -113,9 +114,12 @@ def assess_quality(
img_np = np.asarray(img)
reasons = []
# Run all checks, collect failures
# Compute laplacian variance once (used by check_blur and stored as blur_score)
gray = cv2.cvtColor(img_np, cv2.COLOR_RGB2GRAY) if img_np.ndim == 3 else img_np
blur_score = float(cv2.Laplacian(gray, cv2.CV_64F).var())
checks = [
check_blur(img_np, blur_threshold),
(blur_score >= blur_threshold, f"Blurry (laplacian={blur_score:.1f}, threshold={blur_threshold})" if blur_score < blur_threshold else ""),
check_grayscale(img_np),
check_exposure(img_np),
check_confidence(confidence, min_confidence),
@@ -129,5 +133,5 @@ def assess_quality(
if not passed:
reasons.append(reason)
return QualityResult(passed=len(reasons) == 0, reasons=reasons)
return QualityResult(passed=len(reasons) == 0, reasons=reasons, blur_score=blur_score)