feat: backup architecture docs, source code, and scripts

This commit is contained in:
Warren
2026-04-25 17:15:45 +08:00
parent 59809dae1f
commit 1f84e5469f
368 changed files with 146329 additions and 261 deletions

View 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

View 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 實現了從「關鍵字匹配」到「語意理解」的跨越。系統不僅能告訴使用者「某個物件出現了」,還能解釋「**誰**在**哪裡**利用**什麼**做了**什麼**」,提供完整的場景認知。

View 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 的定義。

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

View 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;
```

View 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 | 涵蓋 framesconf > 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 設計架構 |
---
**文件結束**

File diff suppressed because it is too large Load Diff