docs: add PATCH identity endpoint doc + BCP 47 alias reference

This commit is contained in:
M5Max128
2026-05-22 08:56:07 +08:00
parent e1619c724a
commit 2b025a014e
3 changed files with 635 additions and 3 deletions

View File

@@ -0,0 +1,516 @@
<!-- module: identity -->
<!-- description: Global identities — CRUD, detail, files, faces, bind, unbind, search -->
<!-- depends: 01_auth -->
## Global Identities
### `GET /api/v1/identities`
**Auth**: Required
**Scope**: identity-level
List all registered identities with pagination.
#### Example
```bash
curl -s "$API/api/v1/identities?page=1&page_size=20" -H "X-API-Key: $KEY" | jq '{count, identities: [.identities[] | {name}]}'
```
---
### `GET /api/v1/identity/:identity_uuid`
**Auth**: Required
**Scope**: identity-level
Get detailed information for a specific identity, including metadata and TMDb references.
#### Example
```bash
curl -s "$API/api/v1/identity/$IDENTITY_UUID" -H "X-API-Key: $KEY"
```
#### Response (200)
```json
{
"success": true,
"identity_uuid": "a9a901056d6b46ff92da0c3c1a57dff4",
"name": "Cary Grant",
"identity_type": "people",
"source": "tmdb",
"status": "confirmed",
"tmdb_id": 112,
"tmdb_profile": "{output}/identities/{identity_uuid}/profile.jpg",
"metadata": {},
"reference_data": {},
"created_at": "2026-05-16T12:00:00Z",
"updated_at": null
}
```
| Field | Type | Description |
|-------|------|-------------|
| `identity_uuid` | string | Identity identifier |
| `name` | string | Identity name |
| `identity_type` | string | `"people"` or null |
| `source` | string | `.json`, `auto`, `tmdb`, `user_defined`, or `merged` |
| `status` | string | `"confirmed"`, `"pending"`, or `"inactive"` |
| `tmdb_id` | integer | TMDb person ID (only if source = tmdb) |
| `tmdb_profile` | string | Local profile image path (`{output}/identities/{uuid}/profile.jpg`) |
| `metadata` | object | Metadata JSON (tmdb_character, cast_order, etc.) |
| `created_at` | string | Creation timestamp |
---
### `DELETE /api/v1/identity/:identity_uuid`
**Auth**: Required
**Scope**: identity-level
Delete an identity permanently.
---
### `PATCH /api/v1/identity/:identity_uuid`
**Auth**: Required
**Scope**: identity-level
Partially update an identity. Only provided fields are modified. The `name` field is a display label and may repeat across identities. Aliases for multilingual display are stored in `metadata.aliases` (see BCP 47 reference below).
#### Request (JSON, all fields optional)
| Field | Type | Description |
|-------|------|-------------|
| `name` | string | New display name |
| `metadata` | object | Merged into existing metadata. Use `"aliases"` key for locale-tagged names |
| `status` | string | `"confirmed"`, `"pending"`, or `"skipped"` |
| `identity_type` | string | `"people"`, `"brand"`, `"object"`, `"concept"`, etc. |
#### Example
```bash
curl -s -X PATCH "$API/api/v1/identity/$IDENTITY_UUID" \
-H "X-API-Key: $KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "John Smith",
"metadata": {
"aliases": [
{"locale": "en", "name": "John Smith"},
{"locale": "zh-TW", "name": "約翰·史密斯"},
{"locale": "ja", "name": "ジョン・スミス"}
]
}
}'
```
#### Response (200)
```json
{
"success": true,
"identity_uuid": "a9a901056d6b46ff92da0c3c1a57dff4",
"updated_fields": ["name", "metadata"]
}
```
#### Error Responses
| HTTP | When |
|------|------|
| `400` | No fields to update or invalid UUID format |
| `404` | Identity not found |
---
### `GET /api/v1/identity/:identity_uuid/files`
**Auth**: Required
**Scope**: identity-level
Get all files where this identity appears. Returns per-file summary including face count, confidence, and appearance time range.
#### Example
```bash
curl -s "$API/api/v1/identity/$IDENTITY_UUID/files" -H "X-API-Key: $KEY"
```
#### Response (200)
```json
{
"success": true,
"identity_uuid": "c3545906c82d4b66aa1d150bc02decce",
"total": 1,
"page": 1,
"page_size": 20,
"data": [
{
"file_uuid": "aeed71342a899fe4b4c57b7d41bcb692",
"file_name": "Charade (1963) Cary Grant & Audrey Hepburn.mp4",
"file_path": "/path/to/videos/Charade.mp4",
"status": "completed",
"face_count": 19695,
"speaker_count": 0,
"first_appearance": 206.76,
"last_appearance": 6756.68,
"confidence": 0.803
}
]
}
```
#### Response Fields
| Field | Type | Description |
|-------|------|-------------|
| `file_uuid` | string | File identifier (full 32-char hex) |
| `file_name` | string | Video file name |
| `file_path` | string | Absolute path to video file |
| `status` | string | Video processing status (`"completed"`, `"processing"`, etc.) |
| `face_count` | int | Total face detections for this identity in this file |
| `speaker_count` | int | Speaker segments (reserved, always `0`) |
| `first_appearance` | float | First appearance time in seconds (computed from `frame_number / fps`) |
| `last_appearance` | float | Last appearance time in seconds |
| `confidence` | float | Average detection confidence |
---
### `GET /api/v1/identity/:identity_uuid/faces`
**Auth**: Required
**Scope**: identity-level
Get all face detection records associated with this identity.
#### Example
```bash
curl -s "$API/api/v1/identity/$IDENTITY_UUID/faces?page=1&page_size=20" -H "X-API-Key: $KEY"
```
#### Response (200)
```json
{
"success": true,
"identity_uuid": "c3545906c82d4b66aa1d150bc02decce",
"total": 19695,
"page": 1,
"page_size": 20,
"data": [
{
"id": 655704,
"file_uuid": "aeed71342a899fe4b4c57b7d41bcb692",
"frame_number": 5169,
"timestamp_secs": 206.76,
"face_id": "5169_0",
"bbox": {
"x": 706,
"y": 469,
"width": 618,
"height": 618
},
"confidence": 0.855
}
]
}
```
#### Response Fields
| Field | Type | Description |
|-------|------|-------------|
| `id` | int64 | Face detection record ID |
| `file_uuid` | string | File where face was detected |
| `frame_number` | int64 | Frame number (primary coordinate) |
| `timestamp_secs` | float | Time in seconds (computed as `frame_number / fps`) |
| `face_id` | string | Face ID (format: `{frame_number}_{detection_index}`) |
| `bbox` | object | Bounding box |
| `bbox.x` | float | Left coordinate |
| `bbox.y` | float | Top coordinate |
| `bbox.width` | float | Width in pixels |
| `bbox.height` | float | Height in pixels |
| `confidence` | float | Detection confidence (0.01.0) |
---
### `GET /api/v1/identity/:identity_uuid/chunks`
**Auth**: Required
**Scope**: identity-level
Get all text chunks (sentences) spoken while this identity's face was on screen. Useful for finding what a person said.
#### Example
```bash
curl -s "$API/api/v1/identity/$IDENTITY_UUID/chunks" -H "X-API-Key: $KEY"
```
#### Response (200)
```json
{
"success": true,
"identity_uuid": "a9a901056d6b46ff92da0c3c1a57dff4",
"data": [
{
"id": 0,
"file_uuid": "bd80fec92b0b6963d177a2c55bf713e2",
"chunk_id": "bd80fec92b0b6963d177a2c55bf713e2_2",
"chunk_type": "sentence",
"start_frame": 5103,
"end_frame": 5127,
"fps": 24.0,
"start_time": 212.64,
"end_time": 213.64,
"text_content": "[213s-214s] Cary Grant: \"Olá!\""
}
]
}
```
| Field | Type | Description |
|-------|------|-------------|
| `file_uuid` | string | File identifier |
| `chunk_id` | string | Sentence chunk identifier |
| `start_frame` | integer | Frame-accurate start position |
| `end_frame` | integer | Frame-accurate end position |
| `fps` | float | Frames per second |
| `start_time` | float | Start time in seconds |
| `end_time` | float | End time in seconds |
| `text_content` | string | Spoken text content |
---
### `POST /api/v1/identity/:identity_uuid/bind`
**Auth**: Required
**Scope**: identity-level
Bind a face detection to an identity. Associates the face trace with the identity for future search and recognition.
#### Request Parameters
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `file_uuid` | string | Yes | File where face is detected |
| `face_id` | string | Yes | Face ID (format: `{frame}_{idx}`) |
#### Example
```bash
curl -s -X POST "$API/api/v1/identity/$IDENTITY_UUID/bind" \
-H "X-API-Key: $KEY" \
-H "Content-Type: application/json" \
-d '{"file_uuid": "'"$FILE_UUID"'", "face_id": "1_5"}'
```
---
### `POST /api/v1/identity/:identity_uuid/unbind`
**Auth**: Required
**Scope**: identity-level
Unbind a face detection from an identity. Removes the identity association from the face record.
---
### `GET /api/v1/identities/search`
**Auth**: Required
**Scope**: identity-level
Search identities by name (ILIKE search). Returns matching identity records.
#### Example
```bash
curl -s "$API/api/v1/identities/search?q=Cary" -H "X-API-Key: $KEY"
```
| Field | Type | Description |
|-------|------|-------------|
| `name` | string | Identity name |
| `source` | string | Identity source |
| `tmdb_id` | integer | TMDb ID (if source = tmdb) |
| `file_uuid` | string | Associated file |
---
---
### `POST /api/v1/identity/upload`
**Auth**: Required
**Scope**: identity-level
Upload an identity.json file to create or update an identity. Accepts the same format as the identity.json files stored on disk.
If an identity with the same `identity_uuid` already exists, it will be updated with the new values.
#### Request
The request body is an `IdentityFile` object:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `identity_uuid` | string | Yes | Identity identifier |
| `name` | string | Yes | Identity display name |
| `identity_type` | string | No | `"people"` or null |
| `source` | string | No | `.json`, `auto`, `tmdb`, `user_defined`, or `merged` |
| `status` | string | No | `"confirmed"`, `"pending"`, or `"inactive"` |
| `tmdb_id` | integer | No | TMDb person ID |
| `tmdb_profile` | string | No | TMDb profile image URL |
| `metadata` | object | No | Arbitrary metadata JSON |
| `file_bindings` | array | No | Array of `{ file_uuid, trace_ids, face_count }` (informational) |
#### Example
```bash
curl -s -X POST "$API/api/v1/identity/upload" \
-H "X-API-Key: $KEY" \
-H "Content-Type: application/json" \
-d '{
"version": 1,
"identity_uuid": "a9a901056d6b46ff92da0c3c1a57dff4",
"name": "Cary Grant",
"identity_type": "people",
"source": ".json",
"status": "confirmed",
"metadata": {},
"file_bindings": []
}'
```
#### Response (200)
```json
{
"success": true,
"identity_uuid": "a9a901056d6b46ff92da0c3c1a57dff4",
"name": "Cary Grant",
"message": "Identity uploaded successfully"
}
```
---
---
### `POST /api/v1/identity/:identity_uuid/profile-image`
**Auth**: Required
**Scope**: identity-level
Upload a profile image (JPEG or PNG) for an identity. The image is saved to `{output}/identities/{uuid}/profile.{ext}`.
Uses `multipart/form-data` with field name `image`.
#### Example
```bash
curl -s -X POST "$API/api/v1/identity/$IDENTITY_UUID/profile-image" \
-H "X-API-Key: $KEY" \
-F "image=@/path/to/photo.jpg"
```
#### Response (200)
```json
{
"success": true,
"identity_uuid": "a9a901056d6b46ff92da0c3c1a57dff4",
"path": "/path/to/output/identities/.../profile.jpg",
"message": "Profile image saved: profile.jpg"
}
```
#### Error Responses
| HTTP | When |
|------|------|
| `400` | Missing image field or unsupported format |
| `404` | Identity not found |
| `415` | Unsupported image type (use JPEG or PNG) |
---
### `GET /api/v1/identity/:identity_uuid/profile-image`
**Auth**: Required
**Scope**: identity-level
Retrieve the profile image for an identity. Returns the raw image data with appropriate Content-Type header.
```bash
curl -s "$API/api/v1/identity/$IDENTITY_UUID/profile-image" \
-H "X-API-Key: $KEY" -o profile.jpg
```
| Response Header | Value |
|----------------|-------|
| `content-type` | `image/jpeg` or `image/png` |
---
## 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.
### BCP 47 Locale Tags Reference
| Locale | Tag | Example |
|--------|-----|---------|
| English | `en` | John Smith |
| Traditional Chinese | `zh-TW` | 約翰·史密斯 |
| Simplified Chinese | `zh-CN` | 约翰·史密斯 |
| Japanese | `ja` | ジョン・スミス |
| Korean | `ko` | 존 스미스 |
| Cantonese | `yue` | 約翰·史密夫 |
| French | `fr` | John Smith (French spelling) |
| Spanish | `es` | Juan Smith |
| Arabic | `ar` | جون سميث |
| Russian | `ru` | Джон Смит |
| Thai | `th` | จอห์น สมิธ |
BCP 47 is the IETF standard for language tags. Format: `language` (e.g. `en`, `ja`) or `language-Region` (e.g. `zh-TW`, `zh-CN`).
### Frontend Display Logic
```javascript
function getDisplayName(identity, preferredLocale) {
const match = identity.metadata?.aliases?.find(a => a.locale === preferredLocale);
if (match) return match.name;
const lang = preferredLocale.split('-')[0];
const langMatch = identity.metadata?.aliases?.find(a => a.locale.startsWith(lang));
if (langMatch) return langMatch.name;
return identity.name;
}
```
### Updating Aliases via PATCH
```json
PATCH /api/v1/identity/:identity_uuid
{
"metadata": {
"aliases": [
{"locale": "en", "name": "John Smith"},
{"locale": "zh-TW", "name": "約翰·史密斯"}
]
}
}
```
---
*Updated: 2026-05-22*

