feat: progressive multi-round face matching + pending person API

- Identity agent: per-face max matching, multi-round with derived
  seeds from high-confidence faces, angle diversity filter (cosine sim < 0.90)
- Pending person API: POST /file/:file_uuid/pending-person
  + GET /file/:file_uuid/pending-persons with status=pending, source=manual
- Update API docs (07_identity.md)
This commit is contained in:
Accusys
2026-06-24 03:42:04 +08:00
parent 766a1d9a6d
commit 14e886cc08
31 changed files with 5882 additions and 742 deletions

View File

@@ -127,13 +127,15 @@ curl -s "$API/api/v1/file/$FILE_UUID/probe" -H "X-API-Key: $KEY"
---
### `GET /api/v1/progress/:file_uuid`
### `POST /api/v1/progress/:file_uuid`
**Auth**: Required
**Scope**: file-level
Get real-time processing progress for a file via Redis pub/sub. Includes per-processor status, current/total frames, ETA, and system resource stats.
**Note**: This endpoint uses **POST** method, not GET. The progress data is stored in Redis as a hash, and POST is used to retrieve the latest state.
#### Pipeline Order
| Order | Processor | Dependencies | Description |
@@ -154,7 +156,7 @@ All processors except `story` and `5w1h` run concurrently when their dependencie
#### Example
```bash
curl -s "$API/api/v1/progress/$FILE_UUID" -H "X-API-Key: $KEY" | jq '{overall_progress, processors: [.processors[] | {processor_type, status}]}'
curl -s -X POST "$API/api/v1/progress/$FILE_UUID" -H "X-API-Key: $KEY" | jq '{overall_progress, processors: [.processors[] | {name, status}]}'
```
#### Response (200)

View File

@@ -923,6 +923,128 @@ curl -s "$API/api/v1/identity/$IDENTITY_UUID/json" \
---
---
### `POST /api/v1/file/:file_uuid/pending-person`
**Auth**: Required
**Scope**: file-level
Create a manually managed "pending person" under a specific file. A pending person is an identity with `status='pending'` and `source='manual'`, used for unmatched traces that the user wants to manually label before a full identity resolution.
Optionally binds a list of trace IDs to this new identity.
#### Request
```json
{
"trace_ids": [100, 150, 200],
"name": "Mystery Man #1"
}
```
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `trace_ids` | array[int] | No | `[]` | Trace IDs to bind to this pending person |
| `name` | string | No | `"Person N"` | Human-readable name. Auto-generated if omitted |
#### Example
```bash
# Create pending person with name and no traces
curl -s -X POST "$API/api/v1/file/$FILE_UUID/pending-person" \
-H "X-API-Key: $KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Unknown Woman #2", "trace_ids": []}'
# Create pending person with auto-name and bind traces
curl -s -X POST "$API/api/v1/file/$FILE_UUID/pending-person" \
-H "X-API-Key: $KEY" \
-H "Content-Type: application/json" \
-d '{"trace_ids": [100, 150, 200]}'
```
#### Response (200)
```json
{
"success": true,
"message": "Created pending person: Mystery Man #1 (uuid: 4d96b25b-68f0-4c52-b238-d69f7dfd588b)",
"data": {
"identity_uuid": "4d96b25b-68f0-4c52-b238-d69f7dfd588b",
"identity_id": 55,
"name": "Mystery Man #1",
"bound_traces": 0
}
}
```
| Field | Type | Description |
|-------|------|-------------|
| `identity_uuid` | string | UUID of the newly created pending identity |
| `identity_id` | integer | Internal ID of the new identity |
| `name` | string | Display name |
| `bound_traces` | integer | Number of traces bound |
#### Side Effects
- Creates an `identities` row with `status='pending'`, `source='manual'`, `file_uuid=<file_uuid>`
- If `trace_ids` provided: `UPDATE face_detections SET identity_id = ...` for matching traces
- If `trace_ids` provided: TKG face_track nodes get `identity_id` / `identity_name` in properties
- Identity JSON file synced to disk
---
### `GET /api/v1/file/:file_uuid/pending-persons`
**Auth**: Required
**Scope**: file-level
List all pending persons for a file.
#### Example
```bash
curl -s "$API/api/v1/file/$FILE_UUID/pending-persons" \
-H "X-API-Key: $KEY"
```
#### Response (200)
```json
{
"success": true,
"message": "Found 2 pending persons for c36f35685177c981aa139b66bbbccc5b",
"data": [
{
"identity_uuid": "232ecd08-a2bf-4bd0-bd25-0bd8fb7a7dae",
"identity_id": 56,
"name": "Person 2",
"created_at": "2026-06-23 17:13:23",
"trace_count": 3,
"bound_traces": null
}
]
}
```
| Field | Type | Description |
|-------|------|-------------|
| `identity_uuid` | string | Identity UUID |
| `identity_id` | integer | Internal identity ID |
| `name` | string | Display name |
| `created_at` | string | Creation timestamp |
| `trace_count` | integer | Number of face traces bound to this pending person |
| `bound_traces` | array[int] | List of bound trace IDs (currently null, reserved for future expansion) |
#### Notes
- Pending persons are normal `identities` rows with `status='pending'` — they can be promoted to confirmed via `PATCH /api/v1/identity/:identity_uuid` (`{"status": "confirmed"}`)
- They can be merged into known identities via `POST /api/v1/identity/:identity_uuid/mergeinto`
- Use `GET /api/v1/identity/:identity_uuid/traces` to get detailed trace info for each pending person
---
## Alias System (BCP 47 Locale Tags)
Identity aliases support multilingual display names. Aliases are stored in `metadata.aliases` as an array of `{locale, name}` objects.