Merge M5 docs into M4

This commit is contained in:
Warren
2026-05-08 00:26:09 +08:00
78 changed files with 9606 additions and 98 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,83 @@
# Embedding 跨機器部署方案 v1.0.0
## 分工原則
```
M5Pipeline + 主力 Embedding M4Portal + Fallback Embedding
├── 批量 vectorize1709 chunks ├── Portal search query embedding
├── EmbeddingGemma 主 server ├── 備援 embed server
├── 模型已上線port 11436 └── 預設呼叫 M5 API
└── 出門 demo 可離線運作
```
## 部署架構
```
Portal Search Query
┌─────────────┐ 成功 ┌──────────────────┐
│ M4 Portal │ ──────────→ │ M5:11436 │
│ embed │ │ EmbeddingGemma │
│ client │ │ (主力) │
│ │ 失敗 └──────────────────┘
│ retry │ ──────────→ ┌──────────────────┐
│ fallback │ │ M4:11436 │
└─────────────┘ │ EmbeddingGemma │
│ (備援) │
└──────────────────┘
```
## M4 安裝步驟
```bash
# 1. 安裝 Python 依賴
pip install torch transformers flask
# 2. 登入 HuggingFace需接受授權
open https://huggingface.co/google/embeddinggemma-300m
huggingface-cli login --token YOUR_TOKEN
# 3. 取得 script
rsync -av accusys@192.168.110.201:/Users/accusys/momentry_core_0.1/scripts/embeddinggemma_server.py \
./scripts/embeddinggemma_server.py
# 4. 啟動備援 server
python3 scripts/embeddinggemma_server.py --port 11436
```
## Portal Embed Client
```javascript
async function embedQuery(text) {
const servers = [
'http://192.168.110.201:11436/v1/embeddings', // M5 主力
'http://localhost:11436/v1/embeddings', // M4 備援
];
for (const url of servers) {
try {
const res = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ input: text }),
});
const data = await res.json();
return data.data[0].embedding;
} catch (e) {
continue; // 下一台
}
}
throw new Error('Embedding servers unreachable');
}
```
## 模型一致性
| 項目 | M5 | M4 |
|------|-----|-----|
| 模型 | EmbeddingGemma 300M | EmbeddingGemma 300M |
| 維度 | 768D | 768D |
| Server | Python MPS (port 11436) | Python CPU/MPS (port 11436) |
| Qdrant | 192.168.110.201:6333 | 192.168.110.201:6333 |
兩台使用同一模型、同一維度,確保 query embedding 與索引 embedding 可比對。

View File

@@ -0,0 +1,91 @@
---
document_type: "spec"
service: "MOMENTRY_CORE"
title: "5W1H+ Agent v1.0.0"
date: "2026-05-07"
version: "V1.0"
status: "active"
owner: "Warren"
tags:
- "momentry"
- "agent"
- "5w1h"
- "llm"
- "summary"
related_documents:
- "../../TRACE/TRACE_API_REFERENCE_V1.0.0.md"
- "../CHUNK_DEFINITION_V1.0.0.md"
- "../VECTOR_SPEC_V1.0.0.md"
---
# 5W1H+ Agent v1.0.0
## 概述
對每個 cut scene 產生 5W1H+ 摘要parent summary + child enhanced text
## 遞迴 ContextStory So Far
採用方案 B每段 scene 的 LLM call 帶入前面所有 scene 的摘要。
```
Scene 1 → LLM(context="") → summary_1
Scene 2 → LLM(context=summary_1) → summary_2
Scene 3 → LLM(context=summary_1+summary_2) → summary_3
```
Context truncation保留最近 ~500 tokens 的前情,避免超過模型 limit。
## Prompt 結構
每個 scene 的 LLM call 包含以下資訊:
| Prompt 區塊 | 來源 | 說明 |
|------------|------|------|
| Scene time | chunk metadata | 目前 scene 的時間區間 |
| Dialogue | sentences in scene | 該 scene 內的對話行 |
| Actors present | face_detections JOIN identity_bindings JOIN identities | 場景中出現的演員 |
| Objects detected | pre_chunks WHERE processor_type='yolo' | YOLO 偵測到的物體 |
| Face traces | face_detections JOIN identity_bindings JOIN identities | trace 與對應的演員名稱 |
| Active speakers | pre_chunks WHERE processor_type='asrx' JOIN identity_bindings | 說話者與對應的演員 |
| Story so far | 前 N 個 scene 的 parent_summary | 前情摘要 |
## LLM 模型
| 項目 | 值 |
|------|-----|
| 模型 | Gemma4 26B MoE (Q5_K_M, 18GB) |
| 部署 | llama-serverMetal GPU, port 8082 |
| 環境變數 | `MOMENTRY_LLM_SUMMARY_URL=http://localhost:8082/v1/chat/completions` |
| 溫度 | 0.1 |
| max_tokens | 4096 |
## 產出
| 輸出 | 儲存位置 | 說明 |
|------|---------|------|
| parent_summary | `cut.summary_text` | 5 句 scene_summary5W1H 流暢段落) |
| parent_5w1h | `cut.metadata -> 5w1h` | 結構化 who/what/where/when/why/how |
| child_enhanced | `sentence.text_content` | 自包含的 enhanced sentence供 embedding + search |
| child_5w1h | `sentence.content -> 5w1h` | 逐句的 5w1h 結構 |
| embedding | `sentence.embedding` | EmbeddingGemma 300M 768D產出 summary 後自動 vectorize |
## API
```
POST /api/v1/agents/5w1h/analyze
POST /api/v1/agents/5w1h/batch
GET /api/v1/agents/5w1h/status
```
## Pipeline 觸發
Job Worker 中的 P4 trigger
```rust
// all_completed + has_cut + has_asr → run_5w1h_agent(db, uuid)
```
## 選型文件
詳細方案比較:`M5_workspace/2026-05-07_5w1h_recursive_summary_design.md`

View File

@@ -0,0 +1,84 @@
---
document_type: "spec"
service: "MOMENTRY_CORE"
title: "Identity Agent v1.0.0"
date: "2026-05-07"
version: "V1.0"
status: "active"
owner: "Warren"
tags:
- "momentry"
- "agent"
- "identity"
- "face"
- "speaker"
related_documents:
- "../DATA_SCHEMA_FILE_IDENTITY_V1.0.0.md"
- "../../TRACE/TRACE_API_REFERENCE_V1.0.0.md"
- "../PROCESSORS/FACE_V1.0.0.md"
- "../PROCESSORS/ASRX_V1.0.0.md"
---
# Identity Agent v1.0.0
## 概述
將 face trace 與 speaker 綁定到人物身份identity實現跨場景的人員辨識。
## 處理流程
```
face_clustered.json + asrx.json
→ extract_persons (face clusters)
→ extract_speakers (ASRX segments)
→ analyze_person_speaker_overlap
→ 寫入 dev.identities
→ match_faces_iterative (TMDb seed → propagation)
→ bind_speakers (speaker_id → identity_id)
```
## 迭代多角度 Face Matching
```
TMDb seeds (12 identities, with mulitple angles)
→ Round 1: ~33% trace-to-identity
→ Round 2: propagate matched traces as new seeds
→ Round 3: propagate again
→ Final: 99% binding (6,175 / 6,186 face detections)
```
## Speaker Binding
```
face_detections (trace_id, frame_number)
+ ASRX segments (speaker_id, start_time, end_time)
→ frame-level overlap computation
→ winner-takes-all: best_overlap > 30%
→ 寫入 identity_bindings (identity_type='speaker')
```
## Pipeline 觸發
Job Worker 中的 P3 trigger
```rust
// has_face + has_asrx → run_identity_agent(db, uuid)
```
觸發時機all_completedface 與 asrx 皆完成後。
## DB 結構
| Table | 用途 |
|-------|------|
| `identities` | 身份主表name, type, metadata, embedding |
| `identity_bindings` | 綁定表identity_id → trace_id 或 speaker_id |
| `file_identities` | 檔案級身份對應 |
## API
```
POST /api/v1/agents/identity/analyze
POST /api/v1/agents/identity/suggest
GET /api/v1/agents/identity/status
```

View File

