---
document_type: "develop_guide"
service: "MOMENTRY_CORE"
title: "Momentry Core V1.0.0 API 示範與整合指南"
date: "2026-05-01"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
  - "momentry"
  - "core"
  - "api-usage"
  - "demo"
  - "n8n"
  - "wordpress"
ai_query_hints:
  - "查詢 V1.0.0 API 示範與整合指南的內容"
  - "如何使用 n8n 呼叫 V1.0.0 API？"
  - "如何整合 V1.0.0 API 到 WordPress？"
  - "V1.0.0 API 的 curl 範例"
  - "PHP 整合 V1.0.0 API 的方式（wp_remote_request）"
  - "n8n 工作流如何串接 V1.0.0 API"
  - "Face 綁定錯誤修正的 API 操作步驟"
  - "前端 Face Interpolation 的實作方式"
related_documents:
  - "API_V1.0.0/MOMENTRY_CORE_API_V1.0.0.md"
  - "API_V1.0.0/API_DICTIONARY_V1.0.0.md"
  - "API_V1.0.0/API_REFERENCE_v1.0.0.20260501md.md"
  - "API_V1.0.0/CHUNK_DEFINITION_V1.0.0.md"
  - "API_V1.0.0/PROCESSOR_SELECTION_V1.0.0.md"
---

# Momentry Core V1.0.0 API 示範與整合指南

| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-05-01 |
| 文件版本 | V1.0 |
| 適用版本 | Momentry Core V1.0.0+ |

---

## 關鍵術語定義

| 術語 | 定義 |
|------|------|
| file_uuid | 32 碼 SHA256 檔案識別碼 |
| X-API-Key | API 認證方式，透過 HTTP Header 傳遞 |
| face_id | 單一幀中的人臉偵測 ID，格式為 `<檢測ID>_<角色後綴>` |
| Identity | 全域人物身份，跨檔案關聯同一人物 |
| Face Interpolation | 前端線性插值，補足非逐幀臉部標記的顯示 |
| Scan | 掃描檔案系統，列出所有檔案及當前狀態 |

## 1. 快速開始 (Quick Start)

### 1.1 環境 URL

| 環境 | URL | 用途 |
|------|-----|------|
| **對外 URL** | `https://api.momentry.ddns.net` | 外部存取 |
| **Dev Server** | `http://localhost:3003` | **開發環境，所有測試用** |
| **Local Server** | `http://localhost:3002` | Production，僅 release 用 |

### 1.2 測試連線

```bash
curl http://localhost:3003/health
```

```json
{
  "status": "ok",
  "version": "1.0.0 (build: ...)",
  "uptime_ms": 64880
}
```

---

## 2. 核心 API 工作流 (Workflows)

### 2.1 掃描檔案系統 (Scan Files)
**入口 API**: `GET /api/v1/files/scan` — 所有 Demo 流程從這裡開始。

**掃描檔案**:
```bash
curl -s "http://localhost:3003/api/v1/files/scan" \
  -H "X-API-Key: <your_api_key>"
```

**列出檔案 (分頁)**:
```bash
curl -s "http://localhost:3003/api/v1/files?page=1&page_size=10" \
  -H "X-API-Key: <your_api_key>"
```

**取得單一檔案詳情**:
```bash
curl -s "http://localhost:3003/api/v1/files/<file_uuid>" \
  -H "X-API-Key: <your_api_key>"
```

### 2.2 搜尋 (Search)
支援語意搜尋、混合搜尋與視覺搜尋。

```bash
curl -X POST "http://localhost:3003/api/v1/search" \
  -H "X-API-Key: <your_api_key>" \
  -H "Content-Type: application/json" \
  -d '{"query": "尋找紅色信封", "uuid": "<file_uuid>"}'
```

### 2.3 單獨 Face 綁定流程 (Single Face Binding Workflow)

此流程適用於手動將特定臉部關聯到已知人物或建立新人物的場景。系統支援**一人分飾多角**，透過 `face_id` 加上角色後綴來區分。

#### 步驟 1: 選定 Face (Input Format)
使用者需提供一個 **`file_uuid`** 搭配 **`face_id`** 來鎖定目標。
選定的意思是輸入 **`<file_uuid>:<face_id>`** 的組合。

*   **命名規則**: `face_id` 格式通常為 `<原始檢測 ID>_<後綴>`，用於區分同一人的不同臉部實體或角色。
    *   **有角色名稱**: 使用角色名 (如 `123_PeterJoshua`)。
    *   **無角色名稱**: 使用通用代號 (如 `123_RoleA`, `123_RoleB`)。