View File

@@ -74,6 +74,66 @@ Delete an identity permanently.
--- ---
### `PATCH /api/v1/identity/:identity_uuid`
**Auth**: Required
**Scope**: identity-level
Partially update an identity. Only provided fields are modified. The `name` field is a display label and may repeat across identities (removed UNIQUE constraint). Aliases for multilingual display are stored in `metadata.aliases` (see BCP 47 reference below).
#### Request (JSON, all fields optional)
| Field | Type | Description |
|-------|------|-------------|
| `name` | string | New display name |
| `metadata` | object | Merged into existing metadata. Use `"aliases"` key for locale-tagged names |
| `status` | string | `"confirmed"`, `"pending"`, or `"skipped"` |
| `identity_type` | string | `"people"`, `"brand"`, `"object"`, `"concept"`, etc. |
#### Example
```bash
# Update name and add aliases
curl -s -X PATCH "$API/api/v1/identity/$IDENTITY_UUID" \
-H "X-API-Key: $KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "John Smith",
"metadata": {
"aliases": [
{"locale": "en", "name": "John Smith"},
{"locale": "zh-TW", "name": "約翰·史密斯"},
{"locale": "ja", "name": "ジョン・スミス"}
]
}
}'
# Update status only
curl -s -X PATCH "$API/api/v1/identity/$IDENTITY_UUID" \
-H "X-API-Key: $KEY" \
-H "Content-Type: application/json" \
-d '{"status": "confirmed"}'
```
#### Response (200)
```json
{
"success": true,
"identity_uuid": "a9a901056d6b46ff92da0c3c1a57dff4",
"updated_fields": ["name", "metadata"]
}
```
#### Error Responses
| HTTP | When |
|------|------|
| `400` | No fields to update or invalid UUID format |
| `404` | Identity not found |
---
### `GET /api/v1/identity/:identity_uuid/files` ### `GET /api/v1/identity/:identity_uuid/files`
**Auth**: Required **Auth**: Required
@@ -225,7 +285,7 @@ curl -s "$API/api/v1/identities/search?q=Cary" -H "X-API-Key: $KEY"
Upload an identity.json file to create or update an identity. Accepts the same format as the identity.json files stored on disk. Upload an identity.json file to create or update an identity. Accepts the same format as the identity.json files stored on disk.
If an identity with the same `name` already exists, it will be updated with the new values. If an identity with the same `identity_uuid` already exists, it will be updated with the new values.
#### Request #### Request
@@ -330,7 +390,63 @@ curl -s "$API/api/v1/identity/$IDENTITY_UUID/profile-image" \
|----------------|-------| |----------------|-------|
| `content-type` | `image/jpeg` or `image/png` | | `content-type` | `image/jpeg` or `image/png` |
---
## 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.
### BCP 47 Locale Tags Reference
| Locale | Tag | Example |
|--------|-----|---------|
| English | `en` | John Smith |
| Traditional Chinese | `zh-TW` | 約翰·史密斯 |
| Simplified Chinese | `zh-CN` | 约翰·史密斯 |
| Japanese | `ja` | ジョン・スミス |
| Korean | `ko` | 존 스미스 |
| Cantonese | `yue` | 約翰·史密夫 |
| French | `fr` | John Smith (French spelling) |
| Spanish | `es` | Juan Smith |
| Arabic | `ar` | جون سميث |
| Russian | `ru` | Джон Смит |
| Thai | `th` | จอห์น สมิธ |
BCP 47 is the IETF standard for language tags. Format: `language` (e.g. `en`, `ja`) or `language-Region` (e.g. `zh-TW`, `zh-CN`). Region suffix distinguishes regional variants.
### Frontend Display Logic
```javascript
function getDisplayName(identity, preferredLocale) {
// 1. Exact locale match
const match = identity.metadata?.aliases?.find(a => a.locale === preferredLocale);
if (match) return match.name;
// 2. Language-only match (zh-TW → zh)
const lang = preferredLocale.split('-')[0];
const langMatch = identity.metadata?.aliases?.find(a => a.locale.startsWith(lang));
if (langMatch) return langMatch.name;
// 3. Fallback to identity.name
return identity.name;
}
```
### Updating Aliases via PATCH
```json
PATCH /api/v1/identity/:identity_uuid
{
"metadata": {
"aliases": [
{"locale": "en", "name": "John Smith"},
{"locale": "zh-TW", "name": "約翰·史密斯"}
]
}
}
```
This **replaces** the entire `aliases` array. To add to existing aliases, include all existing entries in the request.
--- ---
*Updated: 2026-05-19 12:49:24* *Updated: 2026-05-22

View File

@@ -225,7 +225,7 @@ curl -s "$API/api/v1/identities/search?q=Cary" -H "X-API-Key: $KEY"
Upload an identity.json file to create or update an identity. Accepts the same format as the identity.json files stored on disk. Upload an identity.json file to create or update an identity. Accepts the same format as the identity.json files stored on disk.
If an identity with the same `name` already exists, it will be updated with the new values. If an identity with the same `identity_uuid` already exists, it will be updated with the new values.
#### Request #### Request