feat: backup architecture docs, source code, and scripts
This commit is contained in:
273
docs_v1.0/CHUNKING/CORE/CHUNKING_ARCHITECTURE.md
Normal file
273
docs_v1.0/CHUNKING/CORE/CHUNKING_ARCHITECTURE.md
Normal file
@@ -0,0 +1,273 @@
|
||||
---
|
||||
document_type: "architecture_design"
|
||||
service: "MOMENTRY_CORE"
|
||||
title: "Momentry Core 分片架構總綱 (Master Chunking Architecture) (v1.1)"
|
||||
date: "2026-04-22"
|
||||
version: "V1.0"
|
||||
status: "active"
|
||||
owner: "Warren"
|
||||
created_by: "OpenCode"
|
||||
tags:
|
||||
- "chunking"
|
||||
- "momentry"
|
||||
- "core"
|
||||
- "分片架構總綱"
|
||||
ai_query_hints:
|
||||
- "查詢 Momentry Core 分片架構總綱 (Master Chunking Architecture) (v1.1) 的內容"
|
||||
- "Momentry Core 分片架構總綱 (Master Chunking Architecture) (v1.1) 的主要目的是什麼?"
|
||||
- "如何操作或實施 Momentry Core 分片架構總綱 (Master Chunking Architecture) (v1.1)?"
|
||||
---
|
||||
|
||||
# Momentry Core 分片架構總綱 (Master Chunking Architecture) (v1.1)
|
||||
|
||||
| 項目 | 內容 |
|
||||
|------|------|
|
||||
| 建立者 | OpenCode |
|
||||
| 建立時間 | 2026-04-22 |
|
||||
| 最後更新 | 2026-04-22 |
|
||||
| 文件版本 | V1.1 |
|
||||
| **狀態** | **設計文檔(與實際實現有差異)** |
|
||||
|
||||
---
|
||||
|
||||
## 版本歷史
|
||||
|
||||
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|
||||
|------|------|------|--------|-----------|
|
||||
| V1.1 | 2026-04-22 | 術語標準化整合,添加參考文件連結 | OpenCode | OpenCode / deepseek-v3.2 |
|
||||
| V1.0 | 2026-04-22 | 整合分片規則、標記設計與實現差異 | OpenCode | OpenCode / Qwen3.6-Plus |
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 重要說明:設計與實現差異
|
||||
|
||||
本文檔描述的是**設計目標**,與**實際實現**存在差異。以下是主要差異點:
|
||||
|
||||
### 差異點 1: `chunk_type` 值
|
||||
| 設計文檔 | 實際實現 | 狀態 |
|
||||
|----------|----------|------|
|
||||
| `sentence` | `ChunkType::Sentence` | ✅ 一致 |
|
||||
| `visual` | 未實現 (設計值: visual) | ❌ 缺失 |
|
||||
| `scene` | `ChunkType::Cut` (設計值: scene) | ⚠️ 部分實現 |
|
||||
| `summary` | `ChunkType::Story` (設計值: summary) | ⚠️ 概念調整 |
|
||||
| - | `"time"` | 🔄 額外 |
|
||||
| - | `"cut"` | 🔄 額外 |
|
||||
| - | `"trace"` | 🔄 額外 |
|
||||
| - | `"story"` | 🔄 額外 |
|
||||
|
||||
### 差異點 2: 規則實現
|
||||
| 規則 | 設計描述 | 實際實現 |
|
||||
|------|----------|----------|
|
||||
| Rule 1 | 句子級檢索 | ✅ 已實現 (`rule1_ingest.rs`) |
|
||||
| Rule 2 | 視覺物件級檢索 | ❌ 未實現 |
|
||||
| Rule 3 | 場景級檢索 | ⚠️ 部分實現 (`rule3_ingest.rs`) |
|
||||
| Rule 4 | 摘要級檢索 | ❌ 未實現 |
|
||||
|
||||
---
|
||||
|
||||
## 0. 設計目標
|
||||
|
||||
**分片 (Chunking)** 是 Momentry Core 將連續影音轉化為**可檢索知識**的核心樞紐。本架構定義了如何將處理器產出的原始數據 (Pre-Chunk/Frame),依據標準規則組裝為多層級 Chunk,並透過關聯分析產出高價值摘要。
|
||||
|
||||
- **時間權威 (Frame-Based)**:所有時間計算以 `frame_number` 為唯一權威,秒數僅供參考 (`time = frame / fps`)。
|
||||
- **多模態融合 (Multimodal Fusion)**:每個 Chunk 聚合 ASR (聽覺)、Face (人物)、YOLO (物件) 特徵。
|
||||
- **分層檢索 (Hierarchical Retrieval)**:從微觀台詞 (Rule 1) 到宏觀劇情問答 (Rule 4)。
|
||||
- **自動知識萃取 (Auto-Enrichment)**:利用 LLM 聚合父子內容,自動生成 Summary 與 5W1H。
|
||||
|
||||
---
|
||||
|
||||
## 1. 通用分片結構 (Universal Chunk Schema)
|
||||
|
||||
無論是哪一種 Rule,所有 Chunk 皆遵循以下核心定義:
|
||||
|
||||
| 欄位 | 類型 | 說明 |
|
||||
|:---|:---|:---|
|
||||
| `chunk_id` | UUID | 分片唯一標識符 (PK) |
|
||||
| `asset_uuid` | UUID | 所屬影片資產 UUID |
|
||||
| `chunk_type` | ENUM | **設計值**:`sentence`, `visual`, `scene`, `summary`<br>**實際值**:`"time"` (`ChunkType::TimeBased`), `"sentence"` (`ChunkType::Sentence`), `"cut"` (`ChunkType::Cut`), `"trace"` (`ChunkType::Trace`), `"story"` (`ChunkType::Story`) |
|
||||
| `start_frame` | INT | **起始幀** (時間權威來源) |
|
||||
| `end_frame` | INT | **結束幀** (時間權威來源) |
|
||||
| `content` | TEXT | 主要檢索內容 (ASR 文本 / 物件描述 / 劇情摘要) |
|
||||
| `metadata` | JSONB | 關聯內容 (Speaker, Face IDs, Frame Objects) |
|
||||
|
||||
---
|
||||
|
||||
## 2. 分片規則路由 (Rule Routing Table)
|
||||
|
||||
系統依據規則將原始數據轉化為不同粒度的檢索單元,並寫入對應資料表。
|
||||
|
||||
| Rule | 粒度 | `chunk_type` | 內容來源 (Content) | 關聯內容 (Metadata) | 寫入資料表 | 實現狀態 |
|
||||
|:---|:---|:---|:---|:---|:---|:---|
|
||||
| **Rule 1** | 語句 | `ChunkType::Sentence` (設計值: `sentence`) | **ASR 文本** (單句文字) | Speaker ID, Face IDs (區間聚合) | `chunks_rule1` | ✅ 已實現 |
|
||||
| **Rule 2** | 畫面 | 未實現 (設計值: `visual`) | **物件標籤串** (e.g., "car, person") | YOLO Objects (>0.8), Faces, Speaker | `chunks_rule2` | ❌ 未實現 |
|
||||
| **Rule 3** | 場景 | `ChunkType::Cut` (設計值: `scene`) | **場景摘要** (聚合多個 Rule 1/2) | Aggregated Faces, Objects, Speakers | `chunks_rule3` | ⚠️ 部分實現 |
|
||||
| **Rule 4** | 摘要 | `ChunkType::Story` (設計值: `summary`) | **劇情描述 & 5W1H 分析** (LLM 生成) | 5W1H 結構化數據, 關聯 Rule 3 IDs | `chunks_rule4` | ⚠️ 概念調整 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 關聯與知識萃取流程 (Associative Enrichment Pipeline)
|
||||
|
||||
這是系統將「原始數據」轉化為「結構化知識」的核心機制。針對 **父 Chunk (Rule 3 Scene)**,系統會匯聚其下屬的所有子 Chunk、視覺物件與人物特徵,並透過 LLM 產出全新的敘事內容。
|
||||
|
||||
### 3.1 數據關聯架構 (Input Aggregation)
|
||||
|
||||
針對每一個 Parent Chunk `[start_frame, end_frame]`,系統提取:
|
||||
1. **子 Chunk (Rule 1)**: 提取對話 (`content`) 與說話者 (`speaker_id`)。
|
||||
2. **子 Chunk (Rule 2)**: 提取物件標籤 (`frame_objects`)。
|
||||
3. **身份解析**: 將 `face_id` 解析為真實人名 (e.g., `face_01` -> "Cary Grant")。
|
||||
|
||||
### 3.2 LLM 上下文構造 (Context Construction)
|
||||
|
||||
系統組裝 Prompt 提供給 Gemma4:
|
||||
```text
|
||||
### 場景數據
|
||||
**人物**: Cary Grant, Audrey Hepburn
|
||||
**物件**: car, street, gun
|
||||
**對話**: [Cary] "Look at that car!"
|
||||
|
||||
### 任務
|
||||
1. **New Content**: 融合所有資訊,生成一段詳細的繁體中文敘述。
|
||||
2. **Summary**: 一句話精簡摘要。
|
||||
3. **5W1H**: 結構化提取 (Who, What, Where, Why, How)。
|
||||
```
|
||||
|
||||
### 3.3 輸出與寫入 (Output & Ingestion)
|
||||
|
||||
LLM 返回的 JSON 將直接更新資料庫:
|
||||
```sql
|
||||
UPDATE chunks_rule3
|
||||
SET
|
||||
content = $new_content, -- 覆蓋為詳細敘述
|
||||
summary = $new_summary, -- 儲存精簡摘要
|
||||
analysis_5w1h = $json_5w1h -- 儲存結構化分析
|
||||
WHERE id = $chunk_id;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 實際實現狀態
|
||||
|
||||
### 4.1 已實現功能
|
||||
- **Rule 1 (Sentence Chunk)**: 完整實現,位於 `src/core/chunk/rule1_ingest.rs`
|
||||
- **Rule 3 (Scene Chunk)**: 部分實現,位於 `src/core/chunk/rule3_ingest.rs`
|
||||
- 目前基於 CUT 數據識別場景
|
||||
- 聚合 Rule 1 句子
|
||||
- 調用 LLM 生成 5W1H 摘要
|
||||
|
||||
### 4.2 未實現功能
|
||||
- **Rule 2 (Visual Chunk)**: 未實現
|
||||
- **Rule 4 (Summary Chunk)**: 未實現
|
||||
- **完整的場景分類**: 目前僅基於 CUT 數據,未集成 Places365 場景分類
|
||||
|
||||
### 4.3 實際數據庫結構
|
||||
```sql
|
||||
-- 實際的 chunks 表結構
|
||||
CREATE TABLE chunks (
|
||||
id SERIAL PRIMARY KEY,
|
||||
uuid VARCHAR(32) NOT NULL,
|
||||
chunk_id VARCHAR(64) NOT NULL,
|
||||
chunk_index INTEGER NOT NULL,
|
||||
chunk_type VARCHAR(32) NOT NULL, -- "time", "sentence", "cut", "trace", "story"
|
||||
start_time DOUBLE PRECISION NOT NULL,
|
||||
end_time DOUBLE PRECISION NOT NULL,
|
||||
fps DOUBLE PRECISION DEFAULT 24.0,
|
||||
start_frame BIGINT DEFAULT 0,
|
||||
end_frame BIGINT DEFAULT 0,
|
||||
content JSONB NOT NULL,
|
||||
metadata JSONB,
|
||||
vector_id VARCHAR(64),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(uuid, chunk_id)
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 遷移計劃建議
|
||||
|
||||
### 5.1 短期目標 (1-2個月)
|
||||
1. **實現 Rule 2 (Visual Chunk)**
|
||||
- 集成 YOLO 物件檢測結果
|
||||
- 創建 `chunks_rule2` 表
|
||||
- 實現 `rule2_ingest.rs`
|
||||
|
||||
2. **完善 Rule 3 (Scene Chunk)**
|
||||
- 集成 Places365 場景分類
|
||||
- 完善 LLM 摘要生成
|
||||
- 創建 `chunks_rule3` 表
|
||||
|
||||
### 5.2 中期目標 (3-6個月)
|
||||
1. **實現 Rule 4 (Summary Chunk)**
|
||||
- 跨場景劇情摘要
|
||||
- 創建 `chunks_rule4` 表
|
||||
|
||||
2. **統一 `chunk_type` 枚舉**
|
||||
- 更新 Rust 代碼中的 `ChunkType` 枚舉
|
||||
- 遷移現有數據
|
||||
|
||||
### 5.3 長期目標 (6-12個月)
|
||||
1. **動態分片規則**
|
||||
- 支持用戶自定義分片規則
|
||||
- 可配置的聚合策略
|
||||
|
||||
2. **實時分片處理**
|
||||
- On-the-fly 分片生成
|
||||
- 增量更新機制
|
||||
|
||||
---
|
||||
|
||||
## 6. 相關文件
|
||||
|
||||
| 文件 | 描述 | 狀態 |
|
||||
|------|------|------|
|
||||
| [CHUNK_RULE_1_SENTENCE.md](./CHUNK_RULE_1_SENTENCE.md) | Rule 1: 句子級檢索 | ✅ 與實現一致 |
|
||||
| [CHUNK_RULE_2_VISUAL.md](./CHUNK_RULE_2_VISUAL.md) | Rule 2: 視覺物件級檢索 | ⚠️ 設計文檔 |
|
||||
| [CHUNK_RULE_3_SCENE.md](./CHUNK_RULE_3_SCENE.md) | Rule 3: 場景級檢索 | ⚠️ 部分實現 |
|
||||
| [CHUNK_RULE_4_SUMMARY.md](./CHUNK_RULE_4_SUMMARY.md) | Rule 4: 摘要級檢索 | ⚠️ 設計文檔 |
|
||||
| [CHUNKING_SCHEMA_SPEC.md](./CHUNKING_SCHEMA_SPEC.md) | 數據庫結構規範 | ⚠️ 設計文檔 |
|
||||
| [CHUNKING_ENRICHMENT_PIPELINE.md](./CHUNKING_ENRICHMENT_PIPELINE.md) | 知識萃取流程 | ⚠️ 設計文檔 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 代碼引用
|
||||
|
||||
### 7.1 主要實現文件
|
||||
```rust
|
||||
// Rule 1 實現
|
||||
src/core/chunk/rule1_ingest.rs
|
||||
|
||||
// Rule 3 實現
|
||||
src/core/chunk/rule3_ingest.rs
|
||||
|
||||
// Chunk 類型定義
|
||||
src/core/chunk/types.rs
|
||||
|
||||
// Chunk 分割器
|
||||
src/core/chunk/splitter.rs
|
||||
```
|
||||
|
||||
### 7.2 數據庫操作
|
||||
```rust
|
||||
// 數據庫層的 chunk 處理
|
||||
src/core/db/postgres_db.rs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 更新記錄
|
||||
|
||||
| 日期 | 版本 | 變更內容 | 操作人 |
|
||||
|------|------|----------|--------|
|
||||
| 2026-04-22 | V1.1 | 術語標準化整合,添加參考文件連結 | OpenCode |
|
||||
| 2026-04-22 | V1.0 | 創建整合文檔,標記設計與實現差異 | OpenCode |
|
||||
|
||||
---
|
||||
|
||||
## 參考文件
|
||||
|
||||
1. **[TERMINOLOGY_MAPPING.md](../../TERMINOLOGY_MAPPING.md)** - 完整術語對照表
|
||||
2. **[DESIGN_IMPLEMENTATION_GAP.md](../../DESIGN_IMPLEMENTATION_GAP.md)** - 設計與實現差異分析
|
||||
3. **[ARCHITECTURE_OVERVIEW.md](../../ARCHITECTURE_OVERVIEW.md)** - 架構總覽
|
||||
|
||||
**最後更新**: 2026-04-22
|
||||
177
docs_v1.0/CHUNKING/CORE/CHUNKING_ENRICHMENT_PIPELINE.md
Normal file
177
docs_v1.0/CHUNKING/CORE/CHUNKING_ENRICHMENT_PIPELINE.md
Normal file
@@ -0,0 +1,177 @@
|
||||
---
|
||||
document_type: "architecture_design"
|
||||
service: "MOMENTRY_CORE"
|
||||
title: "Momentry Core 分片關聯與內容生成架構 (Chunk Associative Enrichment) (v1.0)"
|
||||
date: "2026-04-21"
|
||||
version: "V1.0"
|
||||
status: "active"
|
||||
owner: "Warren"
|
||||
created_by: "OpenCode"
|
||||
tags:
|
||||
- "momentry"
|
||||
- "core"
|
||||
- "associative"
|
||||
- "分片關聯與內容生成架構"
|
||||
ai_query_hints:
|
||||
- "查詢 Momentry Core 分片關聯與內容生成架構 (Chunk Associative Enrichment) (v1.0) 的內容"
|
||||
- "Momentry Core 分片關聯與內容生成架構 (Chunk Associative Enrichment) (v1.0) 的主要目的是什麼?"
|
||||
- "如何操作或實施 Momentry Core 分片關聯與內容生成架構 (Chunk Associative Enrichment) (v1.0)?"
|
||||
---
|
||||
|
||||
# Momentry Core 分片關聯與內容生成架構 (Chunk Associative Enrichment) (v1.0)
|
||||
|
||||
| 項目 | 內容 |
|
||||
|------|------|
|
||||
| 建立者 | OpenCode |
|
||||
| 建立時間 | 2026-04-21 |
|
||||
| 文件版本 | V1.0 |
|
||||
|
||||
---
|
||||
|
||||
## 版本歷史
|
||||
|
||||
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|
||||
|------|------|------|--------|-----------|
|
||||
| V1.0 | 2026-04-21 | 定義基於多模態關聯 (Multimodal Association) 的內容生成流程 | OpenCode | OpenCode / Qwen3.6-Plus |
|
||||
|
||||
---
|
||||
|
||||
## 0. 設計目標
|
||||
|
||||
本規範定義了系統如何將**父 Chunk (Parent Chunk)** 與其關聯的視覺、聽覺、人物數據進行深度聚合,並利用 LLM **生成全新的敘事內容 (New Content)**、**摘要 (Summary)** 與 **結構化分析 (5W1H)**,將原始數據轉化為高價值的知識資產。
|
||||
|
||||
---
|
||||
|
||||
## 1. 關聯輸入架構 (Associative Input)
|
||||
|
||||
為了產出高品質內容,系統需聚合以下三層資訊:
|
||||
|
||||
### 1.1 核心數據源
|
||||
|
||||
| 數據源 | 欄位/內容 | 處理方式 |
|
||||
|:---|:---|:---|
|
||||
| **父 Chunk (Rule 3)** | `content` (場景初步描述), `[start_frame, end_frame]` | 作為上下文錨點。 |
|
||||
| **子 Chunk (Rule 1)** | `content` (ASR 對話), `speaker_id` | 提取「誰說了什麼」。 |
|
||||
| **子 Chunk (Rule 2)** | `frame_objects` (YOLO 物件) | 提取「場景中有什麼」。 |
|
||||
|
||||
### 1.2 知識庫解析 (Knowledge Resolution)
|
||||
|
||||
在送入 LLM 前,必須將機器 ID 轉換為人類可讀的名稱:
|
||||
- **Face Resolution**: `face_id_01` → 查詢 `face_identities` → `"Cary Grant"`。
|
||||
- **Object Normalization**: `"automobile"` → 映射為 `"car"` (選用)。
|
||||
|
||||
---
|
||||
|
||||
## 2. 內容生成策略 (Content Generation Strategy)
|
||||
|
||||
系統採用 **「多模態融合 (Multimodal Fusion)」** 策略,將離散的數據重組為連貫的敘事。
|
||||
|
||||
### 2.1 融合範例
|
||||
|
||||
**輸入數據**:
|
||||
- **Dialogue**: "Look at that car!" (Speaker: SPEAKER_00/Cary Grant)
|
||||
- **Objects**: `car`, `street`, `gun`
|
||||
- **Faces**: `Cary Grant`, `Audrey Hepburn`
|
||||
|
||||
**融合後的上下文 (Context)**:
|
||||
> 場景內出現人物:Cary Grant, Audrey Hepburn。
|
||||
> 視覺物件:car, street, gun。
|
||||
> 對話內容:[Cary Grant] "Look at that car!"
|
||||
|
||||
**LLM 輸出 (New Content)**:
|
||||
> "Cary Grant 和 Audrey Hepburn 站在街道上。Grant 注意到一輛車,並似乎對它有所警覺,周圍環境暗示可能存在危險(因為偵測到槍枝)。"
|
||||
|
||||
---
|
||||
|
||||
## 3. 處理流程 (Pipeline)
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Parent Chunk] -->|Time Range| B[Data Aggregator]
|
||||
C[Children Chunks] -->|Content| B
|
||||
D[Knowledge DB] -->|Identity Map| B
|
||||
|
||||
B -->|Context Prompt| E[LLM (Gemma4)]
|
||||
|
||||
E -->|Output 1| F[New Content (Narrative)]
|
||||
E -->|Output 2| G[Summary (Concise)]
|
||||
E -->|Output 3| H[5W1H (Structured)]
|
||||
|
||||
F & G & H --> I[Update DB (Rule 3/4)]
|
||||
```
|
||||
|
||||
### 3.1 提示詞設計 (Prompt Design)
|
||||
|
||||
為了確保輸出的結構化,提示詞必須明確要求 JSON 格式。
|
||||
|
||||
```text
|
||||
### 任務
|
||||
分析以下場景數據,生成結構化的劇情分析。
|
||||
|
||||
### 場景數據
|
||||
**時間**: {start_sec}s - {end_sec}s
|
||||
**人物**: {resolved_faces}
|
||||
**物件**: {objects}
|
||||
**對話片段**:
|
||||
{dialogue_snippets}
|
||||
|
||||
### 輸出要求
|
||||
請以 JSON 格式返回,包含以下欄位:
|
||||
1. **content**: 一段詳細的敘述性文字 (繁體中文),融合所有對話、人物動作與物件資訊。
|
||||
2. **summary**: 一句話的精簡摘要 (繁體中文)。
|
||||
3. **5w1h**:
|
||||
- who: 主要人物列表
|
||||
- what: 核心事件
|
||||
- where: 地點/環境
|
||||
- when: 時間/背景
|
||||
- why: 動機/原因
|
||||
- how: 方式/過程
|
||||
|
||||
### JSON 格式範例
|
||||
{
|
||||
"content": "...",
|
||||
"summary": "...",
|
||||
"5w1h": { "who": [], "what": [], ... }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 輸出結構與儲存 (Output & Storage)
|
||||
|
||||
生成的內容將被寫入資料庫,通常是更新父 Chunk (Rule 3) 或生成新的 Rule 4 Chunk。
|
||||
|
||||
### 4.1 JSON 輸出範例
|
||||
|
||||
```json
|
||||
{
|
||||
"content": "彼得 (Cary Grant) 與雷吉娜 (Audrey Hepburn) 在夜間的街道上駕車行駛。彼得發現了那輛可疑的車子,並警告雷吉娜保持警惕。兩人似乎正在執行一項危險的任務,尋找藏有郵票的保險箱。",
|
||||
"summary": "彼得與雷吉娜夜間駕車尋找郵票,途中遭遇可疑車輛並保持警戒。",
|
||||
"5w1h": {
|
||||
"who": ["Cary Grant", "Audrey Hepburn"],
|
||||
"what": ["Driving", "Spotting suspicious car", "Searching for stamps"],
|
||||
"where": ["Street", "Car"],
|
||||
"when": "Night",
|
||||
"why": "To retrieve the stamps",
|
||||
"how": "By driving and observing surroundings"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 資料庫寫入 (SQL)
|
||||
|
||||
**更新 Rule 3 (Parent Chunk)**:
|
||||
```sql
|
||||
UPDATE chunks_rule3
|
||||
SET
|
||||
content = $new_content, -- 覆蓋或追加新的敘述內容
|
||||
summary = $new_summary, -- 儲存精簡摘要
|
||||
analysis_5w1h = $json_5w1h -- 儲存結構化分析
|
||||
WHERE id = $chunk_id;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 總結
|
||||
|
||||
透過**附加關聯**與**內容生成**,Momentry Core 實現了從「關鍵字匹配」到「語意理解」的跨越。系統不僅能告訴使用者「某個物件出現了」,還能解釋「**誰**在**哪裡**利用**什麼**做了**什麼**」,提供完整的場景認知。
|
||||
271
docs_v1.0/CHUNKING/CORE/CHUNKING_SCHEMA_SPEC.md
Normal file
271
docs_v1.0/CHUNKING/CORE/CHUNKING_SCHEMA_SPEC.md
Normal file
@@ -0,0 +1,271 @@
|
||||
---
|
||||
document_type: "architecture_design"
|
||||
service: "MOMENTRY_CORE"
|
||||
title: "Momentry Core 分片資料庫結構規範 (Chunking Schema Spec) (v1.1)"
|
||||
date: "2026-04-21"
|
||||
version: "V1.0"
|
||||
status: "active"
|
||||
owner: "Warren"
|
||||
created_by: "OpenCode"
|
||||
tags:
|
||||
- "schema"
|
||||
- "momentry"
|
||||
- "core"
|
||||
- "分片資料庫結構規範"
|
||||
ai_query_hints:
|
||||
- "查詢 Momentry Core 分片資料庫結構規範 (Chunking Schema Spec) (v1.1) 的內容"
|
||||
- "Momentry Core 分片資料庫結構規範 (Chunking Schema Spec) (v1.1) 的主要目的是什麼?"
|
||||
- "如何操作或實施 Momentry Core 分片資料庫結構規範 (Chunking Schema Spec) (v1.1)?"
|
||||
---
|
||||
|
||||
# Momentry Core 分片資料庫結構規範 (Chunking Schema Spec) (v1.1)
|
||||
|
||||
| 項目 | 內容 |
|
||||
|------|------|
|
||||
| 建立者 | OpenCode |
|
||||
| 建立時間 | 2026-04-21 |
|
||||
| 最後更新 | 2026-04-22 |
|
||||
| 文件版本 | V1.1 |
|
||||
| **狀態** | **設計文檔(與實際實現有差異)** |
|
||||
|
||||
---
|
||||
|
||||
## 版本歷史
|
||||
|
||||
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|
||||
|------|------|------|--------|-----------|
|
||||
| V1.1 | 2026-04-22 | 術語標準化:更新為實際實現的術語 | OpenCode | OpenCode / deepseek-v3.2 |
|
||||
| V1.0 | 2026-04-21 | 定義符合 Chunking Rule 的完整資料庫結構與欄位對齊 | OpenCode | OpenCode / Qwen3.6-Plus |
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 重要說明:術語標準化
|
||||
|
||||
本文檔已根據實際 Rust 代碼實現更新術語。**核心原則**:當設計與實現出現矛盾時,以實際的 Rust 代碼實現為最高權威。
|
||||
|
||||
### 術語對照表
|
||||
| 設計概念 | 設計值 | 實現值 | 實現狀態 |
|
||||
|----------|--------|--------|----------|
|
||||
| 時間基準分片 | `time` | `TimeBased` | ✅ 已實現 |
|
||||
| 句子級分片 | `sentence` | `Sentence` | ✅ 已實現 |
|
||||
| 場景級分片 | `scene` | `Cut` | ⚠️ 部分實現 |
|
||||
| 視覺物件級分片 | `visual` | (未實現) | ❌ 未實現 |
|
||||
| 摘要級分片 | `summary` | `Story` | ⚠️ 概念調整 |
|
||||
| 軌跡追蹤分片 | (未定義) | `Trace` | ✅ 已實現 |
|
||||
|
||||
**參考文件**:[TERMINOLOGY_MAPPING.md](../../TERMINOLOGY_MAPPING.md)
|
||||
|
||||
---
|
||||
|
||||
## 0. 設計原則
|
||||
|
||||
本規範確保所有資料庫表嚴格遵循 **Chunking Architecture** 定義的通用結構:
|
||||
|
||||
1. **時間權威 (Frame-Based)**:所有時間相關欄位以 `frame` 為核心,`timestamp` 為計算參考。
|
||||
2. **內容與元數據分離 (Content vs Metadata)**:`content` 用於全文檢索與向量嵌入,`metadata` (JSONB) 儲存關聯物件、Speaker、Faces 等結構化數據。
|
||||
3. **路由清晰 (Rule Routing)**:每個 Rule 對應獨立的資料表,透過 `chunk_type` 欄位輔助識別。
|
||||
|
||||
---
|
||||
|
||||
## 1. 通用基礎欄位 (Common Base Columns)
|
||||
|
||||
以下欄位為**所有 Rule 表**的標準配置:
|
||||
|
||||
| 欄位 | 類型 | 約束 | 說明 |
|
||||
|:---|:---|:---|:---|
|
||||
| `id` | UUID | PK | Chunk 唯一標識符 |
|
||||
| `asset_uuid` | UUID | FK, Not Null | 所屬影片資產 UUID |
|
||||
| `chunk_type` | VARCHAR(20) | Not Null | 分片類型標識 (`TimeBased`, `Sentence`, `Cut`, `Trace`, `Story`) |
|
||||
| `start_frame` | INT | Not Null | **起始幀** (時間基準) |
|
||||
| `end_frame` | INT | Not Null | **結束幀** (時間基準) |
|
||||
| `fps` | DOUBLE PRECISION | Not Null | 幀率 (用於換算秒數) |
|
||||
| `content` | TEXT | Not Null | 檢索主體內容 |
|
||||
| `created_at` | TIMESTAMPTZ | Default Now | 建立時間 |
|
||||
|
||||
---
|
||||
|
||||
## 2. Rule 1 結構:句子級 (Sentence)
|
||||
|
||||
對應 `CHUNK_RULE_1_SENTENCE.md`,用於 ASR 語句聚合。
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS chunks_rule1 (
|
||||
-- 通用基礎
|
||||
id UUID PRIMARY KEY,
|
||||
asset_uuid UUID NOT NULL REFERENCES assets(id),
|
||||
chunk_type VARCHAR(20) DEFAULT 'Sentence' NOT NULL,
|
||||
start_frame INT NOT NULL,
|
||||
end_frame INT NOT NULL,
|
||||
fps DOUBLE PRECISION NOT NULL,
|
||||
content TEXT NOT NULL, -- ASR 文本
|
||||
|
||||
-- 關聯元數據
|
||||
speaker_id VARCHAR(50), -- ASRX 說話者
|
||||
face_ids JSONB, -- 區間內出現的 Face ID 陣列
|
||||
face_confidence_map JSONB, -- 對應的臉部信心值 (可選)
|
||||
|
||||
-- 索引優化
|
||||
search_vector tsvector GENERATED ALWAYS AS (to_tsvector('simple', content)) STORED,
|
||||
embedding vector(768) -- nomic-embed-text-v2-moe
|
||||
);
|
||||
|
||||
-- 索引
|
||||
CREATE INDEX idx_r1_asset ON chunks_rule1(asset_uuid);
|
||||
CREATE INDEX idx_r1_speaker ON chunks_rule1(speaker_id);
|
||||
CREATE INDEX idx_r1_search ON chunks_rule1 USING gin(search_vector);
|
||||
CREATE INDEX idx_r1_faces ON chunks_rule1 USING gin(face_ids);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Rule 2 結構:畫面級 (Visual) ⚠️ 未實現
|
||||
|
||||
**注意**: Rule 2 在實際代碼中尚未實現。以下為設計概念。
|
||||
|
||||
對應 `CHUNK_RULE_2_VISUAL.md`,用於 YOLO/Face 幀聚合。
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS chunks_rule2 (
|
||||
-- 通用基礎
|
||||
id UUID PRIMARY KEY,
|
||||
asset_uuid UUID NOT NULL REFERENCES assets(id),
|
||||
chunk_type VARCHAR(20) DEFAULT 'Visual' NOT NULL, -- ⚠️ 設計值,未實現
|
||||
start_frame INT NOT NULL,
|
||||
end_frame INT NOT NULL,
|
||||
fps DOUBLE PRECISION NOT NULL,
|
||||
content TEXT NOT NULL, -- 物件標籤串 (e.g., "car, person")
|
||||
|
||||
-- 關聯元數據
|
||||
frame_objects JSONB, -- 原始 YOLO 物件陣列 (含 BBox, Confidence)
|
||||
face_ids JSONB, -- 區間內出現的 Face ID 陣列
|
||||
speaker_id VARCHAR(50), -- 當前說話者 (若無則為 Null)
|
||||
|
||||
-- 索引優化
|
||||
search_vector tsvector GENERATED ALWAYS AS (to_tsvector('simple', content)) STORED,
|
||||
embedding vector(768)
|
||||
);
|
||||
|
||||
-- 索引
|
||||
CREATE INDEX idx_r2_asset ON chunks_rule2(asset_uuid);
|
||||
CREATE INDEX idx_r2_objects ON chunks_rule2 USING gin(frame_objects);
|
||||
CREATE INDEX idx_r2_faces ON chunks_rule2 USING gin(face_ids);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Rule 3 結構:場景級 (Parent Scene)
|
||||
|
||||
對應 `CHUNK_RULE_3_SCENE.md`,作為 Parent Chunk,聚合多個 Rule 1/2。
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS chunks_rule3 (
|
||||
-- 通用基礎
|
||||
id UUID PRIMARY KEY,
|
||||
asset_uuid UUID NOT NULL REFERENCES assets(id),
|
||||
chunk_type VARCHAR(20) DEFAULT 'Cut' NOT NULL,
|
||||
start_frame INT NOT NULL,
|
||||
end_frame INT NOT NULL,
|
||||
fps DOUBLE PRECISION NOT NULL,
|
||||
content TEXT NOT NULL, -- 場景摘要 (Scene Summary)
|
||||
|
||||
-- 關聯元數據 (聚合自子 Chunk)
|
||||
faces JSONB, -- 場景內所有不重複 Face IDs
|
||||
speakers JSONB, -- 場景內所有不重複 Speaker IDs
|
||||
objects JSONB, -- 場景內重要物件統計
|
||||
|
||||
-- 索引優化
|
||||
search_vector tsvector GENERATED ALWAYS AS (to_tsvector('simple', content)) STORED,
|
||||
embedding vector(768)
|
||||
);
|
||||
|
||||
-- 索引
|
||||
CREATE INDEX idx_r3_asset ON chunks_rule3(asset_uuid);
|
||||
CREATE INDEX idx_r3_search ON chunks_rule3 USING gin(search_vector);
|
||||
CREATE INDEX idx_r3_faces ON chunks_rule3 USING gin(faces);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Rule 4 結構:敘事分析級 (Story 5W1H) ⚠️ 概念調整
|
||||
|
||||
**注意**: Rule 4 在實際代碼中實現為 `Story` 分片,而非設計中的 `summary`。
|
||||
|
||||
對應 `CHUNK_RULE_4_SUMMARY.md`,LLM 分析產出的頂層 Chunk。
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS chunks_rule4 (
|
||||
-- 通用基礎
|
||||
id UUID PRIMARY KEY,
|
||||
asset_uuid UUID NOT NULL REFERENCES assets(id),
|
||||
chunk_type VARCHAR(20) DEFAULT 'Story' NOT NULL, -- 🔄 實際實現值
|
||||
start_frame INT NOT NULL,
|
||||
end_frame INT NOT NULL,
|
||||
fps DOUBLE PRECISION NOT NULL,
|
||||
content TEXT NOT NULL, -- LLM 生成的流暢劇情摘要
|
||||
|
||||
-- 結構化分析
|
||||
analysis_5w1h JSONB NOT NULL, -- 完整的 5W1H JSON 結構
|
||||
rule3_chunk_ids UUID[], -- 組成此摘要的 Rule 3 ID 列表
|
||||
|
||||
-- 關聯元數據
|
||||
faces JSONB, -- 區塊內人物
|
||||
objects JSONB, -- 區塊內物件
|
||||
|
||||
-- 索引優化
|
||||
search_vector tsvector GENERATED ALWAYS AS (to_tsvector('simple', content)) STORED,
|
||||
embedding vector(768)
|
||||
);
|
||||
|
||||
-- 索引
|
||||
CREATE INDEX idx_r4_asset ON chunks_rule4(asset_uuid);
|
||||
CREATE INDEX idx_r4_5w1h_who ON chunks_rule4 USING gin((analysis_5w1h->'who'));
|
||||
CREATE INDEX idx_r4_5w1h_what ON chunks_rule4 USING gin((analysis_5w1h->'what'));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 父子關聯 (Parent-Child Mapping)
|
||||
|
||||
為了支援規則間的聚合(如 Rule 3 聚合 Rule 1/2),我們需要一個映射表或外鍵。
|
||||
|
||||
### 方案 A:子表增加 Parent 欄位 (推薦)
|
||||
|
||||
在 `chunks_rule1` 與 `chunks_rule2` 增加欄位指向 Rule 3 或 Rule 4。
|
||||
|
||||
```sql
|
||||
ALTER TABLE chunks_rule1 ADD COLUMN parent_rule3_id UUID REFERENCES chunks_rule3(id);
|
||||
ALTER TABLE chunks_rule2 ADD COLUMN parent_rule3_id UUID REFERENCES chunks_rule3(id);
|
||||
ALTER TABLE chunks_rule1 ADD COLUMN parent_rule4_id UUID REFERENCES chunks_rule4(id);
|
||||
ALTER TABLE chunks_rule2 ADD COLUMN parent_rule4_id UUID REFERENCES chunks_rule4(id);
|
||||
ALTER TABLE chunks_rule3 ADD COLUMN parent_rule4_id UUID REFERENCES chunks_rule4(id);
|
||||
```
|
||||
|
||||
### 方案 B:獨立映射表 (更靈活)
|
||||
|
||||
```sql
|
||||
CREATE TABLE chunk_relations (
|
||||
parent_id UUID NOT NULL,
|
||||
child_id UUID NOT NULL,
|
||||
relation_type VARCHAR(20), -- 'contains_sentence', 'contains_visual', 'aggregated_into_summary'
|
||||
PRIMARY KEY (parent_id, child_id)
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 時間換算函數 (Helper)
|
||||
|
||||
資料庫內建輔助函數,確保秒數計算的絕對一致性。
|
||||
|
||||
```sql
|
||||
CREATE OR REPLACE FUNCTION get_chunk_time(chunk_record ANYELEMENT)
|
||||
RETURNS TABLE(start_sec DOUBLE PRECISION, end_sec DOUBLE PRECISION) AS $$
|
||||
BEGIN
|
||||
RETURN QUERY SELECT
|
||||
chunk_record.start_frame::double precision / chunk_record.fps,
|
||||
chunk_record.end_frame::double precision / chunk_record.fps;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql IMMUTABLE;
|
||||
```
|
||||
|
||||
此設計確保了每一張表都完美對應 Chunking Architecture 的定義。
|
||||
398
docs_v1.0/CHUNKING/CORE/CHUNK_DATA_STRUCTURE.md
Normal file
398
docs_v1.0/CHUNKING/CORE/CHUNK_DATA_STRUCTURE.md
Normal file
@@ -0,0 +1,398 @@
|
||||
---
|
||||
document_type: "architecture_design"
|
||||
service: "MOMENTRY_CORE"
|
||||
title: "Momentry Chunk 資料結構說明"
|
||||
date: "2026-03-25"
|
||||
version: "V1.0"
|
||||
status: "active"
|
||||
owner: "Warren"
|
||||
created_by: "OpenCode"
|
||||
tags:
|
||||
- "momentry"
|
||||
- "chunk"
|
||||
- "資料結構說明"
|
||||
ai_query_hints:
|
||||
- "查詢 Momentry Chunk 資料結構說明 的內容"
|
||||
- "Momentry Chunk 資料結構說明 的主要目的是什麼?"
|
||||
- "如何操作或實施 Momentry Chunk 資料結構說明?"
|
||||
---
|
||||
|
||||
# Momentry Chunk 資料結構說明
|
||||
|
||||
> **對象**: marcom 團隊
|
||||
> **版本**: V1.0 | **日期**: 2026-03-25
|
||||
|
||||
---
|
||||
|
||||
## 1. 什麼是 Chunk?
|
||||
|
||||
Chunk(片段)是影片處理後的最小單位。當影片上傳後,系統會自動:
|
||||
|
||||
1. **分析** - 偵測場景、人臉、姿態
|
||||
2. **轉換** - 語音轉文字(ASR)
|
||||
3. **分段** - 將內容切割成可搜尋的片段
|
||||
4. **向量化** - 產生可搜尋的特徵向量
|
||||
|
||||
每個 Chunk 就是一個**可獨立搜尋的內容單位**。
|
||||
|
||||
---
|
||||
|
||||
## 2. Chunk 資料結構
|
||||
|
||||
### 2.1 主要欄位
|
||||
|
||||
| 欄位名 | 類型 | 說明 | 範例 |
|
||||
|--------|------|------|------|
|
||||
| `uuid` | 字串 (32) | 影片唯一識別碼 | `952f5854b9febad1` |
|
||||
| `chunk_id` | 字串 (64) | Chunk 唯一識別碼 | `asr_00001` |
|
||||
| `chunk_index` | 整數 | Chunk 順序號碼 | `1` |
|
||||
| `chunk_type` | 字串 (32) | Chunk 類型 | `sentence` |
|
||||
| `start_time` | 浮點數 | 開始時間(秒) | `12.5` |
|
||||
| `end_time` | 浮點數 | 結束時間(秒) | `18.3` |
|
||||
| `content` | JSONB | 詳細內容 | 見下方 |
|
||||
| `vector_id` | 字串 (64) | 向量 ID | `vec_12345` |
|
||||
| `text_content` | 文字 | 純文字內容 | `這是一段話` |
|
||||
| `fps` | 浮點數 | 影片幀率 | `24.0` |
|
||||
| `start_frame` | 整數 | 開始幀數 | `300` |
|
||||
| `end_frame` | 整數 | 結束幀數 | `439` |
|
||||
| `frame_count` | 整數 | 總幀數 | `139` |
|
||||
|
||||
### 2.2 Chunk 類型說明
|
||||
|
||||
| 類型 | ID | 說明 | 來源處理器 |
|
||||
|------|-----|------|-----------|
|
||||
| `sentence` | `sentence` | 語音轉文字片段 | ASR 處理 |
|
||||
| `time` | `time_based` | 固定時間分段 | 系統自動切割 |
|
||||
| `cut` | `cut` | 場景變化片段 | CUT 處理 |
|
||||
| `trace` | `trace` | 軌跡追蹤片段 | YOLO 追蹤處理 |
|
||||
| `story` | `story` | 故事線片段(父子區塊) | Story 分析處理 |
|
||||
|
||||
**父子區塊關係**:
|
||||
- `story` 是**父區塊**,可包含多個 `sentence`、`cut`、`trace` 子區塊
|
||||
- 透過 `parent_chunk_id` 和 `child_chunk_ids` 建立階層關係
|
||||
|
||||
---
|
||||
|
||||
## 3. Content JSON 結構
|
||||
|
||||
每個 Chunk 的 `content` 欄位包含詳細的處理結果:
|
||||
|
||||
### 3.1 ASR Chunk(語音轉文字)
|
||||
|
||||
```json
|
||||
{
|
||||
"text": "今天天氣非常好,我們去郊外踏青吧",
|
||||
"words": [
|
||||
{
|
||||
"word": "今天",
|
||||
"start": 12.5,
|
||||
"end": 12.8,
|
||||
"confidence": 0.95
|
||||
},
|
||||
{
|
||||
"word": "天氣",
|
||||
"start": 12.8,
|
||||
"end": 13.1,
|
||||
"confidence": 0.92
|
||||
}
|
||||
],
|
||||
"language": "zh-TW",
|
||||
"speaker": null
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 Cut Chunk(場景偵測)
|
||||
|
||||
```json
|
||||
{
|
||||
"scenes": [
|
||||
{
|
||||
"scene_id": "cut_001",
|
||||
"start_time": 12.5,
|
||||
"end_time": 45.2,
|
||||
"transition": "cut",
|
||||
"confidence": 0.98
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 Trace Chunk(軌跡追蹤)
|
||||
|
||||
```json
|
||||
{
|
||||
"track_id": "track_001",
|
||||
"object_class": "person",
|
||||
"frames": [
|
||||
{
|
||||
"frame": 300,
|
||||
"bbox": [120, 80, 200, 300],
|
||||
"confidence": 0.95
|
||||
},
|
||||
{
|
||||
"frame": 301,
|
||||
"bbox": [122, 82, 202, 302],
|
||||
"confidence": 0.94
|
||||
}
|
||||
],
|
||||
"total_frames": 180
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 Story Chunk(故事線)
|
||||
|
||||
```json
|
||||
{
|
||||
"story_id": "story_001",
|
||||
"title": "開場介紹",
|
||||
"summary": "主持人介紹節目主題",
|
||||
"child_chunk_ids": ["sentence_00001", "sentence_00002", "cut_00001"],
|
||||
"tags": ["intro", "host"]
|
||||
}
|
||||
```
|
||||
|
||||
### 3.5 Metadata(其他偵測資訊)
|
||||
|
||||
人臉(Face)、文字辨識(OCR)、姿態(Pose)等偵測結果會附加在 `metadata` 欄位:
|
||||
|
||||
```json
|
||||
{
|
||||
"metadata": {
|
||||
"faces": [
|
||||
{
|
||||
"bbox": [120, 80, 200, 180],
|
||||
"confidence": 0.87,
|
||||
"emotion": "neutral"
|
||||
}
|
||||
],
|
||||
"ocr": {
|
||||
"text": "MOMENTRY",
|
||||
"confidence": 0.96
|
||||
},
|
||||
"pose": {
|
||||
"keypoints": [
|
||||
{"name": "nose", "x": 192, "y": 85, "confidence": 0.95}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 時間格式說明
|
||||
|
||||
### 4.1 秒數格式(常用)
|
||||
|
||||
```
|
||||
格式: 秒.幀數
|
||||
範例: 1234.60 = 第 1234 秒 + 第 60 幀
|
||||
```
|
||||
|
||||
### 4.2 時間軸格式
|
||||
|
||||
```
|
||||
格式: HH:MM:SS.FF
|
||||
範例: 00:20:34.12 = 20分34秒12幀
|
||||
```
|
||||
|
||||
### 4.3 幀數計算
|
||||
|
||||
```
|
||||
幀數 = 秒數 × fps
|
||||
例如: 12.5秒 × 24fps = 300幀
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 實際資料範例
|
||||
|
||||
假設有一個影片,包含以下處理結果:
|
||||
|
||||
### 5.1 語音片段
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "952f5854b9febad1",
|
||||
"chunk_id": "asr_00001",
|
||||
"chunk_type": "sentence",
|
||||
"start_time": 12.5,
|
||||
"end_time": 18.3,
|
||||
"content": {
|
||||
"text": "今天天氣非常好,我們去郊外踏青吧",
|
||||
"language": "zh-TW"
|
||||
},
|
||||
"text_content": "今天天氣非常好,我們去郊外踏青吧",
|
||||
"start_frame": 300,
|
||||
"end_frame": 439,
|
||||
"fps": 24.0
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 場景片段
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "952f5854b9febad1",
|
||||
"chunk_id": "cut_00001",
|
||||
"chunk_type": "cut",
|
||||
"start_time": 45.0,
|
||||
"end_time": 120.5,
|
||||
"content": {
|
||||
"scenes": [{
|
||||
"scene_id": "cut_001",
|
||||
"transition": "cut",
|
||||
"confidence": 0.98
|
||||
}]
|
||||
},
|
||||
"start_frame": 1080,
|
||||
"end_frame": 2892,
|
||||
"fps": 24.0
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 如何使用 Chunk
|
||||
|
||||
### 6.1 API 取得 Chunk
|
||||
|
||||
使用搜尋 API 取得 Chunk:
|
||||
|
||||
```bash
|
||||
curl -X POST "https://api.momentry.ddns.net/api/v1/search" \
|
||||
-H "X-API-Key: YOUR_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"query": "關鍵字",
|
||||
"limit": 10
|
||||
}'
|
||||
```
|
||||
|
||||
**指定影片搜尋**:
|
||||
```bash
|
||||
curl -X POST "https://api.momentry.ddns.net/api/v1/search" \
|
||||
-H "X-API-Key: YOUR_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"query": "關鍵字",
|
||||
"uuid": "39567a0eb16f39fd",
|
||||
"limit": 5
|
||||
}'
|
||||
```
|
||||
|
||||
### 6.2 搜尋相關片段
|
||||
|
||||
當使用者搜尋「天氣」時,系統會:
|
||||
|
||||
1. 將「天氣」轉換為向量
|
||||
2. 在向量資料庫中搜尋相似向量
|
||||
3. 找到相關的 Chunk
|
||||
4. 返回時間軸和內容
|
||||
|
||||
### 6.3 播放指定片段
|
||||
|
||||
取得 Chunk 後可播放:
|
||||
|
||||
```
|
||||
開始時間: 12.5 秒
|
||||
結束時間: 18.3 秒
|
||||
影片 UUID: 39567a0eb16f39fd
|
||||
```
|
||||
|
||||
**播放器連結格式**:
|
||||
```
|
||||
/player?uuid={uuid}&start={start_time}&end={end_time}
|
||||
```
|
||||
|
||||
### 6.4 組合多個 Chunk
|
||||
|
||||
多個相關 Chunk 可以組合成一個章節或故事線。
|
||||
|
||||
### 6.5 Story Chunk(父子關係)
|
||||
|
||||
Story Chunk 可包含多個子 Chunk:
|
||||
|
||||
```json
|
||||
{
|
||||
"chunk_id": "story_001",
|
||||
"chunk_type": "story",
|
||||
"content": {
|
||||
"story_id": "story_001",
|
||||
"title": "開場介紹",
|
||||
"child_chunk_ids": ["sentence_00001", "sentence_00002", "cut_00001"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. API 回應格式
|
||||
|
||||
### /search 回應
|
||||
|
||||
```json
|
||||
{
|
||||
"results": [
|
||||
{
|
||||
"uuid": "39567a0eb16f39fd",
|
||||
"chunk_id": "sentence_1471",
|
||||
"chunk_type": "sentence",
|
||||
"start_time": 5309.08,
|
||||
"end_time": 5311.08,
|
||||
"text": "influenced by a vital way,",
|
||||
"score": 0.68
|
||||
}
|
||||
],
|
||||
"query": "關鍵字"
|
||||
}
|
||||
```
|
||||
|
||||
### /n8n/search 回應
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "關鍵字",
|
||||
"count": 1,
|
||||
"hits": [
|
||||
{
|
||||
"id": "sentence_1471",
|
||||
"vid": "39567a0eb16f39fd",
|
||||
"start": 5309.08,
|
||||
"end": 5311.08,
|
||||
"title": "Chunk sentence_1471",
|
||||
"text": "influenced by a vital way,",
|
||||
"score": 0.68,
|
||||
"file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/video.mp4"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
> **注意**: `file_path` 是影片的實際路徑,可用於本地播放。
|
||||
|
||||
---
|
||||
|
||||
## 8. 快速參考
|
||||
|
||||
| 項目 | 說明 |
|
||||
|------|------|
|
||||
| UUID | 影片唯一識別碼(16位 hex) |
|
||||
| Chunk ID | 片段識別碼(如 `sentence_00001`) |
|
||||
| chunk_type | 片段類型(sentence/time/cut/trace/story) |
|
||||
| start_time | 開始時間(秒) |
|
||||
| end_time | 結束時間(秒) |
|
||||
| text_content | 純文字內容 |
|
||||
| content | 詳細 JSON 結構 |
|
||||
| metadata | 人臉、OCR、姿態等偵測結果 |
|
||||
| parent_chunk_id | 父區塊 ID(用於 story 區塊) |
|
||||
| child_chunk_ids | 子區塊 ID 列表(story 區塊專用) | |
|
||||
|
||||
---
|
||||
|
||||
## 附錄:版本歷史
|
||||
|
||||
| 版本 | 日期 | 內容 | 操作人 |
|
||||
|------|------|------|--------|
|
||||
| V1.0 | 2026-03-25 | 初版建立 | OpenCode |
|
||||
| V1.1 | 2026-03-25 | 新增 API 取得 Chunk 方式、播放連結格式 | OpenCode |
|
||||
553
docs_v1.0/CHUNKING/CORE/CHUNK_DESIGN.md
Normal file
553
docs_v1.0/CHUNKING/CORE/CHUNK_DESIGN.md
Normal file
@@ -0,0 +1,553 @@
|
||||
---
|
||||
document_type: "architecture_design"
|
||||
service: "MOMENTRY_CORE"
|
||||
title: "Momentry Core 數據管理設計文檔 (v4)"
|
||||
date: "2026-03-17"
|
||||
version: "V1.0"
|
||||
status: "active"
|
||||
owner: "Warren"
|
||||
created_by: "OpenCode"
|
||||
tags:
|
||||
- "momentry"
|
||||
- "core"
|
||||
- "數據管理設計文檔"
|
||||
ai_query_hints:
|
||||
- "查詢 Momentry Core 數據管理設計文檔 (v4) 的內容"
|
||||
- "Momentry Core 數據管理設計文檔 (v4) 的主要目的是什麼?"
|
||||
- "如何操作或實施 Momentry Core 數據管理設計文檔 (v4)?"
|
||||
---
|
||||
|
||||
# Momentry Core 數據管理設計文檔 (v4)
|
||||
|
||||
| 項目 | 內容 |
|
||||
|------|------|
|
||||
| 建立者 | Warren |
|
||||
| 建立時間 | 2026-03-17 |
|
||||
| 文件版本 | V1.0 |
|
||||
|
||||
---
|
||||
|
||||
## 版本歷史
|
||||
|
||||
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|
||||
|------|------|------|--------|-----------|
|
||||
| V1.0 | 2026-03-17 | 創建文件 | Warren | OpenCode / MiniMax M2.5 |
|
||||
|
||||
---
|
||||
|
||||
## 0. 核心概念:雙 UUID 系統
|
||||
|
||||
為減少資料庫大小,在現有的 videos 表中增加內部 ID 映射:
|
||||
|
||||
### 0.1 設計原則
|
||||
|
||||
- **external_uuid**: 用戶可見的識別碼(如 UUID)
|
||||
- **id**: 資料庫自動產生的內部 ID (SERIAL),節省空間
|
||||
- **映射關係**: 透過 videos 表的 `id` 欄位關聯
|
||||
|
||||
### 0.2 videos 表 (檔案映射表)
|
||||
|
||||
現有結構,增加 `id` 作為內部 ID:
|
||||
|
||||
```sql
|
||||
-- 現有 videos 表結構
|
||||
CREATE TABLE videos (
|
||||
id SERIAL PRIMARY KEY, -- 內部 ID (自動產生)
|
||||
uuid VARCHAR(32) UNIQUE NOT NULL, -- 外部 UUID (用戶可見)
|
||||
file_name VARCHAR(255) NOT NULL,
|
||||
file_path TEXT,
|
||||
duration DOUBLE PRECISION,
|
||||
width INTEGER,
|
||||
height INTEGER,
|
||||
fps DOUBLE PRECISION,
|
||||
probe_json JSONB,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX idx_videos_uuid ON videos(uuid);
|
||||
```
|
||||
|
||||
### 0.3 對照的好處
|
||||
|
||||
| 方式 | 儲存空間 (1000個視頻,每個1000個chunk) |
|
||||
|------|---------------------------------------|
|
||||
| 直接用 uuid (32字元) | ~32MB |
|
||||
| 使用 id (4字元) | ~4MB |
|
||||
|
||||
## 1. 數據流架構
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ 輸入階段 │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ 視頻文件 │→ │ ffprobe │ │ ASR │ │ YOLO │ │
|
||||
│ │ (.mp4) │→ │ (probe) │→ │ (asr) │→ │ (yolo) │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ ASRX │ │ CUT │ │ OCR │ │ FACE │ │
|
||||
│ │ (asrx) │→ │ (cut) │→ │ (ocr) │→ │ (face) │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Pre-Chunk / Frame 階段 │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ pre_chunks 表 │ │
|
||||
│ │ file_id → videos.id (FK) │ │
|
||||
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
|
||||
│ │ │ type=sentence │ from asr, asrx │ 句子邊界範圍 │ │ │
|
||||
│ │ │ type=cut │ from cut detection │ 場景切換範圍 │ │ │
|
||||
│ │ │ type=time │ from time split │ 固定時間範圍 (10s) │ │ │
|
||||
│ │ │ type=trace │ from yolo trace │ 物件追蹤範圍 │ │ │
|
||||
│ │ └─────────────────────────────────────────────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ frames 表 │ │
|
||||
│ │ file_id → videos.id (FK) │ │
|
||||
│ │ - yolo 每幀識別結果 │ │
|
||||
│ │ - ocr 每幀識別結果 │ │
|
||||
│ │ - face 每幀識別結果 (如需要) │ │
|
||||
│ │ - 單一圖像識別結果 → 直接入 frame │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Chunk 階段 │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ chunks 表 │ │
|
||||
│ │ file_id → videos.id (FK) │ │
|
||||
│ │ │ │
|
||||
│ │ 組合規則1: pre_chunk → chunk (直接轉換) │ │
|
||||
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
|
||||
│ │ │ sentence_pre_chunk → sentence_chunk │ │ │
|
||||
│ │ │ cut_pre_chunk → cut_chunk │ │ │
|
||||
│ │ │ time_pre_chunk → time_chunk │ │ │
|
||||
│ │ │ trace_pre_chunk → trace_chunk │ │ │
|
||||
│ │ └─────────────────────────────────────────────────────────────┘ │ │
|
||||
│ │ │ │
|
||||
│ │ 組合規則2: pre_chunk + frame 內容 → chunk (集合內容) │ │
|
||||
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
|
||||
│ │ │ sentence_pre_chunk + 涵蓋範圍內的 frames → 豐富的 sentence_chunk │ │ │
|
||||
│ │ │ time_pre_chunk + 涵蓋範圍內的 frames → 豐富的 time_chunk │ │ │
|
||||
│ │ └─────────────────────────────────────────────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Vector 階段 │
|
||||
│ ┌──────────────────────┐ ┌──────────────────────┐ │
|
||||
│ │ PostgreSQL vectors │ │ Qdrant vectors │ │
|
||||
│ │ (chunk_vectors) │ │ (chunk_v3) │ │
|
||||
│ └──────────────────────┘ └──────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 2. Pre-Chunk 類型定義
|
||||
|
||||
### 2.1 Pre-Chunk 來源與類型對照表
|
||||
|
||||
| 來源類型 | source_type | 產出 Pre-Chunk Type | 說明 |
|
||||
|---------|-------------|---------------------|------|
|
||||
| ASR ( Whisper ) | asr | sentence | 句子邊界 |
|
||||
| ASRX ( with timestamps ) | asrx | sentence | 帶時間戳的句子 |
|
||||
| CUT (場景檢測) | cut | cut | 場景切換點 |
|
||||
| TIME (固定時間) | time | time | 每 10 秒 |
|
||||
| YOLO Trace | yolo_trace | trace | 物件追蹤軌跡 |
|
||||
| YOLO (單幀) | yolo | **→ frame** | 不入 pre_chunk |
|
||||
| OCR (單幀) | ocr | **→ frame** | 不入 pre_chunk |
|
||||
| FACE (單幀) | face | **→ frame** | 不入 pre_chunk |
|
||||
| PROBE | probe | metadata | 視頻元數據 |
|
||||
|
||||
### 2.2 Pre-Chunk Schema
|
||||
|
||||
```sql
|
||||
CREATE TABLE pre_chunks (
|
||||
id SERIAL PRIMARY KEY,
|
||||
|
||||
-- 檔案識別 (使用 videos 表的內部 ID 以節省空間)
|
||||
file_id INTEGER NOT NULL REFERENCES videos(id),
|
||||
|
||||
-- 來源識別
|
||||
source_type VARCHAR(32) NOT NULL, -- 'asr', 'asrx', 'cut', 'time', 'yolo_trace', 'probe'
|
||||
source_file TEXT, -- 原始 JSON 文件路徑
|
||||
|
||||
-- Chunk 類型
|
||||
chunk_type VARCHAR(32) NOT NULL, -- 'sentence' (ChunkType::Sentence), 'cut' (ChunkType::Cut), 'time' (ChunkType::TimeBased), 'trace' (ChunkType::Trace), 'story' (ChunkType::Story)
|
||||
|
||||
-- 時間範圍
|
||||
start_time DOUBLE PRECISION NOT NULL,
|
||||
end_time DOUBLE PRECISION NOT NULL,
|
||||
|
||||
-- Frame 範圍 (精確到 frame)
|
||||
start_frame INTEGER NOT NULL,
|
||||
end_frame INTEGER NOT NULL,
|
||||
|
||||
-- FPS (用於 frame 計算)
|
||||
fps DOUBLE PRECISION NOT NULL,
|
||||
|
||||
-- 原始 JSON 內容
|
||||
raw_json JSONB NOT NULL,
|
||||
|
||||
-- 解析後的文字內容 (如有)
|
||||
text_content TEXT,
|
||||
|
||||
-- 處理狀態
|
||||
processed BOOLEAN DEFAULT FALSE,
|
||||
chunk_id VARCHAR(64), -- 轉換後的 chunk_id
|
||||
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
UNIQUE(file_id, source_type, start_frame, end_frame)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_pre_chunks_file_id ON pre_chunks(file_id);
|
||||
CREATE INDEX idx_pre_chunks_type ON pre_chunks(file_id, chunk_type);
|
||||
CREATE INDEX idx_pre_chunks_time ON pre_chunks(file_id, start_time, end_time);
|
||||
CREATE INDEX idx_pre_chunks_frame ON pre_chunks(file_id, start_frame, end_frame);
|
||||
CREATE INDEX idx_pre_chunks_processed ON pre_chunks(file_id, processed);
|
||||
```
|
||||
|
||||
## 3. Frame 管理原則
|
||||
|
||||
### 3.1 哪些數據進入 Frame
|
||||
|
||||
只儲存**單一圖像識別**的結果:
|
||||
- YOLO 每幀檢測結果
|
||||
- OCR 每幀識別結果
|
||||
- FACE 每幀檢測結果
|
||||
|
||||
### 3.2 Frame Schema
|
||||
|
||||
```sql
|
||||
CREATE TABLE frames (
|
||||
id SERIAL PRIMARY KEY,
|
||||
|
||||
-- 檔案識別 (使用 videos 表的內部 ID 以節省空間)
|
||||
file_id INTEGER NOT NULL REFERENCES videos(id),
|
||||
|
||||
frame_number INTEGER NOT NULL,
|
||||
timestamp DOUBLE PRECISION NOT NULL,
|
||||
fps DOUBLE PRECISION NOT NULL,
|
||||
|
||||
-- YOLO 結果 (JSONB 陣列)
|
||||
yolo_objects JSONB,
|
||||
|
||||
-- OCR 結果 (JSONB 陣列)
|
||||
ocr_results JSONB,
|
||||
|
||||
-- Face 結果 (JSONB 陣列)
|
||||
face_results JSONB,
|
||||
|
||||
-- 原始幀圖像路徑 (可選)
|
||||
frame_path TEXT,
|
||||
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
UNIQUE(file_id, frame_number)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_frames_file_id ON frames(file_id);
|
||||
CREATE INDEX idx_frames_frame ON frames(file_id, frame_number);
|
||||
CREATE INDEX idx_frames_timestamp ON frames(file_id, timestamp);
|
||||
```
|
||||
|
||||
## 4. Chunk 組合規則
|
||||
|
||||
### 4.1 組合規則 1: 直接轉換 (rule_1)
|
||||
|
||||
將 pre_chunk 直接轉換為 chunk:
|
||||
|
||||
```
|
||||
sentence_pre_chunk → sentence_chunk (rule: "rule_1")
|
||||
cut_pre_chunk → cut_chunk (rule: "rule_1")
|
||||
time_pre_chunk → time_chunk (rule: "rule_1")
|
||||
trace_pre_chunk → trace_chunk (rule: "rule_1")
|
||||
```
|
||||
|
||||
### 4.2 組合規則 2: 集合內容 (rule_2)
|
||||
|
||||
將 pre_chunk 與其時間區間內的所有 frame 識別結果集合:
|
||||
|
||||
```
|
||||
sentence_pre_chunk + frames[在 start_time~end_time 範圍內] → 豐富的 sentence_chunk (rule: "rule_2")
|
||||
time_pre_chunk + frames[在 start_time~end_time 範圍內] → 豐富的 time_chunk (rule: "rule_2")
|
||||
```
|
||||
|
||||
### 4.3 Chunk Schema
|
||||
|
||||
```sql
|
||||
CREATE TABLE chunks (
|
||||
id SERIAL PRIMARY KEY,
|
||||
|
||||
-- 檔案識別 (使用 videos 表的內部 ID 以節省空間)
|
||||
file_id INTEGER NOT NULL REFERENCES videos(id),
|
||||
|
||||
chunk_id VARCHAR(64) NOT NULL,
|
||||
chunk_index INTEGER NOT NULL,
|
||||
chunk_type VARCHAR(32) NOT NULL, -- 'sentence' (ChunkType::Sentence), 'cut' (ChunkType::Cut), 'time' (ChunkType::TimeBased), 'trace' (ChunkType::Trace)
|
||||
|
||||
-- 組合規則 (payload 中記錄)
|
||||
-- rule: 'rule_1' = 直接轉換, 'rule_2' = 集合內容
|
||||
|
||||
-- 時間範圍
|
||||
start_time DOUBLE PRECISION NOT NULL,
|
||||
end_time DOUBLE PRECISION NOT NULL,
|
||||
|
||||
-- Frame 範圍 (精確到 frame)
|
||||
start_frame INTEGER NOT NULL,
|
||||
end_frame INTEGER NOT NULL,
|
||||
|
||||
-- FPS
|
||||
fps DOUBLE PRECISION NOT NULL,
|
||||
|
||||
-- 主要內容
|
||||
text_content TEXT,
|
||||
|
||||
-- 完整內容 (JSONB) - 包含 rule 欄位
|
||||
content JSONB NOT NULL,
|
||||
|
||||
-- 來源的 pre_chunk IDs
|
||||
pre_chunk_ids INTEGER[],
|
||||
|
||||
-- 包含的 frame 數量
|
||||
frame_count INTEGER DEFAULT 0,
|
||||
|
||||
-- 向量 ID
|
||||
vector_id VARCHAR(64),
|
||||
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
UNIQUE(file_id, chunk_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_chunks_file_id ON chunks(file_id);
|
||||
CREATE INDEX idx_chunks_type ON chunks(file_id, chunk_type);
|
||||
CREATE INDEX idx_chunks_time ON chunks(file_id, start_time, end_time);
|
||||
CREATE INDEX idx_chunks_frame ON chunks(file_id, start_frame, end_frame);
|
||||
CREATE INDEX idx_chunks_vector ON chunks(vector_id);
|
||||
```
|
||||
|
||||
## 5. 處理流程範例
|
||||
|
||||
### 5.1 輸入數據
|
||||
|
||||
假設視頻長度 30 秒,fps=30:
|
||||
|
||||
| 來源 | 產出 |
|
||||
|------|------|
|
||||
| ASR | 3 個 sentence_pre_chunk (每句約 10s) |
|
||||
| CUT | 2 個 cut_pre_chunk (場景 1, 場景 2) |
|
||||
| TIME | 3 個 time_pre_chunk (0-10s, 10-20s, 20-30s) |
|
||||
| YOLO | 900 個 frame 記錄 (每幀) |
|
||||
| OCR | 依實際識別結果入 frame |
|
||||
|
||||
### 5.2 Chunk 產出
|
||||
|
||||
**使用規則 1 (直接轉換):**
|
||||
- rule: "rule_1"
|
||||
- 3 個 sentence_chunk
|
||||
- 2 個 cut_chunk
|
||||
- 3 個 time_chunk
|
||||
|
||||
**使用規則 2 (集合內容):**
|
||||
- rule: "rule_2"
|
||||
- 3 個 sentence_chunk (各含涵蓋時間範圍內的 yolo/ocr 結果)
|
||||
- 3 個 time_chunk (各含涵蓋時間範圍內的 yolo/ocr 結果)
|
||||
|
||||
## 8. 數據示例
|
||||
|
||||
### 8.1 videos 表 (檔案映射)
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"uuid": "abc123def456",
|
||||
"file_name": "video_001.mp4",
|
||||
"file_path": "/path/to/video_001.mp4",
|
||||
"duration": 300.5,
|
||||
"width": 1920,
|
||||
"height": 1080,
|
||||
"fps": 30.0
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 pre_chunks 表 (使用 file_id 關聯 videos)
|
||||
|
||||
```json
|
||||
{
|
||||
"file_id": 1,
|
||||
"source_type": "asr",
|
||||
"chunk_type": "sentence",
|
||||
"start_time": 0.0,
|
||||
"end_time": 5.5,
|
||||
"start_frame": 0,
|
||||
"end_frame": 165,
|
||||
"fps": 30.0,
|
||||
"raw_json": {...},
|
||||
"text_content": "This is the first sentence"
|
||||
}
|
||||
```
|
||||
|
||||
### 8.3 frames 表 (使用 file_id 關聯 videos)
|
||||
|
||||
```json
|
||||
{
|
||||
"file_id": 1,
|
||||
"frame_number": 300,
|
||||
"timestamp": 10.0,
|
||||
"fps": 30.0,
|
||||
"yolo_objects": [
|
||||
{"class": "person", "confidence": 0.9, "bbox": [100, 50, 200, 150]},
|
||||
{"class": "car", "confidence": 0.85, "bbox": [50, 100, 150, 180]}
|
||||
],
|
||||
"ocr_results": [],
|
||||
"face_results": []
|
||||
}
|
||||
```
|
||||
|
||||
### 8.4 chunks 表 (使用 file_id 關聯 videos)
|
||||
|
||||
```json
|
||||
{
|
||||
"file_id": 1,
|
||||
"chunk_id": "sentence_0001",
|
||||
"chunk_type": "sentence",
|
||||
"rule": "rule_2",
|
||||
"start_time": 10.0,
|
||||
"end_time": 15.5,
|
||||
"start_frame": 300,
|
||||
"end_frame": 465,
|
||||
"fps": 30.0,
|
||||
"text_content": "The second sentence from the audio",
|
||||
"content": {
|
||||
"rule": "rule_2",
|
||||
"asr_text": "The second sentence from the audio",
|
||||
"objects": [
|
||||
{"class": "person", "first_frame": 300, "last_frame": 450, "appears_in_frames": [300, 310, 320, ...]},
|
||||
{"class": "car", "first_frame": 350, "last_frame": 465, "appears_in_frames": [350, 360, ...]}
|
||||
],
|
||||
"ocr": [...],
|
||||
"faces": [...]
|
||||
},
|
||||
"pre_chunk_ids": [5],
|
||||
"frame_count": 301
|
||||
}
|
||||
```
|
||||
|
||||
### 8.5 chunk_vectors 表 (使用 file_id 關聯 videos)
|
||||
|
||||
```json
|
||||
{
|
||||
"file_id": 1,
|
||||
"chunk_id": "sentence_0001",
|
||||
"chunk_type": "sentence",
|
||||
"start_time": 10.0,
|
||||
"end_time": 15.5,
|
||||
"embedding": "[0.1, 0.2, ...]",
|
||||
"metadata": {"text": "The second sentence..."}
|
||||
}
|
||||
```
|
||||
|
||||
### 8.6 Qdrant Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"file_uuid": "abc123def456",
|
||||
"chunk_id": "sentence_0001",
|
||||
"chunk_type": "sentence",
|
||||
"start_time": 10.0,
|
||||
"end_time": 15.5,
|
||||
"text": "The second sentence from the audio"
|
||||
}
|
||||
```
|
||||
|
||||
## 7. 向量管理原則
|
||||
|
||||
### 7.1 Vector Schema
|
||||
|
||||
```sql
|
||||
-- Chunk 向量表 (PostgreSQL)
|
||||
CREATE TABLE chunk_vectors (
|
||||
id SERIAL PRIMARY KEY,
|
||||
|
||||
-- 檔案識別 (使用 videos 表的內部 ID 以節省空間)
|
||||
file_id INTEGER NOT NULL REFERENCES videos(id),
|
||||
|
||||
chunk_id VARCHAR(64) NOT NULL,
|
||||
chunk_type VARCHAR(32) NOT NULL,
|
||||
|
||||
-- 向量數據
|
||||
embedding TEXT, -- JSON 格式的向量
|
||||
embedding_vector VECTOR(768), -- pgvector 類型 (如可用)
|
||||
|
||||
-- 時間範圍 (用於時間查詢)
|
||||
start_time DOUBLE PRECISION,
|
||||
end_time DOUBLE PRECISION,
|
||||
|
||||
-- Metadata
|
||||
metadata JSONB,
|
||||
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
UNIQUE(chunk_id)
|
||||
);
|
||||
|
||||
-- 索引
|
||||
CREATE INDEX idx_chunk_vectors_file_id ON chunk_vectors(file_id);
|
||||
```
|
||||
|
||||
### 7.2 Qdrant Collection
|
||||
|
||||
- Collection 名稱: `chunks_v3`
|
||||
- Vector 維度: 768 (nomic-embed-text)
|
||||
- Payload 包含: `file_uuid`, `chunk_id`, `chunk_type`, `start_time`, `end_time`, `text`
|
||||
|
||||
> **注意**: Qdrant 中仍使用 uuid (字串),因為需要可讀性和跨系統整合。PostgreSQL 內部使用 videos.id (整數) 以節省空間。
|
||||
|
||||
## 9. 設計原則總結
|
||||
|
||||
1. **單一圖像識別 → Frame**: yolo, ocr, face 等單幀識別結果直接入 frame 表
|
||||
2. **時間序列識別 → Pre-Chunk**: asr, asrx, cut, time, trace 等有時間範圍的結果入 pre_chunk 表
|
||||
3. **組合規則 1 (直接)**: pre_chunk → chunk (保持原有邊界)
|
||||
4. **組合規則 2 (集合)**: pre_chunk + frames → chunk (加入識別內容)
|
||||
5. **精確到 Frame**: 所有時間範圍都記錄 start_frame, end_frame
|
||||
6. **雙向量存儲**: 同時支持 PostgreSQL 和 Qdrant
|
||||
7. **跨視頻搜索**: 透過 videos 表的 uuid 進行搜索,內部使用 id 節省空間
|
||||
8. **空間優化**: 內部表使用 videos.id (4 bytes) 而非 uuid (32 bytes)
|
||||
|
||||
## 10. 查詢範例
|
||||
|
||||
### 10.1 跨視頻搜索所有 chunk
|
||||
|
||||
```sql
|
||||
-- 搜索所有視頻中包含 "hello" 的 chunk
|
||||
SELECT c.*, v.uuid, v.file_name
|
||||
FROM chunks c
|
||||
JOIN videos v ON c.file_id = v.id
|
||||
WHERE c.text_content ILIKE '%hello%';
|
||||
```
|
||||
|
||||
### 10.2 查詢特定視頻的 chunk
|
||||
|
||||
```sql
|
||||
-- 查詢 uuid 為 'abc123' 的視頻的所有 chunk
|
||||
SELECT c.*
|
||||
FROM chunks c
|
||||
JOIN videos v ON c.file_id = v.id
|
||||
WHERE v.uuid = 'abc123';
|
||||
```
|
||||
|
||||
### 10.3 按時間範圍搜索
|
||||
|
||||
```sql
|
||||
-- 搜索所有視頻在 10-20 秒範圍內的 chunk
|
||||
SELECT c.*, v.uuid
|
||||
FROM chunks c
|
||||
JOIN videos v ON c.file_id = v.id
|
||||
WHERE c.start_time >= 10.0 AND c.end_time <= 20.0;
|
||||
```
|
||||
185
docs_v1.0/CHUNKING/CORE/CHUNK_RULES_SPEC.md
Normal file
185
docs_v1.0/CHUNKING/CORE/CHUNK_RULES_SPEC.md
Normal file
@@ -0,0 +1,185 @@
|
||||
---
|
||||
document_type: "reference_doc"
|
||||
service: "MOMENTRY_CORE"
|
||||
title: "Unknown"
|
||||
date: "2026-03-28"
|
||||
version: "V1.0"
|
||||
status: "active"
|
||||
owner: "Warren"
|
||||
created_by: "OpenCode"
|
||||
tags:
|
||||
- "unknown"
|
||||
ai_query_hints:
|
||||
- "查詢 Unknown 的內容"
|
||||
- "Unknown 的主要目的是什麼?"
|
||||
- "如何操作或實施 Unknown?"
|
||||
---
|
||||
|
||||
---
|
||||
title: Chunk Rules 規範總覽
|
||||
description: Momentry Core Chunk 組合規則規範與 Collection 對應
|
||||
version: 1.0
|
||||
created: 2026-03-28
|
||||
updated: 2026-03-28
|
||||
service: MOMENTRY_CORE
|
||||
topic: chunk_rules
|
||||
document_type: spec
|
||||
ai_agent_friendly: true
|
||||
---
|
||||
|
||||
# Chunk Rules 規範總覽
|
||||
|
||||
| 項目 | 內容 |
|
||||
|------|------|
|
||||
| 建立者 | OpenCode |
|
||||
| 建立時間 | 2026-03-28 |
|
||||
| 文件版本 | V1.0 |
|
||||
|
||||
---
|
||||
|
||||
## 版本歷史
|
||||
|
||||
| 版本 | 日期 | 目的 | 操作人 |
|
||||
|------|------|------|--------|
|
||||
| V1.0 | 2026-03-28 | 創建 Chunk Rules 規範總覽 | OpenCode |
|
||||
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
本文檔定義 Momentry Core 系統中 Chunk 向量入庫的組合規則。每個規則對應一個獨立的 Qdrant Collection。
|
||||
|
||||
---
|
||||
|
||||
## 規則總覽
|
||||
|
||||
| Rule | 名稱 | 說明 | Collection | 嵌入模型 |
|
||||
|------|------|------|------------|----------|
|
||||
| **Rule 1** | Simple | 直接轉換,無父子關係,無 frame objects | `momentry_rule1` | `nomic-embed-text-v2-moe:latest` |
|
||||
| **Rule 2** | Frame Objects | 涵蓋 frames,conf > 0.8 的物件加入字串 | `momentry_rule2` | `nomic-embed-text-v2-moe:latest` |
|
||||
| **Rule 3** | Composite | 父子關係 + frame_objects | `momentry_rule3` | `nomic-embed-text-v2-moe:latest` |
|
||||
|
||||
---
|
||||
|
||||
## Collection 對應
|
||||
|
||||
### 命名規範
|
||||
|
||||
```
|
||||
momentry_rule{rule_id}
|
||||
```
|
||||
|
||||
### Collection 列表
|
||||
|
||||
| Collection | Rule | 向量維度 | Distance | 嵌入模型 | 多語言支持 |
|
||||
|------------|------|----------|----------|----------|------------|
|
||||
| `momentry_rule1` | Rule 1 | 768 | Cosine | `nomic-embed-text-v2-moe:latest` | ✅ |
|
||||
| `momentry_rule2` | Rule 2 | 768 | Cosine | `nomic-embed-text-v2-moe:latest` | ✅ |
|
||||
| `momentry_rule3` | Rule 3 | 768 | Cosine | `nomic-embed-text-v2-moe:latest` | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## Payload 欄位說明
|
||||
|
||||
### 共同欄位
|
||||
|
||||
| 欄位 | 類型 | 說明 |
|
||||
|------|------|------|
|
||||
| `uuid` | String | 影片 UUID |
|
||||
| `chunk_id` | String | Chunk 唯一 ID |
|
||||
| `chunk_type` | String | 類型:sentence/cut/time_based |
|
||||
| `chunk_index` | u32 | Chunk 索引 |
|
||||
| `start_frame` | i64 | 開始幀編號 |
|
||||
| `end_frame` | i64 | 結束幀編號 |
|
||||
| `fps` | f64 | 幀率 |
|
||||
| `original_text` | String | 產生 vector 的原始文字 (ASR) |
|
||||
|
||||
### Rule 2+ 專有欄位
|
||||
|
||||
| 欄位 | 類型 | 說明 |
|
||||
|------|------|------|
|
||||
| `frame_objects` | String | 涵蓋 frames 的物件描述 (conf > 0.8) |
|
||||
|
||||
### Rule 3 專有欄位
|
||||
|
||||
| 欄位 | 類型 | 說明 |
|
||||
|------|------|------|
|
||||
| `parent_chunk_id` | Option<String> | 父 Chunk ID |
|
||||
| `child_chunk_ids` | Vec<String> | 子 Chunk IDs |
|
||||
|
||||
---
|
||||
|
||||
## Payload 對照表
|
||||
|
||||
| 欄位 | Rule 1 | Rule 2 | Rule 3 |
|
||||
|------|--------|--------|--------|
|
||||
| uuid | ✅ | ✅ | ✅ |
|
||||
| chunk_id | ✅ | ✅ | ✅ |
|
||||
| chunk_type | ✅ | ✅ | ✅ |
|
||||
| chunk_index | ✅ | ✅ | ✅ |
|
||||
| start_frame | ✅ | ✅ | ✅ |
|
||||
| end_frame | ✅ | ✅ | ✅ |
|
||||
| fps | ✅ | ✅ | ✅ |
|
||||
| original_text | ✅ | ✅ | ✅ |
|
||||
| frame_objects | - | ✅ | ✅ |
|
||||
| parent_chunk_id | - | - | ✅ |
|
||||
| child_chunk_ids | - | - | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## 時間計算
|
||||
|
||||
### Frame 轉時間
|
||||
|
||||
```
|
||||
start_time = start_frame / fps
|
||||
end_time = end_frame / fps
|
||||
```
|
||||
|
||||
### 範例
|
||||
|
||||
```
|
||||
- fps = 24.0
|
||||
- start_frame = 252
|
||||
- end_frame = 378
|
||||
- start_time = 252 / 24.0 = 10.5 秒
|
||||
- end_time = 378 / 24.0 = 15.75 秒
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 選擇標準
|
||||
|
||||
### Rule 1 (Simple)
|
||||
|
||||
- 用途:最基本的向量搜尋
|
||||
- 場景:僅需要 ASR 文字內容進行語義搜尋
|
||||
- 優點:資料量最小,搜尋速度最快
|
||||
|
||||
### Rule 2 (Frame Objects)
|
||||
|
||||
- 用途:需要物體識別結果輔助搜尋
|
||||
- 場景:需要根據影片中的物件(人、車、動物)進行搜尋
|
||||
- 優點:結合 ASR + 物件辨識結果
|
||||
|
||||
### Rule 3 (Composite)
|
||||
|
||||
- 用途:需要父子層級關係和完整資訊
|
||||
- 場景:需要跨層級搜尋、父子關係分析
|
||||
- 優點:最完整的資訊,但資料量最大
|
||||
|
||||
---
|
||||
|
||||
## 相關文件
|
||||
|
||||
| 文件 | 用途 |
|
||||
|------|------|
|
||||
| CHUNK_RULE_1_SIMPLE.md | Rule 1 詳細規範 |
|
||||
| CHUNK_RULE_2_FRAME_OBJECTS.md | Rule 2 詳細規範 |
|
||||
| CHUNK_RULE_3_COMPOSITE.md | Rule 3 詳細規範 |
|
||||
| CHUNK_SPEC.md | Chunk 基礎規範 |
|
||||
| CHUNK_DESIGN.md | Chunk 設計架構 |
|
||||
|
||||
---
|
||||
|
||||
**文件結束**
|
||||
1132
docs_v1.0/CHUNKING/CORE/CHUNK_SPEC.md
Normal file
1132
docs_v1.0/CHUNKING/CORE/CHUNK_SPEC.md
Normal file
File diff suppressed because it is too large
Load Diff
337
docs_v1.0/CHUNKING/RULES/SCENE_BASED/CHUNK_RULE_3_COMPOSITE.md
Normal file
337
docs_v1.0/CHUNKING/RULES/SCENE_BASED/CHUNK_RULE_3_COMPOSITE.md
Normal file
@@ -0,0 +1,337 @@
|
||||
---
|
||||
document_type: "reference_doc"
|
||||
service: "MOMENTRY_CORE"
|
||||
title: "Unknown"
|
||||
date: "2026-03-28"
|
||||
version: "V1.0"
|
||||
status: "active"
|
||||
owner: "Warren"
|
||||
created_by: "OpenCode"
|
||||
tags:
|
||||
- "unknown"
|
||||
ai_query_hints:
|
||||
- "查詢 Unknown 的內容"
|
||||
- "Unknown 的主要目的是什麼?"
|
||||
- "如何操作或實施 Unknown?"
|
||||
---
|
||||
|
||||
---
|
||||
title: Chunk Rule 3 - Composite
|
||||
description: 父子關係 + frame_objects
|
||||
version: 1.0
|
||||
created: 2026-03-28
|
||||
updated: 2026-03-28
|
||||
service: MOMENTRY_CORE
|
||||
topic: chunk_rule
|
||||
document_type: spec
|
||||
rule_id: 3
|
||||
rule_name: Composite
|
||||
collection: momentry_rule3
|
||||
confidence_threshold: 0.8
|
||||
ai_agent_friendly: true
|
||||
---
|
||||
|
||||
# Chunk Rule 3 - Composite
|
||||
|
||||
| 項目 | 內容 |
|
||||
|------|------|
|
||||
| 建立者 | OpenCode |
|
||||
| 建立時間 | 2026-03-28 |
|
||||
| 文件版本 | V1.0 |
|
||||
| Rule ID | 3 |
|
||||
| Rule 名稱 | Composite |
|
||||
| Collection | `momentry_rule3` |
|
||||
| Confidence Threshold | > 0.8 |
|
||||
|
||||
---
|
||||
|
||||
## 版本歷史
|
||||
|
||||
| 版本 | 日期 | 目的 | 操作人 |
|
||||
|------|------|------|--------|
|
||||
| V1.0 | 2026-03-28 | 創建 Rule 3 規範 | OpenCode |
|
||||
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
Rule 3 (Composite) 是最完整的 Chunk 向量入庫規則。包含父子層級關係、frame_objects,以及所有可用資訊。
|
||||
|
||||
---
|
||||
|
||||
## 設計原則
|
||||
|
||||
### 輸入
|
||||
|
||||
- pre_chunk(來自 ASR/Cut/TimeBased 的原始分段)
|
||||
- frames(chunk 時間範圍內的所有 frames)
|
||||
- parent_chunk / child_chunks(層級關係)
|
||||
|
||||
### 處理
|
||||
|
||||
1. 同 Rule 2:收集 frame_objects (conf > 0.8)
|
||||
2. 建立父子層級關係
|
||||
3. 存入完整資訊
|
||||
|
||||
### 輸出
|
||||
|
||||
- chunk + frame_objects + parent_chunk_id + child_chunk_ids
|
||||
|
||||
---
|
||||
|
||||
## Collection 定義
|
||||
|
||||
### 建立 Collection
|
||||
|
||||
```bash
|
||||
curl -X PUT "http://localhost:6333/collections/momentry_rule3" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "api-key: <API_KEY>" \
|
||||
-d '{
|
||||
"vectors": {
|
||||
"size": 768,
|
||||
"distance": "Cosine"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
### Collection 參數
|
||||
|
||||
| 參數 | 值 |
|
||||
|------|-----|
|
||||
| Name | `momentry_rule3` |
|
||||
| Vector Size | 768 |
|
||||
| Distance | Cosine |
|
||||
| HNSW | m=16, ef_construct=100 |
|
||||
|
||||
---
|
||||
|
||||
## Payload 結構
|
||||
|
||||
### 欄位定義
|
||||
|
||||
| 欄位 | 類型 | 必填 | 說明 |
|
||||
|------|------|------|------|
|
||||
| `uuid` | String | ✅ | 影片 UUID (16 字元) |
|
||||
| `chunk_id` | String | ✅ | Chunk 唯一 ID |
|
||||
| `chunk_type` | String | ✅ | 類型:sentence/cut/time_based |
|
||||
| `chunk_index` | u32 | ✅ | Chunk 索引 (從 0 開始) |
|
||||
| `start_frame` | i64 | ✅ | 開始幀編號 |
|
||||
| `end_frame` | i64 | ✅ | 結束幀編號 |
|
||||
| `fps` | f64 | ✅ | 幀率 |
|
||||
| `original_text` | String | ✅ | 產生 vector 的原始文字 (ASR) |
|
||||
| `frame_objects` | String | ✅ | 涵蓋 frames 的物件描述 (conf > 0.8) |
|
||||
| `parent_chunk_id` | Option<String> | - | 父 Chunk ID |
|
||||
| `child_chunk_ids` | Vec<String> | - | 子 Chunk IDs |
|
||||
|
||||
### JSON 範例
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "1636719dc31f78ac",
|
||||
"chunk_id": "sentence_parent_0001",
|
||||
"chunk_type": "sentence",
|
||||
"chunk_index": 1,
|
||||
"start_frame": 0,
|
||||
"end_frame": 2400,
|
||||
"fps": 24.0,
|
||||
"original_text": "Chapter 1: Introduction to the topic",
|
||||
"frame_objects": "person:5, car:2, building:3",
|
||||
"parent_chunk_id": null,
|
||||
"child_chunk_ids": ["sentence_0001", "sentence_0002", "sentence_0003"]
|
||||
}
|
||||
```
|
||||
|
||||
### Rust 結構
|
||||
|
||||
```rust
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VectorPayloadRule3 {
|
||||
pub uuid: String,
|
||||
pub chunk_id: String,
|
||||
pub chunk_type: String,
|
||||
pub chunk_index: u32,
|
||||
pub start_frame: i64,
|
||||
pub end_frame: i64,
|
||||
pub fps: f64,
|
||||
pub original_text: String,
|
||||
pub frame_objects: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub parent_chunk_id: Option<String>,
|
||||
pub child_chunk_ids: Vec<String>,
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 父子層級關係
|
||||
|
||||
### 層級結構
|
||||
|
||||
```
|
||||
Parent Chunk (Story/Caption)
|
||||
|
|
||||
+-- Child Chunk 1 (sentence/cut/time_based)
|
||||
|
|
||||
+-- Child Chunk 2 (sentence/cut/time_based)
|
||||
|
|
||||
+-- Child Chunk 3 (sentence/cut/time_based)
|
||||
```
|
||||
|
||||
### chunk_id 命名規範
|
||||
|
||||
| 類型 | chunk_id 格式 | 範例 |
|
||||
|------|--------------|------|
|
||||
| Parent | `story_XXXX` | `story_0001` |
|
||||
| Parent | `caption_XXXX` | `caption_0001` |
|
||||
| Child | `sentence_XXXX` | `sentence_0001` |
|
||||
| Child | `cut_XXXX` | `cut_0001` |
|
||||
| Child | `time_based_XXXX` | `time_based_0001` |
|
||||
|
||||
### 範例
|
||||
|
||||
```json
|
||||
{
|
||||
"chunk_id": "story_0001",
|
||||
"chunk_type": "story",
|
||||
"parent_chunk_id": null,
|
||||
"child_chunk_ids": ["sentence_0001", "sentence_0002", "sentence_0003"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## frame_objects 生成規則
|
||||
|
||||
(同 Rule 2,請參閱 CHUNK_RULE_2_FRAME_OBJECTS.md)
|
||||
|
||||
### 處理邏輯
|
||||
|
||||
1. 找出 chunk 時間範圍內的所有 frames
|
||||
2. 收集每個 frame 的物件識別結果(YOLO/Face/Pose)
|
||||
3. 過濾 confidence > 0.8 的物件
|
||||
4. 聚合物件名稱和數量
|
||||
|
||||
### 輸出字串
|
||||
|
||||
```
|
||||
"person:3, car:1, dog:2"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 時間計算
|
||||
|
||||
### Frame 轉時間
|
||||
|
||||
```
|
||||
start_time = start_frame / fps
|
||||
end_time = end_frame / fps
|
||||
```
|
||||
|
||||
### 範例
|
||||
|
||||
```
|
||||
- fps = 24.0
|
||||
- start_frame = 0
|
||||
- end_frame = 2400
|
||||
- start_time = 0 / 24.0 = 0 秒
|
||||
- end_time = 2400 / 24.0 = 100 秒
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 搜尋範例
|
||||
|
||||
### 語義搜尋(完整資訊)
|
||||
|
||||
```rust
|
||||
let query_vector = embed_text("找出有人在開車的相關場景").await?;
|
||||
let results = qdrant.search(
|
||||
"momentry_rule3",
|
||||
&query_vector,
|
||||
10,
|
||||
None
|
||||
).await?;
|
||||
```
|
||||
|
||||
### 父子層級搜尋
|
||||
|
||||
```bash
|
||||
# 搜尋 parent chunk 並取得所有 child chunks
|
||||
curl -X POST "http://localhost:6333/collections/momentry_rule3/points/search" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "api-key: <API_KEY>" \
|
||||
-d '{
|
||||
"vector": [0.123, -0.456, ...],
|
||||
"limit": 10,
|
||||
"with_payload": true,
|
||||
"filter": {
|
||||
"must": [
|
||||
{"key": "chunk_type", "match": {"value": "story"}}
|
||||
]
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
### 根據 Child Chunk 找 Parent
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:6333/collections/momentry_rule3/points/search" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "api-key: <API_KEY>" \
|
||||
-d '{
|
||||
"vector": [0.123, -0.456, ...],
|
||||
"limit": 10,
|
||||
"with_payload": true,
|
||||
"filter": {
|
||||
"must": [
|
||||
{"key": "child_chunk_ids", "match": {"value": "sentence_0001"}}
|
||||
]
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 使用場景
|
||||
|
||||
| 場景 | 適用 |
|
||||
|------|------|
|
||||
| 需要父子層級關係搜尋 | ✅ 最佳 |
|
||||
| 需要完整資訊(ASR + 物件 + 層級) | ✅ 最佳 |
|
||||
| 跨層級分析 | ✅ 最佳 |
|
||||
| 僅 ASR 搜尋 | ❌ 請用 Rule 1 |
|
||||
| 僅需物件輔助搜尋 | ❌ 請用 Rule 2 |
|
||||
|
||||
---
|
||||
|
||||
## 優點與限制
|
||||
|
||||
### 優點
|
||||
|
||||
- 最完整的資訊
|
||||
- 支援父子層級搜尋
|
||||
- 可進行跨層級分析
|
||||
|
||||
### 限制
|
||||
|
||||
- 資料量最大
|
||||
- 搜尋速度相對較慢
|
||||
- 實作複雜度最高
|
||||
|
||||
---
|
||||
|
||||
## 相關文件
|
||||
|
||||
| 文件 | 用途 |
|
||||
|------|------|
|
||||
| CHUNK_RULES_SPEC.md | 規則總覽 |
|
||||
| CHUNK_RULE_1_SIMPLE.md | Rule 1 規範 |
|
||||
| CHUNK_RULE_2_FRAME_OBJECTS.md | Rule 2 規範 |
|
||||
| CHUNK_SPEC.md | Chunk 基礎規範 |
|
||||
| CHUNK_DESIGN.md | Chunk 設計架構 |
|
||||
|
||||
---
|
||||
|
||||
**文件結束**
|
||||
215
docs_v1.0/CHUNKING/RULES/SCENE_BASED/CHUNK_RULE_3_SCENE.md
Normal file
215
docs_v1.0/CHUNKING/RULES/SCENE_BASED/CHUNK_RULE_3_SCENE.md
Normal file
@@ -0,0 +1,215 @@
|
||||
---
|
||||
document_type: "architecture_design"
|
||||
service: "MOMENTRY_CORE"
|
||||
title: "Momentry Core Chunk Rule 3: 場景聚合級檢索 (Scene Composite 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 3: 場景聚合級檢索 (Scene Composite Chunk) (v1.0) 的內容"
|
||||
- "Momentry Core Chunk Rule 3: 場景聚合級檢索 (Scene Composite Chunk) (v1.0) 的主要目的是什麼?"
|
||||
- "如何操作或實施 Momentry Core Chunk Rule 3: 場景聚合級檢索 (Scene Composite Chunk) (v1.0)?"
|
||||
---
|
||||
|
||||
# Momentry Core Chunk Rule 3: 場景聚合級檢索 (Scene Composite Chunk) (v1.0)
|
||||
|
||||
| 項目 | 內容 |
|
||||
|------|------|
|
||||
| 建立者 | OpenCode |
|
||||
| 建立時間 | 2026-04-21 |
|
||||
| 文件版本 | V1.0 |
|
||||
|
||||
---
|
||||
|
||||
## 版本歷史
|
||||
|
||||
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|
||||
|------|------|------|--------|-----------|
|
||||
| V1.0 | 2026-04-21 | 定義 Rule 3: 基於 Cut 點的場景級父子聚合結構 | OpenCode | OpenCode / Qwen3.6-Plus |
|
||||
|
||||
---
|
||||
|
||||
## 0. 設計目標
|
||||
|
||||
**Rule 3** 的核心概念是**「場景理解」(Scene Understanding)**。利用 **Cut Processor** 偵測到的鏡頭切換點,將影片劃分為語意完整的場景區塊,並聚合內部的所有句子與視覺資訊。
|
||||
|
||||
- **核心原則**: 一個鏡頭/場景 (Cut) = 一個 Parent Chunk。
|
||||
- **結構**: 採用 **Parent-Child (父子)** 架構。
|
||||
- **Parent (Rule 3)**: 代表整個場景,包含摘要 (Summary) 與聚合向量。
|
||||
- **Children (Rule 1/2)**: 場景內包含的具體句子與視覺幀。
|
||||
- **優勢**: 支援跨句子的長語境搜尋 (例如搜尋整個情節的摘要,而非單一單詞)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 數據源與聚合邏輯
|
||||
|
||||
Rule 3 不直接從原始影片產生,而是依賴 **Rule 1** 與 **Rule 2** 的產出。
|
||||
|
||||
1. **Cut Processor (Primary)**: 提供場景的邊界。
|
||||
- *定義*: `start_frame`, `end_frame` 為一個完整鏡頭。
|
||||
2. **Rule 1 Chunks (Children)**: 收集該場景內所有的 ASR 語句 (Sentences)。
|
||||
3. **Rule 2 Chunks (Children)**: 收集該場景內所有的視覺幀數據 (Visual Frames)。
|
||||
4. **Summary Generation**:
|
||||
- 為了讓 Parent Chunk 具備搜尋能力,系統會將所有子 Chunk 的內容 (ASR 文本 + 物件標籤) 組合成一段「場景描述」,並由 LLM (選用) 或規則生成一段 **Summary**。
|
||||
|
||||
---
|
||||
|
||||
## 2. Chunk 結構定義
|
||||
|
||||
### 2.1 資料庫結構 (PostgreSQL)
|
||||
|
||||
採用 **Parent-Child** 設計,Rule 3 為 Parent,Rule 1/2 透過 `parent_id` 指向 Rule 3。
|
||||
|
||||
```sql
|
||||
-- Parent Table (Rule 3: Scenes)
|
||||
CREATE TABLE parent_chunks (
|
||||
id UUID PRIMARY KEY,
|
||||
asset_uuid UUID NOT NULL,
|
||||
chunk_type VARCHAR(20) DEFAULT 'scene',
|
||||
|
||||
-- 時間軸 (幀為權威)
|
||||
start_frame INT NOT NULL,
|
||||
end_frame INT NOT NULL,
|
||||
start_time_sec DOUBLE PRECISION,
|
||||
end_time_sec DOUBLE PRECISION,
|
||||
|
||||
-- 場景內容 (用於向量索引)
|
||||
summary TEXT NOT NULL, -- 場景摘要 (由內部 ASR 聚合而成)
|
||||
|
||||
-- 元數據聚合
|
||||
faces JSONB, -- 場景內所有出現過的人物 ID
|
||||
speakers JSONB, -- 場景內所有出現過的說話者 ID
|
||||
objects JSONB, -- 場景內出現過的高信心物件
|
||||
|
||||
-- 向量索引
|
||||
embedding vector(768), -- 摘要的向量
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Child Tables (Rule 1/2) 增加 parent_id
|
||||
-- (需對 chunks_rule1 與 chunks_rule2 執行 ALTER TABLE 增加欄位)
|
||||
ALTER TABLE chunks_rule1 ADD COLUMN parent_id UUID REFERENCES parent_chunks(id);
|
||||
ALTER TABLE chunks_rule2 ADD COLUMN parent_id UUID REFERENCES parent_chunks(id);
|
||||
```
|
||||
|
||||
### 2.2 JSON 產出範例 (嵌套結構)
|
||||
|
||||
Rule 3 的 API 返回應包含聚合後的子項目。
|
||||
|
||||
```json
|
||||
{
|
||||
"chunk_id": "550e...0003",
|
||||
"type": "scene",
|
||||
"summary": "Peter Joshua 和 Regina 在車上討論關於金錢的危機。畫面顯示兩人在車內,背景為夜間街道。",
|
||||
"start_frame": 1000,
|
||||
"end_frame": 1500,
|
||||
"children": [
|
||||
{
|
||||
"type": "sentence",
|
||||
"content": "我們必須在那之前找到那筆錢。",
|
||||
"speaker": "SPEAKER_00",
|
||||
"start_frame": 1100,
|
||||
"end_frame": 1200
|
||||
},
|
||||
{
|
||||
"type": "visual_frame",
|
||||
"content": "car, person, night, street",
|
||||
"frame_objects": [ ... ]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"faces": ["cary_grant", "audrey_hepburn"],
|
||||
"speakers": ["SPEAKER_00", "SPEAKER_01"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 搜尋能力定義
|
||||
|
||||
Rule 3 專為**宏觀理解**與**摘要檢索**設計。
|
||||
|
||||
### 3.1 場景摘要搜尋 (Summary Search)
|
||||
* **場景**: "尋找他們討論分贓的場景" (可能包含多句對話)。
|
||||
* **邏輯**:
|
||||
1. Query: "Discussion about splitting the money".
|
||||
2. Match: 搜尋 `parent_chunks.summary` 的向量。
|
||||
3. 結果:直接返回整個場景 (Parent),而非零碎的句子。
|
||||
|
||||
### 3.2 混合檢索 (Hybrid Retrieval)
|
||||
* **場景**: 使用者搜尋 "槍戰"。
|
||||
* **策略**:
|
||||
1. **Hit**: Rule 2 (Visual) 命中 (偵測到 "gun")。
|
||||
2. **Expand**: 系統自動向上查找該 Rule 2 所屬的 Rule 3 Parent。
|
||||
3. **Return**: 返回該場面的完整上下文 (包含槍戰前後的對話)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 處理流程 (Aggregation Pipeline)
|
||||
|
||||
Rule 3 是在 Rule 1 與 Rule 2 完成後執行的「後處理」步驟。
|
||||
|
||||
### 4.1 演算法邏輯 (Pseudocode)
|
||||
|
||||
```python
|
||||
# 輸入: cuts (List of boundaries), rule1_chunks, rule2_chunks
|
||||
|
||||
for cut in cuts:
|
||||
scene_start = cut.start_frame
|
||||
scene_end = cut.end_frame
|
||||
|
||||
# 1. 收集子元素 (Children)
|
||||
children_sentences = get_children_in_range(scene_start, scene_end, rule1_chunks)
|
||||
children_visuals = get_children_in_range(scene_start, scene_end, rule2_chunks)
|
||||
|
||||
# 2. 聚合元數據
|
||||
scene_faces = aggregate_unique_ids(children_sentences, "face_ids")
|
||||
scene_faces.update(aggregate_unique_ids(children_visuals, "face_ids"))
|
||||
|
||||
scene_speakers = aggregate_unique_ids(children_sentences, "speaker_id")
|
||||
|
||||
# 3. 生成 Summary
|
||||
# 組合所有 ASR 文本
|
||||
full_text = " ".join([c.content for c in children_sentences])
|
||||
# 組合所有視覺標籤
|
||||
visual_context = ", ".join(get_top_objects(children_visuals))
|
||||
|
||||
summary = f"[Scene] {full_text}. Visuals: {visual_context}."
|
||||
|
||||
# 4. 建立 Parent Chunk
|
||||
parent = {
|
||||
"start_frame": scene_start,
|
||||
"end_frame": scene_end,
|
||||
"summary": summary,
|
||||
"faces": list(scene_faces),
|
||||
"speakers": list(scene_speakers)
|
||||
}
|
||||
|
||||
# 5. 儲存 Parent,並將子元素關聯到此 Parent ID
|
||||
parent_id = store_parent_chunk(parent)
|
||||
link_children_to_parent(children_sentences + children_visuals, parent_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 總結
|
||||
|
||||
Rule 3 是 Momentry 檢索架構的**頂層視角**。
|
||||
|
||||
| 特性 | 實作方式 |
|
||||
|------|----------|
|
||||
| **粒度** | 場景/鏡頭 (Scene/Cut) |
|
||||
| **資料來源** | Rule 1 (Text) + Rule 2 (Visual) |
|
||||
| **核心內容** | 場景摘要 (Summary) + 聚合元數據 |
|
||||
| **向量內容** | 僅對 Summary 進行 Embedding,確保向量代表宏觀語意 |
|
||||
| **適用場景** | 尋找特定情節、理解長段落上下文、場景過濾 |
|
||||
|
||||
透過 Rule 1/2/3 的三層架構,系統能同時滿足**微觀精確檢索** (Rule 1) 與 **宏觀場景理解** (Rule 3) 的需求。
|
||||
202
docs_v1.0/CHUNKING/RULES/TEXT_BASED/CHUNK_RULE_1_SENTENCE.md
Normal file
202
docs_v1.0/CHUNKING/RULES/TEXT_BASED/CHUNK_RULE_1_SENTENCE.md
Normal file
@@ -0,0 +1,202 @@
|
||||
---
|
||||
document_type: "architecture_design"
|
||||
service: "MOMENTRY_CORE"
|
||||
title: "Momentry Core Chunk Rule 1: 句子級檢索 (Sentence Chunk) (v1.0)"
|
||||
date: "2026-04-21"
|
||||
version: "V1.0"
|
||||
status: "active"
|
||||
owner: "Warren"
|
||||
created_by: "OpenCode"
|
||||
tags:
|
||||
- "momentry"
|
||||
- "core"
|
||||
- "句子級檢索"
|
||||
- "rule"
|
||||
ai_query_hints:
|
||||
- "查詢 Momentry Core Chunk Rule 1: 句子級檢索 (Sentence Chunk) (v1.0) 的內容"
|
||||
- "Momentry Core Chunk Rule 1: 句子級檢索 (Sentence Chunk) (v1.0) 的主要目的是什麼?"
|
||||
- "如何操作或實施 Momentry Core Chunk Rule 1: 句子級檢索 (Sentence Chunk) (v1.0)?"
|
||||
---
|
||||
|
||||
# Momentry Core Chunk Rule 1: 句子級檢索 (Sentence Chunk) (v1.0)
|
||||
|
||||
| 項目 | 內容 |
|
||||
|------|------|
|
||||
| 建立者 | OpenCode |
|
||||
| 建立時間 | 2026-04-21 |
|
||||
| 文件版本 | V1.0 |
|
||||
|
||||
---
|
||||
|
||||
## 版本歷史
|
||||
|
||||
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|
||||
|------|------|------|--------|-----------|
|
||||
| V1.0 | 2026-04-21 | 定義 Rule 1: 單一語句為 Chunk 的數據結構與搜尋邏輯 | OpenCode | OpenCode / Qwen3.6-Plus |
|
||||
|
||||
---
|
||||
|
||||
## 0. 設計目標
|
||||
|
||||
**Rule 1** 的核心概念是**「原子化語義」**。將影片內容切分到「一句話」的粒度,以便進行最高精度的語意搜尋與元數據過濾。
|
||||
|
||||
- **核心原則**: One Sentence = One Chunk。
|
||||
- **時間權威**: 基於 `frame_number` (由 `ffprobe` 定義的 FPS 計算)。
|
||||
- **多模態關聯**: 每個句子 Chunk 必須攜帶該時間區間內的 **Speaker (說話者)** 與 **Faces (出現人物)** 資訊。
|
||||
|
||||
---
|
||||
|
||||
## 1. 數據源與聚合邏輯
|
||||
|
||||
Rule 1 的生成依賴三個上游處理器的產出:
|
||||
|
||||
1. **ASR (Primary)**: 提供文本內容 (`text`)、起始時間 (`start_time`)、結束時間 (`end_time`)。
|
||||
2. **ASRX (Speaker)**: 提供說話者 ID (`speaker_id`)。
|
||||
- *聚合策略*: 使用 ASR 的時間區間去對齊 ASRX,取該區間內**佔比最高**的 `speaker_id`。
|
||||
3. **Face (Visual)**: 提供幀級別的人物 ID (`face_id`)。
|
||||
- *聚合策略*: 在 ASR 的 `[start_frame, end_frame]` 區間內,收集所有出現的 `face_id`。若同一 ID 出現多次,去重後形成 `face_ids` 陣列。
|
||||
|
||||
---
|
||||
|
||||
## 2. Chunk 結構定義
|
||||
|
||||
### 2.1 資料庫結構 (PostgreSQL)
|
||||
|
||||
```sql
|
||||
CREATE TABLE chunks_rule1 (
|
||||
id UUID PRIMARY KEY,
|
||||
asset_uuid UUID NOT NULL, -- 關聯 assets 表
|
||||
chunk_type VARCHAR(20) DEFAULT 'sentence', -- 對應 ChunkType::Sentence
|
||||
|
||||
-- 時間軸 (幀為權威)
|
||||
start_frame INT NOT NULL,
|
||||
end_frame INT NOT NULL,
|
||||
start_time_sec DOUBLE PRECISION, -- 參考值: start_frame / fps
|
||||
end_time_sec DOUBLE PRECISION, -- 參考值: end_frame / fps
|
||||
fps DOUBLE PRECISION NOT NULL,
|
||||
|
||||
-- 核心內容
|
||||
content TEXT NOT NULL, -- ASR 識別出的文字
|
||||
|
||||
-- 關聯元數據 (Metadata)
|
||||
speaker_id VARCHAR(50), -- ASRX 產出
|
||||
face_ids JSONB, -- Face 產出,例如 ["face_01", "face_02"]
|
||||
|
||||
-- 向量與索引
|
||||
embedding vector(768), -- nomic-embed-text-v2-moe
|
||||
search_vector tsvector, -- PostgreSQL BM25
|
||||
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
```
|
||||
|
||||
### 2.2 JSON 產出範例 (供前端 API 返回)
|
||||
|
||||
當 API 搜尋 Rule 1 時,返回結構如下:
|
||||
|
||||
```json
|
||||
{
|
||||
"chunk_id": "550e...0001",
|
||||
"type": "sentence",
|
||||
"content": "這是一個關於尋找真相的故事。",
|
||||
"start_frame": 1200,
|
||||
"end_frame": 1250,
|
||||
"start_time_sec": 40.04,
|
||||
"end_time_sec": 41.71,
|
||||
"metadata": {
|
||||
"speaker": "SPEAKER_00",
|
||||
"faces": [
|
||||
{ "face_id": "person_a", "confidence": 0.98 }
|
||||
]
|
||||
},
|
||||
"highlight": "這是一個關於<span class='highlight'>尋找真相</span>的故事。"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 搜尋能力定義
|
||||
|
||||
Rule 1 支援三種主要搜尋模式:
|
||||
|
||||
### 3.1 語意搜尋 (Vector Search)
|
||||
* **場景**: "有人提到錢嗎?" (即使影片沒說 "錢",而是說 "鈔票" 也能搜到)。
|
||||
* **邏輯**:
|
||||
1. 將 Query 透過 Ollama (`nomic-v2-moe`) 轉為 768-dim 向量。
|
||||
2. 在 Qdrant (`collection: momentry_rule1`) 中進行 Cosine 相似度比對。
|
||||
3. **Filter**: 可加入 `metadata.speaker == "SPEAKER_00"`。
|
||||
|
||||
### 3.2 關鍵字搜尋 (BM25 Search)
|
||||
* **場景**: "搜尋確切字串 'Charade 1963'"。
|
||||
* **邏輯**:
|
||||
1. 使用 PostgreSQL `tsvector` 進行全文檢索。
|
||||
2. 適合精確匹配專有名詞。
|
||||
|
||||
### 3.3 過濾搜尋 (Faceted Search)
|
||||
* **場景**: "找出 **Audrey Hepburn (Face)** 說話的所有片段"。
|
||||
* **邏輯**:
|
||||
1. `face_ids` 包含 "Audrey Hepburn" 的 ID。
|
||||
2. `speaker_id` 不為空 (代表她在說話)。
|
||||
3. 檢索符合條件的 Chunks。
|
||||
|
||||
---
|
||||
|
||||
## 4. 處理流程 (Processing Pipeline)
|
||||
|
||||
### 4.1 聚合演算法 (Pseudocode)
|
||||
|
||||
```python
|
||||
# 輸入: asr_segments (List), asrx_segments (List), face_frames (List)
|
||||
# 常數: FPS (來自 ffprobe)
|
||||
|
||||
for seg in asr_segments:
|
||||
# 1. 確定時間範圍 (Frames)
|
||||
start_f = int(seg.start_time * FPS)
|
||||
end_f = int(seg.end_time * FPS)
|
||||
|
||||
# 2. 匹配 Speaker (取重疊時間最長的)
|
||||
speaker = find_majority_speaker(start_f, end_f, asrx_segments)
|
||||
|
||||
# 3. 聚合 Faces (收集區間內出現過的所有唯一 ID)
|
||||
faces = get_unique_faces(start_f, end_f, face_frames)
|
||||
|
||||
# 4. 建立 Chunk
|
||||
chunk = {
|
||||
"content": seg.text,
|
||||
"start_frame": start_f,
|
||||
"end_frame": end_f,
|
||||
"speaker_id": speaker,
|
||||
"face_ids": faces
|
||||
}
|
||||
|
||||
# 5. 寫入 DB
|
||||
store_chunk_rule1(chunk)
|
||||
```
|
||||
|
||||
### 4.2 時間邊界處理
|
||||
|
||||
若 ASR 的 `end_time` 與 ASRX 的 `start_time` 有微小誤差 (例如 0.05s),系統應容忍 **±2 frames** 的誤差範圍進行匹配。
|
||||
|
||||
---
|
||||
|
||||
## 5. 向量嵌入策略
|
||||
|
||||
* **嵌入模型**: `nomic-embed-text-v2-moe` (768-dim)。
|
||||
* **嵌入內容**: 僅使用 `content` (句子文字)。
|
||||
* *原因*: 避免 speaker 或 face 的 metadata 干擾語意向量空間,確保語意純淨。Metadata 僅用於過濾 (Filter)。
|
||||
|
||||
---
|
||||
|
||||
## 6. 總結
|
||||
|
||||
Rule 1 提供了**最細緻**的影片理解層級。
|
||||
|
||||
| 特性 | 實作方式 |
|
||||
|------|----------|
|
||||
| **粒度** | 句子 (Sentence) |
|
||||
| **時間精度** | Frame 級別 (由 FPS 換算) |
|
||||
| **人物標記** | 自動關聯 Face ID (Visual) |
|
||||
| **說話者標記** | 自動關聯 Speaker ID (Audio) |
|
||||
| **適用場景** | 尋找特定台詞、某人說了什麼、特定鏡頭對話 |
|
||||
|
||||
此規範確保了所有 Rule 1 Chunk 在進入資料庫前,都已經完成了多模態數據的融合 (Audio + Visual + Text)。
|
||||
378
docs_v1.0/CHUNKING/RULES/TEXT_BASED/CHUNK_RULE_1_SIMPLE.md
Normal file
378
docs_v1.0/CHUNKING/RULES/TEXT_BASED/CHUNK_RULE_1_SIMPLE.md
Normal file
@@ -0,0 +1,378 @@
|
||||
---
|
||||
document_type: "reference_doc"
|
||||
service: "MOMENTRY_CORE"
|
||||
title: "Unknown"
|
||||
date: "2026-03-28"
|
||||
version: "V1.0"
|
||||
status: "active"
|
||||
owner: "Warren"
|
||||
created_by: "OpenCode"
|
||||
tags:
|
||||
- "unknown"
|
||||
ai_query_hints:
|
||||
- "查詢 Unknown 的內容"
|
||||
- "Unknown 的主要目的是什麼?"
|
||||
- "如何操作或實施 Unknown?"
|
||||
---
|
||||
|
||||
---
|
||||
title: Chunk Rule 1 - Simple
|
||||
description: 直接轉換,無父子關係,無 frame objects
|
||||
version: 1.0
|
||||
created: 2026-03-28
|
||||
updated: 2026-03-28
|
||||
service: MOMENTRY_CORE
|
||||
topic: chunk_rule
|
||||
document_type: spec
|
||||
rule_id: 1
|
||||
rule_name: Simple
|
||||
collection: momentry_rule1
|
||||
ai_agent_friendly: true
|
||||
---
|
||||
|
||||
# Chunk Rule 1 - Simple
|
||||
|
||||
| 項目 | 內容 |
|
||||
|------|------|
|
||||
| 建立者 | OpenCode |
|
||||
| 建立時間 | 2026-03-28 |
|
||||
| 文件版本 | V1.0 |
|
||||
| Rule ID | 1 |
|
||||
| Rule 名稱 | Simple |
|
||||
| Collection | `momentry_rule1` |
|
||||
|
||||
---
|
||||
|
||||
## 版本歷史
|
||||
|
||||
| 版本 | 日期 | 目的 | 操作人 |
|
||||
|------|------|------|--------|
|
||||
| V1.0 | 2026-03-28 | 創建 Rule 1 規範 | OpenCode |
|
||||
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
Rule 1 (Simple) 是最基本的 Chunk 向量入庫規則。直接將 pre_chunk 轉換為 chunk,不包含父子關係和 frame objects。
|
||||
|
||||
---
|
||||
|
||||
## 設計原則
|
||||
|
||||
### 輸入
|
||||
|
||||
- pre_chunk(來自 ASR/Cut/TimeBased 的原始分段)
|
||||
|
||||
### 處理
|
||||
|
||||
- 直接轉換,無額外處理
|
||||
|
||||
### 輸出
|
||||
|
||||
- chunk(與 pre_chunk 邊界相同)
|
||||
|
||||
---
|
||||
|
||||
## Collection 定義
|
||||
|
||||
### 建立 Collection
|
||||
|
||||
```bash
|
||||
curl -X PUT "http://localhost:6333/collections/momentry_rule1" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "api-key: <API_KEY>" \
|
||||
-d '{
|
||||
"vectors": {
|
||||
"size": 768,
|
||||
"distance": "Cosine"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
### Collection 參數
|
||||
|
||||
| 參數 | 值 |
|
||||
|------|-----|
|
||||
| Name | `momentry_rule1` |
|
||||
| Vector Size | 768 |
|
||||
| Distance | Cosine |
|
||||
| HNSW | m=16, ef_construct=100 |
|
||||
|
||||
---
|
||||
|
||||
## 嵌入模型
|
||||
|
||||
### 專用模型
|
||||
Rule 1 專用 **`nomic-embed-text-v2-moe:latest`** 嵌入模型,提供完整多語言支持:
|
||||
|
||||
#### 模型特性
|
||||
| 特性 | 說明 |
|
||||
|------|------|
|
||||
| **模型名稱** | `nomic-embed-text-v2-moe:latest` |
|
||||
| **模型類型** | Mixture of Experts (MoE) 架構 |
|
||||
| **向量維度** | 768 維 |
|
||||
| **多語言支持** | ✅ 完整支持(英語、中文、日語、韓語等) |
|
||||
| **模型大小** | 475.29 MB |
|
||||
| **推理速度** | 快速,適合實時應用 |
|
||||
|
||||
#### 模型優勢
|
||||
1. **完整多語言能力**: 原生支持多語言文本嵌入,無需語言檢測
|
||||
2. **高效能架構**: MoE 架構提供高效推理
|
||||
3. **統一向量空間**: 所有語言共享相同的 768 維向量空間
|
||||
4. **Ollama 集成**: 通過標準 Ollama API 直接調用
|
||||
|
||||
### 模型配置
|
||||
```rust
|
||||
// Rust 代碼中使用
|
||||
let embedder = Embedder::new("nomic-embed-text-v2-moe:latest".to_string());
|
||||
let vector = embedder.embed_text("搜索文本").await?;
|
||||
```
|
||||
|
||||
```bash
|
||||
# 直接調用 Ollama API
|
||||
curl -X POST "http://localhost:11434/api/embeddings" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"model": "nomic-embed-text-v2-moe:latest",
|
||||
"prompt": "需要嵌入的文本內容"
|
||||
}'
|
||||
```
|
||||
|
||||
### 多語言示例
|
||||
```rust
|
||||
// 英語文本
|
||||
let english_vector = embedder.embed_text("Hello world, this is a test").await?;
|
||||
|
||||
// 中文文本
|
||||
let chinese_vector = embedder.embed_text("你好世界,這是一個測試").await?;
|
||||
|
||||
// 日語文本
|
||||
let japanese_vector = embedder.embed_text("こんにちは世界、これはテストです").await?;
|
||||
|
||||
// 韓語文本
|
||||
let korean_vector = embedder.embed_text("안녕하세요 세계, 이것은 테스트입니다").await?;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Payload 結構
|
||||
|
||||
### 欄位定義
|
||||
|
||||
| 欄位 | 類型 | 必填 | 說明 |
|
||||
|------|------|------|------|
|
||||
| `uuid` | String | ✅ | 影片 UUID (16 字元) |
|
||||
| `chunk_id` | String | ✅ | Chunk 唯一 ID |
|
||||
| `chunk_type` | String | ✅ | 類型:sentence/cut/time_based |
|
||||
| `chunk_index` | u32 | ✅ | Chunk 索引 (從 0 開始) |
|
||||
| `start_frame` | i64 | ✅ | 開始幀編號 |
|
||||
| `end_frame` | i64 | ✅ | 結束幀編號 |
|
||||
| `fps` | f64 | ✅ | 幀率 |
|
||||
| `original_text` | String | ✅ | 產生 vector 的原始文字 (ASR) |
|
||||
|
||||
### JSON 範例
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "1636719dc31f78ac",
|
||||
"chunk_id": "sentence_0001",
|
||||
"chunk_type": "sentence",
|
||||
"chunk_index": 1,
|
||||
"start_frame": 252,
|
||||
"end_frame": 378,
|
||||
"fps": 24.0,
|
||||
"original_text": "Hello world, this is a test message"
|
||||
}
|
||||
```
|
||||
|
||||
### Rust 結構
|
||||
|
||||
```rust
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VectorPayloadRule1 {
|
||||
pub uuid: String,
|
||||
pub chunk_id: String,
|
||||
pub chunk_type: String,
|
||||
pub chunk_index: u32,
|
||||
pub start_frame: i64,
|
||||
pub end_frame: i64,
|
||||
pub fps: f64,
|
||||
pub original_text: String,
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 時間計算
|
||||
|
||||
### Frame 轉時間
|
||||
|
||||
```
|
||||
start_time = start_frame / fps
|
||||
end_time = end_frame / fps
|
||||
```
|
||||
|
||||
### 範例
|
||||
|
||||
```
|
||||
- fps = 24.0
|
||||
- start_frame = 252
|
||||
- end_frame = 378
|
||||
- start_time = 252 / 24.0 = 10.5 秒
|
||||
- end_time = 378 / 24.0 = 15.75 秒
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 搜尋範例
|
||||
|
||||
### 語義搜尋(使用 nomic-embed-text-v2-moe:latest)
|
||||
|
||||
```rust
|
||||
use crate::core::embedding::comic_embed::Embedder;
|
||||
|
||||
// 1. 初始化嵌入器
|
||||
let embedder = Embedder::new("nomic-embed-text-v2-moe:latest".to_string());
|
||||
|
||||
// 2. 生成查詢向量(支持多語言)
|
||||
let query_text = "找出有人在說話的片段"; // 中文查詢
|
||||
// let query_text = "Find segments where someone is speaking"; // 英文查詢
|
||||
// let query_text = "誰かが話しているセグメントを見つける"; // 日文查詢
|
||||
|
||||
let query_vector = embedder.embed_query(query_text).await?;
|
||||
|
||||
// 3. 在 Qdrant 中搜索
|
||||
let results = qdrant.search(
|
||||
"momentry_rule1",
|
||||
&query_vector,
|
||||
10,
|
||||
None
|
||||
).await?;
|
||||
|
||||
// 4. 處理結果
|
||||
for result in results {
|
||||
println!("Score: {}, Chunk ID: {}", result.score, result.payload["chunk_id"]);
|
||||
}
|
||||
```
|
||||
|
||||
### 批量嵌入示例
|
||||
|
||||
```rust
|
||||
// 批量嵌入多語言文本
|
||||
let texts = vec![
|
||||
"Hello world, this is English text",
|
||||
"你好世界,這是中文文本",
|
||||
"こんにちは世界、これは日本語のテキストです",
|
||||
"안녕하세요 세계, 이것은 한국어 텍스트입니다"
|
||||
];
|
||||
|
||||
let mut vectors = Vec::new();
|
||||
for text in texts {
|
||||
let vector = embedder.embed_document(text).await?;
|
||||
vectors.push(vector);
|
||||
}
|
||||
|
||||
// 批量存入 Qdrant
|
||||
for (i, vector) in vectors.iter().enumerate() {
|
||||
qdrant.upsert(
|
||||
"momentry_rule1",
|
||||
i as u64,
|
||||
vector,
|
||||
Some(json!({
|
||||
"uuid": "test_uuid",
|
||||
"chunk_id": format!("test_{}", i),
|
||||
"chunk_type": "sentence",
|
||||
"chunk_index": i as u32,
|
||||
"original_text": texts[i]
|
||||
}))
|
||||
).await?;
|
||||
}
|
||||
```
|
||||
|
||||
### 依賴 Qdrant Filter
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:6333/collections/momentry_rule1/points/search" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "api-key: <API_KEY>" \
|
||||
-d '{
|
||||
"vector": [0.123, -0.456, ...],
|
||||
"limit": 10,
|
||||
"with_payload": true,
|
||||
"filter": {
|
||||
"must": [
|
||||
{"key": "uuid", "match": {"value": "1636719dc31f78ac"}},
|
||||
{"key": "chunk_type", "match": {"value": "sentence"}}
|
||||
]
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 使用場景
|
||||
|
||||
### 多語言搜索場景
|
||||
| 場景 | 適用 | 多語言支持 |
|
||||
|------|------|------------|
|
||||
| 僅 ASR 文字語義搜尋 | ✅ 最佳 | ✅ 英語、中文、日語等 |
|
||||
| 簡單問答系統 | ✅ 最佳 | ✅ 跨語言問答 |
|
||||
| 基礎影片檢索 | ✅ 最佳 | ✅ 多語言檢索 |
|
||||
| 多語言內容分析 | ✅ 適合 | ✅ 混合語言內容 |
|
||||
| 跨語言相似度匹配 | ✅ 適合 | ✅ 語言無關嵌入 |
|
||||
| 需要物體辨識結果 | ❌ 請用 Rule 2/3 | - |
|
||||
| 需要父子層級關係 | ❌ 請用 Rule 3 | - |
|
||||
|
||||
### 多語言示例場景
|
||||
1. **中文搜索英文內容**: 用戶用中文查詢,找到英文影片片段
|
||||
2. **跨語言相似內容發現**: 不同語言描述相同概念的內容匹配
|
||||
3. **混合語言影片處理**: 影片中包含多種語言對話的場景
|
||||
4. **全球化內容檢索**: 支持多國用戶使用母語搜索
|
||||
|
||||
---
|
||||
|
||||
## 優點與限制
|
||||
|
||||
### 優點
|
||||
|
||||
#### 效能優點
|
||||
- **資料量最小**: 僅包含基本 metadata,儲存效率高
|
||||
- **搜尋速度最快**: 簡單結構提供最佳搜索性能
|
||||
- **實作最簡單**: 易於開發和維護
|
||||
|
||||
#### 多語言優點
|
||||
- **原生多語言支持**: 使用 `nomic-embed-text-v2-moe:latest` 模型,無需語言檢測
|
||||
- **跨語言搜索**: 支持查詢語言與內容語言不同的場景
|
||||
- **統一向量空間**: 所有語言共享相同的 768 維向量空間
|
||||
- **語言無關相似度**: 不同語言描述相同概念的內容會被匹配
|
||||
|
||||
#### 模型優點
|
||||
- **高效推理**: MoE 架構提供快速嵌入生成
|
||||
- **統一維度**: 固定 768 維,與 Qdrant collection 完美匹配
|
||||
- **Ollama 集成**: 通過標準 API 調用,部署簡單
|
||||
|
||||
### 限制
|
||||
|
||||
#### 功能限制
|
||||
- **無法利用物體辨識結果**: 僅基於文本內容,不包含視覺信息
|
||||
- **無法進行父子層級搜尋**: 不支持層級結構的複雜查詢
|
||||
|
||||
#### 模型限制
|
||||
- **固定向量維度**: 僅支持 768 維向量,無法調整
|
||||
- **模型依賴**: 依賴 Ollama 服務運行 `nomic-embed-text-v2-moe:latest` 模型
|
||||
- **多語言精度**: 對於極少數語言可能精度較低
|
||||
|
||||
---
|
||||
|
||||
## 相關文件
|
||||
|
||||
| 文件 | 用途 |
|
||||
|------|------|
|
||||
| CHUNK_RULES_SPEC.md | 規則總覽 |
|
||||
| CHUNK_RULE_2_FRAME_OBJECTS.md | Rule 2 規範 |
|
||||
| CHUNK_RULE_3_COMPOSITE.md | Rule 3 規範 |
|
||||
| CHUNK_SPEC.md | Chunk 基礎規範 |
|
||||
|
||||
---
|
||||
|
||||
**文件結束**
|
||||
@@ -0,0 +1,310 @@
|
||||
---
|
||||
document_type: "reference_doc"
|
||||
service: "MOMENTRY_CORE"
|
||||
title: "Unknown"
|
||||
date: "2026-03-28"
|
||||
version: "V1.0"
|
||||
status: "active"
|
||||
owner: "Warren"
|
||||
created_by: "OpenCode"
|
||||
tags:
|
||||
- "unknown"
|
||||
ai_query_hints:
|
||||
- "查詢 Unknown 的內容"
|
||||
- "Unknown 的主要目的是什麼?"
|
||||
- "如何操作或實施 Unknown?"
|
||||
---
|
||||
|
||||
---
|
||||
title: Chunk Rule 2 - Frame Objects
|
||||
description: 涵蓋 frames,conf > 0.8 的物件加入字串
|
||||
version: 1.0
|
||||
created: 2026-03-28
|
||||
updated: 2026-03-28
|
||||
service: MOMENTRY_CORE
|
||||
topic: chunk_rule
|
||||
document_type: spec
|
||||
rule_id: 2
|
||||
rule_name: Frame Objects
|
||||
collection: momentry_rule2
|
||||
confidence_threshold: 0.8
|
||||
ai_agent_friendly: true
|
||||
---
|
||||
|
||||
# Chunk Rule 2 - Frame Objects
|
||||
|
||||
| 項目 | 內容 |
|
||||
|------|------|
|
||||
| 建立者 | OpenCode |
|
||||
| 建立時間 | 2026-03-28 |
|
||||
| 文件版本 | V1.0 |
|
||||
| Rule ID | 2 |
|
||||
| Rule 名稱 | Frame Objects |
|
||||
| Collection | `momentry_rule2` |
|
||||
| Confidence Threshold | > 0.8 |
|
||||
|
||||
---
|
||||
|
||||
## 版本歷史
|
||||
|
||||
| 版本 | 日期 | 目的 | 操作人 |
|
||||
|------|------|------|--------|
|
||||
| V1.0 | 2026-03-28 | 創建 Rule 2 規範 | OpenCode |
|
||||
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
Rule 2 (Frame Objects) 將 chunk 時間範圍內的 frame objects 進行聚合,僅保留 confidence > 0.8 的物件,轉化為文字描述存入 payload。
|
||||
|
||||
---
|
||||
|
||||
## 設計原則
|
||||
|
||||
### 輸入
|
||||
|
||||
- pre_chunk(來自 ASR/Cut/TimeBased 的原始分段)
|
||||
- frames(chunk 時間範圍內的所有 frames)
|
||||
|
||||
### 處理
|
||||
|
||||
1. 找出 chunk 時間範圍內的所有 frames
|
||||
2. 收集每個 frame 的物件識別結果(YOLO/Face/Pose)
|
||||
3. 過濾 confidence > 0.8 的物件
|
||||
4. 聚合物件名稱和數量
|
||||
|
||||
### 輸出
|
||||
|
||||
- chunk + frame_objects 字串
|
||||
|
||||
---
|
||||
|
||||
## Collection 定義
|
||||
|
||||
### 建立 Collection
|
||||
|
||||
```bash
|
||||
curl -X PUT "http://localhost:6333/collections/momentry_rule2" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "api-key: <API_KEY>" \
|
||||
-d '{
|
||||
"vectors": {
|
||||
"size": 768,
|
||||
"distance": "Cosine"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
### Collection 參數
|
||||
|
||||
| 參數 | 值 |
|
||||
|------|-----|
|
||||
| Name | `momentry_rule2` |
|
||||
| Vector Size | 768 |
|
||||
| Distance | Cosine |
|
||||
| HNSW | m=16, ef_construct=100 |
|
||||
|
||||
---
|
||||
|
||||
## Payload 結構
|
||||
|
||||
### 欄位定義
|
||||
|
||||
| 欄位 | 類型 | 必填 | 說明 |
|
||||
|------|------|------|------|
|
||||
| `uuid` | String | ✅ | 影片 UUID (16 字元) |
|
||||
| `chunk_id` | String | ✅ | Chunk 唯一 ID |
|
||||
| `chunk_type` | String | ✅ | 類型:sentence/cut/time_based |
|
||||
| `chunk_index` | u32 | ✅ | Chunk 索引 (從 0 開始) |
|
||||
| `start_frame` | i64 | ✅ | 開始幀編號 |
|
||||
| `end_frame` | i64 | ✅ | 結束幀編號 |
|
||||
| `fps` | f64 | ✅ | 幀率 |
|
||||
| `original_text` | String | ✅ | 產生 vector 的原始文字 (ASR) |
|
||||
| `frame_objects` | String | ✅ | 涵蓋 frames 的物件描述 (conf > 0.8) |
|
||||
|
||||
### JSON 範例
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "1636719dc31f78ac",
|
||||
"chunk_id": "sentence_0001",
|
||||
"chunk_type": "sentence",
|
||||
"chunk_index": 1,
|
||||
"start_frame": 252,
|
||||
"end_frame": 378,
|
||||
"fps": 24.0,
|
||||
"original_text": "Hello world, this is a test message",
|
||||
"frame_objects": "person:3, car:1, dog:2"
|
||||
}
|
||||
```
|
||||
|
||||
### Rust 結構
|
||||
|
||||
```rust
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VectorPayloadRule2 {
|
||||
pub uuid: String,
|
||||
pub chunk_id: String,
|
||||
pub chunk_type: String,
|
||||
pub chunk_index: u32,
|
||||
pub start_frame: i64,
|
||||
pub end_frame: i64,
|
||||
pub fps: f64,
|
||||
pub original_text: String,
|
||||
pub frame_objects: String,
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## frame_objects 生成規則
|
||||
|
||||
### 輸入數據(Frame 範例)
|
||||
|
||||
```json
|
||||
// Frame 252
|
||||
{
|
||||
"frame_number": 252,
|
||||
"yolo_objects": [
|
||||
{"class": "person", "confidence": 0.95, "count": 2},
|
||||
{"class": "car", "confidence": 0.85, "count": 1}
|
||||
],
|
||||
"face_count": 0,
|
||||
"pose_count": 0
|
||||
}
|
||||
|
||||
// Frame 300
|
||||
{
|
||||
"frame_number": 300,
|
||||
"yolo_objects": [
|
||||
{"class": "person", "confidence": 0.92, "count": 3},
|
||||
{"class": "dog", "confidence": 0.88, "count": 2}
|
||||
],
|
||||
"face_count": 1,
|
||||
"pose_count": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 處理邏輯
|
||||
|
||||
1. **收集所有物件**:person, car, dog, face, pose
|
||||
2. **過濾 confidence > 0.8**:
|
||||
- person: 0.95 ✅, 0.92 ✅ → 保留
|
||||
- car: 0.85 ✅ → 保留
|
||||
- dog: 0.88 ✅ → 保留
|
||||
- (其他低於 0.8 的過濾掉)
|
||||
3. **聚合數量**:
|
||||
- person: max(2, 3) = 3
|
||||
- car: 1
|
||||
- dog: 2
|
||||
|
||||
### 輸出字串
|
||||
|
||||
```
|
||||
"person:3, car:1, dog:2"
|
||||
```
|
||||
|
||||
### 物件類型前綴
|
||||
|
||||
| 來源 | 前綴 | 範例 |
|
||||
|------|------|------|
|
||||
| YOLO | (class name) | "person:3, car:1" |
|
||||
| Face | "face:" | "face:2" |
|
||||
| Pose | "pose:" | "pose:1" |
|
||||
|
||||
---
|
||||
|
||||
## 時間計算
|
||||
|
||||
### Frame 轉時間
|
||||
|
||||
```
|
||||
start_time = start_frame / fps
|
||||
end_time = end_frame / fps
|
||||
```
|
||||
|
||||
### 範例
|
||||
|
||||
```
|
||||
- fps = 24.0
|
||||
- start_frame = 252
|
||||
- end_frame = 378
|
||||
- start_time = 252 / 24.0 = 10.5 秒
|
||||
- end_time = 378 / 24.0 = 15.75 秒
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 搜尋範例
|
||||
|
||||
### 語義搜尋(包含物件)
|
||||
|
||||
```rust
|
||||
let query_vector = embed_text("找出有人在開車的片段").await?;
|
||||
let results = qdrant.search(
|
||||
"momentry_rule2",
|
||||
&query_vector,
|
||||
10,
|
||||
None
|
||||
).await?;
|
||||
```
|
||||
|
||||
### 依賴 Frame Objects Filter
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:6333/collections/momentry_rule2/points/search" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "api-key: <API_KEY>" \
|
||||
-d '{
|
||||
"vector": [0.123, -0.456, ...],
|
||||
"limit": 10,
|
||||
"with_payload": true,
|
||||
"filter": {
|
||||
"should": [
|
||||
{"key": "frame_objects", "match": {"value": "car"}},
|
||||
{"key": "frame_objects", "match": {"value": "person"}}
|
||||
]
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 使用場景
|
||||
|
||||
| 場景 | 適用 |
|
||||
|------|------|
|
||||
| 需要物體辨識結果輔助搜尋 | ✅ 最佳 |
|
||||
| 根據影片中的物件(人、車、動物)搜尋 | ✅ 最佳 |
|
||||
| 簡單問答系統 + 物件辨識 | ✅ 最佳 |
|
||||
| 需要父子層級關係 | ❌ 請用 Rule 3 |
|
||||
|
||||
---
|
||||
|
||||
## 優點與限制
|
||||
|
||||
### 優點
|
||||
|
||||
- 結合 ASR + 物件辨識結果
|
||||
- 可根據物件進行搜尋
|
||||
- 資料量適中
|
||||
|
||||
### 限制
|
||||
|
||||
- 無法進行父子層級搜尋
|
||||
- frame_objects 是聚合後的字串,無法取得詳細位置
|
||||
|
||||
---
|
||||
|
||||
## 相關文件
|
||||
|
||||
| 文件 | 用途 |
|
||||
|------|------|
|
||||
| CHUNK_RULES_SPEC.md | 規則總覽 |
|
||||
| CHUNK_RULE_1_SIMPLE.md | Rule 1 規範 |
|
||||
| CHUNK_RULE_3_COMPOSITE.md | Rule 3 規範 |
|
||||
| CHUNK_SPEC.md | Chunk 基礎規範 |
|
||||
|
||||
---
|
||||
|
||||
**文件結束**
|
||||
216
docs_v1.0/CHUNKING/RULES/VISUAL_BASED/CHUNK_RULE_2_VISUAL.md
Normal file
216
docs_v1.0/CHUNKING/RULES/VISUAL_BASED/CHUNK_RULE_2_VISUAL.md
Normal file
@@ -0,0 +1,216 @@
|
||||
---
|
||||
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. 數據源與聚合邏輯
|
||||
|
||||
Rule 2 的生成主要依賴視覺處理器產出,並輔助以音訊元數據。
|
||||
|
||||
1. **YOLO (Primary)**: 提供幀級別的物件檢測。
|
||||
- *過濾*: 僅保留 `confidence > 0.8` 的物件。
|
||||
- *格式*: 轉換為描述性字串,如 "a person", "a car", "a cup"。
|
||||
2. **Face (Secondary)**: 提供幀級別的人物 ID。
|
||||
- *策略*: 記錄當前幀所有可見的 `face_id`。
|
||||
3. **ASRX (Audio Overlay)**: 提供當前時間點的說話者。
|
||||
- *策略*: 取時間重疊的 `speaker_id`,若無則為空。
|
||||
|
||||
### 聚合策略 (Time-Windowing)
|
||||
由於影片幀率極高 (如 60fps),直接為每一幀建立 Chunk 會造成資料庫膨脹。系統採用 **1 秒聚合 (1s Aggregation)** 策略:
|
||||
|
||||
- **Input**: 60 幀 (假設 60fps)。
|
||||
- **Processing**: 合併這 1 秒內所有唯一的 YOLO 物件與 Faces。
|
||||
- **Output**: 1 個 Rule 2 Chunk。
|
||||
- **Time Representation**: 記錄該秒的起始幀 (`start_frame`) 與結束幀 (`end_frame`)。
|
||||
|
||||
---
|
||||
|
||||
## 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 |
|
||||
| **適用場景** | 尋找特定物件 (槍、車)、場景識別、特定鏡頭回顧 |
|
||||
|
||||
此規範確保了影片畫面中的所有高可信度物件都能被系統「看見」並「記住」。
|
||||
Reference in New Issue
Block a user