# Trace API v1.0.0 Reference — M5 Official

**Author**: M5  
**Date**: 2026-05-07  
**Status**: ✅ Production — implemented and verified on Charade (Job 255)

---

## Design Philosophy

> 可以追蹤的 trace 就像雷達看到的物體 — 都可以分析。

A **trace** is any entity detected and tracked across consecutive frames:

```
Detection → Grouping (tracking) → Trace → Analysis → Identity Binding
```

### Coordinate System: 2D+time (current), 3D+time (future)

| Dimension | Current (Face) | Future (Object/Pose) |
|-----------|---------------|---------------------|
| x, y | Bbox center (image plane) | Bbox center (world space) |
| w, h | Bbox size (image plane) | Bbox size (world space) |
| t | Frame number / timestamp | Frame number / timestamp |

Future: 3D bounding cube `[x, y, z, w, h, d, t]` with camera-relative analysis, camera trace (observer), and light source trace (illuminator). See design discussion in `M4_workspace/TRACE_API_REFERENCE_V1.0.0.md`.

---

## Base URL

```
http://localhost:{port}/api/v1
```

Playground: port 3003 | Production: port 3002

## Authentication

All endpoints require `X-API-Key` header.

---

## Trace Model

A **trace** is a sequence of detections of the same entity across consecutive frames:

```
Identity (person) ──has_many──> Trace (tracked segment) ──has_many──> Detection (single frame)
```

| Trace Type | Detection Source | Identity Binding | Status |
|-----------|-----------------|-----------------|--------|
| `face` | Face detector (Vision + FaceNet) | `face_detections.identity_id` → `identities` | ✅ Implemented |
| `object` | YOLO pre_chunks by class label | By object class name | 🔜 Future (needs tracking) |
| `pose` | Pose skeleton keypoints | TBD | 🔜 Future |

### YOLO Object Trace (Future)

YOLO produces frame-level detections with class labels but **no tracking ID**. To enable:
1. Add IoU tracking (SORT) across frames
2. Assign `trace_id` per group, store in `pre_chunks` or new `yolo_traces` table
3. Add routes: `POST /object_trace/sortby`, `GET /object_trace/:id/detections`

---

## Endpoints

### 1. List Face Traces

**`POST /api/v1/file/:file_uuid/face_trace/sortby`**

Aggregated face traces with sorting and filtering.

#### Request Body

```json
{
  "sort_by": "face_count | duration | first_appearance",
  "limit": 100,
  "min_faces": 1,
  "min_confidence": 0.0,
  "max_confidence": 1.0
}
```

#### Response

```json
{
  "success": true,
  "file_uuid": "3abeee81d94597629ed8cb943f182e94",
  "total_traces": 6892,
  "total_faces": 108204,
  "traces": [
    {
      "trace_id": 1271,
      "face_count": 33,
      "first_frame": 68280,
      "last_frame": 69240,
      "first_sec": 2731.2,
      "last_sec": 2769.6,
      "duration_sec": 38.4,
      "avg_confidence": 0.782,
      "sample_face_id": "18441"
    }
  ]
}
```

| Field | Description |
|-------|-------------|
| `trace_id` | Unique ID within the video file |
| `face_count` | Number of detections in this trace |
| `first_frame / last_frame` | Frame range |
| `first_sec / last_sec` | Time range |
| `duration_sec` | Duration in seconds |
| `avg_confidence` | Mean detection confidence |
| `sample_face_id` | ID of the highest-confidence detection |
| `identity_id` *(future)* | Bound identity ID |
| `identity_name` *(future)* | Identity display name |

---

### 2. Trace Face Detections

**`GET /api/v1/file/:file_uuid/trace/:trace_id/faces`**

#### Query Parameters

| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `limit` | int | 200 | Max faces (capped 1000) |
| `offset` | int | 0 | Pagination |
| `interpolate` | bool | false | Enable linear interpolation |

#### Response