#### 步驟 2: 列出 Identities 或新增 Identity
使用者決定將該 Face 綁定到系統中已存在的全域人物 (Identity)，或是建立一個新人物。
*   **Identity 特性**: 代表現實世界中的真實人物，具備**全域唯一性** (如 "Cary Grant")。

- **選項 A: 列出人物清單**
  ```bash
  curl -s "http://localhost:3003/api/v1/identities?page=1&page_size=20" \
    -H "X-API-Key: <your_api_key>"
  ```

- **選項 B: 決定新增人物名稱**
  若列表中沒有對應人物，使用者需準備一個新名稱（如 "Cary Grant"）。

#### 步驟 3: 確認綁定
透過 `POST /api/v1/identities/bind` 完成綁定。
*   **若提供 `identity_id`**: 將帶有後綴的 `face_id` 綁定至該人物。
*   **若提供 `name`**: 系統自動建立新人物 (Identity)，並將該臉部綁定上去。

- **綁定至現有身份 (範例)**:
  假設我們要綁定的目標是檔案 `file_uuid_abc` 中的臉部 `123_PeterJoshua`。
  ```bash
  curl -X POST "http://localhost:3003/api/v1/identities/bind" \
    -H "X-API-Key: <your_api_key>" \
    -H "Content-Type: application/json" \
    -d '{
      "identity_id": 101,
      "binding_type": "face",
      "binding_value": "123_PeterJoshua"
    }'
  ```
  *註: 雖然 API 接收的是 `binding_value`，但系統內部會根據選定的 `file_uuid` 與 `face_id` 組合來精確鎖定目標。*

#### 步驟 4: 循環
完成綁定後，返回列表處理下一個未綁定的 Face。

---

### 2.4 取得 Face 截圖 (Retrieve Face Snapshots)

在確認綁定前，通常需要檢視臉部截圖。根據使用場景，取得截圖有兩種方式：

#### 1. Local Path / Filename (本地路徑)
*   **適用**: Tauri 桌面應用、本機腳本。
*   **說明**: 直接從硬碟讀取圖片檔案，速度最快，無需經過網路層。
*   **路徑**: `<MOMENTRY_OUTPUT_DIR>/<file_uuid>/snapshots/faces/<face_id>.jpg`

#### 2. URL (網路存取)
*   **適用**: Web 前端、外部系統。
*   **說明**: 透過 HTTP GET 請求取得影像串流。
*   **API Endpoint**: `GET /api/v1/files/<file_uuid>/faces/<face_id>/thumbnail`
*   **範例**:
    ```bash
    curl -s -o face.jpg \
      "http://localhost:3003/api/v1/files/<file_uuid>/faces/<face_id>/thumbnail" \
      -H "X-API-Key: <your_api_key>"
    ```

---

### 2.4.1 前端動態辨識與插值 (Face Interpolation Logic)

由於系統對臉部標記並非逐幀 (Frame-by-Frame) 進行（為節省運算資源或受限於取樣率），在 Client 端進行**逐幀播放**或**時間軸拖曳**時，若直接顯示會導致臉部框選忽閃忽滅。

#### 運作邏輯
前端需實作**線性插值 (Linear Interpolation)** 機制：

1.  **取得資料**：從 API 取得該 `face_id` 在所有 `frame_number` 的座標列表（例如：Frame 10, Frame 15 有資料）。
2.  **插值計算**：
    *   當使用者停在 **Frame 12** 時，系統無直接資料。
    *   前端應找出前後最近的有資料幀（Frame 10 與 Frame 15）。
    *   根據時間差比例，動態計算出 Frame 12 的座標 `x, y, w, h`。

#### 實作範例 (JavaScript/TypeScript)

```typescript
// 假設 API 回傳該 Face 的軌跡點
const detections = [
  { frame: 10, bbox: { x: 100, y: 100, w: 50, h: 60 } },
  { frame: 15, bbox: { x: 110, y: 105, w: 50, h: 60 } },
];

// 計算 Frame 12 的預測框選
function getInterpolatedBBox(frameIndex: number, detections) {
  // 找到前一幀與後一幀
  const prev = detections.find(d => d.frame <= frameIndex); // Frame 10
  const next = detections.find(d => d.frame > frameIndex);  // Frame 15

  if (!prev) return null; // 還沒開始出現
  if (!next) return prev.bbox; // 結束了，維持最後位置

  // 計算比例 (0.0 - 1.0)
  const ratio = (frameIndex - prev.frame) / (next.frame - prev.frame);

  return {
    x: prev.bbox.x + (next.bbox.x - prev.bbox.x) * ratio,
    y: prev.bbox.y + (next.bbox.y - prev.bbox.y) * ratio,
    // w, h 亦可依此邏輯進行縮放插值
    w: prev.bbox.w, 
    h: prev.bbox.h, 
  };
}
```

