# Core API 完整測試報告 > 測試時間:2026-06-14 > Base URL:`http://localhost:3002` > 所有端點均需附 `?api_key=KEY` --- ## 1. Files API ### GET /api/v1/files/scan | 項目 | 內容 | |---|---| | **Method** | GET | | **Params** | `page_size` (int), `page` (int), `pattern` (string), `sort_by` (string), `sort_order` (string) | | **HTTP** | 200 | | **Response Key** | `files` (array) | **欄位:** ``` file_name, relative_path, file_path, file_size, modified_time, is_registered, file_uuid, status, registration_time, job_id ``` **注意:** - 未註冊檔案 `file_uuid` 為 `null`(Rust 需 fallback 到 `file_path`) - `status`:`"completed"` 或 `"unregistered"` --- ## 2. Search API ### POST /api/v1/search/llm-smart | 項目 | 內容 | |---|---| | **Method** | POST | | **Body** | `{"query": "string", "limit": int}` | | **HTTP** | 200 | | **Response Key** | `results` (array) | **欄位:** ``` id, file_uuid, parent_id, scene_order, start_frame, end_frame, fps, start_time, end_time, raw_text, summary, metadata, similarity, file_name, serve_url, thumbnail_url ``` --- ## 3. Identities API ### GET /api/v1/identities (list) | 項目 | 內容 | |---|---| | **Method** | GET | | **Params** | `page` (int), `per_page` (int) | | **HTTP** | 200 | | **Response Key** | `identities` (array) | **欄位:** ``` id, identity_uuid, name, metadata ``` **metadata 欄位:** ``` role, aliases, starred, tmdb_gender, tmdb_aliases, tmdb_imdb_id, tmdb_birthday, tmdb_deathday, tmdb_homepage, tmdb_movie_id, tmdb_biography, tmdb_character, tmdb_cast_order, tmdb_department, tmdb_popularity, tmdb_movie_title, tmdb_place_of_birth ``` **注意:** `starred` 在 metadata 內 ### GET /api/v1/identities/search | 項目 | 內容 | |---|---| | **Method** | GET | | **Params** | `q` (string) | | **HTTP** | 200 | | **Response Key** | `results` (array) | **欄位(search result 不同於 list):** ``` identity_id, name, source, tmdb_id, file_uuid, trace_id, chunk_id, start_frame, end_frame, fps, start_time, end_time, text_content ``` --- ## 4. Identity Detail API ### GET /api/v1/identity/{uuid} | 項目 | 內容 | |---|---| | **Method** | GET | | **HTTP** | 200 | | **Response Key** | 頂層物件 | **欄位:** ``` success, identity_uuid, name, identity_type, source, status, metadata, reference_data, tmdb_id, tmdb_profile, created_at, updated_at ``` **注意:** `tmdb_profile` 為本地絕對路徑(如 `/Users/accusys/momentry/output/identities/{uuid}/profile.jpg`) ### PATCH /api/v1/identity/{uuid} (update) | 項目 | 內容 | |---|---| | **Method** | PATCH | | **Body** | `{"name": "string"}` 或其他可更新欄位 | | **HTTP** | 200 | **Response:** ```json {"success": true, "identity_uuid": "...", "updated_fields": ["name"]} ``` ### DELETE /api/v1/identity/{uuid} | 項目 | 內容 | |---|---| | **Method** | DELETE | | **HTTP** | 204 (成功) / 404 (找不到) | ### POST /api/v1/identity (create) | 項目 | 內容 | |---|---| | **Method** | POST | | **Body** | 需要 `face_json_path` + `identity_name` 等欄位 | | **HTTP** | 500 (缺少必要欄位時) | **注意:** 此 API 需要 face JSON 路徑,不是單純建立空人物。需有 face data 才能建立。 --- ## 5. Identity Faces API ### GET /api/v1/identity/{uuid}/faces | 項目 | 內容 | |---|---| | **Method** | GET | | **Params** | `page_size` (int) | | **HTTP** | 200 | | **Response Key** | `data` (array) **不是** `faces` | **欄位(data 內):** ``` id, file_uuid, frame_number, timestamp_secs, face_id, bbox, confidence ``` **Response 結構:** ```json { "success": true, "identity_uuid": "...", "name": "...", "total": int, "page": int, "page_size": int, "data": [...] } ``` --- ## 6. Identity Traces API ### GET /api/v1/identity/{uuid}/traces | 項目 | 內容 | |---|---| | **Method** | GET | | **Params** | `page_size` (int) | | **HTTP** | 200 | | **Response Key** | `traces` (array) | **欄位:** ``` file_uuid, trace_id, frame_count, first_frame, last_frame, first_sec, last_sec, avg_confidence ``` **Response 結構:** ```json { "success": true, "identity_uuid": "...", "name": "...", "total": int, "page": int, "page_size": int, "total_faces": int, "traces": [...] } ``` --- ## 7. Face Candidates API ### GET /api/v1/faces/candidates | 項目 | 內容 | |---|---| | **Method** | GET | | **Params** | `page` (int), `page_size` (int) | | **HTTP** | 200 | | **Response Key** | `candidates` (array) | **欄位:** ``` id, face_id, file_uuid, frame_number, confidence, bbox, attributes ``` **Response 結構:** ```json { "candidates": [...], "total": int, "page": int, "page_size": int } ``` --- ## 8. Bind / Unbind / Merge APIs ### POST /api/v1/identity/{uuid}/bind | 項目 | 內容 | |---|---| | **Method** | POST | | **Body** | `{"face_id": "string", "file_uuid": "string"}` | | **HTTP** | 200 | **Response:** ```json {"success": true, "message": "Bound face ... to ...", "data": {"rows_affected": 0}} ``` **注意:** `face_id` 必須是 **string**,不能是 integer ### POST /api/v1/identity/{uuid}/unbind | 項目 | 內容 | |---|---| | **Method** | POST | | **Body** | `{"face_id": "string", "file_uuid": "string"}` | | **HTTP** | 200 | **Response:** ```json {"success": true, "message": "Unbound face ... from ..."} ``` ### POST /api/v1/identity/{uuid}/mergeinto | 項目 | 內容 | |---|---| | **Method** | POST | | **Body** | `{"into_uuid": "string"}` | | **HTTP** | 200 (成功) / 404 (目標不存在) | **注意:** URL 中的 `{uuid}` 是 **來源** identity,body 中的 `into_uuid` 是 **目標** identity --- ## 9. Media APIs ### GET /api/v1/file/{uuid}/thumbnail | 項目 | 內容 | |---|---| | **Method** | GET | | **Params** | `frame` (int, default 30) | | **HTTP** | 200 | | **Content-Type** | `image/jpeg` | | **Response** | Binary image data | ### GET /api/v1/file/{uuid}/video | 項目 | 內容 | |---|---| | **Method** | GET | | **Params** | `start_time` (float), `end_time` (float), `start_frame` (int), `end_frame` (int) | | **HTTP** | 200 | | **Content-Type** | `video/mp4` | | **Response** | Binary MP4 data | | **格式** | ISO Media, MP4 Base Media v1 | --- ## API Response Key 摘要 | 端點 | Response Key | 備註 | |---|---|---| | `/files/scan` | `files` | | | `/search/llm-smart` | `results` | | | `/identities` (list) | `identities` | | | `/identities/search` | `results` | 欄位不同於 list | | `/identity/{uuid}` | 頂層物件 | 包含 `success` | | `/identity/{uuid}/faces` | `data` | **不是** `faces` | | `/identity/{uuid}/traces` | `traces` | | | `/faces/candidates` | `candidates` | | --- ## Rust Struct 映射建議 ```rust // Files struct FileInfo { file_uuid: String, // null 時 fallback file_path file_name: String, file_size: i64, modified_time: String, is_registered: bool, } // Identities (list) struct PersonInfo { identity_uuid: String, name: String, starred: bool, // 從 metadata.starred 提取 } // Identity detail struct IdentityDetail { identity_uuid: String, name: String, identity_type: String, source: String, status: String, tmdb_id: Option, tmdb_profile: Option, // 本地路徑 created_at: String, } // Face (from /faces endpoint) struct FaceInfo { id: i64, file_uuid: String, frame_number: i64, timestamp_secs: f64, face_id: Option, bbox: Option, confidence: f64, } // Trace struct TraceInfo { trace_id: i64, file_uuid: String, frame_count: i64, first_frame: i64, last_frame: i64, first_sec: f64, last_sec: f64, avg_confidence: f64, } // Face Candidate struct FaceCandidate { id: i64, face_id: Option, file_uuid: String, frame_number: i64, confidence: f64, bbox: Option, } struct BBox { x: f64, y: f64, width: f64, height: f64, } // Search result (不同於 list) struct SearchIdentityResult { identity_id: i64, name: String, source: String, tmdb_id: Option, file_uuid: Option, trace_id: Option, start_time: f64, end_time: f64, text_content: Option, } ```