---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Momentry Core Chunk Rule 2: 畫面物件級檢索 (Visual Frame Chunk) (v1.0)"
date: "2026-04-21"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
  - "momentry"
  - "core"
  - "rule"
  - "chunk"
ai_query_hints:
  - "查詢 Momentry Core Chunk Rule 2: 畫面物件級檢索 (Visual Frame Chunk) (v1.0) 的內容"
  - "Momentry Core Chunk Rule 2: 畫面物件級檢索 (Visual Frame Chunk) (v1.0) 的主要目的是什麼？"
  - "如何操作或實施 Momentry Core Chunk Rule 2: 畫面物件級檢索 (Visual Frame Chunk) (v1.0)？"
---

# Momentry Core Chunk Rule 2: 畫面物件級檢索 (Visual Frame Chunk) (v1.0)

| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-21 |
| 文件版本 | V1.0 |

---

## 版本歷史

| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-04-21 | 定義 Rule 2: 單一幀（或關鍵幀聚合）的數據結構與搜尋邏輯 | OpenCode | OpenCode / Qwen3.6-Plus |

---

## 0. 設計目標

**Rule 2** 的核心概念是**「視覺語義」**。針對影片畫面中出現的具體物件、場景特徵進行精確索引，以支援「畫面內容搜尋」(Visual Search)。

- **核心原則**: 一個視覺幀 (或短時窗聚合) = 一個 Chunk。
- **過濾閾值**: 僅包含 YOLO 信心值 **> 0.8** 的物件，確保索引品質。
- **多模態融合**: 結合 YOLO (物件) + Face (人物) + ASRX (說話者)。

---

## 1. 數據源與處理流程 (Pipeline: Frame to Trace)

Rule 2 的臉部資料生成遵循 **「幀級偵測 → 軌跡聚合」** 的處理流程。

### 1.1 處理階段

1.  **Phase 1: Frame-based Pre-chunk (幀級紀錄)**
    *   **來源**: Face Processor 對原始影片幀進行檢測。
    *   **產出**: 離散的幀級資料 (Discrete Frame Data)。
    *   **特徵**: 包含單一幀的 `bbox`, `confidence`, `face_id`。

2.  **Phase 2: Trace Aggregation (軌跡聚合)**
    *   **處理**: 系統將連續的 `frame base pre_chunk` 串聯成單一軌跡。
    *   **產出**: **Trace-based Pre-chunk** (類別: `trace_face`)。
    *   **特徵**:
        *   **時間跨度**: 包含 `start_frame` (First Frame) 與 `end_frame` (Last Frame)。
        *   **代表幀**: 系統從軌跡中挑選品質最佳的幀 (Representative Frame) 作為索引依據。
    *   **目的**: 將瑣碎的幀資料轉化為具備「持續時間」概念的物件單元。

3.  **Phase 3: Rule 2 組合 (Chunk Creation)**
    *   **Input**: 接收由 Phase 2 產出的 `trace_face`。
    *   **Action**: 根據 `trace_face` 的時間跨度進行視覺 Chunk 的建立與索引。

### 1.2 Trace-based Pre-chunk (`trace_face`) 資料結構

```json
{
  "type": "trace_face",
  "trace_id": "trace_001",
  "face_id": "face_123",
  "file_uuid": "...",
  
  // 時間跨度：定義該臉部軌跡的起始與結束
  "start_frame": 100,
  "end_frame": 150,
  
  // 代表幀：從該軌跡中選出的最佳幀
  "representative_frame": {
    "frame_number": 115,
    "bbox": { "x": 50, "y": 50, "w": 100, "h": 100 },
    "confidence": 0.98,
    "thumbnail_path": "..."
  }
}
```

---

## 2. Chunk 結構定義

### 2.1 資料庫結構 (PostgreSQL)

```sql
CREATE TABLE chunks_rule2 (
    id UUID PRIMARY KEY,
    asset_uuid UUID NOT NULL,
    chunk_type VARCHAR(20) DEFAULT 'visual_frame',
    
    -- 時間軸 (幀為權威)
    start_frame INT NOT NULL,          -- 聚合區塊起始幀
    end_frame INT NOT NULL,            -- 聚合區塊結束幀
    start_time_sec DOUBLE PRECISION,   -- 參考值
    end_time_sec DOUBLE PRECISION,     -- 參考值
    fps DOUBLE PRECISION NOT NULL,

    -- 視覺內容 (由 YOLO 產生)
    content TEXT NOT NULL,             -- 描述文本: "car, person, traffic light"
    frame_objects JSONB,               -- 原始物件結構: [{"class": "car", "conf": 0.95}]
    
    -- 關聯元數據
    speaker_id VARCHAR(50),            -- 當下說話者 (若有)
    face_ids JSONB,                    -- 當下出現的人物 ID
    
    -- 向量與索引
    embedding vector(768),             -- nomic-embed-text-v2-moe
    search_vector tsvector,            -- BM25

    created_at TIMESTAMPTZ DEFAULT NOW()
);
```