---

### 2.5 Face 綁定錯誤修正 (Face Binding Error Correction)

此流程適用於移除錯誤綁定的臉部資料，使其恢復為未綁定狀態。

1.  **選定 Face**: 確認需要解除綁定的臉部 `face_id` 以及所屬的 `file_uuid`。
2.  **解除綁定 (Unbind)**:
    ```bash
    curl -X POST "http://localhost:3003/api/v1/identities/unbind" \
      -H "X-API-Key: <your_api_key>" \
      -H "Content-Type: application/json" \
      -d '{
        "binding_type": "face",
        "binding_value": "<selected_face_id>"
      }'
    ```

---

## 3. n8n 整合範例

### 3.1 HTTP Request 設定

| 欄位 | 值 |
|---|---|
| Method | `GET` 或 `POST` |
| URL | `http://localhost:3003/api/v1/files` (Dev) 或 `https://<your-domain>` (Prod) |
| Header `X-API-Key` | `<your_api_key>` |

### 3.2 列出檔案 Workflow (JSON)
使用 `GET /api/v1/files/scan` 作為入口。

```json
{
  "nodes": [
    {
      "name": "Get Files",
      "type": "n8n-nodes-base.httpRequest",
      "parameters": {
        "method": "GET",
        "url": "http://localhost:3003/api/v1/files/scan",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [{ "name": "X-API-Key", "value": "{{ $env.API_KEY }}" }]
        },
        "options": { "qs": { "page": 1, "page_size": 10 } }
      },
      "position": [450, 300]
    },
    {
      "name": "Extract List",
      "type": "n8n-nodes-base.code",
      "parameters": {
        "jsCode": "return $input.first().json.data.map(f => ({\n  json: {\n    uuid: f.file_uuid,\n    name: f.file_name,\n    status: f.status\n  }\n}));"
      },
      "position": [650, 300]
    }
  ]
}
```

---

## 4. WordPress / PHP 整合範例

### 4.1 PHP Client Library (V1.0.0 相容)

```php
<?php
class Momentry_API {
    private const API_URL = 'http://localhost:3003'; // Dev environment
    private const API_KEY = '<your_api_key>';

    private function request(string $endpoint, array $data = [], string $method = 'GET'): array {
        $url = self::API_URL . $endpoint;
        $args = [
            'headers' => [
                'X-API-Key' => self::API_KEY,
                'Content-Type' => 'application/json',
            ],
            'timeout' => 30,
        ];

        if ($method === 'POST') {
            $args['method'] = 'POST';
            $args['body'] = json_encode($data);
        }

        $response = wp_remote_request($url, $args);
        if (is_wp_error($response)) {
            throw new Exception($response->get_error_message());
        }
        return json_decode(wp_remote_retrieve_body($response), true);
    }

    // 掃描檔案
    public function scan_files(): array {
        return $this->request('/api/v1/files/scan');
    }

    // 列出檔案
    public function list_files(): array {
        return $this->request('/api/v1/files');
    }

    // 搜尋
    public function search(string $query): array {
        return $this->request('/api/v1/search', ['query' => $query], 'POST');
    }
}
?>
```

---

## 5. 疑難排解

| 錯誤 | 原因 | 解決方案 |
|------|------|----------|
| `401 Unauthorized` | API Key 無效 | 檢查 Key 格式與權限 |
| `404 Not Found` | 端點不存在 | 確認是否使用了舊版 `/api/v1/videos`，應改為 `/api/v1/files` |
| `400 Bad Request on Process` | 缺少 Probe 資料 | 先執行 `GET /api/v1/files/:file_uuid/probe` |
| `500 Error` | 伺服器錯誤 | 檢查資料庫連線與 Schema 版本 |

---

## 6. 版本歷史

| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-05-01 | 初始版本 | OpenCode | deepseek-chat |
| V1.1 | 2026-05-01 | 修正 port 為 Dev(3003)，更新 API 路徑與掃描入口 | OpenCode | deepseek-chat |

---

## 7. 附錄：UUID 格式說明

V1.0.0 使用 **32 碼 SHA256** 作為 `file_uuid`。

```
/Users/.../demo/video.mp4 
    ↓
SHA256 Hash (前 32 字元)
    ↓
53e3a229bf68878b7a799e811e097f9c
```
