feat: frame-based positioning and mark system foundation
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
This commit is contained in:
451
docs/proposals/core-api-face-groups-endpoint.md
Normal file
451
docs/proposals/core-api-face-groups-endpoint.md
Normal file
@@ -0,0 +1,451 @@
|
||||
# Core API Face Groups Endpoint - 技術建議書
|
||||
|
||||
**日期**: 2026-07-19
|
||||
**提出團隊**: Momentry Studio
|
||||
**狀態**: 建議中
|
||||
|
||||
---
|
||||
|
||||
## 一、背景
|
||||
|
||||
### 1.1 問題描述
|
||||
|
||||
Momentry Studio Proxy 當前實現以下 endpoints:
|
||||
|
||||
| Endpoint | 當前行為 | 用途 |
|
||||
|----------|---------|------|
|
||||
| `/api/v1/processor-json` | 讀取本地 `{file_hash}.{processor}.json` | 返回 processor 輸出(asrx, ocr, face 等)|
|
||||
| `/api/v1/cluster-results` | 讀取本地 `{file_hash}.cluster_result.json` | 返回 face 分組結果 |
|
||||
|
||||
**問題**:
|
||||
- 遠端瀏覽器訪問 `studio.momentry.ddns.net` 時,無法獲取本地文件數據
|
||||
- Proxy 應該作為 forward 層,將請求轉發到 Core API
|
||||
|
||||
### 1.2 現有 Core API Endpoints
|
||||
|
||||
| Endpoint | 狀態 | 說明 |
|
||||
|----------|------|------|
|
||||
| `POST /api/v1/file/:file_uuid/json/:processor` | ✅ 已存在 | 返回 processor JSON 數據 |
|
||||
| `POST /api/v1/file/:file_uuid/tkg/nodes` | ✅ 已存在 | 查詢 TKG nodes |
|
||||
| `GET /api/v1/trace-profile` | ✅ 已存在 | 查詢單一 trace profile |
|
||||
| `PUT /api/v1/trace-profile` | ✅ 已存在 | 更新 trace profile(含名稱)|
|
||||
| `PUT /api/v1/trace-profile/group` | ✅ 已存在 | 批量更新 trace 名稱 |
|
||||
| `GET /api/v1/file/:file_uuid/cluster-results` | ❌ 不存在 | 需要新增 |
|
||||
|
||||
---
|
||||
|
||||
## 二、架構理解
|
||||
|
||||
### 2.1 Face Group 概念
|
||||
|
||||
**定義**:
|
||||
- Face Group = 多個 face traces 共享同一個名稱(label)
|
||||
- 名稱來自 TKG `face_trace` node 的 `label` 欄位
|
||||
- 名稱可被用戶覆蓋(overridable)
|
||||
|
||||
**技術實現**:
|
||||
```json
|
||||
{
|
||||
"node_type": "face_trace",
|
||||
"label": "Cary Grant", // ← 可被用戶覆蓋
|
||||
"properties": {
|
||||
"trace_id": 9,
|
||||
"face_count": 142,
|
||||
"avg_confidence": 0.87
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 Cluster 與 Face Group 的關係
|
||||
|
||||
**核心觀點**:
|
||||
- **Cluster 是技術手段**:用於將多個 face traces 分組
|
||||
- **Face Group 是語義概念**:多個 traces 共享同一個名稱
|
||||
- **Cluster ID 是技術編號**:無業務語義,僅用於識別分組
|
||||
|
||||
**命名流程**:
|
||||
```
|
||||
用戶修改名稱
|
||||
→ Studio Frontend
|
||||
→ Studio Proxy
|
||||
→ Core API: PUT /api/v1/trace-profile
|
||||
→ 更新 TKG node 的 label
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、建議方案
|
||||
|
||||
### 3.1 Processor JSON Endpoint
|
||||
|
||||
**建議**:使用 Core API 現有 endpoint
|
||||
|
||||
**Studio Proxy 實現**:
|
||||
```
|
||||
GET /api/v1/processor-json?file_hash={uuid}&processor={name}
|
||||
→ Forward to Core API:
|
||||
POST /api/v1/file/{uuid}/json/{name}?api_key={API_KEY}
|
||||
```
|
||||
|
||||
**Core API 需要做的**:無需修改
|
||||
|
||||
---
|
||||
|
||||
### 3.2 Face Groups Endpoint(建議新增)
|
||||
|
||||
#### 選項 A:以 Cluster 格式返回
|
||||
|
||||
**Endpoint**:
|
||||
```
|
||||
GET /api/v1/file/:file_uuid/cluster-results
|
||||
```
|
||||
|
||||
**響應格式**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"file_uuid": "d3f9ae8e471a1fc4d47022c66091b920",
|
||||
"clusters": [
|
||||
{
|
||||
"cluster_id": 1,
|
||||
"name": "Cary Grant",
|
||||
"trace_ids": [9, 6, 8],
|
||||
"trace_count": 3,
|
||||
"representative_trace": 9
|
||||
},
|
||||
{
|
||||
"cluster_id": 2,
|
||||
"name": "Audrey Hepburn",
|
||||
"trace_ids": [1, 11, 4, 10],
|
||||
"trace_count": 4,
|
||||
"representative_trace": 1
|
||||
}
|
||||
],
|
||||
"total_clusters": 2
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 選項 B:以 Face Groups 格式返回(推薦)
|
||||
|
||||
**Endpoint**:
|
||||
```
|
||||
GET /api/v1/file/:file_uuid/face-groups
|
||||
```
|
||||
|
||||
**響應格式**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"file_uuid": "d3f9ae8e471a1fc4d47022c66091b920",
|
||||
"face_groups": [
|
||||
{
|
||||
"group_id": 1,
|
||||
"name": "Cary Grant",
|
||||
"trace_ids": [9, 6, 8],
|
||||
"trace_count": 3,
|
||||
"representative_trace": 9,
|
||||
"editable": true,
|
||||
"total_face_count": 425
|
||||
},
|
||||
{
|
||||
"group_id": 2,
|
||||
"name": "Audrey Hepburn",
|
||||
"trace_ids": [1, 11, 4, 10],
|
||||
"trace_count": 4,
|
||||
"representative_trace": 1,
|
||||
"editable": true,
|
||||
"total_face_count": 380
|
||||
}
|
||||
],
|
||||
"total_groups": 2,
|
||||
"unassigned_traces": [5, 7]
|
||||
}
|
||||
```
|
||||
|
||||
**推薦理由**:
|
||||
- 語義更清晰(Face Group vs Cluster)
|
||||
- 與命名機制對應
|
||||
- 擴展性更好(可加入 `editable`, `total_face_count` 等屬性)
|
||||
- 可區分已命名和未命名的 traces
|
||||
|
||||
---
|
||||
|
||||
### 3.3 實現邏輯(建議)
|
||||
|
||||
```python
|
||||
# Pseudocode
|
||||
def get_face_groups(file_uuid: str):
|
||||
# 1. 查詢 TKG nodes
|
||||
response = post(
|
||||
f"{CORE_API}/api/v1/file/{file_uuid}/tkg/nodes",
|
||||
json={"node_type": "face_trace", "page_size": 500}
|
||||
)
|
||||
nodes = response.json()["nodes"]
|
||||
|
||||
# 2. 按 label 分組
|
||||
groups = {}
|
||||
unassigned = []
|
||||
|
||||
for node in nodes:
|
||||
trace_id = node["properties"]["trace_id"]
|
||||
label = node["label"]
|
||||
face_count = node["properties"].get("face_count", 0)
|
||||
|
||||
# 判斷是否為預設名稱(未命名)
|
||||
if label.startswith("Face Trace ") or label.startswith("Trace "):
|
||||
unassigned.append(trace_id)
|
||||
continue
|
||||
|
||||
if label not in groups:
|
||||
groups[label] = {
|
||||
"trace_ids": [],
|
||||
"total_face_count": 0
|
||||
}
|
||||
|
||||
groups[label]["trace_ids"].append(trace_id)
|
||||
groups[label]["total_face_count"] += face_count
|
||||
|
||||
# 3. 轉換為輸出格式
|
||||
result = []
|
||||
for idx, (name, data) in enumerate(sorted(groups.items()), 1):
|
||||
result.append({
|
||||
"group_id": idx,
|
||||
"name": name,
|
||||
"trace_ids": data["trace_ids"],
|
||||
"trace_count": len(data["trace_ids"]),
|
||||
"representative_trace": data["trace_ids"][0],
|
||||
"editable": True,
|
||||
"total_face_count": data["total_face_count"]
|
||||
})
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"file_uuid": file_uuid,
|
||||
"face_groups": result,
|
||||
"total_groups": len(result),
|
||||
"unassigned_traces": unassigned
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、設計決策問題
|
||||
|
||||
### 4.1 Endpoint 命名
|
||||
|
||||
**問題**:
|
||||
- 使用 `/cluster-results`(現有概念)?
|
||||
- 使用 `/face-groups`(語義更清晰)?
|
||||
|
||||
**建議**:使用 `/face-groups`,理由:
|
||||
- 語義更準確(名稱可被覆蓋,不是固定的 cluster)
|
||||
- 與 `trace-profile` endpoint 命名一致
|
||||
- 未來可以擴展(如 `/face-groups/:name` 查詢單一 group)
|
||||
|
||||
---
|
||||
|
||||
### 4.2 未命名 Traces 處理
|
||||
|
||||
**場景**:
|
||||
- 新創建的 face_trace,`label` 為預設值(如 `"Face Trace 9"`)
|
||||
- 用戶尚未命名
|
||||
|
||||
**建議選項**:
|
||||
|
||||
| 選項 | 處理方式 | 優點 | 缺點 |
|
||||
|------|---------|------|------|
|
||||
| A | 歸類為 `unassigned_traces` 列表 | 清晰區分已命名/未命名 | 需要額外欄位 |
|
||||
| B | 每個未命名 trace 作為獨立 group | 格式統一 | 可能產生大量 group |
|
||||
| C | 不返回未命名 traces | 響應簡潔 | 遺失數據 |
|
||||
|
||||
**建議**:選項 A,返回 `unassigned_traces` 列表
|
||||
|
||||
---
|
||||
|
||||
### 4.3 Cluster ID / Group ID 的必要性
|
||||
|
||||
**問題**:
|
||||
- `cluster_id` 或 `group_id` 是否需要?
|
||||
- 如果只是順序編號,每次查詢可能不同
|
||||
|
||||
**建議選項**:
|
||||
|
||||
| 選項 | 實現方式 | 優點 | 缺點 |
|
||||
|------|---------|------|------|
|
||||
| A | 使用 `name` 作為唯一標識 | 語義清晰,無需額外 ID | 名稱變更時引用會失效 |
|
||||
| B | 生成固定的 `group_id`(如 UUID) | ID 固定,不受名稱變更影響 | 需要額外存儲 |
|
||||
| C | 每次查詢時動態生成順序編號 | 實現簡單 | 編號可能變化 |
|
||||
|
||||
**建議**:選項 C,動態生成順序編號(因為 Cluster ID 只是技術手段)
|
||||
|
||||
---
|
||||
|
||||
### 4.4 分頁支持
|
||||
|
||||
**問題**:
|
||||
- 如果一個文件有大量 face traces(如超過 500),如何處理?
|
||||
|
||||
**建議**:
|
||||
- 支持分頁參數 `page` 和 `page_size`
|
||||
- 默認 `page_size=100`,最大 `500`
|
||||
|
||||
---
|
||||
|
||||
### 4.5 性能考慮
|
||||
|
||||
**問題**:
|
||||
- TKG nodes 查詢是否需要緩存?
|
||||
|
||||
**建議**:
|
||||
- Core API 可以在內部緩存 TKG nodes 查詢結果
|
||||
- 緩存時效:5-10 分鐘(或直到有 trace-profile 更新)
|
||||
|
||||
---
|
||||
|
||||
## 五、Studio Proxy 職責
|
||||
|
||||
### 5.1 Processor JSON Handler
|
||||
|
||||
**修改前**:
|
||||
```rust
|
||||
// 讀取本地文件
|
||||
let path = format!("{}/{}.{}.json", output_dir, file_hash, processor);
|
||||
let content = std::fs::read_to_string(&path)?;
|
||||
```
|
||||
|
||||
**修改後**:
|
||||
```rust
|
||||
// Forward 到 Core API
|
||||
let url = format!("{}/api/v1/file/{}/json/{}?api_key={}",
|
||||
CORE_API, file_hash, processor, API_KEY);
|
||||
let response = client.post(&url).send().await?;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5.2 Cluster Results / Face Groups Handler
|
||||
|
||||
**修改前**:
|
||||
```rust
|
||||
// 讀取本地文件
|
||||
let path = format!("{}/{}/{}.cluster_result.json", base, file_hash, file_hash);
|
||||
let content = std::fs::read_to_string(&path)?;
|
||||
```
|
||||
|
||||
**修改後**:
|
||||
```rust
|
||||
// Forward 到 Core API
|
||||
let url = format!("{}/api/v1/file/{}/face-groups?api_key={}",
|
||||
CORE_API, file_hash, API_KEY);
|
||||
let response = client.get(&url).send().await?;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5.3 共享邏輯
|
||||
|
||||
**建議抽取共享函數**:
|
||||
```rust
|
||||
async fn call_core_api(url: &str, method: Method, body: Option<Value>) -> Response {
|
||||
let client = reqwest::Client::new();
|
||||
// 統一的錯誤處理
|
||||
// 統一的響應轉換
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、數據流向
|
||||
|
||||
### 6.1 當前流程(本地文件)
|
||||
|
||||
```
|
||||
Studio Frontend
|
||||
↓
|
||||
Studio Proxy
|
||||
↓
|
||||
本地文件系統 → {file_hash}.{processor}.json
|
||||
↓
|
||||
返回數據
|
||||
|
||||
問題:遠端瀏覽器無法訪問本地文件
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6.2 建議流程(Forward 到 Core API)
|
||||
|
||||
```
|
||||
Studio Frontend
|
||||
↓
|
||||
Studio Proxy (forward)
|
||||
↓
|
||||
Core API
|
||||
├── POST /file/{uuid}/json/{processor} (已有)
|
||||
└── GET /file/{uuid}/face-groups (新增)
|
||||
↓
|
||||
返回數據
|
||||
|
||||
優點:遠端瀏覽器可正常訪問
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、請求反饋
|
||||
|
||||
### 7.1 請 Core API 團隊確認
|
||||
|
||||
1. **Endpoint 選擇**:
|
||||
- `/cluster-results` 或 `/face-groups`?
|
||||
|
||||
2. **未命名 traces**:
|
||||
- 是否同意返回 `unassigned_traces` 列表?
|
||||
|
||||
3. **Group ID**:
|
||||
- 是否同意使用動態生成的順序編號?
|
||||
- 或需要固定的 UUID?
|
||||
|
||||
4. **分頁**:
|
||||
- 是否需要支持?
|
||||
|
||||
5. **性能**:
|
||||
- 是否需要內部緩存?
|
||||
|
||||
---
|
||||
|
||||
### 7.2 Studio 團隊負責
|
||||
|
||||
1. 修改 Proxy handlers:
|
||||
- `get_processor_json_handler` → Forward 到 Core API
|
||||
- `get_cluster_results_handler` → Forward 到 Core API
|
||||
|
||||
2. 抽取共享邏輯:
|
||||
- 統一 Core API 客戶端
|
||||
- 統一錯誤處理
|
||||
|
||||
---
|
||||
|
||||
## 八、附錄
|
||||
|
||||
### A. 相關 Core API Endpoints
|
||||
|
||||
| Endpoint | 文檔位置 |
|
||||
|----------|---------|
|
||||
| Processor JSON | `docs_v1.0/doc_wasm/modules/04_lookup.md` |
|
||||
| TKG Nodes | `docs_v1.0/doc_wasm/modules/15_tkg.md` |
|
||||
| Trace Profile | `docs_v1.0/doc_wasm/modules/18_profile.md` |
|
||||
| Progress | `docs_v1.0/doc_wasm/modules/17_progress.md` |
|
||||
|
||||
### B. Studio 相關代碼
|
||||
|
||||
| 文件 | 說明 |
|
||||
|------|------|
|
||||
| `src-tauri/src/proxy.rs` | Proxy handlers |
|
||||
| `src/views/PeopleView.vue` | Face 頁面 |
|
||||
| `src/store.ts` | 數據加載邏輯 |
|
||||
|
||||
---
|
||||
|
||||
**以上為 Studio 團隊提出的技術建議,歡迎 Core API 團隊討論與反饋。**
|
||||
285
docs/proposals/face-group-naming-issue.md
Normal file
285
docs/proposals/face-group-naming-issue.md
Normal file
@@ -0,0 +1,285 @@
|
||||
# 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 確認後,再決定修復方向。**
|
||||
Reference in New Issue
Block a user