@@ -0,0 +1,210 @@
---
document_type: "reference_doc"
service: "MOMENTRY_CORE"
title: "Momentry Core Dev API 參考文件"
date: "2026-05-06"
version: "V1.1"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "api"
- "reference"
- "dev"
- "v1.1"
- "restful"
related_documents:
- "MOMENTRY_CORE_API_V1.0.0.md"
- "RELEASE/RELEASE_API_REFERENCE_v1.0.0.md"
---
# Momentry Core Dev API 參考文件
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-05-06 |
| 文件版本 | V1.1 |
| Base URL | `http://localhost:3003` |
| 認證方式 | Header `X-API-Key`(部分端點需要) |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 |
|------|------|------|--------|
| V1.1 | 2026-05-06 | 從程式碼實際路由重新產生 53 端點清單 | OpenCode |
| V1.0 | 2026-04-30 | 原始文件,含多個不存在之端點 | OpenCode |
---
## 認證
- **Header**: `X-API-Key: <your_api_key>`
- 目前 `/api/v1/auth/login` 回傳固定 demo Key: `muser_test_001`
- Protected routes 透過 `api_key_validation` middleware 驗證
- Public routes免 Key: `/health`, `/health/detailed`, `/api/v1/auth/login`
---
## 端點列表
總計 **53 個註冊路由**(另有 1 個定義但未掛載)。
### 1. 系統與認證System & Auth
| # | Method | Path | 說明 | 需 Key |
|---|--------|------|------|--------|
| 1 | GET | `/health` | 基本健康檢查(回傳 status/version/uptime | ❌ |
| 2 | GET | `/health/detailed` | 詳細健康狀態(含 PG/Redis/Qdrant/MongoDB 各別延遲) | ❌ |
| 3 | POST | `/api/v1/auth/login` | 登入(固定 demo/demo回傳 API Key | ❌ |
| 4 | POST | `/api/v1/auth/logout` | 登出 | ✅ |
### 2. 檔案管理File Management
| # | Method | Path | 說明 | 需 Key |
|---|--------|------|------|--------|
| 5 | GET | `/api/v1/files` | 檔案列表支援分頁、status、q、uuid 過濾) | ✅ |
| 6 | GET | `/api/v1/file/:file_uuid` | 檔案詳細資訊(含 probe_json、metadata | ✅ |
| 7 | POST | `/api/v1/files/register` | 從磁碟註冊新檔案(支援 pattern 批次註冊) | ✅ |
| 8 | POST | `/api/v1/unregister` | 取消註冊檔案 | ✅ |
| 9 | GET | `/api/v1/files/scan` | 掃描 SFTPGo demo 目錄中的新檔案 | ✅ |
| 10 | GET | `/api/v1/file/:file_uuid/probe` | 取得/快取 ffprobe 資訊 | ✅ |
| 11 | POST | `/api/v1/file/:file_uuid/process` | 啟動處理 pipeline建立 monitor job | ✅ |
| 12 | GET | `/api/v1/file/:file_uuid/chunks` | 列出 pre_chunks | ✅ |
| 13 | GET | `/api/v1/progress/:uuid` | 即時處理進度(來自 Redis PubSub | ✅ |
| 14 | GET | `/api/v1/jobs` | 任務列表支援分頁、status 過濾) | ✅ |
### 3. 搜尋Search
| # | Method | Path | 說明 | 需 Key |
|---|--------|------|------|--------|
| 15 | POST | `/api/v1/search/visual` | 視覺搜尋 | ✅ |
| 16 | POST | `/api/v1/search/visual/class` | 依物件類別過濾搜尋 | ✅ |
| 17 | POST | `/api/v1/search/visual/density` | 依視覺密度搜尋 | ✅ |
| 18 | POST | `/api/v1/search/visual/stats` | 視覺統計資料 | ✅ |
| 19 | POST | `/api/v1/search/visual/combination` | 視覺組合搜尋(多條件) | ✅ |
| 20 | POST | `/api/v1/search/smart` | 智慧搜尋(語意向量) | ✅ |
| 21 | POST | `/api/v1/search/universal` | 通用搜尋 | ✅ |
| 22 | POST | `/api/v1/search/frames` | 影格搜尋 | ✅ |
### 4. 身份管理Identity
| # | Method | Path | 說明 | 需 Key |
|---|--------|------|------|--------|
| 23 | GET | `/api/v1/identities` | 身份列表 | ✅ |
| 24 | POST | `/api/v1/identity` | 建立身份(從 face.json 建立參考向量) | ✅ |
| 25 | GET | `/api/v1/identity/:identity_uuid` | 身份詳細資訊 | ✅ |
| 26 | DELETE | `/api/v1/identity/:identity_uuid` | 刪除身份 | ✅ |
| 27 | GET | `/api/v1/identity/:identity_uuid/files` | 該身份出現的所有檔案 | ✅ |
| 28 | GET | `/api/v1/identity/:identity_uuid/chunks` | 該身份的時間軸片段 | ✅ |
| 29 | POST | `/api/v1/identity/:identity_uuid/bind` | 綁定信號至身份 | ✅ |
| 30 | POST | `/api/v1/identity/:identity_uuid/unbind` | 解除綁定 | ✅ |
| 31 | POST | `/api/v1/identity/:from_uuid/mergeinto` | 合併身份(將 from 合併至目標) | ✅ |
### 5. 臉部Face
| # | Method | Path | 說明 | 需 Key |
|---|--------|------|------|--------|
| 32 | GET | `/api/v1/faces/candidates` | 臉部候選列表(未綁定者) | ✅ |
### 6. 媒體串流Media
| # | Method | Path | 說明 | 需 Key |
|---|--------|------|------|--------|
| 33 | GET | `/api/v1/file/:file_uuid/video` | 影片串流 | ✅ |
| 34 | GET | `/api/v1/file/:file_uuid/video/bbox` | 含 Bounding Box 的影片串流 | ✅ |
| 35 | GET | `/api/v1/file/:file_uuid/trace/:trace_id/video` | 特定 trace 的影片片段 | ✅ |
| 36 | GET | `/api/v1/file/:file_uuid/thumbnail` | 影片縮圖 | ✅ |
### 7. 檔案身份關聯File-Identity
| # | Method | Path | 說明 | 需 Key |
|---|--------|------|------|--------|
| 37 | GET | `/api/v1/file/:file_uuid/identities` | 該檔案的所有關聯身份 | ✅ |
### 8. Agent
| # | Method | Path | 說明 | 需 Key |
|---|--------|------|------|--------|
| 38 | POST | `/api/v1/agents/translate` | 翻譯 Agent | ✅ |
| 39 | POST | `/api/v1/agents/identity/analyze` | 身份分析 Agent | ✅ |
| 40 | POST | `/api/v1/agents/identity/suggest` | 身份合併建議 | ✅ |
| 41 | GET | `/api/v1/agents/identity/status` | 身份 Agent 狀態 | ✅ |
| 42 | POST | `/api/v1/agents/suggest/clustering` | 聚類建議 | ✅ |
| 43 | POST | `/api/v1/agents/suggest/merge` | 合併建議 | ✅ |
| 44 | POST | `/api/v1/agents/5w1h/analyze` | 5W1H 分析 | ✅ |
| 45 | POST | `/api/v1/agents/5w1h/batch` | 5W1H 批量分析 | ✅ |
| 46 | GET | `/api/v1/agents/5w1h/status` | 5W1H 狀態 | ✅ |
### 9. 資源管理Resource
| # | Method | Path | 說明 | 需 Key |
|---|--------|------|------|--------|
| 47 | POST | `/api/v1/resource/register` | 註冊運算資源 | ✅ |
| 48 | POST | `/api/v1/resource/heartbeat` | 資源心跳回報 | ✅ |
| 49 | GET | `/api/v1/resources` | 資源列表 | ✅ |
### 10. 統計與設定Stats & Config
| # | Method | Path | 說明 | 需 Key |
|---|--------|------|------|--------|
| 50 | GET | `/api/v1/stats/ingest` | 攝取統計video/chunk 計數) | ✅ |
| 51 | GET | `/api/v1/stats/sftpgo` | SFTPGo 使用者狀態 | ✅ |
| 52 | GET | `/api/v1/stats/inference` | 推理叢集健康狀態 | ✅ |
| 53 | POST | `/api/v1/config/cache` | 切換快取開關 | ✅ |
---
## 未掛載的端點(定義了 handler 但未註冊路由)
| Handler | 位置 | 說明 |
|---------|------|------|
| `POST /api/v1/file/:file_uuid/face_trace/sortby` | `trace_agent_api.rs` | 定義了 `trace_agent_routes()` 但從未被 `server.rs` merge |
---
## 程式碼中存在 handler 但未註冊路由的端點
下列 handler 有實作但**沒有對應的 `.route()` 呼叫**,無法透過 HTTP 存取:
- `GET /api/v1/assets/:uuid/status``get_asset_status`
- `GET /api/v1/jobs/:job_id``get_job`
- `GET /api/v1/rules/:rule/status``get_rule_status`
- `GET /api/v1/videos/:uuid/details``video_details`
- `DELETE /api/v1/videos/:uuid``delete_video`
- `POST /api/v1/search``search`(語意搜尋)
- `POST /api/v1/search/hybrid``hybrid_search`
- `POST /api/v1/search/bm25``search_bm25`
- `GET /api/v1/lookup``lookup`
- `POST /api/v1/search/smart``search_smart`server.rs 版,實際註冊的是 search.rs 版)
---
## 與 V1.0 文件的差異
V1.0 文件(`MOMENTRY_CORE_API_V1.0.0.md`)宣稱的端點中有以下**不存在於實際程式碼**
| 文件宣稱 | 實際狀況 |
|----------|---------|
| `DELETE /api/v1/videos/:uuid` | handler 存在但未註冊路由 |
| `POST /api/v1/search` | handler 存在但未註冊路由 |
| `POST /api/v1/search/hybrid` | handler 存在但未註冊路由 |
| `POST /api/v1/assets/:uuid/process` | 實際是 `POST /api/v1/file/:file_uuid/process` |
| `GET /api/v1/files/:uuid/snapshots` | 不存在 |
| `POST /api/v1/files/:uuid/snapshots/migrate` | 不存在 |
| `GET /api/v1/face/list` | 不存在 |
| `POST /api/v1/face/recognize` | 不存在 |
---
## 路徑命名慣例
| 資源 | 路由格式 | 參數 |
|------|---------|------|
| 檔案 | `/api/v1/file/:file_uuid` | 32 碼 hex string |
| 身份 | `/api/v1/identity/:identity_uuid` | UUID v4 |
| 資源 | `/api/v1/resource/...` | - |
注意路徑使用**單數**`file`, `identity`),與 RELEASE 文件的 `files`, `identities` 不同。

View File

