Files
momentry_studio/docs/proposals/core-api-face-groups-endpoint.md
Momentry Studio 5951aca086 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
2026-07-24 20:19:47 +08:00

10 KiB
Raw Blame History

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

技術實現

{
  "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

響應格式

{
  "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

響應格式

{
  "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 實現邏輯(建議)

# 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_tracelabel 為預設值(如 "Face Trace 9"
  • 用戶尚未命名

建議選項

選項 處理方式 優點 缺點
A 歸類為 unassigned_traces 列表 清晰區分已命名/未命名 需要額外欄位
B 每個未命名 trace 作為獨立 group 格式統一 可能產生大量 group
C 不返回未命名 traces 響應簡潔 遺失數據

建議:選項 A返回 unassigned_traces 列表


4.3 Cluster ID / Group ID 的必要性

問題

  • cluster_idgroup_id 是否需要?
  • 如果只是順序編號,每次查詢可能不同

建議選項

選項 實現方式 優點 缺點
A 使用 name 作為唯一標識 語義清晰,無需額外 ID 名稱變更時引用會失效
B 生成固定的 group_id(如 UUID ID 固定,不受名稱變更影響 需要額外存儲
C 每次查詢時動態生成順序編號 實現簡單 編號可能變化

建議:選項 C動態生成順序編號因為 Cluster ID 只是技術手段)


4.4 分頁支持

問題

  • 如果一個文件有大量 face traces如超過 500如何處理

建議

  • 支持分頁參數 pagepage_size
  • 默認 page_size=100,最大 500

4.5 性能考慮

問題

  • TKG nodes 查詢是否需要緩存?

建議

  • Core API 可以在內部緩存 TKG nodes 查詢結果
  • 緩存時效5-10 分鐘(或直到有 trace-profile 更新)

五、Studio Proxy 職責

5.1 Processor JSON Handler

修改前

// 讀取本地文件
let path = format!("{}/{}.{}.json", output_dir, file_hash, processor);
let content = std::fs::read_to_string(&path)?;

修改後

// 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

修改前

// 讀取本地文件
let path = format!("{}/{}/{}.cluster_result.json", base, file_hash, file_hash);
let content = std::fs::read_to_string(&path)?;

修改後

// 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 共享邏輯

建議抽取共享函數

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 團隊討論與反饋。