# STORY-07: Review Interface ## Epic **E2: Routing & Review** — As an annotator, I can view low-confidence videos and label them. ## Related Requirements | ID | Requirement | |----|------| | FR-05 | Manual review interface for low-confidence videos: Displays video + contributing frames/crops + model confidence; Supports binary labeling | | FR-07 | Metadata logging & audit trail: Stores annotated labels for active learning | | NFR-06 | Observability: Tracks review queue depth | | TC-06 | Network Security: Internal LAN only; no auth required | ## Description Implement a lightweight web-based review interface for annotating low-confidence videos. Display the video player, top-k contributing frames, model confidence scores, and allow annotators to toggle the ground truth label. Support CSV/JSON export of annotated data for active learning. ## Scope ### In Scope - Lightweight web UI (Flask/FastAPI) serving on internal LAN - Query DB for videos with routing_decision = REVIEW - Video player with playback controls - Display top-k contributing frames (highest confidence frames) - Display model confidence scores per frame - Binary label toggle (True/False — target class present or not) - Label persistence to DB (review_queue table) - CSV/JSON export of annotated data with ground truth - Accessible via internal IP:Port (no auth, no SSL) ### Out of Scope - Frame sampling (covered in STORY-03) - Face detection (covered in STORY-04) - Classification (covered in STORY-05) - Confidence aggregation (covered in STORY-05) - Active learning pipeline / model retraining (covered in STORY-08) - Monitoring dashboards (covered in STORY-09) ## Deliverables ### 7.1 Review Backend **File:** `src/review_api.py` API Endpoints: - `GET /api/review/queue` — List videos in review queue - Query: `SELECT * FROM review_queue WHERE annotated = false ORDER BY created_at DESC` - Pagination: 20 items per page - Response: `{videos: [...], total: N, page: P, per_page: 20}` - `GET /api/review/{video_id}` — Get video details for annotation - Response: `{video_id, file_path, confidence_score, routing_decision, model_version, frame_count, contributing_frames: [{timestamp, crop_path, confidence}], video_duration}` - `POST /api/review/{video_id}/label` — Submit annotation - Body: `{ground_truth: true/false, notes: string (optional)}` - Updates: `review_queue.annotated = true`, `review_queue.ground_truth = value`, `review_queue.annotated_at = NOW()` - Response: `{status: 'annotated', video_id, ground_truth}` - `GET /api/review/export` — Export annotated data - Query params: `format=csv|json`, `annotated=true/false`, `date_from`, `date_to` - Response: File download with annotated data - `GET /api/review/stats` — Review queue statistics - Response: `{total_in_queue: N, annotated_today: N, avg_confidence: F, confidence_distribution: {...}}` ### 7.2 Review Frontend **File:** `ui/review/` Pages: - **Queue Page (`/`):** List of videos awaiting review - Table columns: Video ID, File Path, Confidence Score, Model Version, Date Added, Actions (View) - Sortable by confidence, date, file path - Filter by confidence range, model version - Pagination (20 items per page) - **Annotation Page (`/review/{video_id}`):** Video annotation interface - Video player with playback controls (HTML5 `