@@ -4,7 +4,7 @@ service: "MOMENTRY_CORE"
title: "Pipeline & Rule Architecture: Processor Lifecycle, Embedding, Search V2.0"
date: "2026-05-05"
version: "V2.0"
status: "active"
status: "deprecated"
owner: "Warren"
created_by: "OpenCode"
tags:
@@ -17,13 +17,11 @@ tags:
- "lifecycle"
- "versioning"
- "v1.0"
- "deprecated"
ai_query_hints:
- "Parent-Child 雙層 summarization 架構"
- "Story (template) vs LLM summarization 兩條獨立 pipeline"
- "Qdrant 3-collection 架構: rule1 / story / llm_summary"
- "Metadata 信度: speaker_confidence, face_confidence, object_confidence"
- "處理器版本追蹤與 stale detection"
- "Processor/Agent 生命週期管理與下游傳播"
- "⚠️ 歷史設計文件,非當前實作"
- "Story (template) summarization 已由 5W1H+ Agent 取代"
- "Qdrant 3-collection 架構已簡化為 1 collection + chunk_type 區分"
related_documents:
- "../PROCESSORS/FACE_V1.0.0.md"
- "../PROCESSORS/FACE_EMBEDDING_FLOW_V1.0.0.md"
@@ -34,6 +32,12 @@ related_documents:
# Pipeline & Rule Architecture: Processor Lifecycle, Embedding, Search V2.0
> ⚠️ **歷史設計文件** — 此文件描述 v1.0 早期開發階段的雙軌 pipeline 設計。Story (template) 與 LLM (on-demand) 兩條 pipeline 皆曾實作,後期因 M5 的 LLM 算力充足template-based summarization 已被 5W1H+ Agent 取代。當前實作請參考:
>
> - `AGENTS/5W1H_AGENT_V1.0.0.md` — 5W1H+ 遞迴摘要
> - `AGENTS/IDENTITY_AGENT_V1.0.0.md` — Identity Agent
> - `VECTOR_SPEC_V1.0.0.md` — 向量化規範
## 架構概述
兩個獨立 pipeline共用同一底層Qdrant + BM25chunk_type 區隔:
@@ -83,7 +87,7 @@ related_documents:
3. generate_story_child_summary(child, parent)
└── Template: "[{start}-{end}] {name}: \"{text}\""
4. embed_text(summary) → Ollama nomic-embed-text-v2-moe → 768D vector
4. embed_text(summary) → EmbeddingGemma 300M (Python MPS, port 11436) → 768D vector
5. Store:
├── Qdrant: upsert (point_id=chunk_id, vector=768D, payload={chunk_type, file_uuid, text})
@@ -100,7 +104,7 @@ related_documents:
### Embedding Target
```
chunk_summary text → nomic-embed-text-v2-moe (768D) → Qdrant collection "momentry_dev"
chunk_summary text → EmbeddingGemma 300M (768D, port 11436) → Qdrant collection "momentry_dev"
→ PostgreSQL chunks.embedding (VECTOR(768))
```
@@ -594,8 +598,7 @@ Pose ──────────┘
| **U02** | TMDb | `api.themoviedb.org/3/movie/{id}/credits` | GET | `movie_id` | `TMDB_API_KEY` | `identities.metadata` | Identity Agent |
| **U03** | TMDb | `image.tmdb.org/t/p/w185/{path}` | GET | `profile_path` | — | `identities.tmdb_profile` | Identity Agent |
| **U04** | TMDb | `tmdb_embed_extractor.py` (local) | Py | `model=coreml-facenet/v2` | — | `identities.face_embedding (512D)` | Identity Agent |
| **U05** | Ollama | `localhost:11434/api/embeddings` | POST | `model=nomic-embed-text-v2-moe`, `dim=768` | — | `chunks.embedding (768D)` | Qdrant search |
| **U06** | Ollama | `localhost:11434/api/embeddings` | POST | `model=nomic-embed-text:latest`, `dim=768` | — | `chunks.embedding (768D)` | Qdrant search |
| **U05** | EmbeddingGemma | `localhost:11436/v1/embeddings` | POST | `input=text`, `model=embeddinggemma-300m` | — | `chunks.embedding (768D)` | Qdrant search |
| **U07** | Ollama | `localhost:11434/api/chat` | POST | `model=qwen3:8b` (future) | — | `chunks.text_content` | Story LLM |
| **U08** | Ollama | `localhost:11434/api/chat` | POST | `model=gemma4` (future) | — | `chunks.text_content` | Story LLM |
| **U09** | Qdrant | `localhost:6333/collections/{name}/points` | PUT | `collection=momentry_dev_rule1` | `QDRANT_API_KEY` | rule1 vectors | Search |
@@ -606,9 +609,8 @@ Pose ──────────┘
| Model | Dim | 用途 | 影響範圍 |
|-------|-----|------|---------|
| `nomic-embed-text-v2-moe` | 768 | 多語言 embedding | 所有 chunk embedding 需重算 |
| `nomic-embed-text:latest` | 768 | 同上,不同版本 | 同上 |
| `mxbai-embed-large` | 1024 | 英文為主 | 改 dim → Qdrant collection 重建 |
| `EmbeddingGemma 300M` | 768 | 多語言 embedding | 所有 chunk embedding 需重算 |
| `mxbai-embed-large` | 1024 | 英文為主(已棄用) | 改 dim → Qdrant collection 重建 |
| `qwen3:8b` | — | LLM summarization | Story parent/child summary 文本變更 |
| `qwen3:14b` | — | 同上,品質較好 | 同上 |
| `gemma4:4b` | — | 同上,較輕量 | 同上 |
@@ -617,7 +619,7 @@ Pose ──────────┘
| 變更類型 | 觸發 | 範例 |
|---------|------|------|
| 換 model | 所有 downstream stale | `nomic-embed-text-v2-moe``mxbai-embed-large` → dim 變更 → Qdrant 重建 |
| 換 model | 所有 downstream stale | `EmbeddingGemma 300M`768D取代 `nomic-embed-text-v2-moe`768Ddim 不變 |
| 同 model 參數變更 | 只影響該層 | Qdrant collection rename |
| API endpoint 變更 | 重試策略 + 通知 | TMDb API v3 → v4 |
@@ -626,7 +628,7 @@ Pose ──────────┘
1. 讀取 Pipeline 產出的原始數據
2. 組織成父子 chunk 結構
3. 生成 summary text
4. 呼叫 Embedding (Ollama nomic-embed)
4. 呼叫 Embedding (EmbeddingGemma 300M, Python MPS, port 11436)
5. 存入 Qdrant + PostgreSQL (vector + BM25)
6. 提供 Search API 查詢
@@ -946,7 +948,7 @@ Pose ──────────┘
|------|------|
| **出生登記** | V1.0 / 2026-05 / OpenCode |
| **類別** | Python |
| **簡要說明** | Ollama nomic-embed-text-v2-moe → 768D vector → pgvector。1,175 chunks for Charade。 |
| **簡要說明** | EmbeddingGemma 300MPython MPS, port 11436→ 768D vector → pgvector + Qdrant。 |
| **依賴** | Story Agent |
| **選型測試** | N/A (API integration) |
| **相關文件** | `docs_v1.0/.../VECTOR_SPEC_V1.0.0.md` |
@@ -1120,7 +1122,7 @@ def check_stale(file_uuid, current_versions):
| TMDbAgent | `tmdb-api/v1` | ✅ |
| IdentityAgent | `cosine-threshold/v1` | ✅ |
| StoryAgent | `template/v2.0` | ✅ |
| EmbeddingAgent | `nomic-embed-768d/v1` | ✅ |
| EmbeddingAgent | `embeddinggemma-300m/v1` | ✅ |
## Schema 隔離原則
@@ -1134,7 +1136,7 @@ def check_stale(file_uuid, current_versions):
| Sequence | 各自獨立,不共用 |
| Index | 各自維護 |
| Qdrant | `momentry_dev_*` vs `momentry_*` |
| Ollama | embedding 共用nomic-embed 不分 dev/prod |
| EmbeddingGemma | embedding server 共用port 11436不分 dev/prod |
## Version History
@@ -1142,3 +1144,5 @@ def check_stale(file_uuid, current_versions):
|---------|------|---------|--------|
| V1.0 | 2026-05-05 | Initial design | OpenCode |
| V1.1 | 2026-05-05 | 3-collection Qdrant + metadata confidence + version tracking | OpenCode |
| V1.2 | 2026-05-07 | EmbeddingGemma 300M 取代 nomic-embed-text-v2-moe768D, Python MPS, port 11436 | OpenCode |
| V2.0 | 2026-05-07 | ⚠️ 標記為 deprecated — Story template pipeline 已由 5W1H+ Agent 取代 | OpenCode |

View File

@@ -4,7 +4,7 @@ service: "MOMENTRY_CORE"
title: "Momentry Core V1.0.0 API 參考文件"
date: "2026-04-30"
version: "V1.0"
status: "active"
status: "superseded"
owner: "Warren"
created_by: "OpenCode"
tags:
@@ -46,6 +46,7 @@ related_documents:
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-04-30 | 創建 V1.0.0 API 列表,移除過時端點 | OpenCode | OpenCode |
| V1.1 | 2026-05-06 | 被 DEV_API_REFERENCE_v1.0.0.md 取代(實際路由與此文件有大量差異) | OpenCode | OpenCode |
---

View File

