From 5b2f9b35bf53c3acc3d01dbedd81fe9ea622d540 Mon Sep 17 00:00:00 2001 From: Accusys Date: Tue, 19 May 2026 12:50:39 +0800 Subject: [PATCH] docs: add video vs clip comparison table + update timestamps to all 14 modules --- docs_v1.0/API_WORKSPACE/modules/01_auth.md | 283 ++++++++++++++++++ docs_v1.0/API_WORKSPACE/modules/02_health.md | 3 + .../API_WORKSPACE/modules/03_register.md | 3 + docs_v1.0/API_WORKSPACE/modules/04_lookup.md | 141 +++++++++ docs_v1.0/API_WORKSPACE/modules/05_process.md | 239 +++++++++++++++ docs_v1.0/API_WORKSPACE/modules/06_search.md | 3 + .../API_WORKSPACE/modules/07_identity.md | 3 + .../modules/08_identity_agent.md | 68 +++++ docs_v1.0/API_WORKSPACE/modules/08_media.md | 175 +++++++++++ docs_v1.0/API_WORKSPACE/modules/09_tmdb.md | 112 +++++++ .../API_WORKSPACE/modules/10_pipeline.md | 3 + .../API_WORKSPACE/modules/11_error_codes.md | 60 ++++ docs_v1.0/API_WORKSPACE/modules/12_agent.md | 121 ++++++++ docs_v1.0/API_WORKSPACE/modules/13_config.md | 3 + docs_v1.0/API_WORKSPACE/modules/_template.md | 63 ++++ 15 files changed, 1280 insertions(+) create mode 100644 docs_v1.0/API_WORKSPACE/modules/01_auth.md create mode 100644 docs_v1.0/API_WORKSPACE/modules/04_lookup.md create mode 100644 docs_v1.0/API_WORKSPACE/modules/05_process.md create mode 100644 docs_v1.0/API_WORKSPACE/modules/08_identity_agent.md create mode 100644 docs_v1.0/API_WORKSPACE/modules/08_media.md create mode 100644 docs_v1.0/API_WORKSPACE/modules/09_tmdb.md create mode 100644 docs_v1.0/API_WORKSPACE/modules/11_error_codes.md create mode 100644 docs_v1.0/API_WORKSPACE/modules/12_agent.md create mode 100644 docs_v1.0/API_WORKSPACE/modules/_template.md diff --git a/docs_v1.0/API_WORKSPACE/modules/01_auth.md b/docs_v1.0/API_WORKSPACE/modules/01_auth.md new file mode 100644 index 0000000..a1d7d31 --- /dev/null +++ b/docs_v1.0/API_WORKSPACE/modules/01_auth.md @@ -0,0 +1,283 @@ + + + + +## Base URL + +| Environment | URL | Purpose | +|-------------|-----|---------| +| Production | `http://localhost:3002` | Production deployment | +| External (M5) | `https://m5api.momentry.ddns.net` | Remote access | + +## Variables + +All examples in this documentation use these environment variables: + +```bash +API="http://localhost:3002" +KEY="your-api-key-here" +``` + +## Authentication + +All endpoints under `/api/v1/*` require authentication. +The following endpoints are public (no auth needed): + +- `GET /health` +- `POST /api/v1/auth/login` +- `POST /api/v1/auth/logout` + +### Three Authentication Modes + +The system supports three authentication methods, checked in **priority order** by the middleware: + +``` +Middleware priority: + 1. Session Cookie (Portal/browser) + 2. JWT Bearer (API clients, CLI) + 3. API Key Header (legacy compatibility) + 4. API Key Query Param (?api_key=) +``` + +| Mode | Transport | Expiry | Scope | Best for | +|------|-----------|--------|-------|----------| +| **Session Cookie** | `Cookie: session_id=` | 24h | per-browser session | Portal (browser) | +| **JWT** | `Authorization: Bearer ` | 1h | per-login token | API clients, CLI, scripts | +| **API Key** | `X-API-Key: ` | 90d | fixed key for automation | Legacy scripts, WordPress | + +--- + +### Login + +**Default accounts & API keys:** + +| Username | Password | API Key | Role | +|----------|----------|---------|------| +| `admin` | `admin` | — | admin | +| `demo` | `demo` | `muser_demo_key_32chars_abcdef1234567890` | user | + +The demo API key is set via `MOMENTRY_DEMO_API_KEY` env var and can be used in place of JWT for marcom integrations: + +```bash +# Using API key instead of JWT +curl -s "$API/api/v1/files/scan" -H "X-API-Key: muser_demo_key_32chars_abcdef1234567890" +``` + +```bash +# Login as admin +curl -s -X POST "$API/api/v1/auth/login" \ + -H "Content-Type: application/json" \ + -d '{"username": "admin", "password": "admin"}' + +# Login as demo user +curl -s -X POST "$API/api/v1/auth/login" \ + -H "Content-Type: application/json" \ + -d '{"username": "demo", "password": "demo"}' +``` + +#### Success Response + +```json +{ + "success": true, + "jwt": "eyJhbGciOiJIUzI1NiIs...", + "api_key": "muser_...", + "user": { + "username": "admin", + "role": "admin" + }, + "expires_at": "2026-05-18T13:00:00Z" +} +``` + +| Field | Type | Description | +|-------|------|-------------| +| `jwt` | string | JWT access token. Use as `Authorization: Bearer `. Expires in 1 hour. | +| `api_key` | string | Legacy API key. Use as `X-API-Key: `. Good for 90 days. | +| `user.username` | string | Username | +| `user.role` | string | Role: `admin`, `user`, or `readonly` | +| `expires_at` | string | ISO8601 timestamp of JWT expiration | + +The login endpoint also sets a `Set-Cookie` header for browser-based clients: + +``` +Set-Cookie: session_id=; Path=/; HttpOnly; SameSite=Strict; Max-Age=86400 +``` + +#### Error Response (401) + +```json +{ + "success": false, + "message": "Invalid username or password" +} +``` + +--- + +### Using JWT + +JWT is preferred for API clients (CLI scripts, WordPress). It is validated by the middleware without a database lookup (stateless). + +```bash +# Login and capture JWT +JWT=$(curl -s -X POST "$API/api/v1/auth/login" \ + -H "Content-Type: application/json" \ + -d '{"username":"admin","password":"admin"}' | python3 -c "import json,sys;print(json.load(sys.stdin)['jwt'])") + +# Use JWT for all subsequent requests +curl -H "Authorization: Bearer $JWT" "$API/api/v1/files/scan" +curl -H "Authorization: Bearer $JWT" "$API/api/v1/resource/tmdb" +``` + +JWT is short-lived (1 hour). When it expires, request a new one via login. + +--- + +### Using Session Cookie (Browser) + +Browser-based clients (Portal) get a session cookie automatically after login. The browser sends the cookie with every request—no manual header needed. + +```bash +# Login captures the session cookie from Set-Cookie header +curl -v -X POST "$API/api/v1/auth/login" \ + -H "Content-Type: application/json" \ + -d '{"username":"admin","password":"admin"}' 2>&1 | grep "Set-Cookie" + +# Browser automatically sends: Cookie: session_id= +# No manual header needed for subsequent requests +``` + +The session cookie is HttpOnly (not accessible from JavaScript) and SameSite=Strict (protected against CSRF). + +--- + +### Using Legacy API Key + +```bash +curl -H "X-API-Key: $KEY" "$API/api/v1/files/scan" + +# Also accepted via Bearer header (non-JWT format) or query parameter: +curl -H "Authorization: Bearer $KEY" "$API/api/v1/files/scan" +curl "$API/api/v1/files/scan?api_key=$KEY" +``` + +API keys are validated via SHA256 hash lookup in the database. They are long-lived (90 days) and intended for automation. + +### Obtaining an API Key (CLI) + +```bash +momentry api-key create "My API Key" --key-type user +``` + +--- + +### Logout + +```bash +# Logout using the session cookie (browser) +curl -X POST "$API/api/v1/auth/logout" \ + -H "Cookie: session_id=" +``` + +#### What logout does + +| Auth mode | Effect | +|-----------|--------| +| **Session Cookie** | Session deleted from database. Same cookie returns 401 on subsequent requests. | +| **JWT** | JWT remains valid until expiry. (JWT is stateless — logout adds JWT to a blacklist only if API key mode is used.) | +| **API Key** | API key remains valid. (Legacy keys are shared across sessions — revoking would break other clients.) | + +#### Example: full session lifecycle + +```bash +# 1. Login +SESSION_ID=$(curl -s -D - -X POST "$API/api/v1/auth/login" \ + -H "Content-Type: application/json" \ + -d '{"username":"admin","password":"admin"}' | grep "Set-Cookie" | sed 's/.*session_id=\([^;]*\).*/\1/') + +# 2. Use session (works) +curl -s -o /dev/null -w "HTTP %{http_code}\n" "$API/api/v1/resource/tmdb" \ + -H "Cookie: session_id=$SESSION_ID" +# → HTTP 200 + +# 3. Logout +curl -s -X POST "$API/api/v1/auth/logout" \ + -H "Cookie: session_id=$SESSION_ID" +# → {"success": true} + +# 4. Use session again (rejected) +curl -s -o /dev/null -w "HTTP %{http_code}\n" "$API/api/v1/resource/tmdb" \ + -H "Cookie: session_id=$SESSION_ID" +# → HTTP 401 +``` + +--- + +### Authentication Flow Summary + +``` +Login Request + │ + ▼ +┌──────────────────┐ +│ 1. Check users │ ← users table (argon2 password verify) +│ table │ +└──────┬───────────┘ + │ + ┌───┴───┐ + │ match │ + └───┬───┘ + │ + ▼ +┌──────────────────┐ +│ 2. Create JWT │ ← 1h expiry, signed with JWT_SECRET +├──────────────────┤ +│ 3. Create │ ← 24h expiry, stored in sessions table +│ session │ +├──────────────────┤ +│ 4. Set-Cookie │ ← HttpOnly, SameSite=Strict, Path=/ +├──────────────────┤ +│ 5. Return │ ← JWT + api_key + user info to client +└──────────────────┘ +``` + +``` +Protected Request + │ + ▼ +┌──────────────────────┐ +│ Middleware checks: │ +│ │ +│ 1. Cookie session? │ → DB lookup session → get api_key → verify +│ │ +│ 2. JWT Bearer? │ → verify JWT signature → decode claims +│ │ +│ 3. X-API-Key? │ → SHA256 hash → DB lookup → verify +│ │ +│ 4. ?api_key=? │ → same as #3 +│ │ +│ 5. None → 401 │ +└──────────────────────┘ +``` + +--- + +### Error Responses + +| HTTP | When | +|------|------| +| `401` | Missing or invalid authentication | +| `401` | Session expired or logged out | +| `401` | JWT expired | +| `401` | API key revoked or inactive | + +--- + +### Related + +- `POST /api/v1/resource/tmdb/check` — test authentication + TMDb API connectivity +- `GET /health/detailed` — view auth status (integrations section) + +--- +*Updated: 2026-05-19 12:49:24* diff --git a/docs_v1.0/API_WORKSPACE/modules/02_health.md b/docs_v1.0/API_WORKSPACE/modules/02_health.md index fa77710..8dbd676 100644 --- a/docs_v1.0/API_WORKSPACE/modules/02_health.md +++ b/docs_v1.0/API_WORKSPACE/modules/02_health.md @@ -185,3 +185,6 @@ curl -s "$API/health/consistency" -H "X-API-Key: $KEY" | jq '.checks[] | {check, | Method | Endpoint | Auth | Description | |--------|----------|------|-------------| | GET | `/api/v1/stats/sftpgo` | No | SFTPGo service status | + +--- +*Updated: 2026-05-19 12:49:24* diff --git a/docs_v1.0/API_WORKSPACE/modules/03_register.md b/docs_v1.0/API_WORKSPACE/modules/03_register.md index b1643cf..0a18c76 100644 --- a/docs_v1.0/API_WORKSPACE/modules/03_register.md +++ b/docs_v1.0/API_WORKSPACE/modules/03_register.md @@ -183,3 +183,6 @@ curl -s "$API/api/v1/files/scan?sort_by=status&page_size=5" -H "X-API-Key: $KEY" | **Sort order** | Default (`sort_by=name`): registered files first, then alphabetically. `sort_by=status`: alphabetical by status string. | | **Pagination** | `page_size` and `limit` are aliases. Default: show all results. | | **Processing order** | `pattern` regex filter → `sort_by`/`sort_order` → `page`/`page_size` slice. | + +--- +*Updated: 2026-05-19 12:49:24* diff --git a/docs_v1.0/API_WORKSPACE/modules/04_lookup.md b/docs_v1.0/API_WORKSPACE/modules/04_lookup.md new file mode 100644 index 0000000..c22a3a7 --- /dev/null +++ b/docs_v1.0/API_WORKSPACE/modules/04_lookup.md @@ -0,0 +1,141 @@ + + + + +## File Lookup + +### `GET /api/v1/files/lookup` + +**Auth**: Required +**Scope**: file-level + +Search registered files by file name. Performs a case-insensitive LIKE search on the file name column. Returns basic info about matching files. + +#### Query Parameters + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `file_name` | string | Yes | File name to search for (partial matches supported) | + +#### Example + +```bash +# Look up a specific file +curl -s "$API/api/v1/files/lookup?file_name=video.mp4" \ + -H "X-API-Key: $KEY" + +# Partial name search +curl -s "$API/api/v1/files/lookup?file_name=charade" \ + -H "X-API-Key: $KEY" | jq '.matches[].file_name' +``` + +#### Response (200) + +```json +{ + "file_name": "video.mp4", + "exists": true, + "matches": [ + { + "file_uuid": "a03485a40b2df2d3", + "file_name": "video.mp4", + "file_type": "video", + "status": "completed" + } + ], + "next_name": "video (2).mp4" +} +``` + +| Field | Type | Description | +|-------|------|-------------| +| `file_name` | string | Searched name | +| `exists` | boolean | Exact name match exists | +| `matches` | array | Array of matching registered files | +| `matches[].file_uuid` | string | 32-char hex UUID | +| `matches[].file_name` | string | Registered file name | +| `matches[].file_type` | string | `"video"`, `"audio"`, or `null` | +| `matches[].status` | string | Registration/processing status | +| `next_name` | string | Suggested name for avoiding conflicts | + +--- + +## Unregister + +### `POST /api/v1/unregister` + +**Auth**: Required +**Scope**: file-level + +Delete a registered file from the system. Supports single file by UUID, or batch by directory + regex pattern. + +#### What gets deleted + +| Removed (default) | Not removed | +|---------|-------------| +| Database records (videos, chunks, embeddings, processor_results, pre_chunks) | The original source video file on disk | +| Processor output JSON files (`{uuid}.*.json`) — unless `delete_output_files: false` | Temp/working directories | +| In-memory cache entries | | +| MongoDB cached lists | | + +> ⚠️ Database deletion is **irreversible**. To keep output files, set `"delete_output_files": false`. + +#### Request Parameters + +At least one mode must be specified: either `file_uuid` alone, or `file_path` + `pattern` together. + +| Field | Type | Required | Default | Description | +|-------|------|----------|---------|-------------| +| `file_uuid` | string | * | — | Single file UUID to delete | +| `file_path` | string | * | — | Directory path (for batch delete) | +| `pattern` | string | * | — | Regex pattern (requires `file_path`) | +| `delete_output_files` | boolean | No | `true` | If `true`, also delete processor output JSON files (`{uuid}.*.json`). Set to `false` to keep them. | + +#### Example + +```bash +# Delete a single file by UUID (default: also deletes output JSON files) +curl -s -X POST "$API/api/v1/unregister" \ + -H "Content-Type: application/json" \ + -H "X-API-Key: $KEY" \ + -d '{"file_uuid": "'"$FILE_UUID"'"}' + +# Keep output JSON files, only delete DB records +curl -s -X POST "$API/api/v1/unregister" \ + -H "Content-Type: application/json" \ + -H "X-API-Key: $KEY" \ + -d '{"file_uuid": "'"$FILE_UUID"'", "delete_output_files": false}' + +# Batch delete all mp4 files in a directory +curl -s -X POST "$API/api/v1/unregister" \ + -H "Content-Type: application/json" \ + -H "X-API-Key: $KEY" \ + -d '{"file_path": "/path/to/dir", "pattern": ".*\\.mp4$"}' +``` + +#### Response (200) + +```json +{ + "success": true, + "file_uuid": "a03485a40b2df2d3", + "message": "Video unregistered successfully" +} +``` + +| Field | Type | Description | +|-------|------|-------------| +| `success` | boolean | True if deletion succeeded | +| `file_uuid` | string | UUID of the deleted file (single mode) | +| `message` | string | Human-readable status | + +#### Error Responses + +| HTTP | When | +|------|------| +| `400` | Neither `file_uuid` nor `file_path`+`pattern` provided | +| `404` | File UUID not found | +| `401` | Missing or invalid API key | + +--- +*Updated: 2026-05-19 12:49:24* diff --git a/docs_v1.0/API_WORKSPACE/modules/05_process.md b/docs_v1.0/API_WORKSPACE/modules/05_process.md new file mode 100644 index 0000000..fcdce8a --- /dev/null +++ b/docs_v1.0/API_WORKSPACE/modules/05_process.md @@ -0,0 +1,239 @@ + + + + +## Processing Pipeline + +### `POST /api/v1/file/:file_uuid/process` + +**Auth**: Required +**Scope**: file-level + +Trigger the processing pipeline for a registered file. Creates a monitor job that the worker picks up and processes sequentially. Returns immediately with the job info—processing runs asynchronously in the background. + +#### Request Parameters + +| Field | Type | Required | Default | Description | +|-------|------|----------|---------|-------------| +| `processors` | string[] | No | all | Specific processors to run: `["cut","asr","asrx","yolo","ocr","face","pose","visual_chunk","story","5w1h"]` | +| `rules` | string[] | No | all | Rule names to apply (currently unused) | + +#### Example + +```bash +# Run all processors +curl -s -X POST "$API/api/v1/file/$FILE_UUID/process" \ + -H "Content-Type: application/json" \ + -H "X-API-Key: $KEY" -d '{}' + +# Run specific processors only +curl -s -X POST "$API/api/v1/file/$FILE_UUID/process" \ + -H "Content-Type: application/json" \ + -H "X-API-Key: $KEY" \ + -d '{"processors": ["asr", "face", "yolo"]}' +``` + +#### Response (200) + +```json +{ + "success": true, + "job_id": 42, + "file_uuid": "3a6c1865...", + "status": "processing", + "pids": [12345, 12346], + "message": "Processing triggered for video.mp4" +} +``` + +| Field | Type | Description | +|-------|------|-------------| +| `success` | boolean | Always true on 200 | +| `job_id` | integer | Monitor job ID (for job tracking) | +| `file_uuid` | string | 32-char hex UUID of the file | +| `status` | string | `"processing"` | +| `pids` | integer[] | Process IDs of started processors | +| `message` | string | Human-readable status | + +#### Error Responses + +| HTTP | When | +|------|------| +| `404` | File UUID not found | +| `401` | Missing or invalid API key | + +--- + +### `GET /api/v1/file/:file_uuid/probe` + +**Auth**: Required +**Scope**: file-level + +Get ffprobe metadata for a registered file. Returns video/audio stream info, codec details, duration, resolution, and frame rate. + +#### Example + +```bash +curl -s "$API/api/v1/file/$FILE_UUID/probe" -H "X-API-Key: $KEY" +``` + +#### Response (200) + +```json +{ + "file_uuid": "3a6c1865...", + "file_name": "video.mp4", + "file_size": 794863677, + "duration": 120.5, + "width": 1920, + "height": 1080, + "fps": 24.0, + "total_frames": 2892, + "cached": true, + "format": { + "filename": "/path/to/video.mp4", + "format_name": "mov,mp4,m4a,3gp", + "duration": "120.5", + "size": "12345678", + "bit_rate": "819200" + }, + "streams": [ + { + "index": 0, + "codec_name": "h264", + "codec_type": "video", + "width": 1920, + "height": 1080, + "r_frame_rate": "24/1", + "duration": "120.5" + } + ] +} +``` + +| Field | Type | Description | +|-------|------|-------------| +| `file_uuid` | string | 32-char hex UUID | +| `file_name` | string | File name | +| `file_size` | integer | File size in bytes (from filesystem) | +| `duration` | float | Duration in seconds | +| `width` | integer | Video width in pixels | +| `height` | integer | Video height in pixels | +| `fps` | float | Frames per second | +| `total_frames` | integer | Estimated total frames | +| `cached` | boolean | True if result was from cached probe JSON | +| `format` | object | Container format info (ffprobe format section) | +| `streams` | array | Array of stream info objects | + +--- + +### `GET /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. + +#### Pipeline Order + +| Order | Processor | Dependencies | Description | +|-------|-----------|-------------|-------------| +| 1 | `cut` | — | Scene detection | +| 2 | `asr` | cut | Speech-to-text (per scene) | +| 3 | `asrx` | asr | Speaker diarization | +| 4 | `yolo` | — | Object detection | +| 5 | `ocr` | — | Text recognition | +| 6 | `face` | — | Face detection & embedding | +| 7 | `pose` | — | Pose estimation | +| 8 | `visual_chunk` | yolo | Visual scene chunks | +| 9 | `story` | asr, asrx, cut, yolo, face | Scene summaries (template) | +| 10 | `5w1h` | story | 5W1H analysis (Gemma4 LLM) | + +All processors except `story` and `5w1h` run concurrently when their dependencies are met. Story and 5W1H run sequentially after their prerequisites. + +#### Example + +```bash +curl -s "$API/api/v1/progress/$FILE_UUID" -H "X-API-Key: $KEY" | jq '{overall_progress, processors: [.processors[] | {processor_type, status}]}' +``` + +#### Response (200) + +```json +{ + "file_uuid": "3a6c1865...", + "overall_progress": 71, + "cpu_percent": 45.2, + "gpu_percent": 30.1, + "memory_percent": 62.4, + "processors": [ + {"processor_type": "asr", "status": "complete", "progress": 100}, + {"processor_type": "yolo", "status": "running", "progress": 65}, + {"processor_type": "face", "status": "pending", "progress": 0} + ] +} +``` + +| Field | Type | Description | +|-------|------|-------------| +| `file_uuid` | string | 32-char hex UUID | +| `overall_progress` | integer | Overall progress percentage (0–100) | +| `processors` | array | Per-processor status list | +| `processors[].processor_type` | string | Processor name (`asr`, `cut`, `yolo`, etc.) | +| `processors[].status` | string | `"pending"`, `"running"`, `"complete"`, or `"failed"` | +| `processors[].progress` | integer | Per-processor progress (0–100) | +| `processors[].eta_seconds` | integer | Estimated seconds remaining (running processors) | +| `processors[].current` | integer | Current frame count | +| `processors[].total` | integer | Total frame count | +| `cpu_percent` | float | Current CPU usage | +| `gpu_percent` | float | Current GPU utilization | +| `memory_percent` | float | Current memory usage | + +--- + +### `GET /api/v1/jobs` + +**Auth**: Required +**Scope**: system-level + +List all processing jobs (monitor jobs) in the system. Shows job status, which file each job is processing, and current processor info. + +#### Example + +```bash +curl -s "$API/api/v1/jobs" -H "X-API-Key: $KEY" | jq '{count, jobs: [.jobs[] | {uuid, status}]}' +``` + +#### Response (200) + +```json +{ + "jobs": [ + { + "id": 42, + "uuid": "3a6c1865...", + "status": "running", + "current_processor": "yolo", + "created_at": "2026-05-16T12:00:00Z", + "started_at": "2026-05-16T12:01:00Z" + } + ], + "count": 15, + "page": 1, + "page_size": 20 +} +``` + +| Field | Type | Description | +|-------|------|-------------| +| `jobs` | array | Array of job info objects | +| `jobs[].id` | integer | Job ID | +| `jobs[].uuid` | string | File UUID being processed | +| `jobs[].status` | string | `"pending"`, `"running"`, `"completed"`, `"failed"` | +| `jobs[].current_processor` | string | Currently active processor, or null | +| `count` | integer | Total job count | +| `page` | integer | Current page number | +| `page_size` | integer | Jobs per page | + +--- +*Updated: 2026-05-19 12:49:24* diff --git a/docs_v1.0/API_WORKSPACE/modules/06_search.md b/docs_v1.0/API_WORKSPACE/modules/06_search.md index e5b13c3..0fad9df 100644 --- a/docs_v1.0/API_WORKSPACE/modules/06_search.md +++ b/docs_v1.0/API_WORKSPACE/modules/06_search.md @@ -143,3 +143,6 @@ Search text chunks spoken by a specific identity. | **Endpoint** | `POST /api/v1/embeddings` on port 11436 | | **Dimension** | 768 | | **Storage** | pgvector (`chunk.embedding` column) | + +--- +*Updated: 2026-05-19 12:49:24* diff --git a/docs_v1.0/API_WORKSPACE/modules/07_identity.md b/docs_v1.0/API_WORKSPACE/modules/07_identity.md index 4b8e3ef..0bdd806 100644 --- a/docs_v1.0/API_WORKSPACE/modules/07_identity.md +++ b/docs_v1.0/API_WORKSPACE/modules/07_identity.md @@ -331,3 +331,6 @@ curl -s "$API/api/v1/identity/$IDENTITY_UUID/profile-image" \ | `content-type` | `image/jpeg` or `image/png` | + +--- +*Updated: 2026-05-19 12:49:24* diff --git a/docs_v1.0/API_WORKSPACE/modules/08_identity_agent.md b/docs_v1.0/API_WORKSPACE/modules/08_identity_agent.md new file mode 100644 index 0000000..7fb3c5f --- /dev/null +++ b/docs_v1.0/API_WORKSPACE/modules/08_identity_agent.md @@ -0,0 +1,68 @@ + + + + +## Identity Agent + +### `POST /api/v1/agents/identity/match-from-photo` + +**Auth**: Required +**Scope**: file-level + +Upload a face photo to match against known identities. Detects face via InsightFace, extracts 512D embedding via CoreML FaceNet, then searches pgvector for the closest identity. + +#### Request + +`multipart/form-data` with field `image` (JPEG/PNG) and optional `file_uuid`. + +#### Example + +```bash +curl -s -X POST "$API/api/v1/agents/identity/match-from-photo" \ + -H "Authorization: Bearer $JWT" \ + -F "image=@/path/to/face.jpg" \ + -F "file_uuid=$FILE_UUID" +``` + +#### Response (200) + +```json +{ + "success": true, + "matches": [ + { + "identity_uuid": "a9a90105...", + "name": "Cary Grant", + "similarity": 0.87 + } + ] +} +``` + +--- + +### `POST /api/v1/agents/identity/match-from-trace` + +**Auth**: Required +**Scope**: file-level + +Match a face trace (tracked face across frames) against known identities. Samples 3 angles from the trace, generates embeddings, and searches pgvector. + +#### Request Parameters + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `file_uuid` | string | Yes | File containing the trace | +| `trace_id` | integer | Yes | Face trace ID to match | + +#### Example + +```bash +curl -s -X POST "$API/api/v1/agents/identity/match-from-trace" \ + -H "Authorization: Bearer $JWT" \ + -H "Content-Type: application/json" \ + -d '{"file_uuid": "'"$FILE_UUID"'", "trace_id": 10}' +``` + +--- +*Updated: 2026-05-19 12:49:24* diff --git a/docs_v1.0/API_WORKSPACE/modules/08_media.md b/docs_v1.0/API_WORKSPACE/modules/08_media.md new file mode 100644 index 0000000..e75e13f --- /dev/null +++ b/docs_v1.0/API_WORKSPACE/modules/08_media.md @@ -0,0 +1,175 @@ + + + + +## Video Streaming & Frame Extraction + +All video streaming endpoints support the following common query parameters: + +| Field | Type | Required | Default | Description | +|-------|------|----------|---------|-------------| +| `mode` | string | No | `normal` | `normal` or `debug` (draws detection overlays) | +| `audio` | string | No | `on` | `on` or `off` | + +--- + +### `GET /api/v1/file/:file_uuid/video` + +Stream the full video file with range support for seeking. + +**Auth**: Required +**Scope**: file-level + +#### Response + +- **200**: Video stream (`Content-Type` based on file extension) +- **206**: Partial content (range request) +- Supports `Range` header for seeking + +--- + +### `GET /api/v1/file/:file_uuid/trace/:trace_id/video` + +Stream video with highlights for a specific face trace (follows a single person across frames with bounding box overlay). + +**Auth**: Required +**Scope**: file-level + +--- + +### `GET /api/v1/file/:file_uuid/video/bbox` + +Stream video with bounding box overlay for all detected objects/faces. + +**Auth**: Required +**Scope**: file-level + +Uses a built-in 5×7 bitmap font renderer to draw labels directly on video frames via FFmpeg `drawtext` filter. + +--- + +### `GET /api/v1/file/:file_uuid/thumbnail` + +Extract a single frame from a video as JPEG image. Uses FFmpeg `select` filter. + +**Auth**: Required +**Scope**: file-level + +#### Query Parameters + +| Field | Type | Required | Default | Description | +|-------|------|----------|---------|-------------| +| `frame` | integer | Yes | — | Zero-based frame number to extract | +| `x` | integer | No | — | Crop start X (left edge). Requires `y`, `w`, `h`. | +| `y` | integer | No | — | Crop start Y (top edge). Requires `x`, `w`, `h`. | +| `w` | integer | No | — | Crop width in pixels. Requires `x`, `y`, `h`. | +| `h` | integer | No | — | Crop height in pixels. Requires `x`, `y`, `w`. | + +All four crop params (`x`, `y`, `w`, `h`) must be provided together or omitted. + +#### Example + +```bash +# Extract frame 1000 (full frame) +curl -s "$API/api/v1/file/bd80fec92b0b6963d177a2c55bf713e2/thumbnail?frame=1000" \ + -H "Authorization: Bearer $JWT" -o frame_1000.jpg + +# Extract and crop face region (x=320, y=240, w=160, h=160) +curl -s "$API/api/v1/file/bd80fec92b0b6963d177a2c55bf713e2/thumbnail?frame=1000&x=320&y=240&w=160&h=160" \ + -H "Authorization: Bearer $JWT" -o face_crop.jpg +``` + +#### Response + +- **200**: `image/jpeg` binary data +- **404**: File not found +- **500**: FFmpeg error (e.g., frame number exceeds video duration) + +### `GET /api/v1/file/:file_uuid/clip` + +Extract a video clip (time range) as MPEG-TS stream. Uses FFmpeg `-ss` fast seek. + +**Auth**: Required +**Scope**: file-level + +#### Query Parameters + +| Field | Type | Required | Default | Description | +|-------|------|----------|---------|-------------| +| `start_frame` | integer | No* | — | Start frame (zero-based). **Frame-accurate** — use this for precision. | +| `end_frame` | integer | No* | — | End frame (zero-based, inclusive). Requires `start_frame`. | +| `start_time` | float | No* | — | Start time in seconds. Approximate (FPS-dependent). Fallback if frames not given. | +| `end_time` | float | No* | — | End time in seconds. Approximate (FPS-dependent). Fallback if frames not given. | +| `fps` | float | No | video FPS | Override frames-per-second for frame↔time calculation. Defaults to video's detected FPS. | +| `mode` | string | No | `normal` | `normal` or `debug` (draws "CLIP" overlay) | +| `audio` | string | No | `on` | `on` or `off` | + +Either (`start_frame`+`end_frame`) OR (`start_time`+`end_time`) must be provided. + +#### Example + +```bash +# Clip by frame range (primary) +curl -s "$API/api/v1/file/bd80fec92b0b6963d177a2c55bf713e2/clip?start_frame=0&end_frame=47" \ + -H "Authorization: Bearer $JWT" -o clip.ts + +# Clip by time range (fallback) +curl -s "$API/api/v1/file/bd80fec92b0b6963d177a2c55bf713e2/clip?start_time=30&end_time=45" \ + -H "Authorization: Bearer $JWT" -o clip.ts +``` + +#### Response + +- **200**: `video/mp2t` MPEG-TS stream +- **400**: Missing/invalid range parameters +- **404**: File not found +- **500**: FFmpeg error + +#### Technical Notes + +| Detail | Value | +|--------|-------| +| **Backend** | FFmpeg (`ffmpeg-full`) | +| **Seek** | `-ss` before `-i` (fast keyframe seek) | +| **Format** | MPEG-TS (`mpegts` muxer, pipe-safe) | +| **Codec** | H.264 + AAC | +| **Cache** | `Cache-Control: public, max-age=86400` (24h) | + +### Video vs Clip: Quality & Format Comparison + +Both endpoints support time range extraction, but serve different use cases: + +| Feature | `/video` | `/clip` | +|---------|----------|---------| +| **No params** | Streams full file (Range seek) | Returns 400 (params required) | +| **HTTP Range** | ✅ Supported | ❌ Not supported | +| **Encoding** | `-c copy` (zero encoding) | `-c:v libx264 -c:a aac` (re-encode) | +| **Quality** | Original (bit-exact, zero loss) | Compressed (default CRF ≈ 23) | +| **Format** | `video/mp4` | `video/mp2t` (MPEG-TS) | +| **Speed** | Fast (no computation) | Slower (encoding required) | +| **Frame control** | Time-based (`dur = (ef-sf)/fps`) | Precise (`-vframes`) | +| **Debug mode** | ❌ | ✅ `mode=debug` overlay | +| **Cache** | ❌ | ✅ `max-age=86400` | + +#### Usage Recommendation + +| Scenario | Use | +|----------|-----| +| Full video streaming / player seek | `/video` | +| Quick preview clip (zero quality loss) | `/video?start_frame=...&end_frame=...` | +| Debug frame verification / text overlay | `/clip?mode=debug` | +| Precise frame count control | `/clip` | +| CDN cacheable clip | `/clip` | + +--- + +| Detail | Value | +|--------|-------| +| **Backend** | FFmpeg (`ffmpeg-full`) | +| **Filter** | `select=eq(n\,FRAME)` to select frame, optional `crop=W:H:X:Y` | +| **Output** | Single JPEG via pipe (`image2pipe`, `mjpeg` codec) | +| **Cache** | `Cache-Control: public, max-age=86400` (24h) | +| **Frame number** | Zero-based (`frame=0` = first frame of video) | + +--- +*Updated: 2026-05-19 12:49:24* diff --git a/docs_v1.0/API_WORKSPACE/modules/09_tmdb.md b/docs_v1.0/API_WORKSPACE/modules/09_tmdb.md new file mode 100644 index 0000000..34c3f00 --- /dev/null +++ b/docs_v1.0/API_WORKSPACE/modules/09_tmdb.md @@ -0,0 +1,112 @@ + + + + +## TMDb Enrichment + +> **Offline operation**: TMDb prefetch now checks local identity files first (`identities/_index.json` + `*.tmdb.json`). +> If local files exist, no external API call is made. Internet is only needed for initial data seeding. + +### Overview + +TMDb enrichment is an optional identity enrichment step that can be run after Pipeline face detection completes. The workflow is: + +1. **Prefetch** (requires internet): Download movie cast data from TMDb API → cache to `{file_uuid}.tmdb.json` +2. **Probe**: Read local cache → create identities for **all** cast members (`source='tmdb'`) + save `identity.json` + download profile image to `{OUTPUT}/identities/{uuid}/profile.jpg` +3. **Match**: The worker automatically matches video faces against TMDb identities when `MOMENTRY_TMDB_PROBE_ENABLED=true` + +### `POST /api/v1/agents/tmdb/prefetch` + +**Auth**: Required +**Scope**: file-level + +Fetch TMDb cast data for a registered file and cache it locally. This is the only step requiring internet access. + +#### Request Parameters + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `file_uuid` | string | Yes | File UUID to enrich | + +#### Example + +```bash +curl -s -X POST "$API/api/v1/agents/tmdb/prefetch" \ + -H "Content-Type: application/json" \ + -H "X-API-Key: $KEY" \ + -d '{"file_uuid": "'"$FILE_UUID"'"}' +``` + +#### Response (200) + +```json +{"success": true, "file_uuid": "...", "cache_path": "/output/...tmdb.json"} +``` + +### `POST /api/v1/file/:file_uuid/tmdb-probe` + +**Auth**: Required +**Scope**: file-level + +Read local TMDb cache and create/update identities. Requires prefetch to have been run first. + +#### Example + +```bash +curl -s -X POST "$API/api/v1/file/$FILE_UUID/tmdb-probe" \ + -H "X-API-Key: $KEY" | jq '{identities_created, movie_title}' +``` + +#### Response (200 — identities created) + +```json +{"success": true, "identities_created": 15, "movie_title": "Charade"} +``` + +#### Response (200 — no cache) + +```json +{"success": false, "message": "No TMDb cache found. Run tmdb-prefetch first."} +``` + +### `GET /api/v1/resource/tmdb` + +**Auth**: Required +**Scope**: system-level + +View TMDb resource status including configuration, identity counts, and cache file count. + +#### Example + +```bash +curl -s "$API/api/v1/resource/tmdb" -H "X-API-Key: $KEY" \ + | jq '{identities_seeded, cache_files}' +``` + +### `POST /api/v1/resource/tmdb/check` + +**Auth**: Required +**Scope**: system-level + +Ping the TMDb API to verify connectivity and measure latency. + +#### Example + +```bash +curl -s -X POST "$API/api/v1/resource/tmdb/check" \ + -H "X-API-Key: $KEY" | jq '.status' +``` + +#### Response + +```json +{ + "api_key_configured": true, + "enabled": false, + "api_reachable": true, + "api_latency_ms": 120 +} +``` + +--- +*Updated: 2026-05-19 12:49:24* diff --git a/docs_v1.0/API_WORKSPACE/modules/10_pipeline.md b/docs_v1.0/API_WORKSPACE/modules/10_pipeline.md index 4ffb115..133b3fa 100644 --- a/docs_v1.0/API_WORKSPACE/modules/10_pipeline.md +++ b/docs_v1.0/API_WORKSPACE/modules/10_pipeline.md @@ -120,3 +120,6 @@ The following routes are defined in source code but are **NOT** currently mounte | `/api/v1/search/persons` | `universal_search.rs` (not mounted) | | `/api/v1/who` | `who.rs` | | `/api/v1/who/candidates` | `who.rs` | + +--- +*Updated: 2026-05-19 12:49:24* diff --git a/docs_v1.0/API_WORKSPACE/modules/11_error_codes.md b/docs_v1.0/API_WORKSPACE/modules/11_error_codes.md new file mode 100644 index 0000000..82580e8 --- /dev/null +++ b/docs_v1.0/API_WORKSPACE/modules/11_error_codes.md @@ -0,0 +1,60 @@ + + + + +## Error Response Format + +All API errors follow this JSON structure: + +```json +{ + "success": false, + "error": { + "code": "E001_NOT_FOUND", + "message": "Resource not found", + "details": {"resource": "file_uuid", "value": "abc"} + } +} +``` + +## Error Code List + +### Generic Errors (E0xx) + +| Code | HTTP | Description | +|------|------|-------------| +| `E001_NOT_FOUND` | 404 | Resource not found (file, identity, chunk) | +| `E002_DUPLICATE` | 409 | Resource already exists | +| `E003_VALIDATION` | 400 | Request parameter validation failed | +| `E004_UNAUTHORIZED` | 401 | Invalid API key or token | +| `E005_INTERNAL` | 500 | Internal server error | + +### Processor Errors (E1xx) + +| Code | HTTP | Description | +|------|------|-------------| +| `E101_PROCESSOR_FAIL` | 500 | Python script execution failed | +| `E102_TIMEOUT` | 504 | Processing timeout | +| `E103_RESUME_FAIL` | 500 | Resume failed (checkpoint not found) | +| `E104_NO_VIDEO` | 400 | Video file path not found | + +### Identity Errors (E2xx) + +| Code | HTTP | Description | +|------|------|-------------| +| `E201_FACE_NOT_FOUND` | 404 | Face detection not found | +| `E202_MERGE_CONFLICT` | 409 | Identity merge conflict | +| `E203_CANDIDATE_EMPTY` | 404 | No candidates available for confirmation | + +### TMDb Errors (E3xx) + +| Code | HTTP | Description | +|------|------|-------------| +| `E301_TMDB_NO_KEY` | 400 | `TMDB_API_KEY` environment variable not set | +| `E302_TMDB_UNREACHABLE` | 502 | TMDb API unreachable or timed out | +| `E303_TMDB_CACHE_NOT_FOUND` | 200 | No local TMDb cache; run prefetch first | +| `E304_TMDB_PROBE_FAILED` | 500 | TMDb probe execution failed | +| `E305_TMDB_MOVIE_NOT_FOUND` | 404 | No matching TMDb movie found from filename | + +--- +*Updated: 2026-05-19 12:49:24* diff --git a/docs_v1.0/API_WORKSPACE/modules/12_agent.md b/docs_v1.0/API_WORKSPACE/modules/12_agent.md new file mode 100644 index 0000000..8793ad3 --- /dev/null +++ b/docs_v1.0/API_WORKSPACE/modules/12_agent.md @@ -0,0 +1,121 @@ +# Agent Endpoints + +Agent endpoints provide AI-powered capabilities including translation, identity analysis, and 5W1H extraction. + +## POST /api/v1/agents/translate + +Translate text between languages using Gemma4 (llama.cpp, port 8082). + +### Request + +```json +{ + "text": "Hello, welcome to Momentry Core.", + "target_language": "Traditional Chinese", + "source_language": "English" +} +``` + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `text` | string | ✅ | Text to translate | +| `target_language` | string | ✅ | Target language name (e.g. "Traditional Chinese", "Japanese") | +| `source_language` | string | ❌ | Source language (default: "auto") | + +### Response + +```json +{ + "success": true, + "translated_text": "您好,歡迎使用 Momentry Core。", + "source_language_detected": "English", + "model_used": "google_gemma-4-26B-A4B-it-Q5_K_M.gguf" +} +``` + +### Supported Language Pairs (tested) + +| Source | Target | Quality | +|--------|--------|---------| +| English | Traditional Chinese | ✅ | +| English | Japanese | ✅ | +| Chinese | English | ✅ | +| English | French | ✅ | +| Chinese | Japanese | ✅ | + +### Model + +- **Model**: Gemma4 26B (Q5_K_M) +- **Engine**: llama.cpp at `localhost:8082` +- **Endpoint**: `/v1/chat/completions` (OpenAI-compatible) +- **Temperature**: 0.1 +- **Max tokens**: 1024 + +### Errors + +| Status | Condition | +|--------|-----------| +| 500 | LLM unreachable or response parse failure | +| 401 | Missing/invalid auth | + +--- + +## POST /api/v1/agents/5w1h/analyze + +Extract 5W1H (Who, What, When, Where, Why, How) from a scene. Uses Gemma4 LLM on port 8082. + +### Request + +```json +{ + "file_uuid": "3abeee81d94597629ed8cb943f182e94", + "scene_id": 42 +} +``` + +### Response + +```json +{ + "success": true, + "5w1h": { + "who": ["Cary Grant"], + "what": ["discussing plans"], + "when": ["1963"], + "where": ["Paris"], + "why": ["vacation"], + "how": ["in person"] + } +} +``` + +## POST /api/v1/agents/5w1h/batch + +Batch analyze all scenes in a file for 5W1H extraction. Uses the pipeline's `parent_chunk_5w1h.py --mode llm`. + +### Request + +```json +{ + "file_uuid": "3abeee81d94597629ed8cb943f182e94" +} +``` + +## GET /api/v1/agents/5w1h/status + +Get status of the 5W1H agent pipeline for a file. + +--- + +## Embedding Model + +| Detail | Value | +|--------|-------| +| **Model** | EmbeddingGemma-300m | +| **Endpoint** | `POST /v1/embeddings` on port 11436 | +| **Dimension** | 768 | +| **Used by** | `parent_chunk_5w1h.py --embed`, story, 5W1H, search | + + +--- +*Updated: 2026-05-19 12:49:24* diff --git a/docs_v1.0/API_WORKSPACE/modules/13_config.md b/docs_v1.0/API_WORKSPACE/modules/13_config.md index d6df298..f23e339 100644 --- a/docs_v1.0/API_WORKSPACE/modules/13_config.md +++ b/docs_v1.0/API_WORKSPACE/modules/13_config.md @@ -85,3 +85,6 @@ curl -s -X POST "$API/api/v1/config/watcher-auto-register" \ -H "X-API-Key: $KEY" \ -d '{"enabled": true}' ``` + +--- +*Updated: 2026-05-19 12:49:24* diff --git a/docs_v1.0/API_WORKSPACE/modules/_template.md b/docs_v1.0/API_WORKSPACE/modules/_template.md new file mode 100644 index 0000000..3a14aff --- /dev/null +++ b/docs_v1.0/API_WORKSPACE/modules/_template.md @@ -0,0 +1,63 @@ +# {Module Name} — API Workspace Module + +> Use this template when adding or editing API endpoint documentation modules. + +## Module Metadata + +Every module MUST start with: + +```markdown + + + +``` + +## Endpoint Template + +Each endpoint MUST use this structure: + +### `METHOD /path/to/endpoint` + +**Auth**: Required / Optional / Public + +**Scope**: file-level / identity-level / system-level + +#### Request Parameters + +| Field | Type | Required | Default | Description | +|-------|------|----------|---------|-------------| +| `param1` | string | Yes | — | Description | + +#### Example + +```bash +# brief description of what this example demonstrates +curl -s -X METHOD "$API/path" \ + -H "X-API-Key: $KEY" \ + -H "Content-Type: application/json" \ + -d '{"param1": "value"}' +``` + +#### Response (200) + +```json +{ "success": true } +``` + +| Field | Type | Description | +|-------|------|-------------| +| `success` | boolean | Always true on 200 | + +#### Error Codes + +| Code | HTTP | When | +|------|------|------| +| E0xx | 4xx | Description | + +## Rules + +1. Each module file covers ONE topic group (e.g., `09_tmdb.md` = all TMDb endpoints) +2. Use `$API` and `$KEY` in all curl examples +3. Use `$FILE_UUID`, `$IDENTITY_UUID` variables for UUID examples +4. Module filename = `NN_topic.md` (NN = execution order, 01-99) +5. `depends` metadata = which modules must be assembled before this one