# People 頁面設計文件 ## 1. 分層架構 | 層級 | 負責 | |---|---| | **Rust (Backend)** | API 代理、檔案系統存取、API key 管理 | | **Vue (Frontend)** | UI 渲染、狀態管理、使用者交互 | --- ## 2. Core API 端點(已實測驗證) 詳見 `CORE_API_REFERENCE.md`。以下摘要 People 頁面使用的端點: | 功能 | Method | 端點 | Response Key | 備註 | |---|---|---|---|---| | 列出人物 | GET | `/api/v1/identities` | `identities` | 含 metadata.starred | | 人物詳情 | GET | `/api/v1/identity/{uuid}` | 頂層 | 含 tmdb_profile 路徑 | | 搜尋人物 | GET | `/api/v1/identities/search?q=` | `results` | 欄位不同於 list | | 大頭照 | — | 本地檔案讀取 | — | 非 Core API | | 人臉列表 | GET | `/api/v1/identity/{uuid}/faces` | `data` | **不是** `faces` | | 追蹤列表 | GET | `/api/v1/identity/{uuid}/traces` | `traces` | | | 改名 | PATCH | `/api/v1/identity/{uuid}` | 頂層 | Body: `{"name": "..."}` | | 刪除 | DELETE | `/api/v1/identity/{uuid}` | — | 204/404 | | 建立 | POST | `/api/v1/identity` | — | 需要 face_json_path | | 合併 | POST | `/api/v1/identity/{uuid}/mergeinto` | — | Body: `{"into_uuid": "..."}` | | 綁定 | POST | `/api/v1/identity/{uuid}/bind` | — | Body: `{"face_id": "string", "file_uuid": "..."}` | | 解綁 | POST | `/api/v1/identity/{uuid}/unbind` | — | Body: 同上 | | 候選人臉 | GET | `/api/v1/faces/candidates` | `candidates` | | | 縮圖 | GET | `/api/v1/file/{uuid}/thumbnail` | Binary | | | 影片 | GET | `/api/v1/file/{uuid}/video` | Binary | | --- ## 3. Rust Structs 定義 ```rust struct PersonInfo { identity_uuid: String, name: String, starred: bool, // 從 metadata.starred 提取 } struct FaceInfo { id: i64, file_uuid: String, frame_number: i64, timestamp_secs: f64, face_id: Option, confidence: f64, } struct TraceInfo { trace_id: i64, file_uuid: String, frame_count: i64, first_sec: f64, last_sec: f64, avg_confidence: f64, } struct FaceCandidate { id: i64, face_id: Option, file_uuid: String, frame_number: i64, confidence: f64, } struct SearchIdentityResult { identity_id: i64, name: String, source: String, tmdb_id: Option, file_uuid: Option, start_time: f64, end_time: f64, text_content: Option, } ``` --- ## 4. Rust Commands 清單 ### 4.1 現有(需修改) | Command | 修改內容 | |---|---| | `get_people` | PersonInfo 加 `starred: bool`,解析 metadata.starred | | `get_faces` | 解析 `data` key 而非 `faces`,FaceInfo 加 timestamp_secs | | `get_video_stream` | **重構**:寫入 temp file → 回傳 `file://` URL | ### 4.2 現有(不變) | Command | 行為 | |---|---| | `get_traces` | `GET /identity/{uuid}/traces` | | `get_identity_profile` | 讀本地 profile.jpg → base64 | | `update_identity_name` | `PATCH /identity/{uuid}` | | `delete_identity` | `DELETE /identity/{uuid}` | | `get_thumbnail` | 抓縮圖 → base64 | ### 4.3 新增 | Command | Core API | Body/Params | 回傳 | |---|---|---|---| | `search_identities` | `GET /identities/search?q=...` | `query: String, limit: usize` | `Vec` | | `merge_identities` | `POST /identity/{uuid}/mergeinto` | `uuid: String, into_uuid: String` | `()` | | `bind_face` | `POST /identity/{uuid}/bind` | `uuid, face_id: String, file_uuid: String` | `()` | | `unbind_face` | `POST /identity/{uuid}/unbind` | `uuid, face_id: String, file_uuid: String` | `()` | | `get_face_candidates` | `GET /faces/candidates` | `page: usize, per_page: usize` | `Vec` | **注意:create_identity 需要 face_json_path,不在 People 頁面直接使用。** --- ## 5. Vue 前端元件樹 ``` PeopleView.vue ├── Toolbar │ ├── h1 "People" │ ├── 搜尋框 → debounce 300ms → invoke('search_identities') │ └── 建立按鈕(暫留,create 需要 face_json_path) │ ├── PeopleGrid │ └── PersonCard × N (v-for filteredPeople) │ ├── 大頭照 → invoke('get_identity_profile') cache │ ├── 名稱 │ ├── ⭐ 星號 (starred) │ └── @click → selectPerson() │ ├── DetailModal │ ├── Header: 大頭照 + 可編輯名稱 + UUID │ ├── FacesTab (橫向捲軸) │ │ └── face × N → confidence % │ ├── TracesTab (縱向列表) │ │ └── trace × N → 時間 + 信心% → @click → VideoPlayer │ └── ActionsTab │ ├── Delete → confirm + invoke('delete_identity') │ ├── Merge → 搜尋目標 + invoke('merge_identities') │ ├── Bind Face → 從 Candidates 選取 → invoke('bind_face') │ └── Unbind Face → invoke('unbind_face') │ ├── CandidatesModal │ └── FaceCandidate × N → @click → bind_face() │ └── VideoPlayer (共用元件) └──