@@ -22,7 +22,7 @@ ai_query_hints:
- "Qdrant collection 的名稱與 payload 結構"
- "Face embedding 的 512-D 向量規格InsightFace ArcFace"
- "Voice embedding 的 192-D 向量規格ECAPA-TDNN"
- "Text embedding 的 768-D 向量規格(nomic-embed-text-v2-moe"
- "Text embedding 的 768-D 向量規格(EmbeddingGemma 300M"
- "Qdrant Payload 中 face 與 voice 的欄位定義"
- "向量化流程中 child chunk 與 parent chunk 的 collection 區別"
related_documents:
@@ -41,6 +41,50 @@ related_documents:
| 建立時間 | 2026-05-02 |
| 文件版本 | V1.0 |
## Collection 命名隔離原則
不同機器、不同環境的向量資料**完全隔離**,命名格式:
```
{machine}_{env}_{type}
```
| 機器 | 環境 | prefix | 用途 |
|------|------|--------|------|
| M5 | dev | `m5_dev_` | M5 開發測試 |
| M5 | prod | `m5_prod_` | M5 正式(未來) |
| M4 | dev | `m4_dev_` | M4 開發測試 |
| M4 | prod | `m4_prod_` | M4 正式 |
### 完整 Collection 列表
| 名稱 | 機器 | 維度 | 用途 |
|------|------|------|------|
| `m5_dev_rule1` | M5 | 768D | Sentence chunks |
| `m5_dev_face` | M5 | 512D | Face embeddings |
| `m5_dev_voice` | M5 | 192D | Voice embeddings未來 |
| `m4_dev_rule1` | M4 | 768D | Sentence chunks |
| `m4_dev_face` | M4 | 512D | Face embeddings |
| `m4_prod_rule1` | M4 | 768D | 正式環境 sentence |
| `m4_prod_face` | M4 | 512D | 正式環境 face |
### 設定方式
透過 `.env.development` 控制:
```bash
# M5 dev
QDRANT_COLLECTION=m5_dev_rule1
# M4 dev
QDRANT_COLLECTION=m4_dev_rule1
# M4 prod
QDRANT_COLLECTION=m4_prod_rule1
```
Face/voice collection 也遵循同樣規則(`m5_dev_face``m4_prod_face` 等)。
## 關鍵術語定義
| 術語 | 定義 |
@@ -48,7 +92,7 @@ related_documents:
| embedding | 向量嵌入,將非結構化資料轉換為數值向量 |
| Qdrant | 向量資料庫,用於儲存與檢索 embedding |
| collection | Qdrant 中的向量集合,類似資料庫中的資料表 |
| 768-D | Text embedding 的維度,由 nomic-embed-text-v2-moe 產出 |
| 768-D | Text embedding 的維度,由 EmbeddingGemma 300M 產出 |
| 512-D | Face embedding 的維度,由 InsightFace ArcFace 產出 |
| 192-D | Voice embedding 的維度,由 SpeechBrain ECAPA-TDNN 產出 |
@@ -68,7 +112,7 @@ related_documents:
```
chunk (sentence / scene)
→ text_content / summary_text
nomic-embed-text-v2-moe (Ollama)
EmbeddingGemma 300M (Python MPS, port 11436, OpenAI-compatible API)
→ 768-D vector
→ Qdrant momentry_dev_rule1 / momentry_dev_chunk_summaries
```
@@ -122,8 +166,23 @@ ASRX processor (ECAPA-TDNN)
}
```
## 已棄用模型
### mxbai-embed-large
| 項目 | 內容 |
|------|------|
| 維度 | 1024-D |
| 部署方式 | ANE CoreML Serverport 11435 |
| API | `/api/embeddings`Ollama 相容) |
| 語言 | English only |
| 狀態 | ❌ 已棄用v1.0 前) |
| 棄用原因 | 無法處理中文等多語內容 |
| 相關檔案 | `scripts/coreml_embed_server.py` |
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-05-02 | 初始版本 | OpenCode | deepseek-chat |
| V1.1 | 2026-05-07 | EmbeddingGemma 300M 取代 nomic-embed-text-v2-moe新增已棄用模型章節 | OpenCode | deepseek-chat |

View File

@@ -0,0 +1,73 @@
# Pipeline 進度報表標準格式
**版本**v2
**日期**2026-05-07
**提供者**M5
---
## 報表範本
```
=== Job {id} 完整報表 (frame總量: {total_frames}) ===
── Processors ──
Proc St Start End 已產出 已處理
------ ---- ----- ----- -------------- ----------
cut ✅ 04:28 04:43 2,260 scenes 169625
face ✅ 04:29 05:05 1,121 frames 169625
ocr ✅ 04:29 04:51 1,212 frames 169625
pose ✅ 04:29 04:40 4,211 frames 169625
yolo ⏳ 04:28 - 7,852 frames 6,803
asr ⏳ 04:28 - 148 segments 17,969
asrx ⬜ - - - -
已處理 4/7
── Post-Processing ──
Stage Status 已產出 依賴進度狀態
------------------- ---------- -------------- ----------
Rule 1 chunks ⬜ - ASR⏳ + ASRX⬜
ANE vectorize ⬜ 0 Rule 1 chunks⬜
Rule 3 scenes ⬜ - all 7 processors⬜
face_trace ⬜ - all 7 processors⬜
Qdrant face sync ⬜ 0 points face_trace⬜
TMDb face match ⬜ 0 face_trace⬜
Identity Agent ⬜ - face_trace✅ + ASRX✅
5W1H Agent ⬜ - Rule 1✅ + Rule 3✅
```
## 欄位說明
### Processors 表
| 欄位 | 說明 |
|------|------|
| Proc | Processor 名稱cut, face, ocr, pose, yolo, asr, asrx |
| St | ✅ completed / ⏳ running / ⬜ pending |
| Start | 開始時間HH:MM |
| End | 完成時間HH:MMrunning 中顯示 - |
| 已產出 | 該 processor 產出的資料量scenes/frames/segments |
| 已處理 | 以 frame 為單位的處理進度running 中顯示當前 frame |
### Post-Processing 表
| 階段 | 觸發時機 | 依賴進度狀態 |
|------|---------|-------------|
| Rule 1 chunks | ASR + ASRX 皆 ✅ | 顯示當前 ASR 與 ASRX 的即時狀態 |
| ANE vectorize | Rule 1 chunks 完成後 | 顯示 Rule 1 狀態 |
| Rule 3 scenes | 全部 7 個 processor 皆 ✅ | 顯示每個 processor 的即時完成狀態 |
| face_trace | 全部 7 個 processor 皆 ✅ | 同 Rule 3 |
| Qdrant face sync | face_trace 完成後 | 顯示 face_trace 狀態 |
| TMDb face match | face_trace 完成後 + TMDb enabled | 顯示 face_trace 狀態 |
| Identity Agent | face_trace + ASRX 皆 ✅ | 顯示 face_trace 與 ASRX 的即時狀態 |
| 5W1H Agent | Rule 1 + Rule 3 皆 ✅ | 顯示 Rule 1 與 Rule 3 狀態 |
## Status 標記
| 標記 | 意義 |
|------|------|
| ✅ completed | 已完成 |
| ⏳ running | 執行中 |
| ⬜ pending | 等待條件成立(條件欄位顯示 waiting for... |
| ❌ failed | 失敗 |
| ⏭️ skipped | 跳過(因依賴失敗) |

View File

@@ -0,0 +1,143 @@
---
document_type: "report"
service: "MOMENTRY_CORE"
title: "Momentry Core V1.0.0 Production (3002) 驗證報告"
date: "2026-05-01"
version: "V1.0"
status: "completed"
owner: "Warren"
created_by: "OpenCode"
tags:
- "production"
- "verification"
- "v1.0.0"
- "api-test"
- "end-to-end"
- "e2e-test"
- "deployment"
ai_query_hints:
- "Production Port 3002 驗證結果"
- "V1.0.0 端對端測試紀錄"
- "API 回應格式驗證"
- "所有 core API 是否在 production 環境正常運作"
- "search API 的端對端測試結果"
- "identity bind API 的資料庫驗證"
- "deprecation verification 測試結果"
related_documents:
- "API_V1.0.0/MOMENTRY_CORE_API_V1.0.0.md"
- "API_V1.0.0/RELEASE_TEST_REPORT_v1.0.0.md"
- "API_V1.0.0/RELEASE_VERIFICATION_V1.0.0.md"
- "API_V1.0.0/API_DICTIONARY_V1.0.0.md"
- "API_V1.0.0/MOMENTRY_CORE_API_V1.0.0.md"
---
# Momentry Core V1.0.0 Production (3002) 驗證報告
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-05-01 |
| 文件版本 | V1.0 |
| 測試環境 | Production Port 3002 |
| 測試帳號 | `demo` / `demo` (API Key: `muser_test_001`) |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-05-01 | 基於 Clean API 藍圖,完成 3002 端對端驗證 | OpenCode | OpenCode |
---
## 關鍵術語定義
| 術語 | 定義 |
|------|------|
| Production | 正式環境 (Port 3002),提供外部服務 |
| end-to-end test | 端對端測試,驗證完整 API 流程 |
| Schema Migration | 資料庫結構升級,確保與程式碼版本一致 |
| deprecation verification | 確認舊版端點已移除的測試 |
| file_uuid | 32 碼 SHA256 檔案識別碼 |
| identity_bindings | 身份綁定資料表,記錄 face/speaker 與 identity 的關聯 |
## 1. 概述
本報告以 `MOMENTRY_CORE_API_V1.0.0.md` 為測試藍圖,對 **Production 環境 (Port 3002)** 進行全面端對端驗證。
所有端點均已通過實測,並記錄實際 HTTP 狀態碼與回應結構。
---
## 2. 核心驗證結果 (端對端測試)
### 2.1 系統與認證 (System & Auth)
| API Endpoint | Method | 測試參數 | HTTP 狀態 | 回應摘要 | 結果 |
| :--- | :--- | :--- | :--- | :--- | :--- |
| `/health` | GET | - | `200 OK` | `{"status": "ok", "version": "1.0.0"}` | ✅ **PASS** |
### 2.2 檔案管理 (File Management)
| API Endpoint | Method | 測試參數 | HTTP 狀態 | 回應摘要 | 結果 |
| :--- | :--- | :--- | :--- | :--- | :--- |
| `/api/v1/files` | GET | `page=1&page_size=1` | `200 OK` | `{"success": true, "data": [{"file_uuid":"232b98...", ...}]}` | ✅ **PASS** |
| `/api/v1/files/:uuid` | GET | `uuid: 232b98ecd4e8f338` | `200 OK` | `{"success": true, "file_uuid": "...", "metadata": {"format": {...}}}` | ✅ **PASS** |
| `/api/v1/videos/:uuid` | DELETE | `uuid: non-existent` | `404 Not Found` | 預期行為 (資源不存在) | ✅ **PASS** |
### 2.3 搜尋與檢索 (Search & Retrieval)
| API Endpoint | Method | 測試參數 | HTTP 狀態 | 回應摘要 | 結果 |
| :--- | :--- | :--- | :--- | :--- | :--- |
| `/api/v1/search` | POST | `{"query":"test", "limit":3}` | `200 OK` | `{"results": [], "query": "test"}` | ✅ **PASS** |
| `/api/v1/search/hybrid` | POST | `{"query":"test", "limit":3}` | `200 OK` | `{"results": [], "query": "test"}` | ✅ **PASS** |
| `/api/v1/search/visual/class`| POST | `{"uuid":"...", "object_class":"person"}`| `200 OK` | `{"chunks": [], "total": 0}` | ✅ **PASS** |
### 2.4 身份與人物管理 (Identity Management)
| API Endpoint | Method | 測試參數 | HTTP 狀態 | 回應摘要 | 結果 |
| :--- | :--- | :--- | :--- | :--- | :--- |
| `/api/v1/identities` | GET | `page=1&page_size=2` | `200 OK` | `{"identities": [{"id": 2, "name": "Audrey Hepburn"}], "count": 2}` | ✅ **PASS** |
| `/api/v1/identities/:uuid`| GET | `uuid: a9a90105...` | `200 OK` | `{"success": true, "uuid": "...", "name": "Trace 2 Fixed Format"}` | ✅ **PASS** |
| `/api/v1/identities/bind` | POST | `{"identity_id": 2, ...}` | `200 OK` | `{"success": true, "message": "Bound face 'release_test_final' to Identity..."}` | ✅ **PASS** |
### 2.5 臉部與快照 (Face & Snapshots)
| API Endpoint | Method | 測試參數 | HTTP 狀態 | 回應摘要 | 結果 |
| :--- | :--- | :--- | :--- | :--- | :--- |
| `/api/v1/files/:uuid/snapshots` | GET | `uuid: 232b98...` | `200 OK` | `{"success": true, "file_uuid": "...", "tier": "cold", "types": [...]}` | ✅ **PASS** |
| `POST /api/v1/files/:uuid/snapshots/migrate` | POST | `{"parent_uuid":"..."}` | `200 OK` | `{"success": true, "message": "Migrated 4 snapshot types"}` | ✅ **PASS** |
### 2.6 任務與代理人 (Jobs & Agents)
| API Endpoint | Method | 測試參數 | HTTP 狀態 | 回應摘要 | 結果 |
| :--- | :--- | :--- | :--- | :--- | :--- |
| `/api/v1/progress/:uuid` | GET | `uuid: 232b98...` | `200 OK` | `{"uuid": "...", "overall_progress": 0, "processors": [...]}` | ✅ **PASS** |
| `/api/v1/assets/:uuid/process`| POST | `uuid: 232b98...` | `400 Bad Request` | `{"message": "Total frames unknown. Run probe first."}` (預期邏輯檢查) | ✅ **PASS** |
---
## 3. 棄用端點驗證 (Deprecation Verification)
確保舊版端點已正確從路由中移除,不會干擾新開發。
| 舊版端點 | 預期行為 | 實際回應 (Port 3002) | 狀態 |
| :--- | :--- | :--- | :--- |
| `GET /api/v1/videos` (列表) | `404 Not Found` | `404 Not Found` | ✅ **已移除** |
| `POST /api/v1/register` (Legacy) | `404 Not Found` | `404 Not Found` | ✅ **已移除** |
| `POST /api/v1/probe` | `404 Not Found` | `404 Not Found` | ✅ **已移除** |
| `GET /api/v1/n8n/search` | `404 Not Found` | `404 Not Found` | ✅ **已移除** |
---
## 4. 關鍵修復驗證紀錄
### 4.1 `probe_json` JSONB 映射修復
* **測試**: `POST /api/v1/files/register`
* **結果**: ✅ 成功寫入 32 碼 UUID`probe_json` 欄位正確序列化存入 PostgreSQL `jsonb` 型別欄位。
### 4.2 `identity_bindings` Schema 升級
* **測試**: `POST /api/v1/identities/bind`
* **結果**: ✅ 成功綁定。資料庫 `identity_bindings` 表格已成功從舊版 `uuid/binding_type` 升級至 V1.0.0 的 `identity_type/identity_value` 結構,並建立對應 Unique Index。
---
## 5. 結論
**Momentry Core V1.0.0 已成功部署至 Production (Port 3002)。**
所有 API 端點均已通過端對端測試,回應格式符合 `MOMENTRY_CORE_API_V1.0.0.md` 藍圖規範。
資料庫結構已同步至 V1.0.0 標準,舊版 API 已清理完畢。系統狀態穩定,可供 Marcom 團隊進行 GUI 整合開發。

View File

@@ -0,0 +1,349 @@
---
document_type: "reference_doc"
service: "MOMENTRY_CORE"
title: "Momentry Core Release API 參考文件 V1.0.0"
date: "2026-05-03"
version: "V4.0"
status: "outdated"
owner: "Warren"
created_by: "OpenCode"
tags:
- "api"
- "reference"
- "release"
- "v1.0.0"
- "marcom"
- "production"
ai_query_hints:
- "Momentry Core Release API 完整列表"
- "API 認證方式與 Base URLport 3002"
- "檔案註冊、處理、搜尋、臉部綁定流程"
- "錯誤回應格式401/400/404"
related_documents:
- "RELEASE/RELEASE_VERIFICATION_V1.0.0.md"
- "RELEASE/PRODUCTION_VERIFICATION_V1.0.0.md"
---
# Momentry Core Release API 參考文件 V1.0.0
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-05-03 |
| 文件版本 | V4.0 |
| Base URL | `http://localhost:3002` |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V4.0 | 2026-05-03 | Release 版本:完整 78 端點 API 參考文件 | OpenCode | deepseek-chat |
---
## 認證方式
- **Header**: `X-API-Key: <your_api_key>`
- 未提供或無效的 key 回傳 `401 Unauthorized`
- 所有端點(除 `/health``/health/detailed` 外)都需要 API key
---
## 錯誤回應格式
```json
// 401 Unauthorized
{ "error": "Unauthorized", "message": "Invalid or missing API key" }
// 400 Bad Request
{ "error": "Bad Request", "message": "Missing required field: file_path" }
// 404 Not Found
{ "error": "Not Found", "message": "Video not found: <uuid>" }
```
---
## 端點列表
### 1. 系統與認證
| # | Method | Path | 說明 |
|---|--------|------|------|
| 1 | GET | `/health` | 系統健康檢查(無需 API key |
| 2 | GET | `/health/detailed` | 詳細健康狀態(無需 API key |
| 3 | POST | `/api/v1/auth/login` | 登入 |
| 4 | POST | `/api/v1/auth/logout` | 登出 |
### 2. 檔案管理
| # | Method | Path | 說明 |
|---|--------|------|------|
| 5 | GET | `/api/v1/files` | 檔案列表 |
| 6 | GET | `/api/v1/files/:uuid` | 檔案詳細資訊 |
| 7 | GET | `/api/v1/files/scan` | 掃描目錄中的新檔案 |
| 8 | POST | `/api/v1/files/register` | 註冊檔案 |
| 9 | POST | `/api/v1/unregister` | 取消註冊檔案 |
| 10 | GET | `/api/v1/files/:file_uuid/probe` | 探測檔案資訊ffprobe |
| 11 | POST | `/api/v1/files/:file_uuid/process` | 啟動處理 pipeline |
| 12 | GET | `/api/v1/assets/:uuid/status` | 資產處理狀態 |
| 13 | GET | `/api/v1/progress/:uuid` | 處理進度查詢 |
| 14 | GET | `/api/v1/videos/:uuid/details` | 影片詳細資料(含 chunks/pre_chunks |
| 15 | GET | `/api/v1/videos/:uuid/pre_chunks` | 影片 pre_chunks 列表 |
| 16 | DELETE | `/api/v1/videos/:uuid` | 刪除影片 |
### 3. 任務與佇列
| # | Method | Path | 說明 |
|---|--------|------|------|
| 17 | GET | `/api/v1/jobs` | 任務列表 |
| 18 | GET | `/api/v1/jobs/:job_id` | 任務狀態 |
| 19 | GET | `/api/v1/rules/:rule/status` | Rule 處理狀態 |
### 4. 搜尋
| # | Method | Path | 說明 |
|---|--------|------|------|
| 20 | POST | `/api/v1/search` | 全文搜尋 |
| 21 | POST | `/api/v1/search/hybrid` | 混合搜尋(向量 + BM25 |
| 22 | POST | `/api/v1/search/bm25` | BM25 全文檢索 |
| 23 | POST | `/api/v1/search/universal` | 通用搜尋 |
| 24 | POST | `/api/v1/smart` | 智慧搜尋(多輪對話) |
| 25 | POST | `/api/v1/search/visual` | 視覺搜尋 |
| 26 | POST | `/api/v1/search/visual/class` | 視覺分類搜尋(依物件類別) |
| 27 | POST | `/api/v1/search/visual/density` | 視覺密度搜尋 |
| 28 | POST | `/api/v1/search/visual/stats` | 視覺統計 |
| 29 | POST | `/api/v1/search/visual/combination` | 視覺組合搜尋 |
| 30 | POST | `/api/v1/search/frames` | 影格搜尋 |
| 31 | GET | `/api/v1/search/persons` | 人物搜尋 |
| 32 | GET | `/api/v1/lookup` | UUID 查詢 |
### 5. 身份Identity
| # | Method | Path | 說明 |
|---|--------|------|------|
| 33 | GET | `/api/v1/identities` | 身份列表 |
| 34 | GET | `/api/v1/identities/:uuid` | 身份詳細資訊 |
| 35 | GET | `/api/v1/identities/:uuid/files` | 身份相關檔案 |
| 36 | GET | `/api/v1/identities/:uuid/chunks` | 身份相關 chunks |
| 37 | POST | `/api/v1/identities/bind` | 綁定身份 |
| 38 | POST | `/api/v1/identities/unbind` | 解除綁定 |
| 39 | POST | `/api/v1/identities/suggest-av` | 建議音視綁定 |
| 40 | POST | `/api/v1/identities/from-face` | 從臉部建立身份 |
| 41 | POST | `/api/v1/identities/from-person` | 從人物建立身份 |
| 42 | GET | `/api/v1/identity/:binding_type/:binding_value` | 依 binding 查詢身份 |
### 6. 臉部Face
| # | Method | Path | 說明 |
|---|--------|------|------|
| 43 | GET | `/api/v1/faces/candidates` | 臉部候選列表 |
| 44 | POST | `/api/v1/face/recognize` | 臉部辨識 |
| 45 | POST | `/api/v1/face/register` | 註冊臉部 |
| 46 | POST | `/api/v1/face/search` | 臉部搜尋 |
| 47 | GET | `/api/v1/face/list` | 臉部列表 |
| 48 | GET | `/api/v1/face/results/:file_uuid` | 臉部辨識結果 |
| 49 | GET | `/api/v1/files/:file_uuid/faces/:face_id` | 臉部詳細資訊 |
| 50 | DELETE | `/api/v1/files/:file_uuid/faces/:face_id` | 刪除臉部 |
| 51 | GET | `/api/v1/files/:file_uuid/faces/:face_id/thumbnail` | 臉部縮圖 |
### 7. 信號Signal
| # | Method | Path | 說明 |
|---|--------|------|------|
| 52 | GET | `/api/v1/signals/unbound` | 未綁定信號列表 |
| 53 | GET | `/api/v1/signals/:uuid/:binding_type/:binding_value/timeline` | 信號時間軸 |
### 8. 檔案身份關聯
| # | Method | Path | 說明 |
|---|--------|------|------|
| 54 | GET | `/api/v1/files/:uuid/identities` | 檔案的身份列表 |
### 9. 快照Snapshot
| # | Method | Path | 說明 |
|---|--------|------|------|
| 55 | GET | `/api/v1/files/:uuid/snapshots` | 取得檔案快照 |
| 56 | POST | `/api/v1/files/:uuid/snapshots` | 產生檔案快照 |
| 57 | GET | `/api/v1/files/:uuid/snapshots/status` | 快照處理狀態 |
| 58 | POST | `/api/v1/files/:uuid/snapshots/migrate` | 遷移快照 |
| 59 | POST | `/api/v1/files/:uuid/snapshots/teardown` | 刪除快照 |
| 60 | GET | `/api/v1/identities/:uuid/snapshots` | 取得身份快照 |
| 61 | POST | `/api/v1/identities/:uuid/snapshots` | 產生身份快照 |
### 10. Agent
| # | Method | Path | 說明 |
|---|--------|------|------|
| 62 | POST | `/api/v1/agents/translate` | 翻譯 Agent |
| 63 | POST | `/api/v1/agents/identity/analyze` | 身份分析 Agent |
| 64 | POST | `/api/v1/agents/identity/suggest` | 身份合併建議 |
| 65 | GET | `/api/v1/agents/identity/status` | 身份 Agent 狀態 |
| 66 | POST | `/api/v1/agents/suggest/clustering` | 聚類建議 |
| 67 | POST | `/api/v1/agents/suggest/merge` | 合併建議 |
| 68 | POST | `/api/v1/agents/5w1h/analyze` | 5W1H 分析 |
| 69 | POST | `/api/v1/agents/5w1h/batch` | 5W1H 批量分析 |
| 70 | GET | `/api/v1/agents/5w1h/status` | 5W1H 狀態 |
### 11. 資源Resource
| # | Method | Path | 說明 |
|---|--------|------|------|
| 71 | POST | `/api/v1/resources/register` | 註冊資源 |
| 72 | POST | `/api/v1/resources/heartbeat` | 資源心跳 |
| 73 | GET | `/api/v1/resources` | 資源列表 |
### 12. 統計與設定
| # | Method | Path | 說明 |
|---|--------|------|------|
| 74 | GET | `/api/v1/stats/ingest` | 攝取統計 |
| 75 | GET | `/api/v1/stats/sftpgo` | SFTPGo 狀態 |
| 76 | GET | `/api/v1/stats/inference` | 推理健康狀態 |
| 77 | POST | `/api/v1/config/cache` | 快取切換 |
---
## 端點範例
### GET /health
```bash
curl http://localhost:3002/health
```
```json
{
"status": "ok",
"version": "1.0.0 (build: ...)",
"uptime_ms": 189049
}
```
### POST /api/v1/files/register
```bash
curl -X POST http://localhost:3002/api/v1/files/register \
-H "Content-Type: application/json" \
-H "X-API-Key: <your_api_key>" \
-d '{"file_path": "/path/to/video.mp4"}'
```
```json
{
"success": true,
"file_uuid": "384b0ff44aaaa1f14cb2cd63b3fea966",
"file_name": "video.mp4",
"duration": 120.5,
"width": 1920,
"height": 1080,
"fps": 30.0
}
```
### POST /api/v1/search
```bash
curl -X POST http://localhost:3002/api/v1/search \
-H "Content-Type: application/json" \
-H "X-API-Key: <your_api_key>" \
-d '{"query": "關鍵字", "uuid": "<file_uuid>"}'
```
```json
{
"results": [
{
"chunk_id": "chunk_42",
"text": "轉錄文字內容",
"start_time": 12.5,
"end_time": 15.3,
"score": 0.89
}
],
"total": 1
}
```
### GET /api/v1/progress/:uuid
```bash
curl http://localhost:3002/api/v1/progress/<file_uuid> \
-H "X-API-Key: <your_api_key>"
```
```json
{
"uuid": "<file_uuid>",
"overall_progress": 65,
"processors": [
{"name": "cut", "status": "completed", "progress": 100},
{"name": "asr", "status": "running", "progress": 50},
{"name": "yolo", "status": "pending", "progress": 0}
]
}
```
### POST /api/v1/identities/bind
```bash
curl -X POST http://localhost:3002/api/v1/identities/bind \
-H "Content-Type: application/json" \
-H "X-API-Key: <your_api_key>" \
-d '{"identity_id": 1, "binding_type": "face", "binding_value": "<face_id>"}'
```
```json
{
"success": true,
"message": "Bound face '<face_id>' to Identity '<name>'"
}
```
### GET /api/v1/files/:file_uuid/faces/:face_id/thumbnail
```bash
curl -o thumbnail.jpg http://localhost:3002/api/v1/files/<file_uuid>/faces/<face_id>/thumbnail \
-H "X-API-Key: <your_api_key>"
```
回傳 JPEG 二進位資料。
### GET /api/v1/identities
```bash
curl "http://localhost:3002/api/v1/identities?page=1&page_size=20" \
-H "X-API-Key: <your_api_key>"
```
```json
{
"identities": [
{"id": 1, "name": "張三", "binding_count": 5}
],
"count": 15
}
```
---
## 常見錯誤
| HTTP 狀態 | 原因 | 解決方式 |
|-----------|------|----------|
| 401 | 缺少或無效的 API key | 確認 header `X-API-Key` 已設定 |
| 400 | 請求參數錯誤 | 檢查必要欄位是否遺漏 |
| 404 | 資源不存在 | 確認 file_uuid / identity_id 是否正確 |
| 500 | 伺服器內部錯誤 | 聯繫系統管理員 |
---
## 重要備註
- `/:uuid``/:file_uuid` 均為 32 碼 hex string
- Process 為非同步操作,完成後需透過 Progress 端點輪詢
- 搜尋端點回傳結果包含 `score`0.0~1.0),越高越相關
- 臉部縮圖端點回傳 JPEG binary非 JSON

View File

@@ -0,0 +1,43 @@
# Release Plan v0.1.0 (2026-05-08)
## Status Summary
### ✅ Completed
| Item | Detail | Time |
|------|--------|------|
| Output JSON rsync (3.8GB) | `rsync` from M5 → M4 output_dev | ~30s |
| Qdrant face vectors (4873 pts) | Export scroll → curl upsert to M4 | ~10s |
| EmbeddingGemma server | M4 port 11436 running (Python MPS) | — |
| Dev server | M4 port 3003 running | — |
| Portal | `embedQuery()` retry client (M5→M4 fallback) | — |
| Git remote | `git remote add m5` configured | — |
### ❌ Issues Found
| Issue | Detail |
|-------|--------|
| **UUID mismatch** | Same Charade video: M5=`3abeee...`, M4=`aeed71...` |
| **pg_dump ID conflict** | COPY commands use absolute IDs that collide with M4's existing rows |
| **`\restrict`** | PostgreSQL 18 pg_dump adds `\restrict` command that M4's psql rejects |
| **Face detections (108K) not imported** | ID collision with existing M4 face_detection rows |
| **Identities (2810) not imported** | ID collision with existing M4 identity rows |
| **Text Qdrant vectors** | 0 points (waiting for M5 5W1H+ completion) |
### Next Steps
| Priority | Action | Owner |
|----------|--------|-------|
| 1 | M5 完成 5W1H+ pipeline~9h from 2026-05-07 23:33 | M5 |
| 2 | M5 用 export/import script 產出 tar.gz不含 JSON只 DB | M5 |
| 3 | M4 import identities + face_detectionsON CONFLICT | M4 |
| 4 | M5 vectorize → text Qdrant (768D) | M5 |
| 5 | M4 sync text Qdrant | M4 |
| 6 | Restart dev server → verify search | M4 |
| 7 | Release binary + tag | M4+M5 |
### Rollback
- Current M4 dev schema is **preserved** (36 videos, 18585 face dets, 41 identities)
- M5 data imported alongside existing data (different UUIDs)
- Qdrant face points upserted (5929 → 6643, additive)
- Output JSONs co-exist by UUID

View File

@@ -0,0 +1,171 @@
---
document_type: "report"
service: "MOMENTRY_CORE"
title: "Release V1.0.0 詳細測試報告"
date: "2026-04-30"
version: "V1.0"
status: "completed"
owner: "Warren"
created_by: "OpenCode"
tags:
- "release"
- "test-process"
- "v1.0.0"
- "production"
- "schema-migration"
- "debug-log"
- "regression-test"
ai_query_hints:
- "Release V1.0.0 詳細測試過程"
- "V1.0.0 Schema Migration 紀錄"
- "V1.0.0 API Bug 修復紀錄"
- "Release 時發現的資料庫問題與修復方法"
- "identity_bindings 表格的 schema 升級過程"
- "probe_json JSONB 型別錯誤的修正過程"
- "deprecation verification 確認舊 API 已移除"
related_documents:
- "API_V1.0.0/MOMENTRY_CORE_API_V1.0.0.md"
- "STANDARDS/DOCS_STANDARD.md"
- "API_V1.0.0/PRODUCTION_VERIFICATION_V1.0.0.md"
- "API_V1.0.0/RELEASE_VERIFICATION_V1.0.0.md"
- "API_V1.0.0/MOMENTRY_CORE_API_V1.0.0.md"
---
# Release V1.0.0 詳細測試報告
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-30 |
| 文件版本 | V1.1 (Detailed) |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-04-30 | 初始發布報告 | OpenCode | OpenCode |
| V1.1 | 2026-04-30 | 補充詳細測試步驟與除錯過程 | OpenCode | OpenCode |
---
## 關鍵術語定義
| 術語 | 定義 |
|------|------|
| Schema Migration | 資料庫結構升級,確保與 V4.0 程式碼一致 |
| identity_bindings | 身份綁定資料表,記錄 face/speaker 與 identity 的關聯 |
| JSONB | PostgreSQL 的二進位 JSON 格式,用於儲存 probe_json |
| Unique Index | 資料庫唯一性約束,用於支援 ON CONFLICT 邏輯 |
| orphan record | 孤立紀錄,外鍵指向不存在的父紀錄 |
| deprecation verification | 確認舊版端點已移除的測試 |
## 1. 概述
本報告紀錄 **Momentry Core V1.0.0** 的部署過程與詳細測試結果。本次 Release 不僅包含程式碼更新(移除過時 API、修復 `probe_json` 型別錯誤),還涉及 `public` 資料庫的結構調整Schema Migration
### 1.1 測試環境
* **Production (Port 3002)**: 目標部署環境。
* **Development (Port 3003)**: 用於預先驗證修復方案。
* **Database**: PostgreSQL (`public` schema).
---
## 2. Schema Migration 與資料修復
在將 Production Binary 切換至 3002 並執行測試時,發現 `public` schema 的部分表格結構仍為舊版,導致 API 報錯。以下是發現問題與修復的詳細過程。
### 2.1 問題發現Identity 綁定失敗
* **測試端點**: `POST /api/v1/identities/bind`
* **錯誤訊息**: `error returned from database: column "identity_type" of relation "identity_bindings" does not exist`
* **根因分析**: 程式碼已升級至 V4.0 邏輯,預期 `identity_bindings` 表格擁有 `identity_type``identity_value` 欄位,但 Production DB 仍使用舊版欄位 (`binding_type`, `uuid`)。
### 2.2 Migration 執行過程
我們執行了一系列 SQL 指令以升級表格結構並清洗資料:
1. **欄位新增與資料轉移**:
```sql
ALTER TABLE public.identity_bindings
ADD COLUMN IF NOT EXISTS identity_type VARCHAR(32),
ADD COLUMN IF NOT EXISTS identity_value VARCHAR(255),
...;
UPDATE public.identity_bindings
SET identity_type = binding_type, identity_value = binding_value;
```
2. **孤立紀錄清理 (Orphan Records)**:
發現舊版 Foreign Key 指向的資料在新架構下無效。
* *動作*: 刪除 2 筆 `identity_id` 不存在於 `public.identities` 中的紀錄。
* *結果*: `DELETE 2`。
3. **索引重建 (Index Reconstruction)**:
* *錯誤*: 建立 FK 失敗,因舊 FK 名稱衝突。
* *修正*: 移除舊 FK重新建立指向 `public.identities(id)` 的新約束。
* *優化*: 建立 Unique Index `(identity_id, identity_type, identity_value)` 以支援 `ON CONFLICT` 邏輯。
4. **舊欄位移除**: 成功移除 `uuid`, `binding_type`, `binding_value`。
### 2.3 問題發現Identity Bind 缺少 Unique 約束
* **錯誤訊息**: `error returned from database: there is no unique or exclusion constraint matching the ON CONFLICT specification`
* **原因**: Rust 程式碼在 Insert 時使用了 `ON CONFLICT (identity_id, identity_type, identity_value)`,但表格上僅有 Primary Key缺乏相對應的 Unique Index。
* **修正**: 執行 `CREATE UNIQUE INDEX identity_bindings_talent_id_identity_type_identity_value_key ...`。
---
## 3. API 詳細測試紀錄
以下為修復完成後的端對端測試結果。
### 3.1 核心系統測試 (System Core)
| 步驟 | API Endpoint | 輸入資料 (Input) | 預期結果 | 實際回應 (Actual Response) | 狀態 |
| :--- | :--- | :--- | :--- | :--- | :--- |
| **1** | `GET /health` | - | Version: 1.0.0 | `{"status":"ok", "version":"1.0.0 (build: ...)"}` | ✅ **PASS** |
| **2** | `GET /api/v1/files` | `page=1` | List of Files | `{"success": true, "data": [...]}` | ✅ **PASS** |
| **3** | `GET /api/v1/files/:uuid` | `{file_uuid}` | File Detail | `{"file_uuid": "...", "probe_json": {...}}` | ✅ **PASS** |
### 3.2 關鍵修復驗證 (Critical Fixes)
此區塊專門驗證本次 Release 中修復的資料庫問題。
| 步驟 | API Endpoint | 測試情境 | 詳細過程與回應 | 狀態 |
| :--- | :--- | :--- | :--- | :--- |
| **4** | `POST /api/v1/files/register` | **驗證 `probe_json` JSONB 寫入** | **Payload**: `{"file_path": "/path/to/view7.mp4"}`<br>**回應**: `{"success": true, "file_uuid": "e79890..."}`<br>**驗證**: DB 內 `probe_json` 欄位正確儲存 JSON 物件而非字串。 | ✅ **PASS** |
| **5** | `POST /api/v1/identities/bind` | **驗證 Schema Migration** | **Payload**: `{"identity_id": 2, "binding_type": "face", "binding_value": "test"}`<br>**回應**: `{"success": true, "message": "Bound face 'test' to Identity 'Audrey Hepburn'"}`<br>**驗證**: 成功寫入 V4.0 格式的 `identity_bindings` 表格。 | ✅ **PASS** |
### 3.3 過時 API 移除驗證 (Deprecation Verification)
確保舊版端點已正確移除,不會造成混淆。
| API Endpoint | 測試動作 | 預期結果 | 實際結果 | 狀態 |
| :--- | :--- | :--- | :--- | :--- |
| `POST /api/v1/register` (Legacy) | POST Request | Status: 404 | Status: 404 Not Found | ✅ **PASS** |
| `POST /api/v1/probe` (Legacy) | POST Request | Status: 404 | Status: 404 Not Found | ✅ **PASS** |
| `GET /api/v1/videos` (Legacy List)| GET Request | Status: 404 | Status: 404 Not Found | ✅ **PASS** |
---
## 4. 錯誤日誌與除錯 (Logs & Debug)
在測試過程中捕獲的關鍵 Log 紀錄:
* **[FIXED]** `column "probe_json" is of type jsonb but expression is of type text`
* *發生時機*: 初次測試 Register API。
* *解法*: 修正 `postgres_db.rs` 中 `register_video` 的 bind 邏輯,確保 Rust 傳入型別與 SQLx 預期一致。
* **[FIXED]** `column "identity_type" of relation "identity_bindings" does not exist`
* *發生時機*: 初次測試 Bind API。
* *解法*: 執行上述 2.2 節的 Schema Migration。
* **[FIXED]** `there is no unique or exclusion constraint matching the ON CONFLICT specification`
* *發生時機*: 第二次測試 Bind API (Insert 時)。
* *解法*: 建立對應的 Unique Index。
---
## 5. 結論
Release V1.0.0 **部署成功**
雖然在 Production 環境遇到了 Schema 版本不一致的挑戰,但透過詳細的測試過程與即時修復,系統目前已穩定運行於 V1.0.0 標準。所有核心功能(檔案、搜尋、身份綁定)均已驗證通過。

View File

@@ -0,0 +1,316 @@
---
document_type: "report"
service: "MOMENTRY_CORE"
title: "Release V1.0.0 Production 驗證報告"
date: "2026-05-01"
version: "V1.0"
status: "completed"
owner: "Warren"
created_by: "OpenCode"
tags:
- "release"
- "verification"
- "v1.0.0"
- "api-test"
- "production"
- "wipe-and-replace"
- "deployment-log"
ai_query_hints:
- "V1.0.0 Release 驗證結果"
- "Production 3002 API 測試紀錄"
- "Wipe & Replace 部署策略的執行細節"
- "所有 core API 在 production 的實際 curl 測試結果"
- "identity bind API 的端對端驗證"
- "search API 的 production 測試結果"
- "deployment 過程中的 schema 修復項目"
related_documents:
- "API_V1.0.0/MOMENTRY_CORE_API_V1.0.0.md"
- "API_V1.0.0/RELEASE_TEST_REPORT_v1.0.0.md"
- "API_V1.0.0/PRODUCTION_VERIFICATION_V1.0.0.md"
- "API_V1.0.0/RELEASE_API_REFERENCE_v1.0.0.md"
---
# Release V1.0.0 Production 驗證報告
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-05-01 |
| 文件版本 | V2.0 (Final) |
| 測試環境 | Production Port 3002 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-05-01 | 初始版本 | OpenCode | deepseek-chat |
| V2.0 | 2026-05-07 | 新增 Pipeline 更新驗證EmbeddingGemma、5W1H+、Identity Agent、Progress v2 | OpenCode | deepseek-chat |
---
## 關鍵術語定義
| 術語 | 定義 |
|------|------|
| Wipe & Replace | 部署策略:清除 production schema 後以 dev schema 完整替換 |
| pgvector | PostgreSQL 向量擴展,用於儲存與檢索 embedding |
| 32 碼 UUID | 以 SHA256 前 32 字元作為 file_uuid 的識別規範 |
| identity_embedding | identities 表中的人物向量嵌入欄位 |
| face_embedding | identities 表中的人臉向量嵌入欄位 |
| voice_embedding | identities 表中的語音向量嵌入欄位 |
## 1. 部署紀實 (Deployment Log)
本次部署採用 **Wipe & Replace** 策略,確保 Production 環境與 Dev 完全一致。
1. **停止服務**: 成功停止 Port 3002 程序。
2. **資料覆蓋**: 將 `dev` schema 完整導出並替換 `public` schema解決了 16 碼 UUID 遺留問題。
3. **架構修復**:
* 安裝 `pgvector` 擴展。
*`identities` 表格補齊 `identity_embedding`, `face_embedding`, `voice_embedding` 欄位。
4. **部署 Binary**: 替換為 `momentry 1.0.0` 版本。
---
## 2. API 端對端測試紀錄
以下紀錄皆為 Production (3002) 環境的實際 `curl` 測試結果。
### 2.1 系統與認證 (System & Auth)
#### `GET /health`
```bash
curl http://localhost:3002/health
```
**結果**: ✅ **200 OK**
```json
{
"status": "ok",
"version": "1.0.0 (build: 2026-05-01 00:32:07)",
"uptime_ms": 189049
}
```
---
### 2.2 檔案管理 (File Management)
#### `GET /api/v1/files` (列表)
```bash
curl -H "X-API-Key: muser_test_001" "http://localhost:3002/api/v1/files?page=1&page_size=1"
```
**結果**: ✅ **200 OK**
```json
{
"success": true,
"data": [
{
"file_uuid": "53e3a229bf68878b7a799e811e097f9c",
"file_name": "view15.mp4",
...
}
]
}
```
*驗證*: `file_uuid` 長度為 32 碼,符合 V1.0.0 規範。
#### `GET /api/v1/files/:uuid` (詳情)
```bash
curl -H "X-API-Key: muser_test_001" "http://localhost:3002/api/v1/files/53e3a229bf68878b7a799e811e097f9c"
```
**結果**: ✅ **200 OK**
```json
{
"success": true,
"file_uuid": "53e3a229bf68878b7a799e811e097f9c",
"metadata": {
"format": { "duration": "12.012000", ... }
}
}
```
---
### 2.3 搜尋 (Search)
#### `POST /api/v1/search`
```bash
curl -X POST -H "X-API-Key: muser_test_001" -H "Content-Type: application/json" \
-d '{"query":"test", "uuid":"53e3a229bf68878b7a799e811e097f9c"}' \
"http://localhost:3002/api/v1/search"
```
**結果**: ✅ **200 OK**
```json
{
"results": [],
"query": "test"
}
```
#### `POST /api/v1/search/visual/class`
```bash
curl -X POST -H "X-API-Key: muser_test_001" -H "Content-Type: application/json" \
-d '{"uuid":"53e3a229bf68878b7a799e811e097f9c", "object_class":"person"}' \
"http://localhost:3002/api/v1/search/visual/class"
```
**結果**: ✅ **200 OK**
```json
{
"chunks": [],
"total": 0
}
```
---
### 2.4 身份與人物 (Identity)
#### `GET /api/v1/identities`
```bash
curl -H "X-API-Key: muser_test_001" "http://localhost:3002/api/v1/identities?page=1&page_size=2"
```
**結果**: ✅ **200 OK**
```json
{
"identities": [
{"id": 22, "name": "Trace 2 Fixed Format", ...},
{"id": 21, "name": "Trace 2 High Confidence Person", ...}
],
"count": 15
}
```
#### `POST /api/v1/identities/bind` (關鍵修復驗證)
```bash
curl -X POST -H "X-API-Key: muser_test_001" -H "Content-Type: application/json" \
-d '{"identity_id": 22, "binding_type": "face", "binding_value": "release_test_final_success"}' \
"http://localhost:3002/api/v1/identities/bind"
```
**結果**: ✅ **200 OK**
```json
{
"success": true,
"message": "Bound face 'release_test_final_success' to Identity 'Trace 2 Fixed Format'"
}
```
---
### 2.5 任務與進度 (Jobs)
#### `GET /api/v1/progress/:uuid`
```bash
curl -H "X-API-Key: muser_test_001" "http://localhost:3002/api/v1/progress/53e3a229bf68878b7a799e811e097f9c"
```
**結果**: ✅ **200 OK**
```json
{
"uuid": "53e3a229bf68878b7a799e811e097f9c",
"overall_progress": 0,
"processors": [{"name": "asr", "status": "pending"}, ...]
}
```
---
## 3. Pipeline 自動化與代理修正驗證2026-05-07
### 3.1 EmbeddingGemma 300M 向量化
| 項目 | 內容 |
|------|------|
| 模型 | EmbeddingGemma 300MGoogle 官方) |
| 維度 | 768-D |
| 部署方式 | Python MPS ServerMetal GPU, port 11436 |
| API 格式 | OpenAI-compatible `{base_url}/v1/embeddings` |
| 平均延遲 | ~10ms per call |
| 多語支援 | ✅ 中英雙語 |
| 取代模型 | mxbai-embed-largeEnglish only, 1024D, ANE CoreML, port 11435 — 已棄用) |
**驗證**: ✅ 向量化成功768-D 向量正確寫入 Qdrant `momentry_dev_rule1` / `momentry_dev_chunk_summaries`,中英文 query 皆可召回。
---
### 3.2 5W1H+ 遞迴摘要 Agent
採用方案 B遞迴式 context每段 scene 帶入前情摘要:
```
Scene 1 → LLM(context="") → summary_1
Scene 2 → LLM(context=summary_1) → summary_2
Scene N → LLM(context=recent_summaries_~500_tokens) → summary_N
```
| 項目 | 內容 |
|------|------|
| Context 策略 | 保留最近 ~500 tokens 前情(按 token 數 truncate |
| Prompt 額外資訊 | Face trace何人出場、Active speaker誰在說話、YOLO objects畫面物體 |
| 總 input tokens | ~500K721 scenes |
| 預估執行時間 | ~12-25 分鐘Gemma4 26B |
| 實作位置 | `src/api/five_w1h_agent_api.rs` |
**驗證**: ✅ 5W1H 摘要依序產出context accumulator 正確傳遞face trace / speaker / YOLO 資訊正確填入 prompt。
---
### 3.3 Identity Agent 自動觸發P3修復
| 項目 | 內容 |
|------|------|
| Pipeline 位置 | Processors → Rule 1 → Rule 3 → Face Trace → Qdrant Sync → TMDb → **P3 Identity Agent** → P4 |
| 先前狀態 | ❌ stub只 log "started",未呼叫 `match_faces_iterative` |
| 修正後 | ✅ 實際呼叫 `match_faces_iterative`,進行 face→identity binding |
| 驗證 | ✅ Pipeline 完成後file_identities 表中正確建立 identity 綁定 |
---
### 3.4 5W1H Agent 自動觸發P4修復
| 項目 | 內容 |
|------|------|
| Pipeline 位置 | P3 完成後 → **P4 5W1H Agent** |
| 先前狀態 | ❌ stubsleep 30s 後 log "started",未呼叫 API |
| 修正後 | ✅ 實際呼叫 `five_w1h` API進行遞迴式 5W1H 摘要 |
| 驗證 | ✅ 每段 scene 的 5W1H 摘要正確產出context 含前情摘要 |
---
### 3.5 Pipeline Bug Fixes
| 修復項目 | 說明 | 狀態 |
|----------|------|------|
| sweep_stale | 重設 stuck processor → Pending避免永久停滯 | ✅ |
| kill_existing_processor | 啟動前終止已存在的同名 processor防止重複執行 | ✅ |
| 保留 partial output on timeout | Timeout 時保留已產出的 partial 結果,不丟棄 | ✅ |
| Temporal collision QC | 修正時間軸碰撞導致 chunk 重疊或遺漏 | ✅ |
| any_pending / any_skipped checks | 完善 pipeline 狀態檢查邏輯,避免錯誤轉換 | ✅ |
---
### 3.6 Progress Report Template v2
| 版本 | 內容 | 狀態 |
|------|------|------|
| v1 | 原始模板:僅 7 processors + 基本狀態 | — |
| **v2** | ✅ 新增ANE vectorize、TMDb face match、Identity Agent、5W1H Agent 進度報告 | ✅ 已實裝 |
**驗證**: ✅ `GET /api/v1/progress/:uuid` 回傳 v2 格式,包含所有 pipeline 階段狀態processors → vectorize → TMDb → Identity Agent → 5W1H Agent
---
## 4. 最終驗證結論
**Release V1.0.0 部署成功Pipeline 已完整自動化。**
1. **環境一致性**: 透過 Wipe & ReplaceProduction 資料庫已完全清除 16 碼 UUID所有資料均為 32 碼。
2. **Schema 完整性**: 成功補齊 `pgvector` 擴展與 `identities` 向量欄位,解決了 Bind API 的資料庫錯誤。
3. **功能驗證**: 所有核心 API (Files, Search, Identity, Progress) 均回應 `200 OK`,且資料格式正確。
4. **EmbeddingGemma 300M** 取代 mxbai-embed-large多語支援完備768-D 向量維度一致。
5. **5W1H+ Agent** 採用遞迴式 contextstory so farprompt 包含 face trace / speaker / YOLO 資訊。
6. **Identity AgentP3****5W1H AgentP4** 已從 stub 修正為實際執行pipeline 全自動。
7. **Progress Report** 更新至 v2涵蓋所有 pipeline 階段狀態。
8. **6 項 bug fixes** 全部驗證通過sweep_stale、kill_existing_processor、partial output、temporal collision QC、any_pending、any_skipped
Marcom 團隊可依據 `MOMENTRY_CORE_API_V1.0.0.md` 開始進行前端開發。

View File

@@ -0,0 +1,255 @@
# Trace API v1.0.0 Reference — M5 Official
**Author**: M5
**Date**: 2026-05-07
**Status**: ✅ Production — implemented and verified on Charade (Job 255)
---
## Design Philosophy
> 可以追蹤的 trace 就像雷達看到的物體 — 都可以分析。
A **trace** is any entity detected and tracked across consecutive frames:
```
Detection → Grouping (tracking) → Trace → Analysis → Identity Binding
```
### Coordinate System: 2D+time (current), 3D+time (future)
| Dimension | Current (Face) | Future (Object/Pose) |
|-----------|---------------|---------------------|
| x, y | Bbox center (image plane) | Bbox center (world space) |
| w, h | Bbox size (image plane) | Bbox size (world space) |
| t | Frame number / timestamp | Frame number / timestamp |
Future: 3D bounding cube `[x, y, z, w, h, d, t]` with camera-relative analysis, camera trace (observer), and light source trace (illuminator). See design discussion in `M4_workspace/TRACE_API_REFERENCE_V1.0.0.md`.
---
## Base URL
```
http://localhost:{port}/api/v1
```
Playground: port 3003 | Production: port 3002
## Authentication
All endpoints require `X-API-Key` header.
---
## Trace Model
A **trace** is a sequence of detections of the same entity across consecutive frames:
```
Identity (person) ──has_many──> Trace (tracked segment) ──has_many──> Detection (single frame)
```
| Trace Type | Detection Source | Identity Binding | Status |
|-----------|-----------------|-----------------|--------|
| `face` | Face detector (Vision + FaceNet) | `face_detections.identity_id``identities` | ✅ Implemented |
| `object` | YOLO pre_chunks by class label | By object class name | 🔜 Future (needs tracking) |
| `pose` | Pose skeleton keypoints | TBD | 🔜 Future |
### YOLO Object Trace (Future)
YOLO produces frame-level detections with class labels but **no tracking ID**. To enable:
1. Add IoU tracking (SORT) across frames
2. Assign `trace_id` per group, store in `pre_chunks` or new `yolo_traces` table
3. Add routes: `POST /object_trace/sortby`, `GET /object_trace/:id/detections`
---
## Endpoints
### 1. List Face Traces
**`POST /api/v1/file/:file_uuid/face_trace/sortby`**
Aggregated face traces with sorting and filtering.
#### Request Body
```json
{
"sort_by": "face_count | duration | first_appearance",
"limit": 100,
"min_faces": 1,
"min_confidence": 0.0,
"max_confidence": 1.0
}
```
#### Response
```json
{
"success": true,
"file_uuid": "3abeee81d94597629ed8cb943f182e94",
"total_traces": 6892,
"total_faces": 108204,
"traces": [
{
"trace_id": 1271,
"face_count": 33,
"first_frame": 68280,
"last_frame": 69240,
"first_sec": 2731.2,
"last_sec": 2769.6,
"duration_sec": 38.4,
"avg_confidence": 0.782,
"sample_face_id": "18441"
}
]
}
```
| Field | Description |
|-------|-------------|
| `trace_id` | Unique ID within the video file |
| `face_count` | Number of detections in this trace |
| `first_frame / last_frame` | Frame range |
| `first_sec / last_sec` | Time range |
| `duration_sec` | Duration in seconds |
| `avg_confidence` | Mean detection confidence |
| `sample_face_id` | ID of the highest-confidence detection |
| `identity_id` *(future)* | Bound identity ID |
| `identity_name` *(future)* | Identity display name |
---
### 2. Trace Face Detections
**`GET /api/v1/file/:file_uuid/trace/:trace_id/faces`**
#### Query Parameters
| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `limit` | int | 200 | Max faces (capped 1000) |
| `offset` | int | 0 | Pagination |
| `interpolate` | bool | false | Enable linear interpolation |
#### Response
```json
{
"success": true,
"file_uuid": "3abeee81d94597629ed8cb943f182e94",
"trace_id": 2,
"total": 2,
"faces": [
{
"id": 12400,
"start_frame": 4650,
"start_time": 186.0,
"x": 1047,
"y": 361,
"width": 187,
"height": 187,
"confidence": 0.834,
"interpolated": false
}
]
}
```
Interpolated frames: `id=0, confidence=0.0, interpolated=true`.
#### Interpolation Algorithm
Linear interpolation between consecutive detections:
```
t = (mid_frame - prev.frame) / (next.frame - prev.frame)
x = prev.x + (next.x - prev.x) * t
y = prev.y + (next.y - prev.y) * t
width = prev.w + (next.w - prev.w) * t
height = prev.h + (next.h - prev.h) * t
```
---
### 3. Trace Video Clip
**`GET /api/v1/file/:file_uuid/trace/:trace_id/video`**
MP4 video with bounding box overlay for a trace.
| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `padding` | float | 2.0 | Padding seconds before/after |
---
### 4. Bounding Box Overlay Video
**`GET /api/v1/file/:file_uuid/video/bbox`**
MP4 video segment with face bboxes.
| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `start` | int | — | Start frame (required) |
| `end` | int | — | End frame (required) |
| `duration` | float | 10 | Clip duration seconds |
---
### 5. Frame Thumbnail
**`GET /api/v1/file/:file_uuid/thumbnail`**
Single frame JPEG, with optional crop.
| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `frame` | int | — | Frame number (required) |
| `x, y, w, h` | int | — | Crop region |
---
## CLI Verification (Charade, Job 255)
```
File: Charade (1963), 25fps, 108204 faces, 6892 traces
Dev server: http://localhost:3003
Auth: X-API-Key: muser_test_apikey
```
| # | Endpoint | Request | M5 Result |
|---|----------|---------|-----------|
| 1 | `POST /face_trace/sortby` | `{"limit":2}` | 6892 traces, 108204 faces |
| 2 | `POST /face_trace/sortby` | `{"sort_by":"face_count","limit":3}"` | #1271=33, #2171=26, #1268=24 faces |
| 3 | `POST /face_trace/sortby` | `{"sort_by":"duration","limit":3}` | Longest 38.4s, 30.0s, 27.6s |
| 4 | `POST /face_trace/sortby` | `{"min_faces":10,"min_confidence":0.7}` | Filtered traces |
| 5 | `GET /trace/2/faces` | `?limit=5` | 1 face: frame 4620 |
| 6 | `GET /trace/2/faces` | `?limit=100&interpolate=true` | 31 frames (2 real + 29 interpolated) |
| 7 | `GET /trace/1271/faces` | `?limit=2` | 33 total, paginated |
| 8 | `GET /trace/1271/faces` | `?limit=10&interpolate=true` | 271 frames |
| 9 | `GET /trace/2/video` | — | 2.0MB MP4 |
| 10 | `GET /video/bbox` | `?start=4650&end=4680` | 1.9MB MP4 overlay |
| 11 | `GET /thumbnail` | `?frame=4650` | 82KB JPEG |
---
## Source Files
| File | Purpose |
|------|---------|
| `src/api/trace_agent_api.rs` | Face trace listing + detail + interpolation |
| `src/api/media_api.rs` | Video clip, bbox overlay, thumbnail |
| `src/api/server.rs` | Route merge (lines 25542555) |
| `portal/src/components/FaceTraceTimeline.vue` | Frontend trace display |
## Route Pattern
Current: `/api/v1/file/:file_uuid/face_trace/...`
Future: `/api/v1/file/:file_uuid/{type}_trace/...` where `type` = `object`, `pose`, etc.
New trace types should add new modules (e.g., `object_trace_api.rs`) rather than overloading `trace_agent_api.rs`.