### 2.2 JSON 產出範例

```json
{
  "chunk_id": "550e...0002",
  "type": "visual_frame",
  "content": "car, person, road sign, building",
  "start_frame": 600,
  "end_frame": 659,
  "start_time_sec": 10.00,
  "end_time_sec": 10.99,
  "metadata": {
    "frame_objects": [
      { "class": "car", "confidence": 0.98, "box": [10, 10, 50, 50] },
      { "class": "person", "confidence": 0.95, "box": [100, 100, 40, 80] }
    ],
    "faces": ["face_id_01"],
    "speaker": "SPEAKER_01"
  }
}
```

---

## 3. 搜尋能力定義

Rule 2 專為**視覺語意 (Visual Semantics)** 設計。

### 3.1 視覺關鍵字搜尋 (Visual Keyword Search)
- **場景**: "找出有車子的畫面"、"搜尋開車場景"。
- **邏輯**: 
    1. Query: "driving a car"。
    2. Embedding: 將 "driving a car" 轉為向量。
    3. Match: 與 `content` ("car, person...") 的向量進行比對。
  - *注意*: 雖然使用者搜尋是自然語言，但 Rule 2 的底層索引是物件標籤。由於 `nomic-v2-moe` 具有強大的語意對齊能力，"driving a car" 會高度匹配 "car" 標籤。

### 3.2 高信心值過濾 (Confidence Filtering)
- **場景**: "找出 100% 確定有槍的畫面"。
- **邏輯**: 
  - 直接查詢 `frame_objects` JSONB 欄位，要求 `confidence > 0.95`。

### 3.3 跨模態搜尋
- **場景**: "找出 Cary Grant 說話且背景有車的畫面"。
- **邏輯**: 
  - `face_ids` 包含 "Cary Grant" **AND** 
  - `frame_objects` 包含 "car"。

---

## 4. 處理流程 (Processing Pipeline)

### 4.1 聚合演算法 (Pseudocode)

```python
# 設定: FPS = 30, WINDOW = 30 frames (1 second)

for i in range(0, total_frames, WINDOW):
    window_frames = frames[i : i + WINDOW]
    
    all_objects = []
    all_faces = set()
    
    # 1. 遍歷視窗內的幀
    for frame in window_frames:
        # YOLO 過濾: 只取信心值 > 0.8
        valid_objects = [obj for obj in frame.yolo if obj.conf > 0.8]
        all_objects.extend(valid_objects)
        
        # Face 收集
        if frame.faces:
            all_faces.update([f.id for f in frame.faces])
            
    # 2. 建立內容摘要 (Content)
    # 提取唯一類別標籤: "car, person, dog"
    unique_classes = list(set([obj["class"] for obj in all_objects]))
    content_desc = ", ".join(unique_classes)
    
    # 3. 取得該時間段的 Speaker
    speaker = get_speaker_at_frame(i, asrx_data)
    
    # 4. 建立 Rule 2 Chunk
    chunk = {
        "content": content_desc,
        "start_frame": i,
        "end_frame": i + WINDOW - 1,
        "frame_objects": all_objects, # 保留原始結構供精確過濾
        "face_ids": list(all_faces),
        "speaker_id": speaker
    }
    
    store_chunk_rule2(chunk)
```

### 4.2 嵌入策略 (Embedding Strategy)

- **輸入文本**: 僅使用 `content` (物件標籤字串)。
- **原因**: 確保向量空間專注於**視覺語意**。若混入 Audio (ASR) 文本，會導致搜尋 "車" 時意外匹配到只提到車但未出現車的畫面。

---

## 5. 總結

Rule 2 提供了**視覺層面**的精確檢索能力，與 Rule 1 (聽覺/語句) 形成互補。

| 特性 | 實作方式 |
|------|----------|
| **粒度** | 幀級聚合 (通常為 1 秒區塊) |
| **資料過濾** | 僅納入 YOLO Confidence > 0.8 的物件 |
| **核心內容** | 物件類別標籤 (Object Tags) |
| **人物標記** | 包含 Face ID 與 Speaker ID |
| **適用場景** | 尋找特定物件 (槍、車)、場景識別、特定鏡頭回顧 |

此規範確保了影片畫面中的所有高可信度物件都能被系統「看見」並「記住」。
