diff --git a/deliverable_v1.1.0/modules/07_identity.md b/deliverable_v1.1.0/modules/07_identity.md new file mode 100644 index 0000000..8d853d4 --- /dev/null +++ b/deliverable_v1.1.0/modules/07_identity.md @@ -0,0 +1,516 @@ + + + + +## 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.0–1.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* + + diff --git a/docs_v1.0/API_WORKSPACE/modules/07_identity.md b/docs_v1.0/API_WORKSPACE/modules/07_identity.md index 0bdd806..66dc65a 100644 --- a/docs_v1.0/API_WORKSPACE/modules/07_identity.md +++ b/docs_v1.0/API_WORKSPACE/modules/07_identity.md @@ -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` **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. -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 @@ -330,7 +390,63 @@ curl -s "$API/api/v1/identity/$IDENTITY_UUID/profile-image" \ |----------------|-------| | `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 diff --git a/docs_v1.0/doc_wasm/modules/07_identity.md b/docs_v1.0/doc_wasm/modules/07_identity.md index 0bdd806..d0ca1b1 100644 --- a/docs_v1.0/doc_wasm/modules/07_identity.md +++ b/docs_v1.0/doc_wasm/modules/07_identity.md @@ -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. -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