Core Changes: - Fix SearchView to use start_frame/end_frame directly (no time*fps conversion) - Add hard_delete support to delete_trace API - VideoPlayer: Main timeline + Mark system foundation - Proxy: Add local routes for auth, media, identity-matches, cluster-results - Add .gitignore to exclude build artifacts and dependencies Design Documents: - Multi-track Mark system design (.opencode/plans/) - Video editing positioning standards research Files Modified: - src/views/SearchView.vue: Frame positioning, ensureMinDuration (240 frames) - src/views/PeopleView.vue: batchDeleteGroups with hard_delete - src/api/index.ts: delete_trace with hard_delete body - src/components/VideoPlayer.vue: Timeline + Mark UI - src-tauri/src/proxy.rs: New local routes - AGENTS.md: Update documentation
285 lines
8.3 KiB
Markdown
285 lines
8.3 KiB
Markdown
# Face Group 命名持久化問題 - 技術分析報告
|
||
|
||
**日期**: 2026-07-19
|
||
**提出團隊**: Momentry Studio
|
||
**狀態**: 待 Core Team 討論
|
||
|
||
---
|
||
|
||
## 一、問題現象
|
||
|
||
### 1.1 用戶操作流程
|
||
|
||
1. 選擇影片檔案
|
||
2. 建立 face group 並命名(如 "test group")
|
||
3. 將 trace 移入該 group
|
||
4. 成功顯示新 group,可播放影片
|
||
5. 跳轉到其他頁面
|
||
6. 返回 Face 頁面
|
||
7. **"test group" 消失**
|
||
|
||
### 1.2 影響範圍
|
||
|
||
| 功能 | 影響 |
|
||
|------|------|
|
||
| 新建 face group | ❌ 無法持久化 |
|
||
| 重新命名 face group | ❌ 無法持久化 |
|
||
| 移動 trace 到 group | ❌ 無法持久化 |
|
||
| 系統自動生成的 group | ✅ 正常 |
|
||
|
||
---
|
||
|
||
## 二、技術分析
|
||
|
||
### 2.1 數據流追蹤
|
||
|
||
```
|
||
Frontend Core API TKG
|
||
│ │ │
|
||
│ updateTraceProfileGroup( │ │
|
||
│ fileUuid, traceIds, │ │
|
||
│ { name: "test group" } │ │
|
||
│ ) │ │
|
||
├─────────────────────────────────►│ │
|
||
│ │ PUT /trace-profile/group │
|
||
│ │ { name: "test group" } │
|
||
│ ├─────────────────────────►│
|
||
│ │ │
|
||
│ │ 存入 face_trace.label
|
||
│ │ │
|
||
│ loadClusterResults() │ │
|
||
├─────────────────────────────────►│ │
|
||
│ │ GET /file/{uuid}/ │
|
||
│ │ face-groups │
|
||
│ ├─────────────────────────►│
|
||
│ │ │
|
||
│ │ 從 TKG 讀取 label
|
||
│ │◄─────────────────────────┤
|
||
│ │ │
|
||
│ ◄───────────────────────────────┤ { face_groups: [...] } │
|
||
│ │ │
|
||
```
|
||
|
||
### 2.2 Bug 定位
|
||
|
||
**文件位置**: `/Users/accusys/momentry_studio/src/api/index.ts`
|
||
**行號**: 379
|
||
|
||
**問題代碼**:
|
||
```javascript
|
||
case 'update_trace_profile_group': {
|
||
return {
|
||
url: '/api/v1/trace-profile/group',
|
||
method: 'PUT',
|
||
body: {
|
||
file_uuid: a.fileUuid,
|
||
trace_ids: a.traceIds,
|
||
name: a.group_name || a.label, // ← BUG: 忽略 a.name
|
||
key_frame: a.keyFrame,
|
||
key_face: a.keyFace
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**Frontend 調用分析**:
|
||
|
||
| 行號 | 文件 | 調用方式 | 參數 |
|
||
|------|------|---------|------|
|
||
| 430 | PeopleView.vue | `updateTraceProfileGroup(..., { name })` | `name` ✅ |
|
||
| 864 | PeopleView.vue | `updateTraceProfileGroup(..., { label: name })` | `label` ⚠️ |
|
||
| 928 | PeopleView.vue | `updateTraceProfileGroup(..., { name: ... })` | `name` ✅ |
|
||
| 971 | PeopleView.vue | `updateTraceProfileGroup(..., { name })` | `name` ✅ |
|
||
|
||
**結果**:
|
||
- API Builder 期望 `group_name` 或 `label`
|
||
- Frontend 大部分傳入 `name`
|
||
- 導致 Core API 收到 `name: undefined`
|
||
|
||
---
|
||
|
||
## 三、命名不一致問題
|
||
|
||
### 3.1 各層級欄位對照
|
||
|
||
| 層級 | 欄位名稱 | 說明 |
|
||
|------|---------|------|
|
||
| TKG `face_trace` node | `label` | 根本存儲位置 |
|
||
| Core API `/trace-profile` (GET) | `name` | 返回給前端 |
|
||
| Core API `/trace-profile/group` (PUT) | `name` | 接受前端參數 |
|
||
| Frontend 大部分調用 | `name` | ✅ 正確 |
|
||
| Frontend line 864 | `label` | ⚠️ 不一致 |
|
||
| API Builder 期望 | `group_name \|\| label` | ❌ 不匹配 |
|
||
|
||
### 3.2 Core API 文檔定義
|
||
|
||
**`PUT /api/v1/trace-profile/group`**
|
||
|
||
| 參數 | 類型 | 必填 | 說明 |
|
||
|------|------|------|------|
|
||
| `file_uuid` | string | Yes | File UUID |
|
||
| `trace_ids` | integer[] | Yes | Trace IDs |
|
||
| `name` | string | Yes | 新群組名稱 |
|
||
|
||
**Core API 明確接受 `name` 參數。**
|
||
|
||
---
|
||
|
||
## 四、架構設計問題
|
||
|
||
### 4.1 TKG Label 類型混淆
|
||
|
||
**現狀**: TKG `label` 欄位可能代表不同意圖:
|
||
|
||
| 來源 | 值範例 | 說明 |
|
||
|------|-------|------|
|
||
| 用戶命名 | "Peter", "Cary Grant" | 用戶主動指定 |
|
||
| 系統生成 | "Trace_1", "Face Trace 9" | 自動生成 |
|
||
| 其他 | 可能還有其他類型 | 待確認 |
|
||
|
||
**問題**: 無法區分 label 的來源/類型
|
||
|
||
### 4.2 建議方案
|
||
|
||
#### 選項 A:增加 `label_type` 欄位
|
||
|
||
```javascript
|
||
// TKG face_trace node
|
||
{
|
||
"node_type": "face_trace",
|
||
"label": "Peter",
|
||
"label_type": "face_name", // 新增欄位
|
||
"properties": {
|
||
"trace_id": 9,
|
||
"face_count": 142,
|
||
...
|
||
}
|
||
}
|
||
```
|
||
|
||
**`label_type` 可能值**:
|
||
|
||
| 值 | 說明 |
|
||
|----|------|
|
||
| `face_name` | 用戶定義的名稱 |
|
||
| `system` | 系統自動生成 |
|
||
| `tmdb` | 來自 TMDB 識別 |
|
||
|
||
#### 選項 B:使用 `labels` 陣列(支援多標籤)
|
||
|
||
```javascript
|
||
{
|
||
"node_type": "face_trace",
|
||
"labels": [
|
||
{ "value": "Peter", "type": "face_name", "source": "user" },
|
||
{ "value": "Trace_9", "type": "system", "source": "auto" }
|
||
],
|
||
...
|
||
}
|
||
```
|
||
|
||
#### 選項 C:維持現狀
|
||
|
||
- TKG 保持 `label` 單一欄位
|
||
- Core API 翻譯:`label` ↔ `name`
|
||
- Frontend 統一使用 `name`
|
||
|
||
---
|
||
|
||
## 五、修復方案
|
||
|
||
### 5.1 方案 A:前端統一使用 `name`(最小改動)
|
||
|
||
**修改點**:
|
||
|
||
| 文件 | 行號 | 原代碼 | 新代碼 |
|
||
|------|------|--------|--------|
|
||
| `src/api/index.ts` | 379 | `name: a.group_name \|\| a.label` | `name: a.name` |
|
||
| `src/views/PeopleView.vue` | 864 | `{ label: name }` | `{ name }` |
|
||
|
||
**優點**:
|
||
- 改動少
|
||
- 符合 Core API 文檔
|
||
- 立即解決問題
|
||
|
||
**缺點**:
|
||
- 未處理 TKG label 類型問題
|
||
- 未來可能有類似問題
|
||
|
||
**預計工作量**: 0.5 小時
|
||
|
||
### 5.2 方案 B:TKG 增加 `label_type`(完整方案)
|
||
|
||
**需要修改**:
|
||
|
||
1. **TKG Schema**
|
||
- 增加 `label_type` 欄位
|
||
|
||
2. **Core API**
|
||
- `/trace-profile/group` 增加 `label_type` 參數(默認 `face_name`)
|
||
- 更新 TKG node 時設定 `label_type`
|
||
|
||
3. **Frontend**
|
||
- 傳遞 `{ name: "...", label_type: "face_name" }`
|
||
|
||
**優點**:
|
||
- 完整解決命名類型問題
|
||
- 支援未來擴展
|
||
|
||
**缺點**:
|
||
- 需要改動 TKG 和 Core API
|
||
- 工作量較大
|
||
|
||
**預計工作量**: 2-4 小時(跨團隊)
|
||
|
||
---
|
||
|
||
## 六、討論議題
|
||
|
||
### 6.1 短期決策
|
||
|
||
1. **是否先執行方案 A**,讓功能正常運作?
|
||
2. **方案 A 的風險評估**?
|
||
|
||
### 6.2 長期設計
|
||
|
||
1. **TKG 是否需要 `label_type` 欄位**?
|
||
2. **如果需要,`label_type` 應該有哪些值**?
|
||
3. **Core API 是否需要同時支援 `name` 和 `label_type` 參數**?
|
||
|
||
### 6.3 命名規範
|
||
|
||
**建議建立正式對照表**:
|
||
|
||
| 層級 | 欄位 | 類型 | 說明 |
|
||
|------|------|------|------|
|
||
| TKG | `label` | string | 根本存儲 |
|
||
| TKG | `label_type` | string | 類型標識(新增?) |
|
||
| Core API | `name` | string | API 參數/返回 |
|
||
| Frontend | `name` | string | 統一使用 |
|
||
|
||
---
|
||
|
||
## 七、附錄
|
||
|
||
### A. 相關代碼位置
|
||
|
||
| 文件 | 說明 |
|
||
|------|------|
|
||
| `/Users/accusys/momentry_studio/src/api/index.ts:379` | API Builder |
|
||
| `/Users/accusys/momentry_studio/src/store.ts:252` | updateTraceProfileGroup |
|
||
| `/Users/accusys/momentry_studio/src/views/PeopleView.vue:430,864,928,971` | 調用點 |
|
||
| `/Users/accusys/momentry_core/docs_v1.0/doc_wasm/modules/18_profile.md` | Core API 文檔 |
|
||
|
||
### B. Core API 端點
|
||
|
||
| 端點 | 方法 | 說明 |
|
||
|------|------|------|
|
||
| `/api/v1/trace-profile` | GET | 獲取單一 trace profile |
|
||
| `/api/v1/trace-profile` | PUT | 更新單一 trace profile |
|
||
| `/api/v1/trace-profile/group` | PUT | 批量更新 trace profile |
|
||
| `/api/v1/file/{uuid}/face-groups` | GET | 獲取 face groups |
|
||
|
||
---
|
||
|
||
**以上問題請 Core Team 確認後,再決定修復方向。** |