```json
{
  "success": true,
  "file_uuid": "3abeee81d94597629ed8cb943f182e94",
  "trace_id": 2,
  "total": 2,
  "faces": [
    {
      "id": 12400,
      "start_frame": 4650,
      "start_time": 186.0,
      "x": 1047,
      "y": 361,
      "width": 187,
      "height": 187,
      "confidence": 0.834,
      "interpolated": false
    }
  ]
}
```

Interpolated frames: `id=0, confidence=0.0, interpolated=true`.

#### Interpolation Algorithm

Linear interpolation between consecutive detections:

```
t = (mid_frame - prev.frame) / (next.frame - prev.frame)
x = prev.x + (next.x - prev.x) * t
y = prev.y + (next.y - prev.y) * t
width = prev.w + (next.w - prev.w) * t
height = prev.h + (next.h - prev.h) * t
```

---

### 3. Trace Video Clip

**`GET /api/v1/file/:file_uuid/trace/:trace_id/video`**

MP4 video with bounding box overlay for a trace.

| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `padding` | float | 2.0 | Padding seconds before/after |

---

### 4. Bounding Box Overlay Video

**`GET /api/v1/file/:file_uuid/video/bbox`**

MP4 video segment with face bboxes.

| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `start` | int | — | Start frame (required) |
| `end` | int | — | End frame (required) |
| `duration` | float | 10 | Clip duration seconds |

---

### 5. Frame Thumbnail

**`GET /api/v1/file/:file_uuid/thumbnail`**

Single frame JPEG, with optional crop.

| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `frame` | int | — | Frame number (required) |
| `x, y, w, h` | int | — | Crop region |

---

## CLI Verification (Charade, Job 255)

```
File: Charade (1963), 25fps, 108204 faces, 6892 traces
Dev server: http://localhost:3003
Auth: X-API-Key: muser_test_apikey
```

| # | Endpoint | Request | M5 Result |
|---|----------|---------|-----------|
| 1 | `POST /face_trace/sortby` | `{"limit":2}` | 6892 traces, 108204 faces |
| 2 | `POST /face_trace/sortby` | `{"sort_by":"face_count","limit":3}"` | #1271=33, #2171=26, #1268=24 faces |
| 3 | `POST /face_trace/sortby` | `{"sort_by":"duration","limit":3}` | Longest 38.4s, 30.0s, 27.6s |
| 4 | `POST /face_trace/sortby` | `{"min_faces":10,"min_confidence":0.7}` | Filtered traces |
| 5 | `GET /trace/2/faces` | `?limit=5` | 1 face: frame 4620 |
| 6 | `GET /trace/2/faces` | `?limit=100&interpolate=true` | 31 frames (2 real + 29 interpolated) |
| 7 | `GET /trace/1271/faces` | `?limit=2` | 33 total, paginated |
| 8 | `GET /trace/1271/faces` | `?limit=10&interpolate=true` | 271 frames |
| 9 | `GET /trace/2/video` | — | 2.0MB MP4 |
| 10 | `GET /video/bbox` | `?start=4650&end=4680` | 1.9MB MP4 overlay |
| 11 | `GET /thumbnail` | `?frame=4650` | 82KB JPEG |

---

## Source Files

| File | Purpose |
|------|---------|
| `src/api/trace_agent_api.rs` | Face trace listing + detail + interpolation |
| `src/api/media_api.rs` | Video clip, bbox overlay, thumbnail |
| `src/api/server.rs` | Route merge (lines 2554–2555) |
| `portal/src/components/FaceTraceTimeline.vue` | Frontend trace display |

## Route Pattern

Current: `/api/v1/file/:file_uuid/face_trace/...`
Future: `/api/v1/file/:file_uuid/{type}_trace/...` where `type` = `object`, `pose`, etc.

New trace types should add new modules (e.g., `object_trace_api.rs`) rather than overloading `trace_agent_api.rs`.
