Files
2026-08-03 11:30:49 -04:00

7.9 KiB

STORY-07: Review Interface

Epic

E2: Routing & Review — As an annotator, I can view low-confidence videos and label them.

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 <video> element)
    • Top-k contributing frames displayed as thumbnails (k=5 default)
    • Confidence scores displayed per frame
    • Label toggle button (True/False) with confirmation
    • Optional notes field
    • Submit button (saves to DB via API)
    • Navigation: Previous/Next video in queue

7.3 Data Export

File: src/review_export.py

Features:

  • CSV Export:
    video_id,file_path,confidence_score,routing_decision,model_version,ground_truth,annotated_at,contributing_frames
    12345,/data/input/video.mp4,0.62,REVIEW,v1.2.0,true,2026-08-03T10:30:00Z,"[{'timestamp': 30.0, 'crop_path': '/scratch/12345/crops/30000.jpg', 'confidence': 0.82}, ...]"
    
  • JSON Export:
    [
      {
        "video_id": 12345,
        "file_path": "/data/input/video.mp4",
        "confidence_score": 0.62,
        "routing_decision": "REVIEW",
        "model_version": "v1.2.0",
        "ground_truth": true,
        "annotated_at": "2026-08-03T10:30:00Z",
        "contributing_frames": [
          {"timestamp": 30.0, "crop_path": "/scratch/12345/crops/30000.jpg", "confidence": 0.82}
        ]
      }
    ]
    
  • Export Options:
    • Filter by annotation status (annotated/unannotated)
    • Filter by date range
    • Filter by model version
    • Filter by ground truth label
  • Output Location: /data/output/reviews/

7.4 UI Container

File: ui/Dockerfile

Base image: python:3.10-slim

Installed packages:

  • Flask 3.0+ or FastAPI 0.100+ (lightweight web framework)
  • Jinja2 3.1+ (template engine)
  • PyMySQL (database connection for API)
  • gunicorn (WSGI server)

7.5 Docker Compose Update

File: docker-compose.yml (update)

Add UI service:

ui:
  build:
    context: ./ui
    dockerfile: Dockerfile
  ports:
    - "5000:5000"
  volumes:
    - ./ui:/app/ui
  environment:
    - DB_HOST=mariadb
    - DB_PORT=3306
    - DB_NAME=videodetect
    - DB_USER=videodetect
    - DB_PASSWORD=${DB_PASSWORD}
  depends_on:
    - mariadb
  networks:
    - videodetect-network

7.6 Database Update

File: db/schema.sql (review_queue table — from STORY-01)

The review_queue table was defined in STORY-01. This story populates and queries it.

7.7 Configuration Updates

File: config.yaml (updates)

New fields:

review_ui:
  host: "0.0.0.0"
  port: 5000
  per_page: 20
  top_k_frames: 5
  export_path: /data/output/reviews
  auth_enabled: false  # per TC-06
  ssl_enabled: false   # per TC-06

Acceptance Criteria

Functional

  • Review queue displays all videos with routing_decision = REVIEW and annotated = false
  • Video player loads and plays the video correctly
  • Top-k contributing frames are displayed as thumbnails with confidence scores
  • Annotator can toggle label (True/False) and submit
  • Submitted label is persisted to DB (review_queue table)
  • Annotated videos are removed from the default queue view
  • CSV export produces valid CSV with all required fields
  • JSON export produces valid JSON with all required fields
  • Export includes ground truth labels and contributing frame data
  • UI is accessible via http://:5000 (no auth, no SSL)
  • Pagination works correctly (20 items per page)
  • Sort and filter operations work on the queue page

Non-Functional

  • Queue page loads in < 2 seconds (with 1000+ videos in queue)
  • Video player loads in < 3 seconds
  • Label submission completes in < 1 second
  • Export of 1000 annotated videos completes in < 10 seconds
  • UI uses < 100MB RAM at idle
  • No authentication or SSL configured (per TC-06)

Technical Constraints

  • UI runs in Docker container (per TC-05)
  • No reverse proxy configured
  • No SSL certificates configured
  • No authentication mechanism configured
  • All API responses are JSON
  • Database queries use parameterized statements
  • Export files are UTF-8 encoded

Dependencies

  • Prerequisites: STORY-01 (Foundation — DB schema), STORY-05 (Classification — provides routing decisions)
  • Depends on: None (can be built in parallel with STORY-04, STORY-05)
  • Enables: STORY-08 (Active Learning — provides labeled training data)

Risks & Mitigations

Risk Mitigation
Video playback in browser requires compatible format Serve videos in web-compatible format (H.264 MP4); transcode if needed
Crop paths may not be accessible from UI container Store crop paths in DB; serve via API endpoint
No auth means anyone on LAN can access Acceptable per TC-06; document in security notes
Large review queue slows page loads Implement server-side pagination; lazy load thumbnails

Estimated Effort

  • Sprint: 7
  • Story Points: 21
  • Dependencies: STORY-01, STORY-05