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
@@ -0,0 +1,215 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "API Key Management System Architecture"
date: "2026-03-20"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "api-key"
- "security"
- "authentication"
- "architecture"
ai_query_hints:
- "API Key 管理系統架構是什麼?"
- "如何設計 API Key 驗證流程?"
- "API Key 異常檢測機制如何運作?"
---
# API Key Management System Architecture
## System Overview
```
┌─────────────────────────────────────────────────────────────────────────────────┐
│ API Key Management System │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ CLI │ │ HTTP API │ │ Service │ │ External │ │
│ │ Layer │────▶│ Layer │────▶│ Layer │────▶│ Services │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ Core Modules │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Service │ │Validator│ │ Anomaly │ │Rotation │ │ Cleanup │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Webhook │ │Encrypt │ │Blacklist│ │ Report │ │ Error │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ PostgreSQL │ │ Redis │ │ External │ │
│ │ (Storage) │ │ (Cache) │ │ (Gitea/n8n)│ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
```
## Module Dependencies
```
┌──────────────┐
│ models.rs │
│ (Types) │
└──────┬───────┘
┌──────────────────┼──────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ service.rs │ │ error.rs │ │ validator.rs │
│ (Core CRUD) │ │ (Errors) │ │ (Cache+Rate) │
└───────┬───────┘ └───────────────┘ └───────────────┘
│ ┌───────────────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ anomaly.rs │ │ rotation.rs │ │ blacklist.rs │
│ (Detection) │ │ (Rotation) │ │ (IP Block) │
└───────────────┘ └───────────────┘ └───────────────┘
```
## Request Flow
```
Client Request
┌─────────────┐
│ CLI/API │
└──────┬──────┘
┌─────────────┐ ┌─────────────┐
│ Rate Limit │────▶│ IP Blacklist│
│ Check │ │ Check │
└──────┬──────┘ └──────┬──────┘
│ │
└─────────┬─────────┘
┌───────────────┐
│ Hash API Key │
└───────┬───────┘
┌───────────────┐ ┌───────────────┐
│ Cache Lookup │────▶│ PostgreSQL │
└───────┬───────┘ │ Lookup │
│ └───────┬───────┘
│ │
└──────────┬──────────┘
┌───────────────┐
│ Validate │
│ (Status, │
│ Expiry) │
└───────┬───────┘
┌─────────────┼─────────────┐
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Valid │ │ Invalid │ │ Error │
│ Response│ │ Response │ │ Response │
└──────────┘ └──────────┘ └──────────┘
```
## Database Schema
```
┌─────────────────────────────────────────────────────────────────┐
│ PostgreSQL │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ api_keys │ │ api_key_audit_ │ │
│ ├─────────────────┤ │ log │ │
│ │ id │ ├─────────────────┤ │
│ │ key_id │─────▶│ id │ │
│ │ key_hash │ │ key_id (FK) │ │
│ │ name │ │ action │ │
│ │ key_type │ │ ip_address │ │
│ │ status │ │ details │ │
│ │ expires_at │ └─────────────────┘ │
│ │ ... │ │
│ └─────────────────┘ ┌─────────────────┐ │
│ │ api_key_anomalies│ │
│ ┌─────────────────┐ ├─────────────────┤ │
│ │ gitea_tokens │ │ id │ │
│ ├─────────────────┤ │ key_id (FK) │ │
│ │ id │ │ anomaly_type │ │
│ │ gitea_token_id │ │ severity │ │
│ │ token_name │ │ details │ │
│ │ scopes │ └─────────────────┘ │
│ └─────────────────┘ │
│ │
│ ┌─────────────────┐ │
│ │ n8n_api_keys │ │
│ ├─────────────────┤ │
│ │ id │ │
│ │ n8n_key_id │ │
│ │ label │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```
## External Integrations
```
┌─────────────────────────────────────────────────────────────────────────────────┐
│ External Integrations │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Gitea │ │ n8n │ │ Webhook │ │
│ ├─────────────────┤ ├─────────────────┤ ├─────────────────┤ │
│ │ • Create Token │ │ • Create API Key│ │ • Key Created │ │
│ │ • List Tokens │ │ • List API Keys │ │ • Key Revoked │ │
│ │ • Delete Token │ │ • Delete API Key│ │ • Anomaly │ │
│ │ • Verify Token │ │ • Verify │ │ • Rate Limited │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
```
## Security Layers
```
┌─────────────────────────────────────────────────────────────────┐
│ Security Layers │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Layer 1: Network │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • IP Blacklist │ │
│ │ • Rate Limiting │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Layer 2: Authentication │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • API Key Hash (SHA256) │ │
│ │ • Constant-time Comparison │ │
│ │ • Key Validation (Status, Expiry) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Layer 3: Monitoring │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • Anomaly Detection │ │
│ │ • Audit Logging (Encrypted) │ │
│ │ • Webhook Notifications │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```
@@ -0,0 +1,479 @@
---
document_type: "architecture_design"
service: "N8N"
title: "Momentry API 使用流程"
date: "2026-03-25"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "momentry"
- "使用流程"
ai_query_hints:
- "查詢 Momentry API 使用流程 的內容"
- "Momentry API 使用流程 的主要目的是什麼?"
- "如何操作或實施 Momentry API 使用流程?"
---
# Momentry API 使用流程
> **目標**: 從影片上傳到搜尋的完整流程
> **適用**: WordPress / n8n 整合
> **版本**: V1.0 | **日期**: 2026-03-25
---
## 流程總覽
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 1. 上傳 │ → │ 2. 註冊 │ → │ 3. 確認 │ → │ 4. 處理 │ → │ 5. 搜尋 │
│ SFTPGo │ │ 自動完成 │ │ UUID │ │ 查詢進度 │ │ 測試 │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
```
---
## Step 1: 上傳影片
### 方式 A: SFTP 上傳(推薦)
```bash
# 連線資訊
主機: sftpgo.momentry.ddns.net
連接埠: 2022
用戶名: demo
密碼: demopassword123
```
使用 FileZilla 或 SFTP 客戶端上傳到 `/` 目錄
### 方式 B: SFTP 命令列
```bash
sshpass -p "demopassword123" sftp -P 2022 demo@sftpgo.momentry.ddns.net
```
上傳後確認檔案在 SFTPGo 中的位置
---
## Step 2: 自動註冊
上傳後,系統會自動:
1. 偵測新檔案
2. 計算 UUIDSHA256
3. 建立資料庫記錄
**無需手動操作**
---
## Step 3: 確認註冊成功
### 查詢所有影片
```bash
curl -s -H "X-API-Key: YOUR_API_KEY" \
"https://api.momentry.ddns.net/api/v1/videos" | jq '.videos | length'
```
### 查詢特定檔案
```bash
curl -s -H "X-API-Key: YOUR_API_KEY" \
"https://api.momentry.ddns.net/api/v1/videos" | jq '.videos[] | select(.file_name | contains("你的檔案名"))'
```
### 預期回應
```json
{
"uuid": "952f5854b9febad1",
"file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/你的檔案.mp4",
"file_name": "你的檔案.mp4",
"duration": 123.45,
"width": 1920,
"height": 1080
}
```
**確認要點**:
- ✅ UUID 已產生(16位 hex
-`file_path` 正確
-`duration` > 0
---
## Step 4: 查詢處理進度
### 取得任務 UUID
```bash
# 從影片資訊取得 job_id
curl -s -H "X-API-Key: YOUR_API_KEY" \
"https://api.momentry.ddns.net/api/v1/videos" | \
jq '.videos[] | select(.file_name == "你的檔案.mp4") | {uuid, job_id}'
```
### 查詢任務狀態
```bash
curl -s -H "X-API-Key: YOUR_API_KEY" \
"https://api.momentry.ddns.net/api/v1/jobs/{uuid}"
```
### 任務狀態說明
| status | 說明 | 動作 |
|--------|------|------|
| `pending` | 等待處理 | 等待中 |
| `processing` | 處理中 | 繼續輪詢 |
| `completed` | 已完成 | 可進入 Step 5 |
| `failed` | 處理失敗 | 檢查錯誤 |
### n8n 輪詢範例
```javascript
// n8n Workflow: 檢查處理狀態
const jobUuid = $input.item.json.job_uuid;
const response = await fetch(
`https://api.momentry.ddns.net/api/v1/jobs/${jobUuid}`,
{
headers: {
"X-API-Key": "YOUR_API_KEY"
}
}
);
const job = await response.json();
// 狀態檢查
if (job.status === 'completed') {
return [{ json: { done: true, video_uuid: job.video_uuid } }];
} else {
return [{ json: { done: false, status: job.status } }];
}
```
---
## Step 5: 搜尋測試
處理完成後,資料會入庫到向量資料庫,可進行搜尋測試。
### 測試向量搜尋
```bash
curl -s -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": 5
}'
```
### 取得分段(Chunk)內容
搜尋結果會返回影片分段(Chunk),包含可播放的時間軸資訊:
```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
}
]
}
```
**Chunk 欄位說明**:
| 欄位 | 說明 |
|------|------|
| `uuid` | 影片 UUID(用於取得影片網址) |
| `chunk_id` | 分段 ID |
| `chunk_type` | 分段類型(sentence/cut/time/trace/story |
| `start_time` | 開始時間(秒) |
| `end_time` | 結束時間(秒) |
| `text` | 語音內容文字 |
| `score` | 相似度分數(0-1 |
### 播放分段
取得 Chunk 後可組合成播放網址:
```
影片網址?start={start_time}&end={end_time}
```
範例:
```
https://wp.momentry.ddns.net/video.mp4?start=5309.08&end=5311.08
```
---
## 完整 n8n Workflow 範例
```
┌──────────────┐
│ 觸發 (定時) │
└──────┬───────┘
┌──────────────┐ ┌──────────────┐
│ 查詢影片 │────►│ 比對新檔案 │
│ /videos │ │ │
└──────┬───────┘ └──────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ 等待處理 │◄────│ 輪詢任務狀態 │
│ /jobs/:uuid │ │ /jobs/:uuid │
└──────┬───────┘ └──────────────┘
▼ (completed)
┌──────────────┐
│ 搜尋測試 │
│ /search │
└──────────────┘
```
---
## 快速參考
| 步驟 | API | 用途 |
|------|-----|------|
| 查詢影片 | `GET /api/v1/videos` | 確認上傳成功 |
| 查詢任務 | `GET /api/v1/jobs/:uuid` | 查看處理進度 |
| 搜尋內容 | `POST /api/v1/search` | 測試搜尋功能 |
---
## WordPress PHP 範例
### 基本設定
```php
<?php
class Momentry_API {
private const API_URL = 'https://api.momentry.ddns.net';
private const API_KEY = 'YOUR_API_KEY';
public static function request(string $method, string $endpoint, ?array $data = null): array {
$url = self::API_URL . $endpoint;
$args = [
'method' => $method,
'headers' => [
'X-API-Key' => self::API_KEY,
'Content-Type' => 'application/json',
],
'timeout' => 30,
];
if ($data !== null) {
$args['body'] = json_encode($data);
}
$response = wp_remote_request($url, $args);
if (is_wp_error($response)) {
throw new Exception($response->get_error_message());
}
return json_decode(wp_remote_retrieve_body($response), true);
}
public static function getVideos(): array {
return self::request('GET', '/api/v1/videos');
}
public static function getVideo(string $uuid): array {
return self::request('GET', "/api/v1/videos/{$uuid}/details");
}
public static function getJob(string $uuid): array {
return self::request('GET', "/api/v1/jobs/{$uuid}");
}
public static function search(string $query, int $topK = 5): array {
return self::request('POST', '/api/v1/search', [
'query' => $query,
'top_k' => $topK,
]);
}
}
```
### Step 3: 確認註冊成功
```php
<?php
// 查詢所有影片
$videos = Momentry_API::getVideos();
foreach ($videos['videos'] as $video) {
echo "UUID: " . $video['uuid'] . "\n";
echo "檔案: " . $video['file_name'] . "\n";
echo "時長: " . $video['duration'] . "\n";
echo "---\n";
}
// 查詢特定影片
$video = Momentry_API::getVideo('952f5854b9febad1');
print_r($video);
```
### Step 4: 查詢處理進度
```php
<?php
// 取得任務狀態
$job = Momentry_API::getJob('9760d0820f0cf9a7');
switch ($job['status']) {
case 'pending':
echo "等待處理中...\n";
break;
case 'processing':
echo "處理中: " . $job['progress'] . "%\n";
break;
case 'completed':
echo "處理完成!\n";
break;
case 'failed':
echo "處理失敗: " . ($job['error'] ?? '未知錯誤') . "\n";
break;
}
```
### Step 5: 搜尋內容並取得 Chunk
```php
<?php
// 搜尋相關片段
$results = Momentry_API::search('測試關鍵字', 5);
foreach ($results['results'] as $result) {
echo "影片 UUID: " . $result['uuid'] . "\n";
echo "Chunk ID: " . $result['chunk_id'] . "\n";
echo "類型: " . $result['chunk_type'] . "\n";
echo "開始: " . $result['start_time'] . "s\n";
echo "結束: " . $result['end_time'] . "s\n";
echo "內容: " . ($result['text'] ?? '') . "\n";
echo "相似度: " . $result['score'] . "\n";
echo "---\n";
}
```
### WordPress Shortcode 範例(可點擊播放)
```php
<?php
// 在 functions.php 中加入
add_shortcode('momentry_search', function($atts) {
$atts = shortcode_atts([
'query' => '',
'limit' => 10,
], $atts);
if (empty($atts['query'])) {
return '<p>請輸入搜尋關鍵字</p>';
}
try {
$results = Momentry_API::search($atts['query'], $atts['limit']);
if (empty($results['results'])) {
return '<p>找不到相關結果</p>';
}
$html = '<div class="momentry-results">';
$html .= '<h3>搜尋結果: ' . esc_html($atts['query']) . '</h3>';
$html .= '<ul>';
foreach ($results['results'] as $result) {
$video_uuid = $result['uuid'];
$start = $result['start_time'] ?? 0;
$end = $result['end_time'] ?? 0;
$text = $result['text'] ?? '無文字描述';
$html .= '<li>';
$html .= '<a href="/player?uuid=' . esc_attr($video_uuid) .
'&start=' . esc_attr($start) .
'&end=' . esc_attr($end) . '">';
$html .= '播放 ' . $start . 's - ' . $end . 's';
$html .= '</a>';
$html .= '<br>';
$html .= '<small>相似度: ' . round($result['score'] * 100) . '%</small>';
$html .= '<br>';
$html .= esc_html($text);
$html .= '</li>';
}
$html .= '</ul></div>';
return $html;
} catch (Exception $e) {
return '<p>搜尋服務暫時無法使用</p>';
}
});
```
**使用方式**:
```html
[momentry_search query="關鍵字" limit="5"]
```
---
## 完整 n8n Workflow 範例
```
┌──────────────┐
│ 觸發 (定時) │
└──────┬───────┘
┌──────────────┐ ┌──────────────┐
│ 查詢影片 │────►│ 比對新檔案 │
│ /videos │ │ │
└──────┬───────┘ └──────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ 等待處理 │◄────│ 輪詢任務狀態 │
│ /jobs/:uuid │ │ /jobs/:uuid │
└──────┬───────┘ └──────────────┘
▼ (completed)
┌──────────────┐
│ 搜尋測試 │
│ /search │
└──────────────┘
```
---
**注意**:
- 處理時間視影片長度而定(1分鐘影片約需 2-5 分鐘處理)
- 大量影片時建議分批上傳
---
## 附錄:版本歷史
| 版本 | 日期 | 內容 | 操作人 |
|------|------|------|--------|
| V1.0 | 2026-03-25 | 初版建立 | OpenCode |
| V1.1 | 2026-03-25 | 新增 Chunk 取得與播放說明、Shortcode 範例 | OpenCode |
| V1.2 | 2026-03-25 | 修正 SFTPGo 主機名稱為 sftpgo.momentry.ddns.net | OpenCode |
@@ -0,0 +1,223 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "架構決策卡片"
date: "2026-04-22"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "架構決策卡片"
ai_query_hints:
- "查詢 架構決策卡片 的內容"
- "架構決策卡片 的主要目的是什麼?"
- "如何操作或實施 架構決策卡片?"
---
# 架構決策卡片
## 卡片 1: 分片類型設計
| 項目 | 內容 |
|------|------|
| **決策編號** | AD-2026-001 |
| **決策名稱** | ChunkType 枚舉設計 |
| **決策時間** | 2026-04-22 |
| **決策狀態** | ✅ 已實施 |
| **相關代碼** | `src/core/chunk/types.rs:6-12` |
### 問題描述
設計文檔中定義的分片類型 (`sentence|visual|scene|summary`) 與實際代碼實現不一致,導致設計與實現脫節。
### 決策選項
1. **選項 A**: 修改代碼適應設計文檔
- 優點:保持設計一致性
- 缺點:需要大量代碼修改,可能影響現有功能
2. **選項 B**: 更新設計文檔反映實際實現
- 優點:反映真實系統狀態,維護成本低
- 缺點:設計文檔與原始設計偏離
### 最終決策
選擇 **選項 B**,以實際代碼實現為準,更新設計文檔。
### 實施方案
1. 更新所有架構文檔使用實際的 `ChunkType` 枚舉值
2. 創建術語對照表
3. 更新代碼註釋
### 影響評估
- **正面影響**: 設計與實現一致,減少團隊困惑
- **負面影響**: 需要更新大量文檔
- **風險**: 術語混亂過渡期
---
## 卡片 2: 數據結構類型安全
| 項目 | 內容 |
|------|------|
| **決策編號** | AD-2026-002 |
| **決策名稱** | 分片內容類型安全設計 |
| **決策時間** | 2026-04-22 |
| **決策狀態** | ⚠️ 待實施 |
| **相關代碼** | `src/core/chunk/types.rs:43-65` |
### 問題描述
當前 `Chunk` 結構使用 `serde_json::Value` 存儲動態內容,缺乏類型安全,容易導致運行時錯誤。
### 決策選項
1. **選項 A**: 保持動態 JSON 結構
- 優點:靈活性高,易於擴展
- 缺點:缺乏類型安全,編譯時無法檢測錯誤
2. **選項 B**: 實現類型安全結構
- 優點:編譯時類型檢查,代碼更安全
- 缺點:靈活性降低,需要為每個分片類型定義專用結構
### 最終決策
選擇 **選項 B**,分階段實現類型安全重構。
### 實施方案
1. Phase 1: 為每個 `ChunkType` 定義專用內容結構
2. Phase 2: 實現自動化遷移工具
3. Phase 3: 保持向後兼容性,逐步遷移
### 影響評估
- **正面影響**: 提高代碼安全性,減少運行時錯誤
- **負面影響**: 開發複雜度增加,需要遷移現有數據
- **風險**: 遷移過程中可能出現兼容性問題
---
## 卡片 3: 處理管道設計
| 項目 | 內容 |
|------|------|
| **決策編號** | AD-2026-003 |
| **決策名稱** | 統一處理器執行框架 |
| **決策時間** | 2026-04-22 |
| **決策狀態** | ✅ 已實施 |
| **相關代碼** | `src/core/processor/executor.rs` |
### 問題描述
不同的 AI 處理器使用不同的執行方式,缺乏統一的錯誤處理和超時控制。
### 決策選項
1. **選項 A**: 每個處理器獨立實現執行邏輯
- 優點:各處理器可以優化自身執行
- 缺點:代碼重複,錯誤處理不一致
2. **選項 B**: 創建統一執行器框架
- 優點:代碼復用,統一的錯誤處理和超時控制
- 缺點:可能需要適配現有處理器
### 最終決策
選擇 **選項 B**,實現 `PythonExecutor` 統一框架。
### 實施方案
1. 創建 `PythonExecutor` 結構,提供統一的腳本執行接口
2. 支持超時控制、錯誤恢復和結果解析
3. 所有 Python 腳本處理器使用統一的執行器
### 影響評估
- **正面影響**: 代碼復用,統一的錯誤處理,易於維護
- **負面影響**: 需要修改現有處理器適配新框架
- **風險**: 過渡期可能出現執行問題
---
## 卡片 4: 多數據庫架構
| 項目 | 內容 |
|------|------|
| **決策編號** | AD-2026-004 |
| **決策名稱** | 多數據庫系統設計 |
| **決策時間** | 2026-04-22 |
| **決策狀態** | ✅ 已實施 |
| **相關代碼** | `src/core/db/` 目錄 |
### 問題描述
系統需要處理不同類型的數據:結構化數據、向量數據、緩存數據和文檔數據。
### 決策選項
1. **選項 A**: 單一數據庫系統
- 優點:架構簡單,維護成本低
- 缺點:性能可能受限,不適合所有數據類型
2. **選項 B**: 多數據庫系統
- 優點:每種數據類型使用最適合的數據庫,性能最佳
- 缺點:架構複雜,維護成本高
### 最終決策
選擇 **選項 B**,實現多數據庫系統。
### 實施方案
1. **PostgreSQL**: 存儲結構化數據(視訊、分片、任務)
2. **Redis**: 緩存和隊列管理
3. **Qdrant**: 向量數據存儲和檢索
4. **MongoDB**: 文檔數據存儲
### 影響評估
- **正面影響**: 每種數據類型性能最優,系統擴展性好
- **負面影響**: 架構複雜,需要管理多個數據庫連接
- **風險**: 數據一致性維護複雜
---
## 卡片 5: 環境隔離設計
| 項目 | 內容 |
|------|------|
| **決策編號** | AD-2026-005 |
| **決策名稱** | 開發與生產環境隔離 |
| **決策時間** | 2026-04-22 |
| **決策狀態** | ✅ 已實施 |
| **相關代碼** | `src/bin/momentry_playground.rs` |
### 問題描述
開發環境和生產環境需要隔離,避免開發測試影響生產數據。
### 決策選項
1. **選項 A**: 單一環境,通過配置切換
- 優點:架構簡單,部署方便
- 缺點:開發測試可能污染生產數據
2. **選項 B**: 完全隔離的多環境
- 優點:環境完全隔離,安全可靠
- 缺點:需要維護多套環境
### 最終決策
選擇 **選項 B**,實現完全環境隔離。
### 實施方案
1. **生產環境**: `momentry` 二進制,使用 `momentry:` Redis 網址
2. **開發環境**: `momentry_playground` 二進制,使用 `momentry_dev:` Redis 網址
3. **環境配置**: 通過環境變數和配置文件區分
### 影響評估
- **正面影響**: 環境完全隔離,開發測試不影響生產
- **負面影響**: 需要維護多套部署配置
- **風險**: 配置錯誤可能導致環境混亂
---
## 如何使用決策卡片
### 新增決策
1. 創建新的決策卡片
2. 填寫決策編號 (AD-YYYY-NNN)
3. 記錄決策過程和結果
4. 更新到本文檔
### 決策審查
1. 每季度審查所有決策卡片
2. 評估決策實施效果
3. 必要時調整或撤銷決策
### 決策歸檔
1. 已完成的決策歸檔到歷史記錄
2. 失敗的決策記錄失敗原因和學習點
3. 成功的決策作為最佳實踐參考
---
**最後更新**: 2026-04-22
**卡片數量**: 5
**狀態分布**: ✅ 已實施 4,⚠️ 待實施 1
@@ -0,0 +1,163 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "架構決策執行計畫"
date: "2026-04-22"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "架構決策執行計畫"
ai_query_hints:
- "查詢 架構決策執行計畫 的內容"
- "架構決策執行計畫 的主要目的是什麼?"
- "如何操作或實施 架構決策執行計畫?"
---
# 架構決策執行計畫
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-22 |
| 最後更新 | 2026-04-22 |
| 文件版本 | V1.2 |
| 相關文件 | [DESIGN_IMPLEMENTATION_GAP.md](./DESIGN_IMPLEMENTATION_GAP.md)<br>[ARCHITECTURE_OVERVIEW.md](./ARCHITECTURE_OVERVIEW.md)<br>[TECHNICAL_DECISION_RECORDS.md](./TECHNICAL_DECISION_RECORDS.md)<br>[ARCHITECTURE_ROADMAP.md](./ARCHITECTURE_ROADMAP.md)<br>[TERMINOLOGY_MAPPING.md](./TERMINOLOGY_MAPPING.md) |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.2 | 2026-04-22 | 更新 Phase 1.2 任務完成狀態 | OpenCode | OpenCode / deepseek-v3.2 |
| V1.1 | 2026-04-22 | 更新 Phase 1.1 任務完成狀態 | OpenCode | OpenCode / deepseek-v3.2 |
| V1.0 | 2026-04-22 | 創建架構決策執行計畫 | OpenCode | OpenCode / deepseek-v3.2 |
---
## 1. 執行計畫概述
本執行計畫基於 [DESIGN_IMPLEMENTATION_GAP.md](./DESIGN_IMPLEMENTATION_GAP.md) 中識別的設計與實現差異,制定具體的執行方案。
### 1.1 核心原則
1. **優先級驅動**:根據影響程度和實現難度確定優先級
2. **漸進式改進**:小步快跑,快速驗證,持續迭代
3. **風險可控**:每個階段都有明確的退出條件和回滾方案
### 1.2 執行階段
| 階段 | 時間範圍 | 主要目標 |
|------|----------|----------|
| **Phase 1** | 2026-04-22 至 2026-05-22 | 基礎一致性建立 |
| **Phase 2** | 2026-05-23 至 2026-07-22 | 缺失功能補齊 |
| **Phase 3** | 2026-07-23 至 2026-09-22 | 功能增強優化 |
| **Phase 4** | 2026-09-23 至 2026-12-22 | 架構現代化 |
---
## 2. Phase 1: 基礎一致性建立 (1個月)
### 2.1 目標
- 統一設計與實現的術語和概念
- 建立設計與實現同步機制
- 完成所有架構文檔的更新
### 2.2 具體任務
#### 任務 1.1: 術語標準化 (優先級 P0) ✅ 已完成
- **問題**: 設計文檔使用 `sentence|visual|scene|summary`,代碼使用 `TimeBased|Sentence|Cut|Trace|Story`
- **解決方案**:
1. 更新所有設計文檔使用代碼中的術語
2. 創建術語對照表
3. 更新代碼註釋和文檔生成工具
- **負責人**: OpenCode
- **時間**: 2026-04-22 至 2026-04-26
- **實際完成**: 2026-04-22
- **產出物**:
1. `TERMINOLOGY_MAPPING.md` - 完整術語對照表
2. `CHUNKING_ARCHITECTURE.md` V1.1 - 更新術語
3. `ARCHITECTURE_OVERVIEW.md` V1.2 - 更新術語和索引
4. `chunking/CHUNKING_SCHEMA_SPEC.md` V1.1 - 更新術語
5. `chunking/CHUNKING_ARCHITECTURE.md` V1.1 - 更新術語和參考
#### 任務 1.2: 文檔一致性檢查工具 (優先級 P0) ✅ 已完成
- **問題**: 手動檢查文檔與代碼一致性效率低
- **解決方案**:
1. 擴展現有的 `scripts/check_architecture_docs.py`
2. 添加代碼與文檔一致性檢查
3. 集成到 CI/CD 流程
- **負責人**: OpenCode
- **時間**: 2026-04-27 至 2026-05-01
- **實際完成**: 2026-04-22
- **產出物**:
1. `scripts/check_code_document_consistency.py` - 代碼與文檔一致性檢查工具
2. `scripts/check_architecture_all.py` - 整合檢查腳本
3. 更新 `scripts/check_architecture_docs.py` - 增強術語檢查功能
- **成果**:
1. 自動化檢測設計術語與實現狀態不一致問題
2. 提供詳細修復建議
3. 整合兩個檢查工具為統一入口
---
## 3. Phase 2: 缺失功能補齊 (2個月)
### 3.1 目標
- 實現 Rule 2 視覺分片基礎框架
- 建立視覺分片處理管道
- 完成基礎視覺檢索功能
### 3.2 具體任務
#### 任務 2.1: 視覺分片數據結構設計 (優先級 P0)
- **問題**: 缺乏視覺分片專用數據結構
- **解決方案**:
1. 設計 `VisualChunk` 數據結構
2. 擴展 `ChunkType` 枚舉
3. 創建視覺分片專用內容格式
- **負責人**: OpenCode
- **時間**: 2026-05-23 至 2026-05-30
#### 任務 2.2: YOLO 處理器集成 (優先級 P0)
- **問題**: YOLO 處理器存在但未用於分片生成
- **解決方案**:
1. 擴展現有 YOLO 處理器輸出格式
2. 創建視覺分片生成器
3. 集成到處理管道
- **負責人**: OpenCode
- **時間**: 2026-05-31 至 2026-06-14
---
## 4. 執行監控與評估
### 4.1 關鍵績效指標 (KPIs)
| KPI | 目標值 | 測量頻率 | 負責人 |
|-----|--------|----------|--------|
| **設計實現一致性** | ≥95% | 每週 | OpenCode |
| **功能完成率** | ≥90% | 每月 | OpenCode |
### 4.2 進度報告機制
1. **每週進度報告** (週五)
- 本週完成工作總結
- 下週工作計劃
- 風險和問題報告
---
## 5. 成功標準
### 5.1 最終成功標準
1. **設計實現一致性**:設計與實現差異 ≤5%
2. **功能完整性**:所有設計功能實現率 ≥95%
3. **系統穩定性**:生產環境可用性 ≥99.9%
---
**最後更新**: 2026-04-22
@@ -0,0 +1,389 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "架構文檔關係圖與導航指南"
date: "2026-04-22"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "架構文檔關係圖與導航指南"
ai_query_hints:
- "查詢 架構文檔關係圖與導航指南 的內容"
- "架構文檔關係圖與導航指南 的主要目的是什麼?"
- "如何操作或實施 架構文檔關係圖與導航指南?"
---
# 架構文檔關係圖與導航指南
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-22 |
| 文件版本 | V1.0 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-04-22 | 創建架構文檔關係圖 | OpenCode | OpenCode / deepseek-v3.2 |
---
## 1. 文檔關係圖
```
核心文檔
├──> [ARCHITECTURE_OVERVIEW.md] (總覽)
│ │
│ ├──> [ARCHITECTURE_ROADMAP.md] (路線圖)
│ ├──> [TECHNICAL_DECISION_RECORDS.md] (決策記錄)
│ ├──> [DESIGN_IMPLEMENTATION_GAP.md] (設計實現差異)
│ ├──> [ARCHITECTURE_DECISION_EXECUTION_PLAN.md] (執行計畫)
│ └──> [ARCHITECTURE_REVIEW_PROCESS.md] (審查流程)
├──> [PERFORMANCE_AND_SCALABILITY.md] (效能與擴展)
│ │
│ ├──> [MONITORING_ARCHITECTURE.md] (監控架構)
│ └──> [MONITORING_SETUP_GUIDE.md] (監控部署指南)
├──> [SECURITY_ARCHITECTURE.md] (安全架構)
│ │
│ ├──> [API_KEY_ARCHITECTURE.md] (API Key 管理)
│ └──> scripts/security_check.sh (安全檢查腳本)
├──> 培訓材料
│ │
│ ├──> [QUICK_START_GUIDE.md] (5分鐘快速入門)
│ ├──> [ARCHITECTURE_DECISION_CARDS.md] (決策卡片)
│ └──> [FAQ.md] (常見問題解答)
└──> chunking/ (分片架構專題)
├──> [CHUNKING_ARCHITECTURE.md] (分片總覽)
├──> [CHUNK_RULE_1_SENTENCE.md] (句子級分片)
├──> [CHUNK_RULE_2_VISUAL.md] (視覺物件級分片)
├──> [CHUNK_RULE_3_SCENE.md] (場景級分片)
└──> [CHUNK_RULE_4_SUMMARY.md] (摘要級分片)
特定主題文檔
├──> [PROCESSOR_LIFECYCLE.md] (處理器生命週期)
├──> [SERVICE_REGISTRY_ARCHITECTURE.md] (服務註冊)
├──> [PROCESSOR_REGISTRY_ARCHITECTURE.md] (處理器註冊)
└──> [PROCESSING_PIPELINE.md] (處理管道)
```
---
## 2. 文檔導航指南
### 2.1 新手入門路徑
如果你是 **新加入的開發者****第一次接觸 Momentry Core**,建議閱讀順序:
1. **第一步:系統概覽**
- [ARCHITECTURE_OVERVIEW.md](./ARCHITECTURE_OVERVIEW.md) - 了解整體架構
- [ARCHITECTURE_ROADMAP.md](./ARCHITECTURE_ROADMAP.md) - 了解發展方向
2. **第二步:核心概念**
- [CHUNKING_ARCHITECTURE.md](./chunking/CHUNKING_ARCHITECTURE.md) - 理解分片架構
- [PROCESSING_PIPELINE.md](./PROCESSING_PIPELINE.md) - 了解處理流程
3. **第三步:實際實現**
- [DESIGN_IMPLEMENTATION_GAP.md](./DESIGN_IMPLEMENTATION_GAP.md) - 了解設計與實現差異
- [TECHNICAL_DECISION_RECORDS.md](./TECHNICAL_DECISION_RECORDS.md) - 了解重要技術決策
### 2.2 開發者參考路徑
如果你是 **正在開發功能的開發者**,需要參考的順序:
1. **功能開發前**
- [TECHNICAL_DECISION_RECORDS.md](./TECHNICAL_DECISION_RECORDS.md) - 查看相關決策
- [DESIGN_IMPLEMENTATION_GAP.md](./DESIGN_IMPLEMENTATION_GAP.md) - 了解當前狀態
2. **架構設計時**
- [PERFORMANCE_AND_SCALABILITY.md](./PERFORMANCE_AND_SCALABILITY.md) - 效能考量
- [SECURITY_ARCHITECTURE.md](./SECURITY_ARCHITECTURE.md) - 安全要求
3. **實現完成後**
- [PROCESSOR_LIFECYCLE.md](./PROCESSOR_LIFECYCLE.md) - 處理器管理
- [MONITORING_ARCHITECTURE.md](./MONITORING_ARCHITECTURE.md) - 監控需求
### 2.3 運維人員路徑
如果你是 **系統運維或 DevOps 工程師**,建議閱讀順序:
1. **部署與配置**
- [MONITORING_ARCHITECTURE.md](./MONITORING_ARCHITECTURE.md) - 監控設置
- [MONITORING_SETUP_GUIDE.md](./MONITORING_SETUP_GUIDE.md) - 監控部署指南
- [SERVICE_REGISTRY_ARCHITECTURE.md](./SERVICE_REGISTRY_ARCHITECTURE.md) - 服務管理
2. **效能優化**
- [PERFORMANCE_AND_SCALABILITY.md](./PERFORMANCE_AND_SCALABILITY.md) - 效能基準
- [PROCESSOR_REGISTRY_ARCHITECTURE.md](./PROCESSOR_REGISTRY_ARCHITECTURE.md) - 處理器調度
3. **安全維護**
- [SECURITY_ARCHITECTURE.md](./SECURITY_ARCHITECTURE.md) - 安全配置
- [API_KEY_ARCHITECTURE.md](./API_KEY_ARCHITECTURE.md) - API Key 管理
- scripts/security_check.sh - 安全檢查腳本
### 2.4 架構師/技術經理路徑
如果你是 **技術決策者或架構師**,建議閱讀順序:
1. **戰略規劃**
- [ARCHITECTURE_ROADMAP.md](./ARCHITECTURE_ROADMAP.md) - 發展路線
- [TECHNICAL_DECISION_RECORDS.md](./TECHNICAL_DECISION_RECORDS.md) - 歷史決策
- [ARCHITECTURE_DECISION_EXECUTION_PLAN.md](./ARCHITECTURE_DECISION_EXECUTION_PLAN.md) - 執行計畫
- [ARCHITECTURE_REVIEW_PROCESS.md](./ARCHITECTURE_REVIEW_PROCESS.md) - 審查流程
2. **技術評估**
- [DESIGN_IMPLEMENTATION_GAP.md](./DESIGN_IMPLEMENTATION_GAP.md) - 現狀分析
- [PERFORMANCE_AND_SCALABILITY.md](./PERFORMANCE_AND_SCALABILITY.md) - 效能評估
- [ARCHITECTURE_DECISION_CARDS.md](./ARCHITECTURE_DECISION_CARDS.md) - 決策卡片
3. **風險管理**
- [SECURITY_ARCHITECTURE.md](./SECURITY_ARCHITECTURE.md) - 安全風險
- [MONITORING_ARCHITECTURE.md](./MONITORING_ARCHITECTURE.md) - 運維風險
---
## 3. 文檔更新流程
### 3.1 文檔修改觸發條件
| 觸發條件 | 需要更新的文檔 | 更新負責人 |
|----------|----------------|------------|
| **新增功能** | 所有相關架構文檔 | 功能開發者 + 架構師 |
| **架構變更** | 架構概覽 + 相關專題文檔 | 架構師 |
| **重大決策** | 技術決策記錄 | 決策參與者 |
| **實現差異** | 設計實現差異文檔 | 開發團隊 |
| **效能改進** | 效能與擴展文檔 | 效能工程師 |
### 3.2 文檔更新檢查清單
修改任何架構文檔前,請檢查:
1. **相關性檢查**
- [ ] 是否影響其他文檔?
- [ ] 是否需要更新關係圖?
- [ ] 是否需要通知相關人員?
2. **一致性檢查**
- [ ] 術語使用是否一致?
- [ ] 版本號是否更新?
- [ ] 時間戳是否更新?
3. **完整性檢查**
- [ ] 版本歷史是否記錄?
- [ ] 相關文件鏈接是否正確?
- [ ] 參考資料是否完整?
### 3.3 文檔版本管理規則
1. **版本號格式**`V<主版本>.<次版本>`
- 主版本:架構重大變更
- 次版本:內容更新或修正
2. **版本更新時機**
- 主版本:架構重新設計
- 次版本:新增內容、修正錯誤、更新鏈接
3. **版本兼容性**
- 相同主版本應保持向後兼容
- 不同主版本可能需要遷移指南
---
## 4. 文檔質量標準
### 4.1 內容質量要求
| 維度 | 標準 | 檢查方法 |
|------|------|----------|
| **準確性** | 內容與實際實現一致 | 代碼審查、測試驗證 |
| **完整性** | 覆蓋所有相關主題 | 檢查清單、同行評審 |
| **一致性** | 術語、格式、風格統一 | 自動化檢查、人工審核 |
| **可讀性** | 結構清晰、語言簡潔 | 可讀性測試、用戶反饋 |
| **實用性** | 對讀者有實際幫助 | 使用統計、用戶反饋 |
### 4.2 格式規範
1. **文件頭部**:必須包含項目表格和版本歷史
2. **目錄結構**:使用標準 Markdown 標題層級
3. **鏈接格式**:使用相對路徑,確保可移植性
4. **代碼示例**:使用正確的語法高亮
5. **表格使用**:複雜信息使用表格呈現
### 4.3 維護責任
| 文檔類型 | 主要負責人 | 審核人 | 更新頻率 |
|----------|------------|--------|----------|
| **核心文檔** | 架構師 | CTO | 每月審閱 |
| **專題文檔** | 專題負責人 | 架構師 | 隨功能更新 |
| **決策記錄** | 決策參與者 | 全體成員 | 實時更新 |
| **實現差異** | 開發團隊 | 架構師 | 每週更新 |
---
## 5. 常見問題與解決方案
### 5.1 文檔找不到或鏈接失效
**問題**:點擊鏈接時找不到文件或顯示錯誤
**解決方案**
1. 檢查文件是否移動或重命名
2. 更新鏈接中的文件路徑
3. 如果文件已刪除,更新所有引用
### 5.2 文檔內容過時
**問題**:文檔描述與實際實現不一致
**解決方案**
1. 首先更新 `DESIGN_IMPLEMENTATION_GAP.md`
2. 然後更新相關的架構文檔
3. 最後更新本文檔的關係圖
### 5.3 術語不一致
**問題**:不同文檔使用不同術語描述同一概念
**解決方案**
1.`ARCHITECTURE_OVERVIEW.md` 中定義術語表
2. 統一所有文檔的術語使用
3. 建立術語審查流程
### 5.4 文檔過多難以管理
**問題**:文檔數量太多,難以找到所需信息
**解決方案**
1. 使用本文檔作為導航入口
2. 建立良好的搜索機制
3. 定期整理和歸檔舊文檔
---
## 6. 工具與自動化支持
### 6.1 文檔生成工具
```bash
# 生成文檔關係圖
python scripts/generate_doc_graph.py
# 檢查鏈接有效性
python scripts/check_doc_links.py
# 更新版本歷史
python scripts/update_doc_versions.py
```
### 6.2 CI/CD 集成
在 CI/CD 流程中添加文檔檢查:
```yaml
# .github/workflows/docs-check.yml
name: Documentation Check
on:
push:
paths:
- 'docs_v1.0/ARCHITECTURE/**'
jobs:
check-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Check documentation links
run: python scripts/check_doc_links.py
- name: Validate documentation format
run: python scripts/validate_doc_format.py
```
### 6.3 監控與分析
1. **使用統計**:追蹤文檔訪問頻率
2. **搜索分析**:分析用戶搜索關鍵詞
3. **反饋收集**:收集用戶對文檔的反饋
---
## 7. 總結與建議
### 7.1 當前狀態評估
**已完成的工作**
1. 建立了完整的架構文檔體系
2. 明確了文檔之間的關係
3. 制定了文檔質量標準
4. 建立了更新流程
🔄 **進行中的工作**
1. 保持文檔與代碼同步
2. 收集用戶反饋持續改進
3. 建立自動化工具支持
📋 **後續改進計劃**
1. 建立文檔搜尋引擎
2. 增加多語言支持
3. 建立文檔培訓體系
### 7.2 最佳實踐建議
1. **文檔即代碼**:將文檔納入版本控制
2. **持續更新**:隨代碼變更同步更新文檔
3. **用戶為中心**:以讀者需求設計文檔結構
4. **質量優先**:確保文檔準確、完整、一致
### 7.3 成功指標
| 指標 | 目標值 | 測量方法 |
|------|--------|----------|
| **文檔覆蓋率** | > 95% | 代碼功能對應文檔比例 |
| **文檔準確率** | > 98% | 文檔與實現一致性檢查 |
| **用戶滿意度** | > 4.5/5.0 | 用戶反饋調查 |
| **更新及時性** | < 24小時 | 代碼變更到文檔更新時間 |
---
## 8. 聯繫與支持
### 8.1 文檔維護團隊
| 角色 | 負責人 | 聯繫方式 | 負責文檔類型 |
|------|--------|----------|--------------|
| **架構文檔負責人** | OpenCode | opencode@momentry.ai | 所有核心文檔 |
| **技術文檔審核** | 開發團隊 | dev@momentry.ai | 專題文檔 |
| **用戶文檔支持** | 產品團隊 | product@momentry.ai | 用戶指南 |
### 8.2 問題回報流程
1. **發現問題**:在文檔中標記或創建 Issue
2. **問題分類**:根據類型分配給相應負責人
3. **問題解決**:負責人更新文檔
4. **驗證關閉**:報告人驗證問題已解決
### 8.3 文檔貢獻指南
歡迎貢獻文檔改進:
1. **小修改**:直接提交 Pull Request
2. **中等修改**:先創建 Issue 討論
3. **重大修改**:需要架構師審核批准
**貢獻者獎勵**:優秀的文檔貢獻將獲得 recognition 和獎勵。
---
**最後更新**2026-04-22
**文檔狀態**:活躍維護中
**建議反饋**:請通過 GitHub Issues 或郵件提供反饋
@@ -0,0 +1,348 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "架構優化待評估事項"
date: "2026-03-21"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "架構優化待評估事項"
ai_query_hints:
- "查詢 架構優化待評估事項 的內容"
- "架構優化待評估事項 的主要目的是什麼?"
- "如何操作或實施 架構優化待評估事項?"
---
# 架構優化待評估事項
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-03-21 |
| 文件版本 | V1.0 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 |
|------|------|------|--------|
| V1.0 | 2026-03-21 | 創建文件 | OpenCode |
| V1.1 | 2026-03-22 | 新增 TigerGraph/GraphRAG 說故事評估 | OpenCode |
---
## 架構優化項目
### 1. PostgreSQL → Redis 故障轉移
**說明**: 當 PostgreSQL 不可用時,降級到 Redis 作為臨時存儲
**複雜度**: 中
**影響範圍**:
- `src/core/db/postgres_db.rs`
- `src/core/db/redis_client.rs`
**風險**:
- 數據一致性問題
- 需要定義轉移策略
**優先級**: 待評估
---
### 2. 連接池監控
**說明**: 添加 PostgreSQL 和 Redis 連接池指標到 Prometheus
**複雜度**: 低
**影響範圍**:
- `src/core/db/postgres_db.rs`
- `src/core/db/redis_client.rs`
- `src/api/` (新增 metrics endpoint)
**風險**: 低
**優先級**: 待評估
---
### 3. Processor 重試機制
**說明**: 當 processor 失敗時自動重試
**複雜度**: 中
**影響範圍**:
- `src/core/processor/executor.rs` (新增 `run_with_retry` 方法)
- `src/core/processor/mod.rs` (導出 `RetryConfig`)
**風險**:
- 無限重試風險 → 已通過 `max_attempts` 控制
- 需要指數退避 → 已實現
**優先級**: ✅ 已完成 (2026-03-21)
**實作內容**:
- `RetryConfig` 結構體 (可配置重試次數、初始延遲、最大延遲、退避倍數)
- `run_with_retry()` 方法 (自動重試 + 指數退避)
- 單元測試覆蓋
**使用範例**:
```rust
use crate::core::processor::{PythonExecutor, RetryConfig};
let executor = PythonExecutor::new()?;
let config = RetryConfig::new(3).with_delay(1000).with_max_delay(30000);
executor.run_with_retry(
"asr_processor.py",
&["--input", "/path/to/video"],
Some(&uuid),
"asr",
Some(Duration::from_secs(3600)),
Some(config),
).await?;
```
---
### 4. PyO3 整合
**說明**: Python/Rust 直接調用,移除子進程調用
**複雜度**: 高
**影響範圍**:
- `src/core/processor/executor.rs` (重寫)
- Python 模組 (修改為可直接 import)
**風險**:
- Python GIL 問題
- 依賴版本兼容性
- 需要大量重寫
**優先級**: 低 (長期目標)
---
### 5. HTTP 健康端點
**說明**: 添加 `/health` API 用於外部監控
**複雜度**: 低
**影響範圍**:
- `src/api/server.rs` (新增路由)
**風險**: 低
**優先級**: ✅ 已完成 (2026-03-21)
**實作內容**:
- `GET /health` - 基本健康檢查 (status, version, uptime)
- `GET /health/detailed` - 詳細健康檢查 (PostgreSQL, Redis, Qdrant 狀態和延遲)
---
### 6. Gitea Actions CI/CD
**說明**: 配置 Gitea Actions 自動化 CI/CD,在合併前執行檢查
**複雜度**: 中
**影響範圍**:
- `.gitea/workflows/` (新增 workflow 文件)
**優點**:
- 強制執行檢查,無法跳過
- 跨設備一致
- PR 審查前自動檢查
**風險**: 低
**優先級**: 待評估
---
### 7. Commit Message Lint
**說明**: 規範化提交訊息格式 (Conventional Commits)
**複雜度**: 低
**影響範圍**:
- `.git/hooks/commit-msg` (新增 hook)
- `~/dotfiles/hooks/commit-msg`
**風險**: 低
**優先級**: ✅ 已完成 (2026-03-21)
**實作內容**:
- 驗證格式: `<type>(<scope>): <description>`
- 有效類型: feat, fix, docs, style, refactor, test, chore, perf, ci, build, revert
- 警告: 第一行超過 72 字符
**範例**:
```
feat(api): add health check endpoint
fix(db): resolve connection pool issue
docs: update README
```
---
### 8. 自動化安裝腳本
**說明**: 創建腳本一次安裝所有開發工具
**複雜度**: 低
**影響範圍**:
- `scripts/install-dev-tools.sh` (新增)
**風險**: 低
**優先級**: 待評估
---
## 評估標準
| 標準 | 說明 |
|------|------|
| 業務價值 | 對用戶有何幫助 |
| 技術風險 | 實現難度和潛在問題 |
| 維護成本 | 未來維護負擔 |
| 依賴性 | 對其他系統的影響 |
---
## 評估記錄
| 項目 | 評估日期 | 決策 | 原因 |
|------|----------|------|------|
| PostgreSQL → Redis 故障轉移 | 待評估 | - | - |
| 連接池監控 | 待評估 | - | - |
| Processor 重試機制 | 2026-03-21 | 已完成 | - |
| PyO3 整合 | 待評估 | - | - |
| HTTP 健康端點 | 2026-03-21 | 已完成 | - |
| Gitea Actions CI/CD | 待評估 | - | - |
| Commit Message Lint | 2026-03-21 | 已完成 | - |
| 自動化安裝腳本 | 待評估 | - | - |
---
## 9. TigerGraph / Knowledge Graph 圖譜說故事
**說明**: 使用知識圖譜 (Knowledge Graph) 增強視頻敘事 (Storytelling) 和 RAG 檢索
**複雜度**: 高
**研究來源**:
- [TigerGraph Agentic GraphRAG](https://www.tigergraph.com/blog/agentic-graphrag-gives-ai-a-playbook-for-smarter-retrieval/) (2025-12-15)
- [TigerGraph GraphRAG GitHub](https://github.com/tigergraph/graphrag) (v1.2.0, 2026-03-11)
- [GraphRAG in 2026: Practitioner's Guide](https://medium.com/graph-praxis/graph-rag-in-2026-a-practitioners-guide-to-what-actually-works-dca4962e7517) (2026-02-22)
- [GraphRAG Complete Guide](https://medium.com/@brian-curry-research/graphrag-the-complete-guide-to-graph-powered-retrieval-augmented-generation-eeb58a6bb4d1) (2026-02-11)
### 核心概念
| 概念 | 說明 |
|------|------|
| **GraphRAG** | 結合知識圖譜與 RAG,比傳統向量檢索更智能 |
| **知識圖譜** | 實體 (Entity) + 關係 (Relationship) 的結構化表示 |
| **多跳推理** | Multi-hop traversal,可連接多個相關節點 |
| **混合檢索** | Graph traversal + Vector similarity 結合 |
### 對 Momentry 的潛在應用
```
視頻場景 → 實體識別 → 關係建立 → 故事圖譜
↓ ↓ ↓ ↓
CUT [人物, 物品, 動作] [誰做了什麼, 什麼導致什麼] [敘事鏈]
```
**1. 敘事圖譜構建 (Narrative Graph)**
- 從 Story/Chunks 模組提取實體
- 建立場景之間的因果關係
- 追蹤角色互動和情節發展
**2. 故事檢索增強**
```python
# 現有: Parent-child chunks
parent_chunk: "場景描述"
child_chunks: [詳細內容]
# 加入圖譜:
場景A --led_to--> 場景B
角色X --interacted_with--> 角色Y
主題Y --related_to--> 主題Z
```
**3. 查詢模式**
| 查詢類型 | 傳統 RAG | GraphRAG |
|----------|----------|----------|
| 事實查找 | ✅ "這個場景在說什麼" | ✅ |
| 主題推理 | ❌ "這個視頻的主要情節" | ✅ Global search |
| 多跳關係 | ❌ | ✅ "A導致BB導致C" |
| 可解釋性 | ❌ | ✅ 關係路徑可追溯 |
### 實作方案
**方案 A: TigerGraph Cloud (推薦)**
- ✅ 原生 Graph + Vector 混合查詢
- ✅ GraphRAG 官方支援
- ✅ 200GB 免費額度
- ❌ 雲端依賴,延遲敏感場景需考慮
**方案 B: Neo4j + Qdrant**
- ✅ 成熟開源生態
- ✅ LangChain/LlamaIndex 整合
- ❌ 需要維護兩個系統
**方案 C: 自建混合架構**
- PostgreSQL + Neo4j (或Typesense)
- 利用現有 BM25 + 向量檢索基礎
- ❌ 開發成本高
### 技術棧整合建議
```rust
// 現有架構
Vector Search (Qdrant) BM25 (PostgreSQL)
// 加入 GraphRAG
Knowledge Graph (TigerGraph/Neo4j)
Vector + Graph traversal
```
### 優先級: 待評估
**考慮因素**:
- 用戶是否需要複雜的故事情節查詢?
- 實體識別 (NER) 成本是否可以接受?
- 與現有 BM25 + Vector 混合搜索的比較優勢?
---
## 10. LazyGraphRAG / FastGraphRAG 成本優化
**說明**: GraphRAG 索引成本高昂,LazyGraphRAG 推遲圖譜構建到查詢時
**來源**: [GraphRAG in 2026](https://medium.com/graph-praxis/graph-rag-in-2026-a-practitioners-guide-to-what-actually-works-dca4962e7517)
**Microsoft GraphRAG 問題**: $33K 索引大型數據集
**替代方案**:
- **LazyGraphRAG**: 按需構建,查詢時再建立子圖
- **FastGraphRAG**: 優化索引管道,10-90% 成本節省
- **HippoRAG**: 使用 Personalised PageRank 優化遍歷
**優先級**: 待評估 (作為 GraphRAG 的一部分)
@@ -0,0 +1,329 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Momentry Core 架構總覽"
date: "2026-04-22"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "momentry"
- "架構總覽"
- "core"
ai_query_hints:
- "查詢 Momentry Core 架構總覽 的內容"
- "Momentry Core 架構總覽 的主要目的是什麼?"
- "如何操作或實施 Momentry Core 架構總覽?"
---
# Momentry Core 架構總覽
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-22 |
| 文件版本 | V1.2 |
| 最後更新 | 2026-04-22 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.1 | 2026-04-22 | 更新文檔索引,整合新文檔 | OpenCode | OpenCode / deepseek-v3.2 |
| V1.0 | 2026-04-22 | 創建架構總覽文件 | OpenCode | OpenCode / Qwen3.6-Plus |
---
## 1. 系統概覽
Momentry Core 是一個基於 Rust 的數字資產管理系統,專注於視頻分析與多模態檢索能力。系統結合了語音識別(ASR/ASRX)、人臉識別(Face Recognition)、物體檢測(YOLO)、場景分類(Places365)等多種 AI 模型,實現全面的視頻內容理解。
### 核心設計理念
- **邊緣 AI 優先**:在本地設備上運行,減少雲端依賴
- **多模態融合**:結合視覺、聽覺、文本等多種信號
- **層級分片架構**:將連續視頻轉化為結構化知識單元
- **實時處理能力**:支持 on-the-fly 處理,縮短等待時間
---
## 2. 整體架構圖
```
┌─────────────────────────────────────────────────────────────────────────┐
│ Momentry Core Architecture │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ API Layer (Axum) │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Core Business Logic │ │
│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │
│ │ │ Chunking │ │Processor │ │Text │ │Embedding │ │ │
│ │ │ Engine │ │Registry │ │Processing │ │Engine │ │ │
│ │ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Data Access Layer │ │
│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │
│ │ │PostgreSQL │ │Redis │ │MongoDB │ │Qdrant │ │ │
│ │ │(Primary) │ │(Cache) │ │(Cache) │ │(Vectors) │ │ │
│ │ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ External Tool Integration │ │
│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │
│ │ │Python │ │FFmpeg/ │ │WhisperX │ │InsightFace │ │ │
│ │ │Scripts │ │FFprobe │ │(ASR) │ │(Face) │ │ │
│ │ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
```
---
## 3. 核心模塊
### 3.1 API 層 (`src/api/`)
- **技術棧**: Axum + Tower + Serde
- **功能**: RESTful API 接口,支持同步/異步處理
- **關鍵文件**:
- `server.rs`: 主 API 服務器
- `search.rs`: 搜索相關 API
- `face_recognition.rs`: 人臉識別 API
- `person_identity.rs`: 人物身份管理 API
### 3.2 核心業務邏輯 (`src/core/`)
- **分片引擎** (`chunk/`): 視頻分片與知識萃取
- **處理器註冊表** (`processor/`): AI 模型執行管理
- **文本處理** (`text/`): 同義詞擴展、分詞
- **嵌入引擎**: 語義向量生成
### 3.3 數據訪問層 (`src/core/db/`)
- **PostgreSQL**: 主數據存儲,關係型數據
- **Redis**: 緩存和隊列管理
- **MongoDB**: 文檔緩存
- **Qdrant**: 向量數據庫,語義搜索
### 3.4 外部工具集成 (`scripts/`)
- **Python 腳本**: ASR、Face、YOLO、OCR、Scene 等處理器
- **FFmpeg/FFprobe**: 視頻處理與元數據提取
- **AI 模型**: WhisperX、InsightFace、YOLOv8 等
---
## 4. 數據流架構
### 4.1 視頻註冊流程
```
1. 用戶上傳視頻 → 2. 生成 UUID → 3. 提取元數據 (FFprobe)
→ 4. 存入 PostgreSQL → 5. 觸發處理任務 → 6. 返回響應
```
### 4.2 分片處理流程
```
1. 原始視頻 → 2. 各處理器執行 (ASR, Face, YOLO, Scene)
→ 3. 生成 Pre-Chunk 數據 → 4. 應用分片規則 (Rule 1-4)
→ 5. 存入對應數據表 → 6. 向量化並存入 Qdrant
```
### 4.3 搜索查詢流程
```
1. 用戶查詢 → 2. 同義詞擴展 → 3. BM25 文本搜索
→ 4. 向量語義搜索 → 5. 結果融合排序 → 6. 返回檢索結果
```
---
## 5. 技術棧
### 5.1 後端 (Rust)
- **Web 框架**: Axum + Tower
- **異步運行時**: Tokio (full features)
- **序列化**: Serde + Serde JSON
- **數據庫驅動**: SQLx, Redis 1.0.x, MongoDB, Qdrant-client
- **錯誤處理**: Anyhow + Thiserror
- **日誌**: Tracing + Tracing-subscriber
### 5.2 數據存儲
- **主數據庫**: PostgreSQL (SQLx)
- **緩存**: Redis 1.0.x + MongoDB
- **向量數據庫**: Qdrant
- **文件存儲**: SFTPGo
### 5.3 AI 模型
- **語音識別**: WhisperX (Python)
- **人臉識別**: InsightFace (Python)
- **物體檢測**: YOLOv8 (Python)
- **場景分類**: Places365 (Python)
- **語義嵌入**: Nomic-embed-text-v2-moe (Ollama)
- **文本生成**: Gemma4 (llama.cpp)
### 5.4 基礎設施
- **反向代理**: Caddy
- **CI/CD**: GitHub Actions
- **監控**: 自定義指標 + 日誌聚合
- **配置管理**: 環境變量 + 配置文件
---
## 6. 實現狀態
### 6.1 分片規則實現狀態
基於詳細的設計與實現差異分析(參見 [DESIGN_IMPLEMENTATION_GAP.md](./DESIGN_IMPLEMENTATION_GAP.md)):
| 分片規則 | 設計概念 | 實現狀態 | 實現對應 | 完成度 |
|----------|----------|----------|----------|--------|
| **Rule 1** | 句子級分片 (`sentence`) | ✅ 完整實現 | `ChunkType::Sentence` | 95% |
| **Rule 2** | 視覺物件級分片 (`visual`) | ❌ 未實現 | 無對應實現 | 0% |
| **Rule 3** | 場景級分片 (`scene`) | ⚠️ 部分實現 | `ChunkType::Cut` | 60% |
| **Rule 4** | 摘要級分片 (`summary`) | ⚠️ 概念調整 | `ChunkType::Story` | 40% |
| **附加規則** | 時間基準分片 (`time`) | ✅ 完整實現 | `ChunkType::TimeBased` | 100% |
| **附加規則** | 軌跡追蹤分片 (`trace`) | ✅ 完整實現 | `ChunkType::Trace` | 100% |
### 6.2 核心功能實現狀態
| 功能模塊 | 實現狀態 | 備註 |
|----------|----------|------|
| **視頻註冊** | ✅ 完整實現 | 支持多種視頻格式 |
| **ASR 處理** | ✅ 完整實現 | WhisperX 集成 |
| **OCR 處理** | ✅ 完整實現 | GPU 加速支持 |
| **人臉識別** | ✅ 完整實現 | InsightFace 集成 |
| **YOLO 檢測** | ✅ 完整實現 | 物件檢測與分類 |
| **場景分類** | ✅ 完整實現 | Places365 模型 |
| **向量搜索** | ✅ 完整實現 | Qdrant 集成 |
| **同義詞擴展** | ✅ 完整實現 | 在線+離線模式 |
### 6.3 近期開發重點
1. **設計與實現一致性**:統一術語,更新文檔
2. **視覺分片框架**:實現 Rule 2 基礎功能
3. **場景語義增強**:改進 Rule 3 質量
4. **LLM 集成**:為 Rule 4 添加摘要生成
---
## 7. 部署架構
### 6.1 本地部署 (當前)
```
┌─────────────────────────────────────────┐
│ macOS (M4 Mac Mini) │
│ │
│ ┌────────────┐ ┌────────────┐ │
│ │ Momentry │ │ Redis │ │
│ │ Core │ │ │ │
│ │ (Rust) │ │ │ │
│ └────────────┘ └────────────┘ │
│ │
│ ┌────────────┐ ┌────────────┐ │
│ │ PostgreSQL │ │ Python │ │
│ │ │ │ Scripts │ │
│ │ │ │ │ │
│ └────────────┘ └────────────┘ │
└─────────────────────────────────────────┘
```
### 6.2 未來擴展架構
```
┌─────────────────────────────────────────────────────┐
│ Momentry Platform │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ Core API Server │ │
│ │ (Load Balancer + Service Discovery) │ │
│ └─────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Worker Node │ │ Worker Node │ │ Worker Node │ │
│ │ (ASR) │ │ (Face) │ │ (YOLO) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ Data Storage Cluster │ │
│ │ PostgreSQL | Redis | Qdrant | Object Store │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
```
---
## 8. 擴展性設計
### 8.1 水平擴展
- **無狀態 API 服務器**: 可通過負載均衡器擴展
- **處理器工作節點**: 可動態添加/移除 AI 處理節點
- **數據庫分片**: PostgreSQL 可配置讀寫分離
### 8.2 垂直擴展
- **GPU 加速**: 支持多種 AI 模型的 GPU 加速
- **內存優化**: 支持大內存配置的視頻處理
- **存儲擴展**: 支持 TB 級視頻文件存儲
### 8.3 模塊化設計
- **插件化處理器**: 可熱插拔 AI 模型
- **可替換組件**: 數據庫、緩存、向量存儲可替換
- **API 擴展**: 可添加新的 API 端點而不影響現有功能
---
## 9. 相關文件索引
### 8.1 核心架構文檔
| 文件 | 描述 | 位置 | 狀態 |
|------|------|------|------|
| ARCHITECTURE_OVERVIEW.md | 架構總覽 | `ARCHITECTURE/` | ✅ 最新版 |
| ARCHITECTURE_ROADMAP.md | 架構發展路線圖 | `ARCHITECTURE/` | ✅ 最新版 |
| TECHNICAL_DECISION_RECORDS.md | 技術決策記錄 | `ARCHITECTURE/` | ✅ 最新版 |
| DESIGN_IMPLEMENTATION_GAP.md | 設計與實現差異分析 | `ARCHITECTURE/` | ✅ 最新版 |
| ARCHITECTURE_DOCUMENTATION_MAP.md | 文檔關係圖與導航 | `ARCHITECTURE/` | ✅ 最新版 |
### 8.2 功能專題文檔
| 文件 | 描述 | 位置 | 狀態 |
|------|------|------|------|
| CHUNKING_ARCHITECTURE.md | 分片架構總綱 | `ARCHITECTURE/chunking/` | 🔄 部分更新 |
| CHUNK_RULE_1_SENTENCE.md | Rule 1: 句子級檢索 | `ARCHITECTURE/chunking/` | ✅ 最新版 |
| CHUNK_RULE_2_VISUAL.md | Rule 2: 視覺物件級檢索 | `ARCHITECTURE/chunking/` | 📋 設計階段 |
| CHUNK_RULE_3_SCENE.md | Rule 3: 場景級檢索 | `ARCHITECTURE/chunking/` | 🔄 部分實現 |
| CHUNK_RULE_4_SUMMARY.md | Rule 4: 摘要級檢索 | `ARCHITECTURE/chunking/` | 🔄 概念調整 |
### 8.3 質量與安全文檔
| 文件 | 描述 | 位置 | 狀態 |
|------|------|------|------|
| PERFORMANCE_AND_SCALABILITY.md | 效能與可擴展性架構 | `ARCHITECTURE/` | ✅ 最新版 |
| SECURITY_ARCHITECTURE.md | 安全架構設計 | `ARCHITECTURE/` | ✅ 最新版 |
| MONITORING_ARCHITECTURE.md | 監控架構設計 | `ARCHITECTURE/` | ✅ 最新版 |
| API_KEY_ARCHITECTURE.md | API Key 管理系統 | `ARCHITECTURE/` | ✅ 最新版 |
### 8.4 服務與處理器文檔
| 文件 | 描述 | 位置 | 狀態 |
|------|------|------|------|
| SERVICE_REGISTRY_ARCHITECTURE.md | 服務資源管理架構 | `ARCHITECTURE/` | ✅ 最新版 |
| PROCESSOR_REGISTRY_ARCHITECTURE.md | 處理器資源管理架構 | `ARCHITECTURE/` | ✅ 最新版 |
| PROCESSOR_LIFECYCLE.md | 處理器生命週期管理 | `ARCHITECTURE/` | ✅ 最新版 |
| PROCESSING_PIPELINE.md | 處理流程文檔 | `ARCHITECTURE/` | ✅ 最新版 |
| MODULE_STANDARDIZATION_IMPLEMENTATION_PLAN.md | 模塊標準化計劃 | `ARCHITECTURE/` | ✅ 最新版 |
| **新增文件** | | | |
| TERMINOLOGY_MAPPING.md | 術語對照表 | `ARCHITECTURE/` | ✅ 最新版 |
| DESIGN_IMPLEMENTATION_GAP.md | 設計與實現差異分析 | `ARCHITECTURE/` | ✅ 最新版 |
| ARCHITECTURE_DECISION_EXECUTION_PLAN.md | 架構決策執行計劃 | `ARCHITECTURE/` | ✅ 最新版 |
| PERFORMANCE_AND_SCALABILITY.md | 效能與可擴展性架構 | `ARCHITECTURE/` | ✅ 最新版 |
| SECURITY_ARCHITECTURE.md | 安全架構設計 | `ARCHITECTURE/` | ✅ 最新版 |
| MONITORING_ARCHITECTURE.md | 監控架構設計 | `ARCHITECTURE/` | ✅ 最新版 |
---
## 10. 更新記錄
| 日期 | 版本 | 變更內容 | 操作人 |
|------|------|----------|--------|
| 2026-04-22 | V1.2 | 術語標準化:添加術語對照表索引 | OpenCode |
| 2026-04-22 | V1.1 | 更新文檔索引,添加新創建的架構文檔 | OpenCode |
| 2026-04-22 | V1.0 | 創建架構總覽文件 | OpenCode |
**最後更新**: 2026-04-22 (V1.2)
@@ -0,0 +1,279 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "架構審查會議流程"
date: "2026-04-25"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "架構審查會議流程"
ai_query_hints:
- "查詢 架構審查會議流程 的內容"
- "架構審查會議流程 的主要目的是什麼?"
- "如何操作或實施 架構審查會議流程?"
---
# 架構審查會議流程
## 1. 概述
### 1.1 目的
建立標準化的架構審查流程,確保:
- 設計與實現的一致性
- 技術債務的有效管理
- 架構決策的透明性和可追溯性
- 團隊成員的技術成長
### 1.2 適用範圍
- 新功能架構設計
- 重大架構變更
- 技術債務評估
- 性能和安全審查
- 設計與實現一致性檢查
## 2. 會議類型
### 2.1 定期審查會議
| 會議類型 | 頻率 | 時長 | 參與者 | 主要議題 |
|----------|------|------|--------|----------|
| **月度架構審查** | 每月一次 | 60分鐘 | 全體開發人員 | 系統架構狀態、技術債務、性能指標 |
| **季度深度審查** | 每季度一次 | 120分鐘 | 架構師、技術負責人 | 架構演進、技術選型、長期規劃 |
| **年度戰略審查** | 每年一次 | 180分鐘 | 管理層、架構師 | 技術戰略、投資規劃、團隊能力 |
### 2.2 特別審查會議
| 觸發條件 | 時限 | 主要議題 |
|----------|------|----------|
| 新增重大功能 | 功能設計完成前 | 架構影響、技術選型、實現方案 |
| 發現重大技術債務 | 發現後1週內 | 債務評估、修復方案、優先級 |
| 性能或安全問題 | 問題發現後3天內 | 問題分析、解決方案、預防措施 |
| 設計實現不一致 | 發現後2天內 | 不一致原因、解決方案、文檔更新 |
## 3. 會議流程
### 3.1 會前準備
#### 3.1.1 主持人職責
1. 確定會議議程和目標
2. 邀請相關參與者
3. 準備審查材料
4. 設定會議時間和地點
#### 3.1.2 報告人職責
1. 準備審查文檔
2. 創建演示材料
3. 準備問題和討論點
4. 收集相關數據和指標
#### 3.1.3 審查材料要求
- **設計文檔**: 完整架構設計說明
- **代碼實現**: 關鍵代碼片段或鏈接
- **數據指標**: 性能、安全、質量指標
- **問題清單**: 需要討論的具體問題
- **決策選項**: 可能的解決方案和評估
### 3.2 會議進行
#### 3.2.1 標準議程 (60分鐘)
| 時間 | 議題 | 負責人 | 產出 |
|------|------|--------|------|
| 0-5分鐘 | 會議目標和議程 | 主持人 | 明確會議目標 |
| 5-20分鐘 | 架構狀態報告 | 報告人 | 當前架構概述 |
| 20-35分鐘 | 問題分析和討論 | 全體 | 問題清單和解決方案 |
| 35-50分鐘 | 決策制定 | 全體 | 架構決策記錄 |
| 50-55分鐘 | 行動計劃 | 主持人 | 任務分配和時間表 |
| 55-60分鐘 | 會議總結 | 主持人 | 會議紀要和後續步驟 |
#### 3.2.2 討論規則
1. **技術導向**: 聚焦技術問題,避免個人攻擊
2. **數據驅動**: 基於數據和事實進行討論
3. **開放包容**: 鼓勵不同意見和建議
4. **時間管理**: 嚴格遵守時間安排
5. **結果導向**: 每個討論都應有明確結論
### 3.3 會後行動
#### 3.3.1 會議紀要要求
- **基本信息**: 會議時間、地點、參與者
- **討論要點**: 主要討論內容和觀點
- **決策記錄**: 所有決策和決策理由
- **行動計劃**: 具體任務、負責人、完成時間
- **後續跟進**: 下次會議安排和準備工作
#### 3.3.2 文檔更新
1. **架構文檔更新**: 根據決策更新相關文檔
2. **決策卡片創建**: 記錄新的架構決策
3. **代碼註釋更新**: 更新相關代碼註釋
4. **知識庫更新**: 更新團隊知識庫
## 4. 審查內容
### 4.1 設計與實現一致性
| 檢查項目 | 檢查方法 | 通過標準 |
|----------|----------|----------|
| **分片類型一致性** | 比較設計文檔與代碼實現 | 設計與實現差異 ≤5% |
| **數據模型一致性** | 檢查數據結構定義 | 所有字段都有明確定義 |
| **API 設計一致性** | 驗證 API 設計與實現 | API 端點和參數一致 |
| **處理管道一致性** | 檢查處理流程實現 | 處理順序和結果符合設計 |
### 4.2 技術債務評估
| 債務類型 | 評估指標 | 處理建議 |
|----------|----------|----------|
| **代碼債務** | 代碼複雜度、重複率 | 重構、提取公共組件 |
| **設計債務** | 架構複雜度、耦合度 | 架構重構、模塊化 |
| **文檔債務** | 文檔完整性、準確性 | 文檔更新、示例添加 |
| **測試債務** | 測試覆蓋率、質量 | 增加測試、改進測試策略 |
### 4.3 性能和安全審查
| 審查維度 | 檢查項目 | 評估標準 |
|----------|----------|----------|
| **性能** | 響應時間、吞吐量、資源使用 | 符合性能要求 |
| **安全** | 認證授權、數據加密、訪問控制 | 無已知安全漏洞 |
| **可擴展性** | 水平擴展能力、負載均衡 | 支持業務增長 |
| **可靠性** | 可用性、故障恢復、監控 | 系統穩定運行 |
## 5. 決策記錄
### 5.1 決策卡片模板
```
決策編號: AD-YYYY-NNN
決策名稱: [簡要描述]
決策時間: YYYY-MM-DD
決策狀態: [待定/已批准/已實施/已撤銷]
問題描述:
[詳細描述需要解決的問題]
決策選項:
1. 選項 A: [描述和評估]
2. 選項 B: [描述和評估]
3. 選項 C: [描述和評估]
最終決策:
[選擇的選項和理由]
實施方案:
[具體實施步驟和時間表]
影響評估:
[正面影響、負面影響、風險]
相關文件:
[鏈接到相關文檔和代碼]
```
### 5.2 決策追蹤
| 決策狀態 | 追蹤要求 | 負責人 |
|----------|----------|--------|
| **待定** | 定期跟進討論進度 | 決策發起人 |
| **已批准** | 制定詳細實施計劃 | 項目負責人 |
| **已實施** | 驗證實施效果 | 質量保證 |
| **已撤銷** | 記錄撤銷原因 | 架構師 |
## 6. 工具和模板
### 6.1 會議工具
- **日程管理**: Google Calendar, Outlook
- **文檔協作**: Google Docs, Confluence
- **代碼審查**: GitHub, GitLab
- **項目管理**: Jira, Trello, Asana
### 6.2 模板文件
1. **會議議程模板**: `templates/meeting_agenda.md`
2. **會議紀要模板**: `templates/meeting_minutes.md`
3. **決策卡片模板**: `templates/decision_card.md`
4. **審查清單模板**: `templates/review_checklist.md`
### 6.3 自動化工具
1. **一致性檢查**: `scripts/check_architecture_docs.py`
2. **安全檢查**: `scripts/security_check.sh`
3. **性能監控**: Prometheus + Grafana
4. **代碼質量**: cargo clippy, cargo fmt
## 7. 角色和職責
### 7.1 架構師
- **主要職責**: 架構設計、技術決策、審查主持
- **具體任務**:
- 制定架構標準和規範
- 主持架構審查會議
- 審批重大架構變更
- 管理技術債務
### 7.2 開發人員
- **主要職責**: 代碼實現、問題報告、建議提供
- **具體任務**:
- 準備審查材料
- 參與技術討論
- 實施審查決策
- 報告技術問題
### 7.3 質量保證
- **主要職責**: 質量驗證、測試執行、指標監控
- **具體任務**:
- 驗證架構決策實施效果
- 監控系統質量和性能
- 提供測試反饋
- 報告質量問題
### 7.4 項目經理
- **主要職責**: 進度跟蹤、資源協調、風險管理
- **具體任務**:
- 協調審查會議安排
- 跟蹤決策實施進度
- 管理項目風險
- 協調跨團隊合作
## 8. 成功指標
### 8.1 過程指標
| 指標 | 目標值 | 測量方法 |
|------|--------|----------|
| **會議準時率** | ≥95% | 會議準時開始和結束 |
| **參與率** | ≥80% | 關鍵人員出席率 |
| **決策效率** | ≤2次會議 | 從問題提出到決策完成 |
| **文檔更新及時性** | ≤3天 | 決策後文檔更新時間 |
### 8.2 結果指標
| 指標 | 目標值 | 測量方法 |
|------|--------|----------|
| **設計實現一致性** | ≥95% | 定期一致性檢查 |
| **技術債務減少** | ≥10%/季度 | 技術債務評估 |
| **系統性能提升** | ≥5%/季度 | 性能監控數據 |
| **團隊滿意度** | ≥4.0/5.0 | 團隊調查問卷 |
### 8.3 質量指標
| 指標 | 目標值 | 測量方法 |
|------|--------|----------|
| **代碼質量** | ≥4.0/5.0 | 代碼審查評分 |
| **文檔質量** | ≥4.0/5.0 | 文檔審查評分 |
| **決策質量** | ≥4.0/5.0 | 決策效果評估 |
| **知識傳播** | ≥80% | 團隊知識測試 |
## 9. 持續改進
### 9.1 反饋收集
1. **會議效果調查**: 每次會議後收集參與者反饋
2. **流程評估**: 每季度評估審查流程效果
3. **工具評估**: 定期評估工具使用效果
4. **培訓需求**: 識別團隊培訓需求
### 9.2 流程優化
1. **簡化流程**: 去除不必要的步驟和文檔
2. **自動化工具**: 增加自動化檢查和報告
3. **模板改進**: 根據使用反饋改進模板
4. **培訓加強**: 提供更多培訓和支持
### 9.3 知識管理
1. **經驗總結**: 記錄成功經驗和失敗教訓
2. **最佳實踐**: 總結和推廣最佳實踐
3. **案例庫建設**: 建立架構決策案例庫
4. **培訓材料**: 創建培訓材料和課程
---
**最後更新**: 2026-04-22
**版本**: V1.0
**生效日期**: 2026-04-22
**審查週期**: 每季度審查更新
@@ -0,0 +1,400 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Momentry Core 架構路線圖 (Architecture Roadmap)"
date: "2026-04-22"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "架構路線圖"
- "momentry"
- "core"
ai_query_hints:
- "查詢 Momentry Core 架構路線圖 (Architecture Roadmap) 的內容"
- "Momentry Core 架構路線圖 (Architecture Roadmap) 的主要目的是什麼?"
- "如何操作或實施 Momentry Core 架構路線圖 (Architecture Roadmap)"
---
# Momentry Core 架構路線圖 (Architecture Roadmap)
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-22 |
| 文件版本 | V1.0 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 |
|------|------|------|--------|
| V1.0 | 2026-04-22 | 創建架構路線圖文件 | OpenCode |
---
## 1. 路線圖總覽
本路線圖定義了 Momentry Core 架構發展的階段性目標和時間規劃,涵蓋從基礎架構到高級功能的全面發展。
### 階段劃分:
```
Phase 0: 現狀 (Current State) [✅ 已實現]
Phase 1: 近期增強 (Short-term Improvements) [🔄 進行中]
Phase 2: 中期擴展 (Medium-term Expansion) [📅 規劃中]
Phase 3: 遠景目標 (Long-term Vision) [🔮 規劃中]
```
---
## 2. 現狀 (Phase 0) - 已實現功能
### 2.1 核心架構
-**API 層**: Axum + Tower + Serde 架構
-**數據訪問層**: PostgreSQL, Redis, MongoDB, Qdrant 集成
-**處理器管理**: PythonExecutor 異步調用
### 2.2 分片規則實現狀態
| 規則 | 實現狀態 | 完成時間 |
|------|----------|----------|
| Rule 1 (句子級) | ✅ 完整實現 | 2026-03-25 |
| Rule 3 (場景級) | ⚠️ 部分實現 | 2026-04-01 |
| Rule 2 (視覺級) | ❌ 未實現 | - |
| Rule 4 (摘要級) | ❌ 未實現 | - |
### 2.3 已完成功能模塊
1. **視頻註冊與元數據提取**
- ✅ FFprobe 元數據提取
- ✅ 檔案 UUID 生成
- ✅ PostgreSQL 存儲
2. **AI 處理器集成**
- ✅ ASR (WhisperX) 語音識別
- ✅ Face (InsightFace) 人臉識別
- ✅ YOLO 物件檢測(部分)
3. **檢索與查詢**
- ✅ 句子級文本搜索
- ✅ 基本場景識別(基於 CUT
---
## 3. 近期增強 (Phase 1) - 1-2個月內完成
### 3.1 分片架構完善
#### 目標 1: 完成 Rule 3 (場景級分片)完整實現
**時間**: 2026年5月底前
**內容**
1. 集成 Places365 場景分類模型
2. 實現基於視覺和語音的場景邊界識別
3. 創建 `chunks_rule3` 表的完整結構
4. 完善 `src/core/chunk/rule3_ingest.rs`
#### 目標 2: 開始 Rule 2 (視覺分片) 實現
**時間**: 2026年6月底前
**內容**
1. 集成 YOLO 物件檢測
2. 創建物件標籤索引
3. 設計 `chunks_rule2` 表結構
4. 開始 `src/core/chunk/rule2_ingest.rs` 框架
### 3.2 技術棧優化
#### 目標 3: Python-Rust 橋接優化
**時間**: 2026年5月中旬前
**內容**
1. 改進 `PythonExecutor` 性能
2. 實現進程池管理
3. 優化序列化/反序列化開銷
4. 添加錯誤重試機制
#### 目標 4: 數據庫優化
**時間**: 2026年6月中旬前
**內容**
1. 優化 PostgreSQL 查詢性能
2. 改進 Redis 緩存策略
3. 優化 Qdrant 向量搜索效率
4. 添加數據庫監控指標
---
## 4. 中期擴展 (Phase 2) - 3-6個月內完成
### 4.1 分片架構完整實現
#### 目標 5: 完成 Rule 2 (視覺分片) 實現
**時間**: 2026年9月底前
**內容**
1. 完整實現 YOLO 物件檢測集成
2. 建立物件標籤標準化和索引
3. 完成 `src/core/chunk/rule2_ingest.rs`
4. 創建完整的 `chunks_rule2`
#### 目標 6: 開始 Rule 4 (摘要分片) 實現
**時間**: 2026年10月底前
**內容**
1. 集成 LLM 摘要生成模型
2. 實現 5W1H 結構化提取
3. 設計 `chunks_rule4` 表結構
4. 開始 `src/core/chunk/rule4_ingest.rs` 框架
### 4.2 系統性能提升
#### 目標 7: 大規模視頻處理能力
**時間**: 2026年11月底前
**內容**
1. 支持批量視頻註冊
2. 實現並行處理優化
3. 添加處理隊列管理
4. 提高系統吞吐量
#### 目標 8: 用戶體驗優化
**時間**: 2026年12月底前
**內容**
1. 改進搜索速度
2. 優化 API 響應時間
3. 添加結果排序和過濾
4. 提升系統穩定性
---
## 5. 遠景目標 (Phase 3) - 6-12個月內完成
### 5.1 平台化發展
#### 目標 9: 微服務架構遷移
**時間**: 2027年2月底前
**內容**
1. 將單體應用拆分成微服務
2. 實現服務發現和負載均衡
3. 添加分布式追蹤
4. 構建可擴展的微服務架構
#### 目標 10: 雲原生支持
**時間**: 2027年4月底前
**內容**
1. 容器化部署支持
- Docker 容器化
- Kubernetes 編排
- Helm 包管理
2. 雲端部署優化
- AWS EKS 集成
- GCP GKE 支持
- Azure AKS 兼容
### 5.2 高級功能實現
#### 目標 11: 實時處理引擎
**時間**: 2027年6月底前
**內容**
1. 支持實時視頻流處理
2. 實現低延遲分析
3. 添加實時通知
4. 構建事件驅動架構
#### 目標 12: 智能工作流
**時間**: 2027年8月底前
**內容**
1. 自動化視頻分析流程
2. 智能任務調度
3. 動態資源分配
4. 自適應處理策略
### 5.3 擴展性增強
#### 目標 13: 多模態分析能力
**時間**: 2027年10月底前
**內容**
1. 集成更多 AI 模型
2. 支持更多視頻格式
3. 提供更多分析維度
4. 增強結果可視化
#### 目標 14: 企業級功能支持
**時間**: 2027年12月底前
**內容**
1. 多租戶支持
2. 權限管理系統
3. 審計日誌功能
4. 合規性支持
---
## 6. 關鍵里程碑
### 2026年:
-**2026-03-25**: Rule 1 (句子級分片)完整實現
-**2026-05-31**: 完成 Rule 3 (場景級分片)
-**2026-09-30**: 完成 Rule 2 (視覺分片)
### 2027年:
- 📅 **2027-02-28**: 微服務架構遷移完成
- 📅 **2027-06-30**: 實時處理引擎上線
- 📅 **2027-12-31**: 企業級功能完整實現
---
## 7. 風險與挑戰
### 技術挑戰:
1. **AI 模型集成**
- 多模型協同工作
- 性能和準確性平衡
- 資源管理優化
2. **數據一致性**
- 多數據庫同步
- 事務管理
- 錯誤恢復機制
3. **性能擴展**
- 大規模視頻處理
- 並發控制
- 資源調度優化
### 非技術挑戰:
1. **資源限制**
- 計算資源需求
- 開發人力配置
- 測試環境準備
2. **優先級管理**
- 功能實現順序
- 技術債務處理
- 用戶需求平衡
---
## 8. 成功標準
### 技術成功標準:
1. **性能指標**
- API 響應時間 < 500ms
- 視頻處理速度 > 10x 實時速度
- 系統可用性 > 99.9%
2. **功能指標**
- 分片規則完整實現率 > 90%
- AI 模型準確率 > 85%
- 檢索結果相關性 > 80%
### 業務成功標準:
1. **用戶滿意度**
- 搜索結果滿意度 > 85%
- 系統易用性評分 > 4/5
- 功能完整性評分 > 4/5
2. **系統可靠性**
- 平均故障間隔時間 > 30天
- 平均修復時間 < 1小時
- 數據丟失率 < 0.1%
---
## 9. 監控與評估
### 性能監控:
1. **實時指標**
- API 延遲
- 並發用戶數
- 資源使用率
2. **業務指標**
- 視頻處理成功率
- 用戶活躍度
- 功能使用頻率
### 評估機制:
1. **每月評估**
- 進度審查
- 性能分析
- 問題識別
2. **季度審計**
- 技術架構評估
- 質量保證
- 風險管理
---
## 10. 更新頻率
### 路線圖更新:
| 更新類型 | 頻率 | 責任人 |
|----------|------|--------|
| 詳細規劃 | 每月 | 技術負責人 |
| 重大調整 | 季度 | 架構委員會 |
| 年度規劃 | 每年 | 管理層 |
### 溝通機制:
1. **內部溝通**
- 每周技術會議
- 月度架構審查
- 季度成果展示
2. **外部溝通**
- 每月進度報告
- 季度技術更新
- 年度發展規劃
---
## 11. 相關文件
| 文件 | 描述 | 相關性 |
|------|------|--------|
| [ARCHITECTURE_OVERVIEW.md](./ARCHITECTURE_OVERVIEW.md) | 架構總覽 | 整體規劃 |
| [TECHNICAL_DECISION_RECORDS.md](./TECHNICAL_DECISION_RECORDS.md) | 技術決策記錄 | 決策參考 |
| [CHUNKING_ARCHITECTURE.md](./chunking/CHUNKING_ARCHITECTURE.md) | 分片架構 | 技術實現 |
| [PROJECT_DOCS_V1_INTEGRATION_PLAN.md](../PROJECT_DOCS_V1_INTEGRATION_PLAN.md) | 項目整合計劃 | 總體規劃 |
---
## 12. 最後更新記錄
| 版本 | 日期 | 主要變更 | 操作人 |
|------|------|----------|--------|
| V1.0 | 2026-04-22 | 創建架構路線圖文件 | OpenCode |
**最後更新日期**: 2026-04-22
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,348 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "設計與實現差異分析"
date: "2026-04-22"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "設計與實現差異分析"
ai_query_hints:
- "查詢 設計與實現差異分析 的內容"
- "設計與實現差異分析 的主要目的是什麼?"
- "如何操作或實施 設計與實現差異分析?"
---
# 設計與實現差異分析
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-22 |
| 文件版本 | V1.0 |
| 相關文件 | [ARCHITECTURE_OVERVIEW.md](./ARCHITECTURE_OVERVIEW.md)<br>[TECHNICAL_DECISION_RECORDS.md](./TECHNICAL_DECISION_RECORDS.md)<br>[ARCHITECTURE_ROADMAP.md](./ARCHITECTURE_ROADMAP.md) |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-04-22 | 創建設計與實現差異分析文件 | OpenCode | OpenCode / deepseek-v3.2 |
---
## 1. 概述
本文檔記錄 Momentry Core 系統中設計文檔與實際實現之間的差異,包括:
1. 設計與實現不一致的原因分析
2. 當前實現狀態評估
3. 後續改進計劃
4. 臨時解決方案
**核心原則**:當設計與實現出現矛盾時,優先參考實際的 Rust 代碼實現。
---
## 2. 關鍵差異分析
### 2.1 分片類型 (Chunk Type) 不匹配
#### 設計文檔中的分片類型
```
chunk_type 值:
1. sentence # 句子級分片
2. visual # 視覺物件級分片
3. scene # 場景級分片
4. summary # 摘要級分片
```
#### 實際 Rust 代碼中的分片類型
```rust
// src/core/chunk/mod.rs 中的 ChunkType 枚舉
pub enum ChunkType {
TimeBased, // 對應設計中的 "time" 分片
Sentence, // 對應設計中的 "sentence" 分片
Cut, // 對應設計中的 "cut" 分片(場景檢測)
Trace, // 對應設計中的 "trace" 分片(軌跡追蹤)
Story, // 對應設計中的 "story" 分片(敘事)
}
```
#### 差異分析
| 設計概念 | 設計值 | 實現值 | 差異原因 | 狀態 |
|----------|--------|--------|----------|------|
| 句子級分片 | `sentence` | `Sentence` | 命名一致 | ✅ 一致 |
| 時間基準分片 | `time` | `TimeBased` | 命名更精確 | ✅ 一致 |
| 場景級分片 | `scene` | `Cut` | 基於 CUT 算法實現 | ⚠️ 部分一致 |
| 視覺物件級分片 | `visual` | 無對應實現 | 尚未實現視覺分片 | ❌ 缺失 |
| 摘要級分片 | `summary` | `Story` | 概念近似但實現不同 | ⚠️ 部分一致 |
| 軌跡追蹤分片 | `trace` | `Trace` | 命名一致 | ✅ 一致 |
#### 根本原因
1. **設計先行**:架構設計在代碼實現之前完成
2. **迭代開發**:實際開發中根據技術可行性調整
3. **優先級調整**:某些功能因資源限制推遲實現
---
## 3. 分片規則實現狀態詳情
### 3.1 Rule 1: 句子級分片 ✅ 已完整實現
#### 設計要求
- 基於 ASR 轉錄結果的句子邊界
- 包含時間戳和文本內容
- 支持語義搜索
#### 實際實現
- ✅ 完整實現:`src/core/chunk/rule1_ingest.rs`
- ✅ 功能完整:支持句子提取、時間戳映射、嵌入生成
- ✅ 集成測試:有完整的單元測試和集成測試
#### 一致性評估:95%
- 設計功能全部實現
- 性能符合設計要求
- 接口設計一致
### 3.2 Rule 2: 視覺物件級分片 ❌ 未實現
#### 設計要求
- 基於 YOLO 物件檢測的視覺分片
- 物件類別、位置、時間戳
- 視覺搜尋能力
#### 實際實現
- ❌ 未實現:缺乏專門的視覺分片處理器
- ⚠️ 部分功能:YOLO 處理器存在但未用於分片生成
- ❌ 數據結構:缺乏視覺分片專用數據結構
#### 差距分析
1. **技術依賴**:需要成熟的 YOLO 集成方案
2. **資源限制**GPU 資源優先給其他處理器
3. **優先級調整**:語義分片優先於視覺分片
#### 臨時解決方案
- 使用現有的 YOLO 檢測結果作為元數據
- 通過關鍵幀提取實現基礎視覺檢索
- 計劃在 Phase 2 完整實現
### 3.3 Rule 3: 場景級分片 ⚠️ 部分實現
#### 設計要求
- 基於視覺和音頻特徵的場景分割
- 語義連續的視頻段落
- 場景級檢索和分析
#### 實際實現
- ⚠️ 部分實現:使用 CUT 算法檢測場景邊界
- ❌ 功能不完整:缺乏場景語義分析
- ✅ 基礎框架:有場景分片的數據結構
#### 具體差距
1. **算法限制**:CUT 主要基於視覺相似度,缺乏語義理解
2. **時間粒度**:場景邊界檢測不夠精確
3. **集成程度**:未與其他分片規則深度集成
#### 改進方向
1. 集成音頻特徵增強場景檢測
2. 添加語義聚類提升場景質量
3. 完善場景與其他分片的關聯
### 3.4 Rule 4: 摘要級分片 ⚠️ 部分實現(概念調整)
#### 設計要求
- 基於 LLM 的視頻內容摘要
- 結構化摘要格式(5W1H
- 高層級敘事理解
#### 實際實現
- ⚠️ 概念調整:實現為 `Story` 分片而非 `Summary`
- ❌ 功能缺失:缺乏自動摘要生成
- ✅ 框架支持:有故事分片的數據結構
#### 差異說明
- **設計概念**`summary` - 基於 LLM 的結構化摘要
- **實現概念**`story` - 基於分片聚合的敘事重建
- **原因**:LLM 集成複雜度高,優先實現基於現有數據的敘事
#### 過渡計劃
1. 短期:完善 `Story` 分片基於現有數據
2. 中期:集成 LLM 增強敘事質量
3. 長期:實現完整的摘要生成
---
## 4. 數據模型差異
### 4.1 設計中的數據模型
```json
{
"chunk_type": "sentence|visual|scene|summary",
"content": {
"text": "轉錄文本",
"visual_objects": ["person", "car", "dog"],
"scene_context": "辦公室會議",
"summary": "會議討論項目進度"
},
"metadata": {
"timestamp": 1234567890,
"duration": 5.0,
"source_video": "video_123"
}
}
```
### 4.2 實際實現的數據模型
```rust
// src/core/chunk/mod.rs 中的 Chunk 結構
pub struct Chunk {
pub id: i64,
pub uuid: String,
pub video_record_id: i64,
pub chunk_type: ChunkType, // TimeBased|Sentence|Cut|Trace|Story
pub start_time: f64,
pub end_time: f64,
pub content: serde_json::Value, // 動態 JSON 內容
pub embedding: Option<Vec<f32>>,
pub created_at: DateTime<Utc>,
}
```
### 4.3 差異分析
| 維度 | 設計 | 實現 | 影響 |
|------|------|------|------|
| **類型定義** | 四個固定類型 | 可擴展枚舉 | 更好的可擴展性 |
| **內容結構** | 固定字段結構 | 動態 JSON | 更靈活但類型不安全 |
| **時間表示** | 單一時間戳 + 時長 | 開始/結束時間 | 更精確的時間管理 |
| **嵌入存儲** | 未明確定義 | 可選向量存儲 | 支持向量搜索 |
### 4.4 建議改進
1. **類型安全**:為不同分片類型定義專用的內容結構
2. **遷移路徑**:從動態 JSON 逐步過渡到類型安全結構
3. **版本兼容**:保持向後兼容性
---
## 5. 處理管道差異
### 5.1 設計中的處理管道
```
ASR → OCR → YOLO → CUT → LLM → 分片生成
```
### 5.2 實際實現的處理管道
```
ASR → OCR → YOLO → CUT → 分片生成
LLM(尚未集成)
```
### 5.3 關鍵差異
1. **LLM 集成**:設計中有完整的 LLM 階段,實際尚未集成
2. **順序調整**:部分處理器執行順序根據依賴關係調整
3. **並行處理**:實際實現中有更多並行處理優化
### 5.4 改進計劃
1. **LLM 集成**Phase 2 計劃集成 Gemma-4 模型
2. **管道重構**:根據實際經驗優化處理順序
3. **錯誤處理**:增強管道中的錯誤恢復機制
---
## 6. 臨時解決方案記錄
### 6.1 當前採用的臨時方案
| 問題 | 臨時方案 | 風險 | 長期方案 |
|------|----------|------|----------|
| 視覺分片缺失 | 使用關鍵幀 + YOLO 結果 | 檢索精度有限 | 實現完整的視覺分片規則 |
| 摘要生成缺失 | 基於句子聚合生成敘事 | 缺乏高層理解 | 集成 LLM 摘要生成 |
| 場景語義缺失 | 使用 CUT 結果 + 簡單聚類 | 場景質量一般 | 增強語義場景檢測 |
| 動態 JSON 類型 | 現有實現 | 類型不安全 | 定義類型安全結構 |
### 6.2 臨時方案的影響評估
1. **功能完整性**:核心功能完整,高級功能有限
2. **用戶體驗**:基礎搜索良好,高級檢索受限
3. **維護成本**:當前實現相對簡單,易於維護
4. **擴展性**:動態 JSON 提供良好擴展性但犧牲類型安全
---
## 7. 改進路線圖
### 7.1 短期改進(1-2個月)
#### 優先級 P0:修復設計與實現不一致
1. **文檔更新**:更新所有架構文檔反映實際實現
2. **類型定義統一**:統一設計與實現中的術語
3. **實現狀態標記**:在所有文檔中標記實現狀態
#### 優先級 P1:補齊缺失功能
1. **視覺分片基礎**:實現 Rule 2 基礎框架
2. **場景語義增強**:改進 Rule 3 語義分析
3. **故事生成完善**:增強 Rule 4 敘事質量
### 7.2 中期改進(3-6個月)
#### 完整實現設計功能
1. **Rule 2 完整實現**:集成 YOLO 生成視覺分片
2. **Rule 3 語義增強**:實現語義場景分割
3. **Rule 4 LLM 集成**:集成 Gemma-4 生成摘要
#### 架構優化
1. **類型安全重構**:從動態 JSON 遷移到類型安全結構
2. **處理管道優化**:根據實際經驗重新設計管道
3. **效能改進**:基於監控數據進行效能優化
### 7.3 長期願景(6-12個月)
#### 超越原始設計
1. **多模態融合**:深度融合視覺、音頻、文本特徵
2. **智能分片**:基於 AI 的自適應分片策略
3. **實時處理**:支持實時視頻流的在線處理
---
## 8. 結論與建議
### 8.1 當前狀態總結
1. **核心功能**:✅ 完整實現(Rule 1 句子級分片)
2. **高級功能**:⚠️ 部分實現(Rule 3 場景分片)
3. **缺失功能**:❌ 尚未實現(Rule 2 視覺分片,Rule 4 完整摘要)
4. **架構一致性**:⚡ 存在差異但可管理
### 8.2 後續行動建議
#### 立即行動(本週)
1. ✅ 已創建本文檔記錄所有差異
2. 🔄 更新架構概覽文檔反映實際狀態
3. 📋 制定詳細改進計劃
#### 近期行動(1個月內)
1. 🛠️ 實現 Rule 2 視覺分片基礎框架
2. 🔧 增強 Rule 3 場景語義分析
3. 📊 建立設計與實現一致性檢查流程
#### 長期策略
1. 🎯 定期審查設計與實現一致性
2. 🔄 建立文檔與代碼同步機制
3. 📈 基於用戶反饋持續優化架構
### 8.3 風險管理
| 風險 | 影響 | 緩解措施 |
|------|------|----------|
| **設計與實現脫節** | 功能混亂,維護困難 | 定期一致性檢查 |
| **臨時方案固化** | 技術債務積累 | 明確遷移計劃和時間表 |
| **用戶期望不匹配** | 用戶體驗差 | 清晰溝通功能狀態 |
### 8.4 最終建議
1. **接受現狀**:承認設計與實現的差異是正常開發過程
2. **有序改進**:按照優先級逐步縮小差距
3. **持續優化**:建立長期機制確保設計與實現的一致性
4. **用戶為中心**:以實際用戶需求為導向調整設計
**核心原則重申**:在出現矛盾時,實際的 Rust 代碼實現是最高權威,設計文檔應反映實際實現狀態並指導未來改進方向。
@@ -0,0 +1,167 @@
# Document Embedding Strategy - Parent-Child Chunks
| Item | Content |
|------|---------|
| Author | Warren |
| Created | 2026-03-23 |
| Document Version | V1.0 |
---
## Version History
| Version | Date | Purpose | Operator | Tool/Model |
|---------|------|---------|----------|------------|
| V1.0 | 2026-03-23 | Create document embedding strategy | Warren | OpenCode |
---
## Overview
Momentry uses a **parent-child chunk hierarchy** for improved RAG retrieval. This document describes the embedding strategy for this hierarchy.
## Chunk Structure
### Parent Chunk
- **Purpose**: Summarize multiple child chunks with narrative description
- **Content**: High-level description of multiple scenes/segments
- **Example**:
```json
{
"chunk_id": "story_asr_0000",
"chunk_type": "story",
"text_content": "[0s-125s] A man enters a building. He walks down a hallway.",
"child_chunk_ids": ["asr_0001", "asr_0002", "asr_0003", "asr_0004", "asr_0005"]
}
```
### Child Chunk
- **Purpose**: Individual segments from ASR, scenes from CUT, etc.
- **Content**: Raw transcription or detection results
- **Example**:
```json
{
"chunk_id": "asr_0001",
"chunk_type": "sentence",
"text_content": "Hello world",
"parent_chunk_id": "story_asr_0000"
}
```
## Embedding Strategy
### For Vector Search
When embedding chunks for vector search, we combine **parent description + child content** to provide both context and detail.
#### Parent Chunk Embedding
```
embedding_text = f"Summary: {parent.text_content}
Children: {child_text_1}. {child_text_2}. {child_text_3}..."
```
**Prefix**: `search_document:` (for documents in Qdrant)
**Example**:
```
search_document: Summary: A man enters a building. He walks down a hallway.
Children: Hello, how are you? I'm fine thank you. The weather is nice today.
```
#### Child Chunk Embedding
```
embedding_text = f"[{child.chunk_type}] {child.text_content}
Parent: {parent.description}"
```
**Prefix**: `search_document:`
**Example**:
```
search_document: [sentence] Hello, how are you?
Parent: A man enters a building. He walks down a hallway.
```
### For BM25 Text Search
BM25 operates on raw text with PostgreSQL full-text search.
- **Index**: `search_vector` (TSVECTOR) on `chunks.text_content`
- **Search**: Uses `ts_rank_cd()` for ranking
## Hybrid Search Ranking
Combined score = `(vector_score * 0.7) + (bm25_score * 0.3)`
### Why 0.7/0.3?
| Weight | Vector | BM25 |
|--------|--------|------|
| Pros | Semantic similarity | Exact keyword match |
| Cons | May miss specific terms | No semantic understanding |
| Best for | Thematic queries | Fact lookup |
## Query Patterns
### Thematic Query ("What are the main themes?")
- Use higher `vector_weight` (0.8-0.9)
- Vector search finds semantically similar content
### Fact Lookup ("Who said X?")
- Use higher `bm25_weight` (0.5-0.7)
- BM25 finds exact matches
### Balanced ("Tell me about scene 5")
- Use default 0.7/0.3
## Implementation
### Embedding Generation
```rust
fn build_embedding_text(chunk: &Chunk, parent_text: Option<&str>) -> String {
match chunk.chunk_type {
ChunkType::Story => {
format!(
"Summary: {}\nChildren: {}",
chunk.text_content,
get_children_text(chunk)
)
}
_ => {
format!(
"[{}] {}\nParent: {}",
chunk.chunk_type.as_str(),
chunk.text_content,
parent_text.unwrap_or("N/A")
)
}
}
}
```
### Storage
- Parent chunks stored with their `child_chunk_ids`
- Child chunks reference `parent_chunk_id`
- Both stored in PostgreSQL with full-text index
- Vectors stored in Qdrant
## Example Flow
1. **Story Processing** generates parent-child hierarchy
2. **Embedding** creates vector for each chunk
3. **Storage** saves to PostgreSQL + Qdrant
4. **Search** retrieves using hybrid search
5. **Results** include both parent context and child details
## Best Practices
1. **Chunk Size**: 5 child chunks per parent (configurable)
2. **Text Length**: Keep embeddings under 512 tokens
3. **Parent Description**: Include temporal markers (timestamps)
4. **Child Content**: Preserve original transcription
## Future Enhancements
- [ ] GraphRAG integration for relationship traversal
- [ ] Cross-chunk entity linking
- [ ] Temporal graph building
@@ -0,0 +1,918 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "事件識別(Event Recognition)技術方案分析"
date: "2026-04-01"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
ai_query_hints:
- "查詢 事件識別(Event Recognition)技術方案分析 的內容"
- "事件識別(Event Recognition)技術方案分析 的主要目的是什麼?"
- "如何操作或實施 事件識別(Event Recognition)技術方案分析?"
---
# 事件識別(Event Recognition)技術方案分析
| 項目 | 內容 |
|------|------|
| 分析日期 | 2026-04-01 |
| 目標 | 影片中的人類行為與事件識別 |
| 應用場景 | 安全監控、運動分析、日常活動記錄 |
---
## 事件識別分類
### 1. 按事件類型
```
暴力事件:
├─ 打架
├─ 吵架
├─ 推擠
└─ 破壞物品
運動事件:
├─ 球類運動
│ ├─ 籃球
│ ├─ 足球
│ ├─ 網球
│ └─ 排球
├─ 格鬥運動
│ ├─ 拳擊
│ ├─ 柔道
│ └─ 跆拳道
└─ 其他運動
├─ 跑步
├─ 游泳
└─ 騎自行車
日常活動:
├─ 飲食相關
│ ├─ 吃飯
│ ├─ 喝水
│ ├─ 做菜
│ └─ 清洗碗筷
├─ 居家活動
│ ├─ 打掃
│ ├─ 洗衣服
│ ├─ 整理房間
│ └─ 看電視
├─ 社交互動
│ ├─ 交談
│ ├─ 擁抱
│ ├─ 握手
│ └─ 玩耍
└─ 個人護理
├─ 刷牙
├─ 洗臉
└─ 化妝
安全事件:
├─ 跌倒
├─ 暈倒
├─ 火災
└─ 入侵
```
### 2. 按時序特性
```
瞬時事件 (< 1秒):
├─ 拍手
├─ 跳躍
└─ 投擲
短期事件 (1-10秒):
├─ 打架
├─ 跌倒
├─ 握手
└─ 喝水
長期事件 (> 10秒):
├─ 吃飯
├─ 做菜
├─ 運動
└─ 交談
```
---
## 技術方法分類
### 方法 1:時空動作檢測(Spatiotemporal Action Detection
**特點**
- 檢測影片中的人物位置 + 行為類別
- 輸出:時空管(spatiotemporal tube
**代表模型**
#### 1.1 SlowFast Network
```python
# Facebook AI Research (FAIR)
# CVPR 2019
特點:
- 雙路徑架構
- Slow pathway: 高空間分辨率低時間分辨率
- Fast pathway: 低空間分辨率高時間分辨率
- AVA 數據集上 mAP 28.3%
優點:
平衡空間和時間信息
適合長短時事件
準確率高
缺點:
計算量大
記憶體消耗高適合 Mac Studio
```
#### 1.2 VideoMAE
```python
# 2022, Masked Autoencoder for Video
特點:
- 基於 Transformer
- 使用掩碼自編碼器預訓練
- Kinetics-400 81.5% Top-1
優點:
準確率高
數據效率好
可擴展性強
缺點:
訓練成本高
推理速度較慢
```
#### 1.3 MViT (Multiscale Vision Transformer)
```python
# 2021, Facebook AI
特點:
- 多尺度特徵金字塔
- 池化注意力機制
- Kinetics-400 80.8% Top-1
優點:
準確率高
效率較好
缺點:
模型較大
```
---
### 方法 2:骨架動作識別(Skeleton-based Action Recognition
**特點**
- 基於人體關鍵點(Pose
- 對背景不敏感
- 計算量小
**實現流程**
```python
流程:
影片 Pose 檢測 骨架序列 時序建模 動作分類
工具:
- Pose 檢測: MediaPipe, OpenPose, MMPose
- 時序建模: ST-GCN, CTR-GCN
```
#### 2.1 ST-GCN (Spatial Temporal Graph Convolutional Networks)
```python
# 2018, AAAI
特點:
- 將骨架建模為時空圖
- 鄰接關係身體連接 + 時間相鄰
- NTU-RGB+D 81.5% 準確率
優點:
計算量小適合邊緣 AI
對背景不敏感
實時性好
缺點:
需要準確的 Pose 檢測
遮擋問題
```
#### 2.2 CTR-GCN (Channel-wise Topology Refinement GCN)
```python
# 2021, ICCV
特點:
- 自適應學習圖拓撲
- 通道級特徵建模
- NTU-RGB+D 92.0% 準確率
優點:
準確率最高
自適應能力強
缺點:
複雜度較高
```
---
### 方法 3:雙流網絡(Two-Stream Networks
**特點**
- 空間流:單幀 RGB
- 時間流:光流(Optical Flow
- 融合預測
```python
架構:
RGB 空間 CNN 空間特徵
融合 動作類別
光流 時間 CNN 時間特徵
優點:
兼顧外觀和運動
準確率高
缺點:
需要計算光流
兩個網絡記憶體翻倍
```
---
### 方法 43D 卷積網絡(3D CNN)
**特點**
- 直接處理視頻片段
- 時空聯合建模
#### 4.1 I3D (Inflated 3D ConvNet)
```python
# 2017, CVPR
特點:
- 2D CNN 膨脹為 3D
- Kinetics-400 71.1% Top-1
優點:
端到端訓練
時空聯合建模
缺點:
計算量大
參數量多
```
#### 4.2 SlowFast
```python
# 見 1.1
改進:
- 雙速率處理
- 減少計算量
```
---
### 方法 5:時序動作檢測(Temporal Action Detection
**特點**
- 定位動作發生的時間段
- 不關心空間位置
#### 5.1 BMN (Boundary Matching Network)
```python
# 2019, ICCV
特點:
- 邊界匹配機制
- 生成動作提議
- THUMOS14 56.0% mAP@0.5
優點:
時間定位準確
適合長視頻
缺點:
需要後處理
```
#### 5.2 TAGS (Temporal Action Detection with Global Segmentation)
```python
# 2020
特點:
- 全局分割
- 端到端檢測
```
---
### 方法 6:多模態融合(Multimodal Fusion
**特點**
- 結合視覺、音頻、文本
- 提升準確率和魯棒性
```python
多模態融合:
視覺 (RGB)
融合模型 事件類別
音頻 (Audio)
文本 (ASR)
優點:
準確率最高
魯棒性強
可處理複雜事件如吵架
缺點:
複雜度高
需要多個處理器
```
---
## 數據集分析
### 大規模動作識別數據集
| 數據集 | 類別數 | 影片數 | 時長 | 標註類型 |
|--------|--------|--------|------|---------|
| **Kinetics-400** | 400 | 240K | 10s | 分類 |
| **Kinetics-700** | 700 | 650K | 10s | 分類 |
| **AVA** | 80 | 430 | 15min | 時空檢測 |
| **EPIC-KITCHENS** | 125 | 100h | 長視頻 | 時空檢測 |
| **NTU-RGB+D** | 60 | 56K | 骨架 | 分類 |
| **THUMOS14** | 20 | 20h | 長視頻 | 時間定位 |
### 適合的事件類型
#### Kinetics-400 包含的事件
```
日常活動:
├─ eating
├─ drinking
├─ cooking
├─ cleaning
├─ brushing teeth
├─ washing hands
└─ 等等
運動:
├─ playing basketball
├─ playing soccer
├─ swimming
├─ running
└─ 等等
互動:
├─ hugging
├─ shaking hands
├─ talking to
└─ 等等
暴力事件:
⚠️ 較少(需專門數據集)
```
#### 暴力事件專門數據集
| 數據集 | 類別 | 規模 |
|--------|------|------|
| **Hockey Fight** | 打架 | 1000 段 |
| **Movies Fight** | 打架 | 200 段 |
| **Violent-Flows** | 暴力 | 246 段 |
| **RWF-2000** | 暴力 | 2000 段 |
| **UBI-Fight** | 暴力 | 80h |
---
## 實現方案(Momentry 整合)
### 方案 A:基於骨架的輕量方案(推薦)⭐
**適合場景**:邊緣 AI、實時處理
```python
架構:
影片 Pose 檢測 骨架序列 ST-GCN 動作類別
使用現有 Pose 處理器
優點:
計算量小
可復用 Pose 結果
實時性好
適合 Mac Studio 並行處理
缺點:
依賴 Pose 檢測準確度
遮擋問題
```
**實現**
```python
# 新增處理器: Action Recognition
scripts/action_processor.py
依賴:
- Pose 檢測結果已存在
- ST-GCN 模型
流程:
1. 讀取 Pose 結果JSON
2. 提取骨架序列
3. ST-GCN 推理
4. 輸出動作類別 + 時間戳
輸出格式:
{
"actions": [
{
"start_time": 10.5,
"end_time": 15.2,
"action": "eating",
"confidence": 0.85,
"person_id": 1
}
]
}
```
---
### 方案 B:雙流網絡(平衡方案)
**適合場景**:準確率要求高
```python
架構:
影片 RGB ResNet-50 空間特徵
融合 動作
影片 光流 ResNet-50 時間特徵
優點:
準確率高
兼顧外觀和運動
缺點:
需要計算光流
記憶體消耗大
```
**優化**
```python
# 使用 TV-L1 光流(快速)
cv2.optflow.DualTVL1OpticalFlow_create()
# 或使用 RAFT 光流(準確)
from raft import RAFT
```
---
### 方案 CSlowFast(高端方案)
**適合場景**Mac Studio、最高準確率
```python
架構:
影片 SlowFast 網絡 動作類別
模型選擇:
- SlowFast R50: 中等準確率
- SlowFast R101: 高準確率
- SlowFast X3D: 輕量級
優點:
準確率最高
SOTA 性能
缺點:
計算量大
Mac Studio 64GB
```
---
### 方案 D:多模態融合(完整方案)
**適合場景**:複雜事件識別(如吵架)
```python
架構:
視覺 SlowFast 視覺特徵
融合 事件類別
音頻 ASR 文本特徵
示例吵架識別:
- 視覺: 肢體動作激烈
- 音頻: 語調高語速快
- 文本: 爭論性詞彙
優點:
準確率最高
可處理複雜事件
魯棒性強
缺點:
複雜度高
需要多個處理器協同
```
---
## 各類事件的識別策略
### 1. 暴力事件識別(打架、吵架)
#### 打架識別
```python
方法: 時空動作檢測
特徵:
- 快速肢體運動
- 多人近距離接觸
- 攻擊性動作模式
實現:
1. Pose 檢測 骨架序列
2. ST-GCN 動作分類
3. 結合 YOLO武器檢測
4. 時間滑動窗口檢測
模型:
- 數據集: RWF-2000, UBI-Fight
- 模型: SlowFast + ST-GCN 融合
- 閾值: confidence > 0.7
挑戰:
數據集小
類內變異大
遮擠遮擋
```
#### 吵架識別
```python
方法: 多模態融合
特徵:
視覺:
- 揮手指指點點
- 面部表情憤怒
- 近距離對峙
音頻:
- 音量突然提高
- 語速加快
- 語調激動
文本:
- 爭論性詞彙
- 情緒詞
實現:
1. 視覺: Face表情+ Pose手勢
2. 音頻: ASR語音內容+ 情感分析
3. 多模態融合 吵架判定
模型:
- 視覺: ST-GCN
- 音頻: 情感識別模型
- 文本: 情感分析BERT
準確率:
- 單模態: 60-70%
- 多模態融合: 80-85%
```
---
### 2. 運動事件識別
#### 球類運動
```python
方法: 骨架動作識別 + 物體檢測
籃球:
Pose: 投籃運球傳球動作
YOLO: 籃球檢測
組合: 投籃 = 投籃姿勢 + 籃球拋物線
足球:
Pose: 踢球帶球動作
YOLO: 足球檢測
組合: 射門 = 踢球姿勢 + 足球軌跡
網球:
Pose: 揮拍動作
YOLO: 球拍網球檢測
優點:
可復用現有處理器Pose, YOLO
準確率高
可識別細分動作
```
#### 格鬥運動
```python
方法: ST-GCN
拳擊:
特徵: 出拳動作序列
模型: ST-GCN訓練在 Kinetics-400 boxing 類別
柔道:
特徵: 摔投動作
模型: ST-GCN需專門數據集
跆拳道:
特徵: 踢腿動作
模型: ST-GCN
挑戰:
高速動作需高幀率
遮擠
```
---
### 3. 日常活動識別
#### 吃飯
```python
方法: 骨架動作識別
特徵:
- 手部動作: 拿筷子/叉子 送入口中
- 重複模式: 每隔數秒重複
- 物體: 筷子食物YOLO
實現:
1. Pose 提取手臂關鍵點
2. ST-GCN "eating" 動作
3. YOLO 餐具檢測輔助驗證
4. 時間統計 吃飯時長
準確率:
Kinetics-400 "eating": 85-90%
```
#### 喝水
```python
方法: 骨架動作識別
特徵:
- 手部: 拿杯子 送至嘴邊 放下
- 頭部: 仰頭動作
- 物體: 杯子水瓶YOLO
實現:
1. Pose 手部 + 頭部關鍵點
2. ST-GCN "drinking" 動作
3. YOLO 杯子檢測
4. 時間窗口: 3-10
準確率:
Kinetics-400 "drinking": 88-92%
```
#### 做菜
```python
方法: 長時序動作識別
特徵:
- 多步驟: 備料 切菜 炒菜 裝盤
- 物體: 菜刀鏟子食材
- 場景: 廚房Scene Classification
實現:
1. Scene 廚房場景
2. YOLO 廚具食材檢測
3. Pose 切菜翻炒動作
4. 時序模型 長時序分析
挑戰:
長時序數分鐘到數小時
多步驟識別
細分動作多
數據集:
EPIC-KITCHENS-100: 專門的廚房活動數據集
```
#### 交談
```python
方法: 多模態融合
特徵:
視覺:
- 面對面姿勢
- 手勢
- 面部表情變化
音頻:
- 交替說話
- 語音存在
實現:
1. Face 面部朝向
2. Pose 交談姿勢
3. ASR 檢測語音
4. 時序分析 持續時間
難點:
與其他活動重疊如邊吃邊聊
需要多模態融合
```
---
## 效能與資源評估
### Mac Studio 64GB 測試預估
| 方法 | 模型 | 記憶體 | FPS | 準確率 |
|------|------|--------|-----|--------|
| **ST-GCN** | 輕量 | 1-2GB | 100+ | 80-85% |
| **SlowFast R50** | 中等 | 4-6GB | 30-40 | 85-90% |
| **SlowFast R101** | 大型 | 6-8GB | 15-20 | 90-95% |
| **多模態** | 融合 | 8-10GB | 10-15 | 95%+ |
### 處理時間(10分鐘影片)
| 方法 | 處理時間 | On-the-Fly |
|------|---------|-----------|
| **ST-GCN** | 15秒 | ✅ 可以 |
| **SlowFast R50** | 40秒 | ✅ 可以(100Mbps |
| **SlowFast R101** | 100秒 | ⚠️ 勉強 |
| **多模態** | 150秒 | ❌ 無法 |
---
## 推薦方案
### 階段 1:骨架動作識別(立即實施)
```python
處理器: Action Recognition Processor
模型: ST-GCN預訓練在 Kinetics-400
依賴: Pose 處理器已存在
事件類別:
日常活動: eating, drinking, cooking, cleaning
運動: running, swimming, playing basketball
互動: hugging, shaking hands, talking
優點:
輕量級
可復用 Pose 結果
實時性好
適合 On-the-Fly
```
### 階段 2:暴力事件檢測(第二階段)
```python
處理器: Violence Detection Processor
方法: ST-GCN + 多模態融合
數據集: RWF-2000, UBI-Fight
事件類別:
打架: 結合 Pose + 物體檢測
吵架: 結合 Pose + ASR + 情感分析
挑戰:
數據集小
需要專門訓練
```
### 階段 3:細粒度動作識別(第三階段)
```python
處理器: Fine-grained Action Processor
方法: SlowFast + 多模態
數據集: EPIC-KITCHENS, AVA
事件類別:
廚房活動: 切菜炒菜洗碗
工作活動: 打字開會演講
運動細節: 投籃運球傳球
需求:
- Mac Studio 64GB+
- 專門數據集微調
```
---
## 實施步驟
### Phase 1ST-GCN 處理器(第 1-2 週)
```bash
1. 安裝依賴
pip install torch torchvision
pip install mmcv mmdet mmpose
2. 下載預訓練模型
wget https://download.openmmlab.com/mmaction/pyskeleton/adaagnet/adaagnet_8xb16_ntu60_xsub_1e.py
wget https://download.openmmlab.com/mmaction/pyskeleton/adaagnet/adaagnet_ntu60_xsub_1e-44e6f770.pth
3. 創建處理器
scripts/action_processor.py
4. 整合 API
POST /api/v1/process
{"processors": ["pose", "action"]}
5. 測試
python3 scripts/test_action_recognition.py video.mp4
```
### Phase 2:暴力事件檢測(第 3-4 週)
```bash
1. 收集/標註數據
2. 微調 ST-GCN 模型
3. 實現多模態融合
4. 測試與優化
```
### Phase 3:完整事件識別(第 5-6 週)
```bash
1. 部署 SlowFast 模型
2. 實現細粒度分類
3. 優化 On-the-Fly 性能
4. 用戶測試與反饋
```
---
## 總結
### 推薦技術路線
```
短中期(Mac Studio 64GB:
✅ 骨架動作識別(ST-GCN
✅ 復用 Pose 結果
✅ 輕量級、實時性好
✅ 支援 60+ 日常活動
長期(Mac Studio 128GB:
✅ SlowFast 大模型
✅ 多模態融合
✅ 細粒度動作識別
✅ 達到 SOTA 水準
```
### 預期效果
| 事件類型 | 方法 | 準確率 | 處理時間 |
|---------|------|--------|---------|
| **日常活動** | ST-GCN | 85-90% | 15s/10min |
| **運動** | ST-GCN + YOLO | 88-92% | 20s/10min |
| **打架** | ST-GCN | 80-85% | 15s/10min |
| **吵架** | 多模態 | 85-90% | 60s/10min |
| **細粒度動作** | SlowFast | 90-95% | 100s/10min |
+438
View File
@@ -0,0 +1,438 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Momentry Core 架構常見問題解答 (FAQ)"
date: "2026-04-25"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "momentry"
- "core"
- "架構常見問題解答"
ai_query_hints:
- "查詢 Momentry Core 架構常見問題解答 (FAQ) 的內容"
- "Momentry Core 架構常見問題解答 (FAQ) 的主要目的是什麼?"
- "如何操作或實施 Momentry Core 架構常見問題解答 (FAQ)"
---
# Momentry Core 架構常見問題解答 (FAQ)
## 目錄
1. [設計與實現相關問題](#設計與實現相關問題)
2. [開發與部署相關問題](#開發與部署相關問題)
3. [分片與處理相關問題](#分片與處理相關問題)
4. [數據庫與存儲相關問題](#數據庫與存儲相關問題)
5. [性能與擴展相關問題](#性能與擴展相關問題)
6. [安全與監控相關問題](#安全與監控相關問題)
---
## 設計與實現相關問題
### Q1.1: 為什麼設計文檔與實際代碼實現不一致?
**A**: 這是開發過程中的常見現象。主要原因包括:
1. **設計先行**:架構設計通常在代碼實現之前完成
2. **技術調整**:實際開發中根據技術可行性調整設計
3. **資源限制**:某些功能因資源限制推遲實現
4. **迭代開發**:敏捷開發中的持續改進
**解決方案**
- 以實際 Rust 代碼實現為最高權威
- 定期更新設計文檔反映實際狀態
- 建立設計與實現一致性檢查機制
### Q1.2: 如何理解分片類型的差異?
**A**: 設計文檔與實際代碼的分片類型對照:
| 設計概念 | 設計值 | 實現值 | 狀態 |
|----------|--------|--------|------|
| 句子級分片 | `sentence` | `Sentence` | ✅ 已實現 |
| 視覺物件級分片 | `visual` | 無對應實現 | ❌ 未實現 |
| 場景級分片 | `scene` | `Cut` | ⚠️ 部分實現 |
| 摘要級分片 | `summary` | `Story` | ⚠️ 概念調整 |
| 時間基準分片 | `time` | `TimeBased` | ✅ 已實現 |
| 軌跡追蹤分片 | `trace` | `Trace` | ✅ 已實現 |
### Q1.3: 如何處理設計與實現的衝突?
**A**: 遵循以下原則:
1. **優先級原則**:以實際代碼實現為準
2. **文檔更新原則**:更新設計文檔反映實際實現
3. **版本控制原則**:記錄設計變更歷史
4. **團隊溝通原則**:確保團隊理解實際架構
---
## 開發與部署相關問題
### Q2.1: 如何快速開始開發?
**A**: 建議步驟:
1. **環境設置**
```bash
# 安裝 Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 安裝項目依賴
cargo build
```
2. **開發工作流**
```bash
# 構建項目
cargo build
# 運行測試
cargo test
# 格式化代碼
cargo fmt
# 代碼檢查
cargo clippy
```
3. **調試工具**
- 使用 `tracing` 日誌系統
- 設置 `RUST_LOG=debug` 環境變數
- 使用 `cargo test -- --nocapture` 查看測試輸出
### Q2.2: 開發環境和生產環境如何區分?
**A**: 系統支持完全環境隔離:
| 環境 | 二進制名稱 | Redis 網址 | 默認端口 |
|------|------------|------------|----------|
| 生產環境 | `momentry` | `momentry:` | 3002 |
| 開發環境 | `momentry_playground` | `momentry_dev:` | 3003 |
**使用方法**
```bash
# 生產環境
cargo run -- server --host 0.0.0.0 --port 3002
# 開發環境
cargo run --bin momentry_playground -- server
```
### Q2.3: 如何添加新的處理器?
**A**: 標準步驟:
1. **創建處理器模塊**
```rust
// src/core/processor/new_processor.rs
use crate::core::processor::Processor;
pub struct NewProcessor;
impl Processor for NewProcessor {
// 實現處理器 trait
}
```
2. **註冊到處理器註冊表**
```rust
// src/core/processor/mod.rs
mod new_processor;
pub use new_processor::NewProcessor;
// 註冊處理器
registry.register("new_processor", Box::new(NewProcessor::new()));
```
3. **集成到處理管道**
- 配置處理順序
- 設置超時參數
- 定義輸出格式
---
## 分片與處理相關問題
### Q3.1: 分片是如何生成的?
**A**: 分片生成流程:
```
視訊輸入 → 多模態處理 → 分片規則應用 → 分片存儲
↓ ↓ ↓ ↓
ASR 文本提取 Rule1/2/3/4 數據庫存儲
OCR 視覺特徵 → 分片類型 → 向量索引
YOLO 場景檢測 → 檢索優化
CUT
```
**分片規則**
1. **Rule 1 (Sentence)**: 基於 ASR 結果的句子級分片
2. **Rule 2 (Visual)**: 基於 YOLO 的視覺物件分片 (未實現)
3. **Rule 3 (Cut)**: 基於 CUT 算法的場景分片
4. **Rule 4 (Story)**: 基於分片聚合的故事級分片
### Q3.2: 處理管道如何工作?
**A**: 處理管道特點:
1. **統一執行框架**
- 所有 Python 腳本通過 `PythonExecutor` 執行
- 統一的超時控制和錯誤處理
- 標準化的輸出格式
2. **並行處理**
- 支持多個處理器並行執行
- 資源分配和調度優化
- 錯誤隔離和恢復
3. **結果整合**
- 多模態結果融合
- 分片生成和關聯
- 向量嵌入計算
### Q3.3: 如何擴展新的分片類型?
**A**: 擴展步驟:
1. **定義新的分片類型**
```rust
// src/core/chunk/types.rs
pub enum ChunkType {
// 現有類型...
NewType, // 新的分片類型
}
```
2. **創建專用內容結構**
```rust
pub struct NewTypeContent {
pub field1: String,
pub field2: Vec<String>,
// ... 其他字段
}
```
3. **實現分片生成規則**
- 創建新的規則處理器
- 集成到處理管道
- 定義分片內容格式
---
## 數據庫與存儲相關問題
### Q4.1: 為什麼使用多個數據庫?
**A**: 多數據庫架構的優勢:
| 數據庫 | 用途 | 優勢 |
|--------|------|------|
| PostgreSQL | 結構化數據 | ACID 事務,關係型查詢 |
| Redis | 緩存和隊列 | 高性能,低延遲 |
| Qdrant | 向量數據 | 向量相似度搜索,ANN 算法 |
| MongoDB | 文檔數據 | 靈活 schema,易於擴展 |
**使用場景**
- **PostgreSQL**: 視訊元數據、分片信息、任務管理
- **Redis**: 會話緩存、隊列管理、實時統計
- **Qdrant**: 語義搜索、視覺檢索、推薦系統
- **MongoDB**: 處理結果、日誌數據、配置存儲
### Q4.2: 數據一致性如何保證?
**A**: 數據一致性策略:
1. **事務處理**
- 關鍵操作使用 PostgreSQL 事務
- 確保數據原子性和一致性
2. **冪等性設計**
- 處理器結果冪等性
- 任務執行冪等性
3. **補償機制**
- 失敗操作的補償處理
- 數據一致性修復工具
4. **監控和告警**
- 數據一致性監控
- 異常檢測和自動修復
### Q4.3: 如何優化數據庫性能?
**A**: 性能優化建議:
1. **PostgreSQL**
```sql
-- 創建索引
CREATE INDEX idx_chunks_video_record_id ON chunks(video_record_id);
CREATE INDEX idx_chunks_chunk_type ON chunks(chunk_type);
-- 分區表
CREATE TABLE chunks_2026_04 PARTITION OF chunks
FOR VALUES FROM ('2026-04-01') TO ('2026-05-01');
```
2. **Redis**
- 使用連接池減少連接開銷
- 合理設置過期時間避免內存洩漏
- 使用 pipeline 批量操作
3. **Qdrant**
- 優化向量索引參數
- 定期重建索引
- 使用量化減少存儲空間
---
## 性能與擴展相關問題
### Q5.1: 如何評估系統性能?
**A**: 關鍵性能指標:
1. **處理性能**
- 視訊處理吞吐量 (分鐘/小時)
- 分片生成速度 (分片/秒)
- 向量嵌入計算時間 (毫秒/分片)
2. **檢索性能**
- 查詢響應時間 (毫秒)
- 檢索準確率 (召回率,精確率)
- 並發處理能力 (QPS)
3. **資源利用率**
- CPU 使用率
- 內存佔用
- 磁盤 I/O
**監控工具**
- Prometheus + Grafana 監控面板
- 自定義性能指標收集
- 壓力測試和基準測試
### Q5.2: 如何擴展系統處理能力?
**A**: 擴展策略:
1. **垂直擴展**
- 升級服務器硬件
- 增加 GPU 資源
- 擴展內存和存儲
2. **水平擴展**
- 微服務架構重構
- 負載均衡和集群
- 分布式處理管道
3. **軟件優化**
- 算法優化和並行化
- 緩存策略優化
- 數據庫查詢優化
### Q5.3: 如何處理大規模數據?
**A**: 大規模數據處理策略:
1. **分布式處理**
- 分片級別並行處理
- 任務隊列和工作者模式
- 結果聚合和歸一化
2. **增量處理**
- 流式處理支持
- 增量更新和索引
- 實時數據同步
3. **存儲優化**
- 數據分區和分片
- 壓縮和編碼優化
- 冷熱數據分離
---
## 安全與監控相關問題
### Q6.1: 系統安全如何保證?
**A**: 安全架構:
1. **訪問控制**
- API 密鑰認證
- 角色基於權限控制 (RBAC)
- 請求限流和防刷
2. **數據安全**
- 傳輸加密 (HTTPS)
- 數據存儲加密
- 敏感信息脫敏
3. **審計日誌**
- 操作日誌記錄
- 安全事件監控
- 異常行為檢測
### Q6.2: 如何監控系統狀態?
**A**: 監控體系:
1. **基礎設施監控**
- 服務器資源監控
- 網絡連接狀態
- 存儲空間使用
2. **應用監控**
- 服務健康檢查
- 性能指標收集
- 錯誤日誌分析
3. **業務監控**
- 用戶行為分析
- 業務指標統計
- 系統可用性監控
### Q6.3: 如何進行故障恢復?
**A**: 故障恢復策略:
1. **預防措施**
- 定期備份和快照
- 系統健康檢查
- 容量規劃和預警
2. **故障檢測**
- 自動化監控告警
- 異常檢測算法
- 性能閾值告警
3. **恢復機制**
- 自動化故障轉移
- 數據恢復工具
- 服務重啟策略
---
## 更多資源
### 官方文檔
- [架構概覽](./ARCHITECTURE_OVERVIEW.md) - 系統架構全面介紹
- [設計實現差異](./DESIGN_IMPLEMENTATION_GAP.md) - 設計與實現不一致分析
- [執行計畫](./ARCHITECTURE_DECISION_EXECUTION_PLAN.md) - 架構改進執行方案
### 開發指南
- [快速入門指南](./QUICK_START_GUIDE.md) - 5分鐘快速上手
- [決策卡片](./ARCHITECTURE_DECISION_CARDS.md) - 架構決策記錄
- [技術決策記錄](./TECHNICAL_DECISION_RECORDS.md) - 詳細技術決策
### 參考資料
- [性能與擴展](./PERFORMANCE_AND_SCALABILITY.md) - 性能優化指南
- [安全架構](./SECURITY_ARCHITECTURE.md) - 安全設計詳解
- [監控架構](./MONITORING_ARCHITECTURE.md) - 監控系統設計
---
**最後更新**: 2026-04-22
**文檔版本**: V1.0
**更新頻率**: 每月審查更新
**維護者**: OpenCode
@@ -0,0 +1,700 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Job Worker 實作計畫"
date: "2026-03-24"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "實作計畫"
- "worker"
ai_query_hints:
- "查詢 Job Worker 實作計畫 的內容"
- "Job Worker 實作計畫 的主要目的是什麼?"
- "如何操作或實施 Job Worker 實作計畫?"
---
# Job Worker 實作計畫
| 項目 | 內容 |
|------|------|
| 建立者 | Warren / OpenCode |
| 建立時間 | 2026-03-24 |
| 文件版本 | V1.1 |
| 狀態 | ✅ 已實作 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 |
|------|------|------|--------|
| V1.0 | 2026-03-24 | 建立實作計畫 | OpenCode |
| V1.1 | 2026-03-25 | 實作完成,更新狀態 | OpenCode |
---
## 實作狀態
### ✅ 已完成
| 元件 | 檔案 | 狀態 |
|------|------|------|
| MonitorJob 結構 | `src/core/db/postgres_db.rs` | ✅ |
| ProcessorResult 結構 | `src/core/db/postgres_db.rs` | ✅ |
| Worker 配置 | `src/worker/config.rs` | ✅ |
| Job Worker | `src/worker/job_worker.rs` | ✅ |
| Processor Pool | `src/worker/processor.rs` | ✅ |
| Worker 模組 | `src/worker/mod.rs` | ✅ |
| PostgreSQL 表格 | `monitor_jobs`, `processor_results` | ✅ |
| 類型修復 | `i32`, `NaiveDateTime` | ✅ |
### 待整合
| 項目 | 說明 |
|------|------|
| Worker 服務啟動 | 需要加入 launchd plist |
| 監控整合 | 需要加入 MOMENTRY_CORE_MONITORING.md |
| 備份涵蓋 | 需要確認備份包含新表格 |
---
## 1. 設計決策
### 1.1 確認的設計決策
| 項目 | 決策 | 理由 |
|------|------|------|
| 觸發方式 | 輪詢(Job Worker) | 暫無可靠的 API 觸發機制 |
| 並行處理 | 最多 2 個 | 可根據 CPU/GPU 能力調整 |
| 失敗處理 | 獨立模組,部分完成可接續 | 任何模組失敗都產出狀態記錄 |
| Worker 啟動 | 獨立進程 | 隔離、易管理 |
| 並行上限調整 | 環境變數 + 預設值 | 靈活、可調整 |
| 狀態同步 | PostgreSQL + Redis | 可靠 + 即時 |
### 1.2 環境變數
| 變數 | 預設值 | 說明 |
|------|--------|------|
| `MOMENTRY_MAX_CONCURRENT` | 2 | 最大並行 processor 數 |
| `MOMENTRY_POLL_INTERVAL` | 5 | 輪詢間隔(秒) |
| `MOMENTRY_WORKER_ENABLED` | true | 是否啟用 worker |
---
## 2. 系統架構
### 2.1 完整流程圖
```
┌─────────────────────────────────────────────────────────────────────────┐
│ 檔案註冊觸發處理流程 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. SFTPGo 上傳 │
│ │ │
│ ▼ │
│ 2. Hook 呼叫 Register API │
│ │ │
│ ▼ │
│ 3. Register API │
│ ├─► ffprobe 提取 metadata │
│ ├─► 寫入 videos 表 │
│ └─► 建立 monitor_jobs 記錄 (status=pending) │
│ │ │
│ ▼ │
│ 4. Job Worker (獨立進程,輪詢機制) │
│ ├─► 輪詢 pending jobs │
│ ├─► 檢查 videos 表 fs_json 決定需要處理什麼 │
│ ├─► 並行執行 processors (最多 2 個) │
│ └─► 更新 videos, monitor_jobs, processor_results 表 │
│ │ │
│ ▼ │
│ 5. 處理結果 │
│ ├─► 更新 videos 表 (fs_json, psql_chunk, qvector_chunk) │
│ ├─► 更新 monitor_jobs 表 (status, progress) │
│ ├─► 更新 processor_results 表 (每個模組狀態) │
│ └─► Redis Pub/Sub 即時進度 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
```
### 2.2 Job Worker 架構
```
┌─────────────────────────────────────────────────────────────────────┐
│ Job Worker 架構 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ PostgreSQL │ ───▶ │ Worker │ ───▶ │ Processor │ │
│ │ Job Queue │ │ Loop │ │ Pool │ │
│ └─────────────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Video State │ │ Processor 1 │ │
│ │ Check │ │ (ASR/YOLO) │ │
│ └─────────────┘ ├─────────────┤ │
│ │ Processor 2 │ │
│ │ (CUT/OCR) │ │
│ └─────────────┘ │
│ │
│ Redis ──── Pub/Sub ──── 即時進度 │
│ │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 3. 資料庫結構
### 3.1 Migration 檔案
**檔案**: `migrations/003_job_worker.sql`
```sql
-- ================================================================
-- Migration 003: Job Worker System
-- ================================================================
-- 3.1.1 更新 videos 表
ALTER TABLE videos ADD COLUMN IF NOT EXISTS status VARCHAR(20) DEFAULT 'pending';
ALTER TABLE videos ADD COLUMN IF NOT EXISTS user_id BIGINT;
ALTER TABLE videos ADD COLUMN IF NOT EXISTS job_id INTEGER REFERENCES monitor_jobs(id);
COMMENT ON COLUMN videos.status IS 'pending, processing, completed, failed';
COMMENT ON COLUMN videos.user_id IS 'WordPress user ID';
COMMENT ON COLUMN videos.job_id IS 'Associated monitor_jobs ID';
-- 3.1.2 更新 monitor_jobs 表
ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS video_id BIGINT REFERENCES videos(id);
ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS user_id BIGINT;
ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS processors VARCHAR(20)[];
ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS completed_processors VARCHAR(20)[];
ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS failed_processors VARCHAR(20)[];
COMMENT ON COLUMN monitor_jobs.processors IS 'Processors to run: asr, cut, yolo, ocr, face, pose, asrx';
COMMENT ON COLUMN monitor_jobs.completed_processors IS 'Successfully completed processors';
COMMENT ON COLUMN monitor_jobs.failed_processors IS 'Failed processors';
-- 3.1.3 新增 processor_results 表
CREATE TABLE IF NOT EXISTS processor_results (
id SERIAL PRIMARY KEY,
job_id INTEGER REFERENCES monitor_jobs(id) ON DELETE CASCADE,
video_id BIGINT REFERENCES videos(id) ON DELETE CASCADE,
processor VARCHAR(20) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'pending',
output_path TEXT,
started_at TIMESTAMP,
completed_at TIMESTAMP,
error_message TEXT,
progress_total INT DEFAULT 0,
progress_current INT DEFAULT 0,
last_checkpoint JSONB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(job_id, processor)
);
CREATE INDEX IF NOT EXISTS idx_processor_results_job ON processor_results(job_id);
CREATE INDEX IF NOT EXISTS idx_processor_results_video ON processor_results(video_id);
CREATE INDEX IF NOT EXISTS idx_processor_results_status ON processor_results(status);
COMMENT ON TABLE processor_results IS 'Tracks individual processor execution status';
COMMENT ON COLUMN processor_results.status IS 'pending, running, completed, failed, skipped';
-- 3.1.4 更新 videos 表標記欄位用途
COMMENT ON COLUMN videos.fs_video IS 'Video file exists on filesystem';
COMMENT ON COLUMN videos.fs_json IS 'All processor JSON files generated';
COMMENT ON COLUMN videos.fs_chunks IS 'Chunk files generated';
COMMENT ON COLUMN videos.fs_vectors IS 'Vector files generated';
COMMENT ON COLUMN videos.psql_chunk IS 'Chunks stored in PostgreSQL';
COMMENT ON COLUMN videos.pvector_chunk IS 'Vectors stored in PostgreSQL';
COMMENT ON COLUMN videos.qvector_chunk IS 'Vectors stored in Qdrant';
```
### 3.2 表關係圖
```
videos monitor_jobs
┌──────────────────────┐ ┌──────────────────────┐
│ id (PK) │◄────────│ video_id (FK) │
│ uuid │ │ user_id │
│ status │ │ processors[] │
│ fs_video │ │ completed_processors[]│
│ fs_json │ │ failed_processors[] │
│ job_id (FK)─────────┼────────►│ status │
│ user_id │ │ id (PK) │
└──────────────────────┘ └──────────────────────┘
processor_results
┌──────────────────────┐
│ job_id (FK) │
│ video_id (FK) │
│ processor │
│ status │
│ progress_current │
│ last_checkpoint │
│ id (PK) │
└──────────────────────┘
```
---
## 4. 模組並行策略
### 4.1 模組分類
| 模組 | 資源需求 | 獨立性 | 建議並行 |
|------|----------|--------|----------|
| ASR | GPU/CPU | 高 | ✅ 可並行 |
| CUT | CPU | 高 | ✅ 可並行 |
| YOLO | GPU | 中 | ✅ 可並行 |
| OCR | GPU/CPU | 高 | ✅ 可並行 |
| Face | GPU | 中 | ✅ 可並行 |
| Pose | GPU | 中 | ✅ 可並行 |
| ASRX | GPU/CPU | 高 | ✅ 可並行 |
### 4.2 建議並行組合
| 組合 | 模組 1 | 模組 2 | 說明 |
|------|---------|---------|------|
| GPU+CPU | YOLO/Pose/Face | ASR/CUT/OCR | 平衡負載 |
| 雙GPU | YOLO | Pose | 雙 GPU 卡片 |
| 雙CPU | ASR | CUT/OCR | 無 GPU 時 |
### 4.3 Worker 配置
```rust
// src/worker/config.rs
#[derive(Debug, Clone)]
pub struct WorkerConfig {
pub max_concurrent: usize, // 預設 2
pub poll_interval_secs: u64, // 預設 5
pub enabled: bool, // 預設 true
}
impl Default for WorkerConfig {
fn default() -> Self {
Self {
max_concurrent: 2,
poll_interval_secs: 5,
enabled: true,
}
}
}
impl WorkerConfig {
pub fn from_env() -> Self {
Self {
max_concurrent: std::env::var("MOMENTRY_MAX_CONCURRENT")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(2),
poll_interval_secs: std::env::var("MOMENTRY_POLL_INTERVAL")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(5),
enabled: std::env::var("MOMENTRY_WORKER_ENABLED")
.ok()
.map(|v| v != "false")
.unwrap_or(true),
}
}
}
```
---
## 5. 失敗處理機制
### 5.1 設計原則
```
每個模組獨立處理:
- 成功 → 產出完整 .jsonstatus=completed
- 失敗 → 產出 .json 包含 error 狀態,status=failed
- 部分完成 → 可從 checkpoint 繼續,status=running
```
### 5.2 Processor 輸出格式
```json
{
"processor": "asr",
"status": "completed|failed|partial",
"completed_at": "2026-03-24T12:00:00Z",
"result": { ... },
"error": null,
"last_checkpoint": {
"frame": 5000,
"timestamp": 180.5
}
}
```
### 5.3 失敗處理流程
```rust
async fn run_processor(&self, module: &str, video: &Video) -> Result<()> {
let output_path = self.get_output_path(video, module);
match self.execute_processor(module, video, &output_path).await {
Ok(result) => {
// 成功:更新狀態
self.db.update_processor_status(job_id, module, "completed").await?;
self.publish_progress(job_id, module, 100).await?;
}
Err(e) => {
// 失敗:仍然保存部分結果
let partial_result = self.get_partial_result(&output_path);
self.db.update_processor_status(job_id, module, "failed").await?;
self.db.save_error_message(job_id, module, &e.to_string()).await?;
// 記錄錯誤但不中斷其他模組
tracing::warn!("Processor {} failed: {}", module, e);
}
}
Ok(())
}
```
---
## 6. 實作結構
### 6.1 目錄結構
```
src/
├── worker/
│ ├── mod.rs # Worker 模組導出
│ ├── config.rs # Worker 配置
│ ├── worker.rs # Worker 主邏輯
│ ├── processor.rs # Processor 執行器
│ ├── queue.rs # Job 佇列管理
│ └── progress.rs # 進度追蹤
├── api/
│ └── server.rs # 更新 Register API
└── main.rs # 新增 worker 命令
```
### 6.2 核心模組
#### 6.2.1 Worker Config (`src/worker/config.rs`)
```rust
pub struct WorkerConfig {
pub max_concurrent: usize,
pub poll_interval_secs: u64,
pub enabled: bool,
}
impl WorkerConfig {
pub fn from_env() -> Self { ... }
}
```
#### 6.2.2 Worker Loop (`src/worker/worker.rs`)
```rust
pub struct JobWorker {
db: PostgresDb,
redis: RedisCache,
config: WorkerConfig,
semaphore: Arc<Semaphore>,
}
impl JobWorker {
pub async fn run(&self) -> Result<()> {
loop {
if self.config.enabled {
self.process_pending_jobs().await?;
}
tokio::time::sleep(Duration::from_secs(self.config.poll_interval_secs)).await;
}
}
async fn process_pending_jobs(&self) -> Result<()> {
// 1. 檢查並發數
// 2. 取得 pending jobs
// 3. 分配給 worker pool
// 4. 並行執行 processors
}
}
```
#### 6.2.3 Processor Pool (`src/worker/processor.rs`)
```rust
pub struct ProcessorPool {
max_concurrent: usize,
}
impl ProcessorPool {
pub async fn execute(&self, job: &Job, video: &Video) -> Result<ProcessorResult> {
// 根據 videos 表決定需要執行哪些 processor
// 並行執行最多 2 個
// 處理失敗但不中斷其他 processor
}
}
```
---
## 7. API 端點設計
### 7.1 新增端點
| 端點 | 方法 | 說明 |
|------|------|------|
| `/api/v1/jobs` | GET | 列出所有 jobs |
| `/api/v1/jobs/:uuid` | GET | 取得特定 job 詳細 |
| `/api/v1/jobs/:uuid/retry` | POST | 重試失敗的 processor |
| `/api/v1/jobs/:uuid/cancel` | POST | 取消 job |
### 7.2 端點詳情
#### GET /api/v1/jobs
```json
Response:
{
"jobs": [
{
"id": 1,
"uuid": "abc123def456",
"status": "running",
"progress": 60,
"processors": ["asr", "cut", "yolo", "ocr", "face", "pose"],
"completed": ["asr", "cut", "yolo"],
"failed": []
}
]
}
```
#### GET /api/v1/jobs/:uuid
```json
Response:
{
"id": 1,
"uuid": "abc123def456",
"video_id": 10,
"status": "running",
"processors": {
"asr": {"status": "completed", "progress": 100},
"cut": {"status": "completed", "progress": 100},
"yolo": {"status": "running", "progress": 45, "current": 5000, "total": 11000},
"ocr": {"status": "pending"},
"face": {"status": "pending"},
"pose": {"status": "pending"}
},
"created_at": "2026-03-24T12:00:00Z",
"started_at": "2026-03-24T12:01:00Z"
}
```
---
## 8. Redis Key 設計
### 8.1 現有 Key 保持
```bash
momentry:job:{uuid} # Job Hash
momentry:job:{uuid}:processor:{name} # Processor Hash
momentry:progress:{uuid} # Pub/Sub Channel
momentry:jobs:active # Set: 運行中 UUIDs
momentry:jobs:completed # Set: 完成 UUIDs
momentry:jobs:failed # Set: 失敗 UUIDs
```
### 8.2 進度更新時序
```
Processor 執行
├─► 每秒更新 Redis Hash (即時)
├─► 每 10% 或完成時更新 PostgreSQL (持久)
└─► 失敗時立即更新 PostgreSQL (錯誤記錄)
```
---
## 9. 實作順序
### Phase 1: 資料庫遷移
| 任務 | 說明 |
|------|------|
| 1.1 | 建立 `migrations/003_job_worker.sql` |
| 1.2 | 更新 `postgres_db.rs` 對應的 struct |
| 1.3 | 執行 migration 驗證 |
### Phase 2: Worker 框架
| 任務 | 說明 |
|------|------|
| 2.1 | 建立 `src/worker/mod.rs` |
| 2.2 | 建立 `src/worker/config.rs` |
| 2.3 | 建立 `src/worker/worker.rs` |
| 2.4 | 建立 `src/worker/processor.rs` |
### Phase 3: Register API 整合
| 任務 | 說明 |
|------|------|
| 3.1 | 修改 `src/api/server.rs` 的 register 函數 |
| 3.2 | 加入建立 monitor_jobs 的邏輯 |
| 3.3 | 更新 videos 表 status 欄位 |
### Phase 4: Processor 執行
| 任務 | 說明 |
|------|------|
| 4.1 | 實作 processor 並行執行(最多 2 個) |
| 4.2 | 實作失敗處理(保存部分結果) |
| 4.3 | 實作 checkpoint 恢復 |
### Phase 5: 進度追蹤
| 任務 | 說明 |
|------|------|
| 5.1 | Redis Pub/Sub 整合 |
| 5.2 | PostgreSQL 定期同步 |
| 5.3 | API 進度端點更新 |
### Phase 6: API 端點
| 任務 | 說明 |
|------|------|
| 6.1 | GET /api/v1/jobs |
| 6.2 | GET /api/v1/jobs/:uuid |
| 6.3 | POST /api/v1/jobs/:uuid/retry |
| 6.4 | POST /api/v1/jobs/:uuid/cancel |
### Phase 7: CLI 命令
| 任務 | 說明 |
|------|------|
| 7.1 | `cargo run -- worker` 命令 |
| 7.2 | Worker 啟動/停止/狀態顯示 |
| 7.3 | launchd plist 設定 |
### Phase 8: 測試
| 任務 | 說明 |
|------|------|
| 8.1 | 單元測試 |
| 8.2 | 端到端測試 |
| 8.3 | 失敗處理測試 |
| 8.4 | 並行執行測試 |
---
## 10. CLI 命令
### 10.1 Worker 命令
```bash
# 啟動 worker
cargo run -- worker
# 顯示 worker 幫助
cargo run -- worker --help
```
### 10.2 環境變數
```bash
# Worker 配置
export MOMENTRY_MAX_CONCURRENT=2
export MOMENTRY_POLL_INTERVAL=5
export MOMENTRY_WORKER_ENABLED=true
# 現有環境變數
export DATABASE_URL=postgres://accusys@localhost:5432/momentry
export REDIS_URL=redis://:accusys@localhost:6379
```
---
## 11. 預估工時
| Phase | 任務 | 預估工時 |
|-------|------|----------|
| 1 | 資料庫遷移 | 2h |
| 2 | Worker 框架 | 4h |
| 3 | Register API 整合 | 2h |
| 4 | Processor 執行 | 4h |
| 5 | 進度追蹤 | 2h |
| 6 | API 端點 | 3h |
| 7 | CLI 命令 | 2h |
| 8 | 測試 | 4h |
| **總計** | | **23h** |
---
## 12. 參考文件
| 文件 | 用途 |
|------|------|
| `docs_v1.0/OPERATIONS/MOMENTRY_CORE_MONITORING.md` | 監控系統規範 |
| `docs_v1.0/REFERENCE/MOMENTRY_CORE_REDIS_KEYS.md` | Redis Key 設計 |
| `docs_v1.0/ARCHITECTURE/PROCESSING_PIPELINE.md` | 處理流程 |
| `docs_v1.0/ARCHITECTURE/CHUNK_DESIGN.md` | 資料庫設計 |
| `docs_v1.0/REFERENCE/API_REFERENCE.md` | API 參考 |
---
## 13. 附錄
### A. 狀態機
```
┌──────────────┐
│ PENDING │
└──────┬───────┘
│ register 後
┌──────────────┐
┌─────▶│ PROCESSING │◀──────┐
│ └──────┬───────┘ │
│ │ │
部分失敗 all completed 全部失敗
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ PARTIAL │ │COMPLETED │ │ FAILED │
└──────────┘ └──────────┘ └──────────┘
```
### B. videos 表 status 欄位
| 值 | 說明 |
|------|------|
| `pending` | 已註冊,等待處理 |
| `processing` | 處理中 |
| `completed` | 所有處理完成 |
| `failed` | 處理失敗 |
### C. processor_results 表 status 欄位
| 值 | 說明 |
|------|------|
| `pending` | 等待執行 |
| `running` | 執行中 |
| `completed` | 執行成功 |
| `failed` | 執行失敗 |
| `skipped` | 跳過(如檔案已存在) |
@@ -0,0 +1,800 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Momentry 系統自動化安裝計劃"
date: "2026-03-23"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "momentry"
- "系統自動化安裝計劃"
ai_query_hints:
- "查詢 Momentry 系統自動化安裝計劃 的內容"
- "Momentry 系統自動化安裝計劃 的主要目的是什麼?"
- "如何操作或實施 Momentry 系統自動化安裝計劃?"
---
# Momentry 系統自動化安裝計劃
> **計劃階段** - 僅供討論,尚未執行
> **建立時間**: 2026-03-23
> **目標**: Thunderbolt NVMe 外開機完整安裝
---
## 系統概述
### 當前環境
| 項目 | 內容 |
|------|------|
| **主控機** | Mac mini (M4, 16GB RAM) |
| **作業系統** | macOS 26.3.1 (Tahoe) |
| **儲存** | Thunderbolt NVMe (2TB) |
| **用途** | 開機碟 + 完整 Momentry 系統 |
### 目標環境
| 項目 | 內容 |
|------|------|
| **目標主機** | 其他 Mac (Intel 或 Apple Silicon) |
| **安裝方式** | Thunderbolt NVMe 外接開機 |
| **連接方式** | Thunderbolt 3/4 |
| **控制方式** | SSH 遠端管理 |
---
## 系統架構
### 服務列表
| 服務 | 版本 | 用途 | Port |
|------|------|------|------|
| **PostgreSQL** | 18.1 | 主資料庫、n8n 資料庫 | 5432 |
| **MongoDB** | 8.0 | 文件資料庫 | 27017 |
| **MariaDB** | 11.4 | WordPress 資料庫 | 3306 |
| **Redis** | 7.x | 快取、佇列 | 6379 |
| **Qdrant** | 1.7.x | 向量資料庫 | 6333 |
| **Ollama** | 0.13.5 | 本地 LLM | 11434 |
| **Caddy** | 2.x | 反向代理 | 80/443 |
| **Gitea** | 1.21 | Git 服務 | 3000 |
| **PHP-FPM** | 8.5 | WordPress | 9000 |
| **n8n** | 2.3.5 | 工作流程自動化 | 5678 |
| **RustDesk** | hbbs/hbbr | 遠端桌面 | 21115-21119 |
| **SFTPGo** | 2.x | SFTP 服務 | 2022 |
| **Momentry Core** | 0.1.0 | 影片處理核心 | 3002 |
| **Prometheus** | 3.9.1 | 監控 | 9090 |
### 目錄結構
```
/Volumes/Momentry/
├── System/
│ └── macOS/ # macOS 系統
├── Applications/
│ └── Homebrew/ # Homebrew 應用程式
├── momentry/
│ ├── var/ # 資料目錄
│ │ ├── postgresql/ # PostgreSQL 資料
│ │ ├── mongodb/ # MongoDB 資料
│ │ ├── mariadb/ # MariaDB 資料
│ │ ├── redis/ # Redis 資料
│ │ ├── qdrant/ # Qdrant 資料
│ │ ├── n8n/ # n8n 資料
│ │ ├── ollama/ # Ollama 模型
│ │ └── ...
│ ├── etc/ # 配置檔案
│ │ ├── Caddyfile
│ │ ├── gitea/
│ │ ├── php/
│ │ └── ...
│ ├── log/ # 日誌
│ ├── scripts/ # 管理腳本
│ └── backup/ # 備份
├── momentry_core/ # Rust 原始碼
└── momentry_dashboard/ # Web Dashboard
```
---
## 階段一:前置準備
### 1.1 收集目標主機資訊
```bash
# 需要收集的資訊
- Mac 型號 (Intel/Apple Silicon)
- macOS 版本
- Thunderbolt 版本 (3/4)
- 可用記憶體
- 目標磁碟代號 (diskX)
- 網路配置 (DHCP/固定 IP)
```
### 1.2 準備 Thunderbolt NVMe
```bash
# 檢查 Thunderbolt NVMe
diskutil list external
# 預期輸出:
# /dev/diskX (external, physical):
# NAME TYPE SIZE
# Thunderbolt NVMe ...
```
### 1.3 準備主控機腳本
```bash
# 主控機需要準備的腳本
~/momentry/setup/
├── 01_prepare_disk.sh
├── 02_install_macos.sh
├── 03_install_homebrew.sh
├── 04_install_dependencies.sh
├── 05_install_services.sh
├── 06_install_momentry.sh
├── 07_configure_network.sh
├── 08_start_services.sh
└── utils/
├── common.sh
├── backup.sh
└── monitor.sh
```
---
## 階段二:Thunderbolt NVMe 準備
### 2.1 分割磁碟方案 A(推薦)
```bash
# 磁碟分割配置
diskutil partitionDisk /dev/diskX \
GPT \
"APFS System" APFS "Momentry System" 200G \
"APFS Data" APFS "Momentry Data" 1.8T
```
### 2.2 分割磁碟方案 B(最小化)
```bash
# 統一 APFS 容器
diskutil partitionDisk /dev/diskX \
GPT \
APFS "Momentry" 100%
```
---
## 階段三:安裝 macOS
### 3.1 建立 macOS 安裝碟
```bash
# 下載 macOS Sonoma (或最新版本)
softwareupdate --fetch-full-installer --full-installer-version 14.0
# 建立可開機安裝碟
sudo /Applications/Install\ macOS\ Sonoma.app/Contents/Resources/createinstallinstmedi \
--volume /Volumes/Momentry \
--nointeraction
```
### 3.2 安裝 macOS 到 Thunderbolt NVMe
**兩種方法:**
#### 方法 A: 復原模式安裝
1. 連接 Thunderbolt NVMe
2. 重啟目標主機,按住Option鍵
3. 選擇 Thunderbolt NVMe 開機
4. 進入 Recovery Mode (Command+R)
5. 使用 Disk Utility 格式化目標磁碟
6. 安裝 macOS
#### 方法 B: ASR 複製(建議)
```bash
# 從主控機執行
# 將現有系統複製到目標磁碟
sudo asr restore \
--source /Volumes/Macintosh\ HD \
--target /Volumes/Momentry \
--erase --noprompt
```
### 3.3 設定 macOS
```bash
# 自動化設定腳本
./setup/scripts/03_install_homebrew.sh
```
**設定項目:**
- 電腦名稱:`momentry-<serial>`
- 使用者帳號:`momentry` (管理員)
- SSH 遠端登入:啟用
- 螢幕鎖定:關閉
- 節能設定:永不休眠
---
## 階段四:安裝 Homebrew
### 4.1 安裝 Homebrew
```bash
#!/bin/bash
# 04_install_homebrew.sh
# 檢查架構
ARCH=$(uname -m)
if [ "$ARCH" = "arm64" ]; then
# Apple Silicon
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [ "$ARCH" = "x86_64" ]; then
# Intel
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
echo 'eval "$(/usr/local/bin/brew shellenv)"' >> ~/.zprofile
eval "$(/usr/local/bin/brew shellenv)"
fi
# 驗證
brew --version
```
### 4.2 安裝基礎工具
```bash
# 基礎開發工具
brew install \
git \
curl \
wget \
jq \
yq \
tree \
htop \
tmux \
zsh \
zsh-completions
```
---
## 階段五:安裝服務
### 5.1 安裝資料庫服務
```bash
#!/bin/bash
# 05_install_services.sh
# PostgreSQL
brew install postgresql@18
brew services start postgresql@18
# MongoDB
brew tap mongodb/brew
brew install mongodb-community
brew services start mongodb-community
# MariaDB
brew install mariadb
brew services start mariadb
# Redis
brew install redis
brew services start redis
# Qdrant (需要 Cargo)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo install qdrant
```
### 5.2 安裝應用服務
```bash
# Ollama
brew install ollama
brew services start ollama
# Caddy
brew install caddy
brew services start caddy
# Gitea
brew install gitea
brew services start gitea
# PHP
brew install php
brew services start php
# n8n
brew install n8n
brew services start n8n
```
### 5.3 Launchd 服務配置
```xml
<!-- /Library/LaunchDaemons/com.momentry.postgresql.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.momentry.postgresql</string>
<key>UserName</key>
<string>momentry</string>
<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/opt/postgresql@18/bin/postgres</string>
<string>-D</string>
<string>/Volumes/Momentry/momentry/var/postgresql</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/Volumes/Momentry/momentry/log/postgresql.log</string>
<key>StandardErrorPath</key>
<string>/Volumes/Momentry/momentry/log/postgresql.error.log</string>
</dict>
</plist>
```
---
## 階段六:安裝 Momentry Core
### 6.1 複製原始碼
```bash
#!/bin/bash
# 06_install_momentry.sh
# 建立 Momentry 目錄
mkdir -p /Volumes/Momentry/momentry/{var,etc,log,scripts,backup}
mkdir -p /Volumes/Momentry/momentry_core
# 複製原始碼
rsync -av \
--exclude 'target' \
--exclude '.git' \
--exclude 'node_modules' \
/Users/accusys/momentry_core_0.1/ \
/Volumes/Momentry/momentry_core/
# 編譯 Rust 專案
cd /Volumes/Momentry/momentry_core
cargo build --release
```
### 6.2 初始化資料庫
```bash
# 建立 PostgreSQL 資料庫
psql -U postgres <<EOF
CREATE DATABASE momentry;
CREATE DATABASE n8n;
CREATE DATABASE video_register;
CREATE USER momentry WITH PASSWORD 'momentry_password';
CREATE USER n8n WITH PASSWORD 'n8n_password';
GRANT ALL PRIVILEGES ON DATABASE momentry TO momentry;
GRANT ALL PRIVILEGES ON DATABASE n8n TO n8n;
EOF
# 執行 migration
cd /Volumes/Momentry/momentry_core
sqlx migrate run
```
### 6.3 配置環境變數
```bash
# ~/.zshrc 或 ~/.bash_profile
export DATABASE_URL="postgres://momentry:momentry_password@localhost:5432/momentry"
export REDIS_URL="redis://:momentry_password@localhost:6379"
export QDRANT_URL="http://localhost:6333"
export MONGODB_URI="mongodb://localhost:27017/momentry"
export MOMENTRY_OUTPUT_DIR="/Volumes/Momentry/momentry/var/output"
export MOMENTRY_LOG_LEVEL="info"
```
---
## 階段七:網路配置
### 7.1 設定固定 IP(可選)
```bash
# 網路配置腳本
#!/bin/bash
# 07_configure_network.sh
# 取得網路介面
INTERFACE=$(networksetup -listallnetworkservices | grep "Thunderbolt")
# 設定固定 IP
networksetup -setmanual "$INTERFACE" \
192.168.1.100 \
255.255.255.0 \
192.168.1.1
# 設定 DNS
networksetup -setdnsservers "$INTERFACE" \
8.8.8.8 \
8.8.4.4
```
### 7.2 配置防火牆
```bash
# 開放服務端口
# 使用 macOS Firewall 或 pfctl
```
### 7.3 設定 SSH 金鑰
```bash
# 產生 SSH 金鑰對
ssh-keygen -t ed25519 -C "momentry@$(hostname)"
# 複製公鑰到目標主機
ssh-copy-id momentry@target-host
# 主控機 SSH 配置
# ~/.ssh/config
Host momentry-target
HostName 192.168.1.100
User momentry
IdentityFile ~/.ssh/id_ed25519
```
---
## 階段八:啟動服務
### 8.1 啟動順序
```bash
#!/bin/bash
# 08_start_services.sh
# 1. 基礎服務
launchctl load /Library/LaunchDaemons/com.momentry.postgresql.plist
launchctl load /Library/LaunchDaemons/com.momentry.mongodb.plist
launchctl load /Library/LaunchDaemons/com.momentry.mariadb.plist
launchctl load /Library/LaunchDaemons/com.momentry.redis.plist
sleep 10
# 2. 向量資料庫
launchctl load /Library/LaunchDaemons/com.momentry.qdrant.plist
sleep 5
# 3. 應用服務
launchctl load /Library/LaunchDaemons/com.momentry.ollama.plist
launchctl load /Library/LaunchDaemons/com.momentry.caddy.plist
sleep 5
# 4. 其他服務
launchctl load /Library/LaunchDaemons/com.momentry.gitea.plist
launchctl load /Library/LaunchDaemons/com.momentry.php.plist
launchctl load /Library/LaunchDaemons/com.momentry.n8n.main.plist
launchctl load /Library/LaunchDaemons/com.momentry.n8n.worker.plist
# 5. Momentry Core
launchctl load /Library/LaunchDaemons/com.momentry.sftpgo.plist
launchctl load /Library/LaunchDaemons/com.momentry.rustdesk.hbbs.plist
launchctl load /Library/LaunchDaemons/com.momentry.rustdesk.hbbr.plist
```
### 8.2 驗證服務
```bash
# 檢查所有服務狀態
function check_services() {
services=(
"postgresql"
"mongodb"
"mariadb"
"redis"
"qdrant"
"ollama"
"caddy"
"gitea"
"php"
"n8n"
"sftpgo"
)
for service in "${services[@]}"; do
if launchctl list | grep "$service" | grep -q "running"; then
echo "$service: Running"
else
echo "$service: Not running"
fi
done
}
check_services
```
---
## 階段九:備份與還原
### 9.1 備份策略
```bash
#!/bin/bash
# 備份腳本
BACKUP_DIR="/Volumes/Momentry/backup/$(date +%Y%m%d)"
# 1. PostgreSQL 備份
pg_dump -U momentry momentry > "$BACKUP_DIR/momentry.sql"
pg_dump -U n8n n8n > "$BACKUP_DIR/n8n.sql"
# 2. MongoDB 備份
mongodump --out "$BACKUP_DIR/mongodb"
# 3. Redis 備份
redis-cli BGSAVE
cp /Volumes/Momentry/var/redis/dump.rdb "$BACKUP_DIR/redis.rdb"
# 4. Qdrant 備份
curl -X POST http://localhost:6333/collections/accusysdb/snapshots
# 5. 配置檔案備份
tar -czf "$BACKUP_DIR/config.tar.gz" \
/Volumes/Momentry/momentry/etc/
```
### 9.2 自動備份 Cron
```bash
# crontab -e
0 2 * * * /Volumes/Momentry/scripts/backup.sh
0 3 * * 0 /Volumes/Momentry/scripts/backup_full.sh
```
---
## 階段十:監控與維護
### 10.1 健康檢查腳本
```bash
#!/bin/bash
# health_check.sh
# 檢查所有服務
check_postgresql() {
pg_isready -q && echo "✅ PostgreSQL" || echo "❌ PostgreSQL"
}
check_mongodb() {
mongosh --eval "db.stats()" > /dev/null 2>&1 && echo "✅ MongoDB" || echo "❌ MongoDB"
}
check_redis() {
redis-cli ping > /dev/null 2>&1 && echo "✅ Redis" || echo "❌ Redis"
}
check_qdrant() {
curl -s http://localhost:6333/health && echo "✅ Qdrant" || echo "❌ Qdrant"
}
check_n8n() {
curl -s http://localhost:5678/api/v1/workflows > /dev/null 2>&1 && echo "✅ n8n" || echo "❌ n8n"
}
check_momentry() {
curl -s http://localhost:3002/api/v1/videos > /dev/null 2>&1 && echo "✅ Momentry" || echo "❌ Momentry"
}
```
### 10.2 日誌輪替
```bash
# 新聞日誌配置
/Volumes/Momentry/momentry/log/*.log {
daily
rotate 7
compress
missingok
notifempty
create 644 momentry staff
}
```
---
## 自動化腳本架構
### 主控腳本:部署控制器
```bash
#!/bin/bash
# deploy_controller.sh
# 用於從主控機部署到目標主機
set -e
# 配置
TARGET_HOST="momentry@192.168.1.100"
TARGET_DISK="/dev/disk2"
# 顏色定義
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
function log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
function log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
function log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 階段執行
function run_stage() {
local stage=$1
local script=$2
log_info "執行階段: $stage..."
ssh "$TARGET_HOST" "bash /Volumes/Momentry/scripts/$script"
if [ $? -eq 0 ]; then
log_info "✅ 階段完成: $stage"
else
log_error "❌ 階段失敗: $stage"
exit 1
fi
}
# 主程序
log_info "開始 Momentry 系統部署..."
# 執行各階段
run_stage "磁碟準備" "01_prepare_disk.sh"
run_stage "macOS 安裝" "02_install_macos.sh"
run_stage "Homebrew 安裝" "03_install_homebrew.sh"
run_stage "依賴安裝" "04_install_dependencies.sh"
run_stage "服務安裝" "05_install_services.sh"
run_stage "Momentry 安裝" "06_install_momentry.sh"
run_stage "網路配置" "07_configure_network.sh"
run_stage "啟動服務" "08_start_services.sh"
log_info "✅ 部署完成!"
```
---
## 待確認事項
### 需要與使用者確認
1. **目標主機型號**
- Intel Mac 或 Apple Silicon
- Thunderbolt 版本 (3/4)
2. **網路配置**
- DHCP 或固定 IP
- 目標 IP 網段?
3. **磁碟配置**
- 分割方案 A (200G 系統 + 1.8T 資料)
- 分割方案 B (統一磁碟區)
4. **服務需求**
- 需要安裝全部服務?
- 還是選擇性安裝?
5. **備份策略**
- 本地備份?
- 遠端備份?
- 備份頻率?
6. **監控需求**
- Prometheus + Grafana
- 簡單腳本監控?
---
## 預估時間
| 階段 | 預估時間 | 備註 |
|------|---------|------|
| 前置準備 | 30 分鐘 | 收集資訊、準備腳本 |
| 磁碟準備 | 10 分鐘 | 分割格式化 |
| macOS 安裝 | 30-60 分鐘 | 視 USB 速度 |
| Homebrew 安裝 | 15 分鐘 | 下載速度 |
| 服務安裝 | 60-90 分鐘 | 多個服務 |
| Momentry 安裝 | 20 分鐘 | 編譯 Rust |
| 網路配置 | 10 分鐘 | 固定 IP |
| 服務啟動 | 15 分鐘 | 依序啟動 |
| 驗證測試 | 30 分鐘 | 完整測試 |
| **總計** | **3-4 小時** | 自動化後可縮短 |
---
## 風險與應對
| 風險 | 機率 | 影響 | 應對措施 |
|------|------|------|---------|
| Thunderbolt 不相容 | 低 | 高 | 準備多種驅動 |
| macOS 安裝失敗 | 低 | 高 | 準備還原方案 |
| 服務啟動失敗 | 中 | 中 | 日誌診斷腳本 |
| 網路連線問題 | 中 | 中 | 有線網路備援 |
| 儲存空間不足 | 低 | 高 | 磁碟空間檢查 |
---
## 下一步行動
1. ✅ 確認目標主機規格
2. ✅ 確認 Thunderbolt NVMe 容量
3. ✅ 確認網路配置
4. ✅ 選擇服務清單
5. ✅ 準備安裝腳本
6. ✅ 測試腳本執行
7. ✅ 正式部署
---
## 附錄
### A. 服務端口對照表
| 服務 | Port | 協議 |
|------|------|------|
| PostgreSQL | 5432 | TCP |
| MongoDB | 27017 | TCP |
| MariaDB | 3306 | TCP |
| Redis | 6379 | TCP |
| Qdrant API | 6333 | HTTP |
| Qdrant gRPC | 6334 | gRPC |
| Ollama | 11434 | HTTP |
| Caddy HTTP | 80 | HTTP |
| Caddy HTTPS | 443 | HTTPS |
| Gitea | 3000 | HTTP |
| PHP-FPM | 9000 | FastCGI |
| n8n | 5678 | HTTP |
| SFTPGo | 2022 | SFTP |
| RustDesk hbbs | 21115 | TCP |
| RustDesk hbbr | 21117 | TCP |
| Momentry | 3002 | HTTP |
| Prometheus | 9090 | HTTP |
### B. 環境變數清單
`.env` 範例檔案或 `docs_v1.0/OPERATIONS/MOMENTRY_CORE_MONITORING.md`
### C. 疑難排解
`docs_v1.0/REFERENCE/PENDING_ISSUES.md`
---
**計劃狀態**: 📝 草稿 - 等待使用者確認後執行
**負責人**: OpenCode AI Assistant
**最後更新**: 2026-03-23
@@ -0,0 +1,549 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "MCP 按需加載策略分析"
date: "2026-04-01"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "按需加載策略分析"
ai_query_hints:
- "查詢 MCP 按需加載策略分析 的內容"
- "MCP 按需加載策略分析 的主要目的是什麼?"
- "如何操作或實施 MCP 按需加載策略分析?"
---
# MCP 按需加載策略分析
| 項目 | 內容 |
|------|------|
| 分析日期 | 2026-04-01 |
| 目標 | 節省 token,按需掛載 MCP 服務器 |
---
## 問題分析
### 當前困境
```
每次對話啟動時,所有 MCP 工具定義都會載入到 context:
例如,當前 session:
├─ Gitea MCP: ~80 個工具 → ~15,000 tokens
├─ N8N MCP: ~30 個工具 → ~6,000 tokens
├─ Playwright MCP: ~25 個工具 → ~5,000 tokens
├─ MongoDB MCP: ~25 個工具 → ~5,000 tokens
├─ Redis MCP: ~5 個工具 → ~1,000 tokens
├─ Postgres MCP: ~1 個工具 → ~200 tokens
├─ Sentry MCP: ~20 個工具 → ~4,000 tokens
├─ Qdrant MCP: ~2 個工具 → ~400 tokens
├─ Filesystem MCP: ~15 個工具 → ~3,000 tokens
└─ Context7 MCP: ~2 個工具 → ~400 tokens
總計: ~205 個工具 → ~40,000 tokens ❌
```
**問題**
- ❌ 每次對話都消耗 ~40k tokens(工具定義)
- ❌ 大部分工具用不到
- ❌ 浪費 context window
- ❌ 降低可用 token 數量
---
## 解決方案
### 方案 1:MCP 配置文件切換 ⭐(推薦)
**原理**:使用不同的配置文件,按需啟動
```bash
目錄結構:
~/.config/claude/
├── claude_desktop_config.json # 預設(最小)
├── claude_desktop_config.dev.json # 開發模式
├── claude_desktop_config.full.json # 完整模式
└── claude_desktop_config.minimal.json # 極簡模式
```
#### 實現方式
**1. 最小配置(日常使用)**
```json
// ~/.config/claude/claude_desktop_config.minimal.json
{
"mcpServers": {
"filesystem": {
"command": "mcp-filesystem",
"args": ["/Users/accusys/momentry_core_0.1"]
},
"redis": {
"command": "mcp-redis"
}
}
}
```
**Token 消耗**: ~4,000 tokens ✅
**2. 開發配置(程式開發)**
```json
// ~/.config/claude/claude_desktop_config.dev.json
{
"mcpServers": {
"filesystem": {...},
"redis": {...},
"gitea": {
"command": "gitea-mcp-server",
"args": ["--config", "~/.gitea-mcp/config.json"]
},
"postgres": {...}
}
}
```
**Token 消耗**: ~20,000 tokens ✅
**3. 完整配置(需要所有工具)**
```json
// ~/.config/claude/claude_desktop_config.full.json
{
"mcpServers": {
"filesystem": {...},
"redis": {...},
"postgres": {...},
"mongodb": {...},
"gitea": {...},
"n8n": {...},
"playwright": {...},
"sentry": {...},
"qdrant": {...},
"context7": {...}
}
}
```
**Token 消耗**: ~40,000 tokens ⚠️
#### 切換腳本
```bash
#!/bin/bash
# switch_mcp_config.sh
CONFIG_DIR="$HOME/.config/claude"
CURRENT_CONFIG="$CONFIG_DIR/claude_desktop_config.json"
case "$1" in
minimal)
cp "$CONFIG_DIR/claude_desktop_config.minimal.json" "$CURRENT_CONFIG"
echo "✅ Switched to minimal config (~4k tokens)"
;;
dev)
cp "$CONFIG_DIR/claude_desktop_config.dev.json" "$CURRENT_CONFIG"
echo "✅ Switched to dev config (~20k tokens)"
;;
full)
cp "$CONFIG_DIR/claude_desktop_config.full.json" "$CURRENT_CONFIG"
echo "✅ Switched to full config (~40k tokens)"
;;
*)
echo "Usage: $0 {minimal|dev|full}"
exit 1
;;
esac
# 重啟 Claude Desktop
osascript -e 'quit app "Claude"'
sleep 2
open -a "Claude"
```
**使用**
```bash
# 日常使用(最小 token
./switch_mcp_config.sh minimal
# 開發模式
./switch_mcp_config.sh dev
# 完整功能
./switch_mcp_config.sh full
```
---
### 方案 2:環境變數控制
**原理**:使用環境變數動態啟用 MCP
```json
// ~/.config/claude/claude_desktop_config.json
{
"mcpServers": {
"filesystem": {
"command": "mcp-filesystem",
"args": ["/Users/accusys/momentry_core_0.1"],
"disabled": false
},
"gitea": {
"command": "gitea-mcp-server",
"disabled": "${GITEA_MCP_ENABLED:-true}" == "false"
},
"mongodb": {
"command": "mcp-mongodb",
"disabled": "${MONGODB_MCP_ENABLED:-true}" == "false"
}
}
}
```
**⚠️ 限制**Claude Desktop 可能不支援環境變數
---
### 方案 3:輕量級 MCP 代理
**原理**:使用代理服務器按需轉發
```python
#!/usr/bin/env python3
"""
MCP Proxy Server - 按需載入 MCP 服務器
"""
import asyncio
import json
from typing import Dict, Any
class MCPProxy:
"""MCP 代理服務器"""
def __init__(self):
self.loaded_servers = {}
self.available_servers = {
"gitea": {"command": "gitea-mcp-server", "token_cost": 15000},
"n8n": {"command": "mcp-n8n", "token_cost": 6000},
"playwright": {"command": "mcp-playwright", "token_cost": 5000},
"mongodb": {"command": "mcp-mongodb", "token_cost": 5000},
"sentry": {"command": "mcp-sentry", "token_cost": 4000},
}
async def list_tools(self, only_loaded: bool = True):
"""列出可用工具"""
if only_loaded:
# 只返回已載入的工具(節省 token)
tools = []
for server_name, server in self.loaded_servers.items():
tools.extend(await server.list_tools())
return tools
else:
# 返回所有可用工具(包含未載入的)
return [
{
"name": f"load_{name}",
"description": f"Load {name} MCP server",
"token_cost": info["token_cost"]
}
for name, info in self.available_servers.items()
]
async def call_tool(self, tool_name: str, arguments: Dict):
"""調用工具"""
# 檢查是否需要先載入服務器
server_name = self._get_server_name(tool_name)
if server_name not in self.loaded_servers:
print(f"[MCP Proxy] Loading {server_name} on demand...")
await self.load_server(server_name)
# 轉發調用
server = self.loaded_servers[server_name]
return await server.call_tool(tool_name, arguments)
async def load_server(self, name: str):
"""按需載入 MCP 服務器"""
if name in self.loaded_servers:
return
if name not in self.available_servers:
raise ValueError(f"Unknown server: {name}")
# 啟動服務器
config = self.available_servers[name]
# ... 啟動邏輯
self.loaded_servers[name] = server
print(f"[MCP Proxy] Loaded {name} ({config['token_cost']} tokens)")
# 啟動代理
if __name__ == "__main__":
proxy = MCPProxy()
# 啟動 MCP 服務器...
```
**優點**
- ✅ 完全按需載入
- ✅ 只在調用時才消耗 token
- ✅ 透明代理
**缺點**
- ⚠️ 需要自行實現代理邏輯
- ⚠️ 首次調用有延遲
---
### 方案 4Claude Desktop 功能請求
**原理**:向 Anthropy 提交功能請求
```markdown
Feature Request: Lazy Loading MCP Servers
Problem:
- All MCP tools loaded at startup
- Consumes ~40k tokens per session
- Most tools unused in typical sessions
Proposed Solution:
1. Add "lazy": true flag to MCP config
2. Only load tool definitions when first called
3. Show "Load {server_name}" placeholder in tool list
Example:
{
"mcpServers": {
"gitea": {
"command": "gitea-mcp-server",
"lazy": true // Only load on demand
}
}
}
Benefits:
- Save ~30-35k tokens per session
- Faster startup
- Better UX
```
**提交位置**
- GitHub Issues: https://github.com/anthropics/anthropic-cookbook/issues
- Discord: Anthropic Community
---
## 實際測試
### Token 消耗對比
| 配置 | 工具數 | Token 消耗 | 適用場景 |
|------|--------|-----------|---------|
| **最小** | 20 | ~4,000 | 日常對話 ⭐ |
| **開發** | 80 | ~20,000 | 程式開發 |
| **完整** | 205 | ~40,000 | 特殊需求 |
### 節省效果
```
預設(最小配置):
每次對話節省: 40,000 - 4,000 = 36,000 tokens
100 次對話節省: 3,600,000 tokens ≈ $36 USD
開發配置:
每次對話節省: 40,000 - 20,000 = 20,000 tokens
100 次對話節省: 2,000,000 tokens ≈ $20 USD
```
---
## 推薦策略
### 策略 1:配置文件分離(立即可用)⭐
```bash
# 1. 創建配置文件
~/.config/claude/
├─ claude_desktop_config.minimal.json # 4k tokens
├─ claude_desktop_config.dev.json # 20k tokens
└─ claude_desktop_config.full.json # 40k tokens
# 2. 使用腳本切換
./switch_mcp_config.sh minimal # 節省 36k tokens
./switch_mcp_config.sh dev # 節省 20k tokens
./switch_mcp_config.sh full # 完整功能
# 3. 重啟 Claude Desktop
```
### 策略 2:預設最小配置
```json
// 預設只載入最常用的 MCP
{
"mcpServers": {
"filesystem": {...}, // 文件操作(必需)
"redis": {...} // 快取(常用)
}
}
// 需要其他功能時,切換配置
```
### 策略 3:按項目配置
```bash
# 不同項目使用不同配置
momentry_core_0.1/
└─ .claude_config.json # 項目專用配置
# 啟動時自動載入項目配置
if [ -f ".claude_config.json" ]; then
cp .claude_config.json ~/.config/claude/claude_desktop_config.json
fi
```
---
## 實施步驟
### Step 1:創建配置文件(立即)
```bash
# 創建配置目錄
mkdir -p ~/.config/claude
# 創建最小配置(推薦預設)
cat > ~/.config/claude/claude_desktop_config.minimal.json << 'EOF'
{
"mcpServers": {
"filesystem": {
"command": "mcp-filesystem",
"args": ["/Users/accusys"]
},
"redis": {
"command": "mcp-redis"
}
}
}
EOF
# 創建開發配置
cat > ~/.config/claude/claude_desktop_config.dev.json << 'EOF'
{
"mcpServers": {
"filesystem": {...},
"redis": {...},
"gitea": {...},
"postgres": {...}
}
}
EOF
# 設定預設為最小配置
cp ~/.config/claude/claude_desktop_config.minimal.json \
~/.config/claude/claude_desktop_config.json
```
### Step 2:創建切換腳本
```bash
# 創建腳本
cat > ~/bin/switch_mcp << 'EOF'
#!/bin/bash
# MCP 配置切換器
CONFIG_DIR="$HOME/.config/claude"
CURRENT="$CONFIG_DIR/claude_desktop_config.json"
case "$1" in
minimal|dev|full)
cp "$CONFIG_DIR/claude_desktop_config.$1.json" "$CURRENT"
echo "✅ Switched to $1 config"
echo "🔄 Restarting Claude Desktop..."
osascript -e 'quit app "Claude"'
sleep 2
open -a "Claude"
;;
status)
if [ -L "$CURRENT" ]; then
echo "Current: $(readlink $CURRENT)"
else
echo "Current: standalone config"
fi
;;
*)
echo "Usage: switch_mcp {minimal|dev|full|status}"
;;
esac
EOF
chmod +x ~/bin/switch_mcp
```
### Step 3:使用
```bash
# 日常使用(最小 token
switch_mcp minimal
# 開發模式
switch_mcp dev
# 完整功能
switch_mcp full
# 查看當前配置
switch_mcp status
```
---
## 總結
### ✅ 推薦方案
**配置文件切換**(立即可用):
- ✅ 節省 20-36k tokens per session
- ✅ 無需等待 Anthropy 實現
- ✅ 靈活可控
- ✅ 快速切換
### 📋 配置建議
```
預設(90% 場景):
├─ filesystem
└─ redis
Token: ~4,000 ✅
開發(8% 場景):
├─ filesystem
├─ redis
├─ gitea
└─ postgres
Token: ~20,000 ✅
完整(2% 場景):
└─ 所有 MCP
Token: ~40,000 ⚠️
```
### 🎯 預期效果
```
每次對話節省:
預設使用最小配置: 節省 36,000 tokens ≈ $0.036
每月節省(假設 500 次對話):
500 × 36,000 = 18,000,000 tokens ≈ $18 USD
年度節省:
$216 USD ✅
```
@@ -0,0 +1,445 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "模組標準化實施計劃"
date: "2026-04-25"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "模組標準化實施計劃"
ai_query_hints:
- "查詢 模組標準化實施計劃 的內容"
- "模組標準化實施計劃 的主要目的是什麼?"
- "如何操作或實施 模組標準化實施計劃?"
---
# 模組標準化實施計劃
## 概述
本計劃詳細說明如何將現有的處理器模組按照《處理器模組標準化規範》進行標準化改造。計劃從 ASR 模組開始,逐步擴展到所有處理器模組。
## 實施策略
### 階段式實施
1. **階段 1**: ASR 模組標準化(示範項目)
2. **階段 2**: OCR、YOLO 模組標準化
3. **階段 3**: Face、Pose、CUT 模組標準化
4. **階段 4**: ASRX、Caption、Story 模組標準化
5. **階段 5**: 系統整合與優化
### 並行工作流
```
分析現有代碼 → 創建標準模板 → 重構模組 → 測試驗證 → 文檔更新
```
## 階段 1: ASR 模組標準化
### 目標
將 ASR 模組作為示範項目,完整實施標準化規範,建立可重用的模板和流程。
### 當前狀態分析
#### Rust 模組 (`src/core/processor/asr.rs`)
**優點**:
- 結構相對清晰
- 已有完整的結果結構定義
- 使用標準的 PythonExecutor
**需要改進**:
1. 配置管理不統一(硬編碼超時 vs 環境變量)
2. 缺少性能監控指標
3. 測試覆蓋不完整
4. 文檔不完整
#### Python 腳本 (`scripts/asr_processor.py`)
**問題**:
1. 過於複雜(953 行)
2. 包含不必要的監控邏輯
3. Redis 發布依賴
4. 錯誤處理不規範
5. 缺少模塊化設計
### 實施步驟
#### 步驟 1: 創建標準化模板
1. 創建 Rust 模組模板
2. 創建 Python 腳本模板
3. 創建配置模板
4. 創建測試模板
#### 步驟 2: 備份現有代碼
```bash
# 備份原始文件
cp src/core/processor/asr.rs src/core/processor/asr_legacy.rs
cp scripts/asr_processor.py scripts/asr_processor_legacy.py
```
#### 步驟 3: 重構 Rust 模組
1. 更新配置管理
2. 添加性能監控
3. 完善錯誤處理
4. 補充文檔註釋
#### 步驟 4: 重構 Python 腳本
1. 簡化架構(目標: <300 行)
2. 移除不必要的監控邏輯
3. 規範錯誤處理
4. 添加模塊化設計
#### 步驟 5: 更新配置
1. 統一環境變量
2. 添加性能相關配置
3. 文檔化配置選項
#### 步驟 6: 添加測試
1. 單元測試
2. 集成測試
3. 性能測試
4. 回歸測試
#### 步驟 7: 驗證功能
1. 功能測試
2. 性能對比
3. 兼容性驗證
### 詳細任務分解
#### 任務 1.1: 分析 ASR 模組依賴
```bash
# 檢查 Python 腳本依賴
grep -n "import" scripts/asr_processor.py
grep -n "from" scripts/asr_processor.py
# 檢查 Rust 依賴
grep -n "use" src/core/processor/asr.rs
```
#### 任務 1.2: 創建標準化模板
```bash
# 創建模板目錄
mkdir -p docs/templates/module_standardization
# 創建 Rust 模板
cat > docs/templates/module_standardization/rust_module_template.rs << 'EOF'
// Rust 模組標準模板
EOF
# 創建 Python 模板
cat > docs/templates/module_standardization/python_processor_template.py << 'EOF'
# Python 處理器標準模板
EOF
```
#### 任務 1.3: 重構 ASR Rust 模組
**改進點**:
1. 統一配置管理
2. 添加 `ProcessingMetrics` 結構
3. 完善錯誤處理鏈
4. 添加詳細日誌
5. 補充文檔註釋
#### 任務 1.4: 重構 ASR Python 腳本
**簡化策略**:
1. 移除 `ResourceMonitor`
2. 移除 Redis 發布邏輯
3. 簡化 chunking 邏輯
4. 規範錯誤處理
5. 添加模塊化設計
#### 任務 1.5: 更新配置系統
```rust
// 在 src/core/config.rs 中添加
pub static ASR_MODEL: Lazy<String> = Lazy::new(|| {
env::var("MOMENTRY_ASR_MODEL").unwrap_or_else(|_| "base".to_string())
});
pub static ASR_CHUNK_SIZE: Lazy<u64> = Lazy::new(|| {
env::var("MOMENTRY_ASR_CHUNK_SIZE")
.unwrap_or_else(|_| "300".to_string())
.parse()
.unwrap_or(300)
});
pub static ASR_CACHE_ENABLED: Lazy<bool> = Lazy::new(|| {
env::var("MOMENTRY_ASR_CACHE_ENABLED")
.unwrap_or_else(|_| "true".to_string())
.parse()
.unwrap_or(true)
});
```
#### 任務 1.6: 創建測試套件
```rust
// 測試文件結構
tests/
unit/
asr_result_test.rs
asr_serialization_test.rs
integration/
asr_integration_test.rs
performance/
asr_benchmark.rs
```
#### 任務 1.7: 創建遷移文檔
```markdown
# ASR 模組標準化遷移指南
## 變更摘要
1. 簡化 Python 腳本架構
2. 統一配置管理
3. 添加性能監控
4. 完善錯誤處理
## 兼容性說明
- API 保持不變
- 輸出格式保持兼容
- 配置方式向後兼容
## 遷移步驟
1. 備份現有文件
2. 更新 Rust 模組
3. 更新 Python 腳本
4. 更新環境變量
5. 運行測試驗證
```
### 時間安排
| 任務 | 預計工時 | 負責人 | 狀態 |
|------|----------|--------|------|
| 分析現有代碼 | 2 小時 | Warren | 待開始 |
| 創建標準模板 | 4 小時 | Warren | 待開始 |
| 重構 Rust 模組 | 6 小時 | Warren | 待開始 |
| 重構 Python 腳本 | 8 小時 | Warren | 待開始 |
| 更新配置系統 | 3 小時 | Warren | 待開始 |
| 創建測試套件 | 6 小時 | Warren | 待開始 |
| 功能驗證測試 | 4 小時 | Warren | 待開始 |
| 文檔更新 | 3 小時 | Warren | 待開始 |
| **總計** | **36 小時** | | |
### 成功標準
#### 功能標準
1. ✅ 保持現有 API 兼容性
2. ✅ 輸出格式保持不變
3. ✅ 處理準確率不降低
4. ✅ 錯誤處理更完善
#### 性能標準
1. ⬆️ 處理時間減少 20%
2. ⬇️ 內存使用減少 30%
3. ⬆️ 代碼可讀性提高
4. ⬆️ 維護性提高
#### 質量標準
1. ✅ 單元測試覆蓋率 >80%
2. ✅ 集成測試通過率 100%
3. ✅ 文檔完整度 100%
4. ✅ 代碼審查通過
## 階段 2: OCR 和 YOLO 模組標準化
### 目標
基於 ASR 模組的經驗,標準化 OCR 和 YOLO 模組。
### 實施步驟
1. 應用 ASR 標準化模板
2. 處理模組特定邏輯
3. 優化性能配置
4. 創建模組特定測試
### 時間安排
- OCR 模組: 20 小時
- YOLO 模組: 24 小時
- 總計: 44 小時
## 階段 3: Face、Pose、CUT 模組標準化
### 目標
完成較簡單的處理器模組標準化。
### 實施步驟
1. 批量應用模板
2. 重點處理配置統一
3. 創建共享工具函數
### 時間安排
- 每個模組: 12-16 小時
- 總計: 40-48 小時
## 階段 4: ASRX、Caption、Story 模組標準化
### 目標
完成所有處理器模組標準化。
### 實施步驟
1. 處理複雜模組邏輯
2. 優化資源使用
3. 創建高級功能測試
### 時間安排
- 每個模組: 16-20 小時
- 總計: 48-60 小時
## 階段 5: 系統整合與優化
### 目標
1. 統一配置管理系統
2. 創建模組管理器
3. 實現動態加載
4. 優化資源共享
### 實施步驟
1. 創建 `ModuleRegistry` 管理所有模組
2. 實現配置熱重載
3. 添加模組健康檢查
4. 創建性能監控面板
### 時間安排
- 系統整合: 40 小時
- 性能優化: 32 小時
- 文檔完善: 16 小時
- 總計: 88 小時
## 總體時間規劃
| 階段 | 預計工時 | 累計工時 | 時間窗口 |
|------|----------|----------|----------|
| 階段 1: ASR 示範 | 36 小時 | 36 小時 | 第 1 周 |
| 階段 2: OCR/YOLO | 44 小時 | 80 小時 | 第 2 周 |
| 階段 3: Face/Pose/CUT | 44 小時 | 124 小時 | 第 3 周 |
| 階段 4: ASRX/Caption/Story | 54 小時 | 178 小時 | 第 4 周 |
| 階段 5: 系統整合 | 88 小時 | 266 小時 | 第 5-6 周 |
| **總計** | **266 小時** | | **6 周** |
## 風險管理
### 技術風險
1. **兼容性問題**: 現有代碼依賴複雜
- 緩解: 逐步遷移,保持 API 兼容
- 監控: 回歸測試套件
2. **性能回歸**: 標準化可能引入開銷
- 緩解: 性能基準測試
- 監控: 持續性能監控
3. **依賴問題**: Python 庫版本衝突
- 緩解: 虛擬環境隔離
- 監控: 依賴版本鎖定
### 項目風險
1. **時間超支**: 複雜度估計不足
- 緩解: 分階段實施,定期評估
- 監控: 每周進度報告
2. **資源不足**: 開發人員時間有限
- 緩解: 優先級排序,外包簡單任務
- 監控: 資源分配跟蹤
3. **質量問題**: 測試覆蓋不足
- 緩解: 測試驅動開發
- 監控: 代碼覆蓋率報告
## 資源需求
### 人力資源
- **技術負責人**: 1 人(Warren
- **開發人員**: 1-2 人(可選)
- **測試人員**: 1 人(可選)
- **文檔專員**: 1 人(可選)
### 技術資源
- **測試服務器**: 用於性能測試
- **CI/CD 管道**: 自動化測試部署
- **監控工具**: 性能監控和告警
- **文檔平台**: 文檔管理和發布
### 軟件資源
- **開發工具**: Rust, Python, 編輯器
- **測試框架**: cargo test, pytest
- **性能工具**: perf, valgrind, py-spy
- **文檔工具**: mdBook, Sphinx
## 溝通計劃
### 定期會議
- **每日站會**: 15 分鐘,進度同步
- **每周評審**: 1 小時,進度評估和調整
- **階段總結**: 每階段結束,經驗總結
### 報告機制
- **進度報告**: 每周書面報告
- **問題報告**: 即時問題上報
- **變更請求**: 規範變更流程
### 文檔更新
- **技術文檔**: 實時更新
- **用戶文檔**: 階段性更新
- **API 文檔**: 自動生成
## 質量保證
### 代碼質量
1. **代碼審查**: 所有變更必須經過審查
2. **靜態分析**: Rust clippy, Python pylint
3. **格式化檢查**: rustfmt, black
4. **依賴檢查**: cargo audit, safety
### 測試質量
1. **測試覆蓋率**: >80% 行覆蓋率
2. **集成測試**: 端到端功能測試
3. **性能測試**: 基準測試和比較
4. **壓力測試**: 高負載場景測試
### 文檔質量
1. **完整性**: 所有功能都有文檔
2. **準確性**: 文檔與代碼同步
3. **可讀性**: 清晰易懂的說明
4. **示例**: 豐富的使用示例
## 驗收標準
### 階段驗收
每個階段完成後需要驗收:
1. ✅ 功能測試通過
2. ✅ 性能測試達標
3. ✅ 文檔更新完成
4. ✅ 代碼審查通過
### 最終驗收
項目完成後需要驗收:
1. ✅ 所有模組標準化完成
2. ✅ 系統整合測試通過
3. ✅ 性能基準達標
4. ✅ 文檔完整發布
5. ✅ 團隊培訓完成
## 後續維護
### 維護計劃
1. **錯誤修復**: 24 小時內響應
2. **性能優化**: 定期性能審查
3. **安全更新**: 及時更新依賴
4. **功能增強**: 根據需求迭代
### 監控指標
1. **運行時指標**: 成功率、延遲、資源使用
2. **代碼指標**: 覆蓋率、複雜度、債務
3. **用戶指標**: 使用頻率、滿意度、問題反饋
### 改進機制
1. **定期回顧**: 每季度技術回顧
2. **用戶反饋**: 收集和分析反饋
3. **技術調研**: 跟蹤新技術發展
4. **重構計劃**: 持續技術債務管理
---
*版本: 1.0.0*
*創建日期: 2026-03-27*
*負責人: Warren (Technical Lead)*
*狀態: 審核中*
@@ -0,0 +1,541 @@
# Momentry Core 全新系統架構設計
> 更新日期: 2026-04-25
> 版本: V1.0 (全新設計)
> 狀態: 設計中
---
## 1. 核心設計理念
### 1.1 兩大核心實體
系統僅有兩種核心概念:
| 實體 | 說明 | 範例 |
|------|------|------|
| **File** | 任何檔案 | video, pdf, ppt, png, doc, audio... |
| **Identity** | 任何可識別列管的 object | 人、物件、品牌、概念、場景... |
### 1.2 關係模型
```
File ──[包含/出現]──→ Identity
Identity ──[出現在]──→ File
```
- 一個 File 可包含多個 Identity
- 一個 Identity 可出現在多個 File
- Identity 可歸屬於分類系統
---
## 2. Identity 設計
### 2.1 Identity 類型
任何可命名的事物都是 Identity:
| 類型 | 說明 | 範例 |
|------|------|------|
| people | 人 | 演員、公眾人物、虛構角色 |
| object | 物件 | 車輛、建築、道具 |
| brand | 品牌 | LV、Hello Kitty、Nike |
| logo | 商標 | LV logo、Nike 勾勾 |
| concept | 概念 | 愛、自由、科技 |
| scene | 場景 | 室內、室外、街道 |
### 2.2 People Identity 特殊設計
**核心需求**: 同一個人(演員)在不同電影中有不同的角色名和定妝造型。
#### 階層結構
```
Identity (真實人物): 張曼玉
├── File A (花樣年華): 角色 "蘇麗珍" → 定妝: 旗袍造型、老妝+白髮頭套
├── File B (東邪西毒): 角色 "歐陽鋒妻子" → 定妝: 武俠造型
├── File C (甜蜜蜜): 角色 "李翹" → 定妝: 現代造型
└── File D: 角色 "XXX" → 定妝: 醜妝+傷妝
```
#### 在 File 中的呈現方式
| 呈現方式 | 說明 | 數據來源 |
|----------|------|----------|
| face | 臉孔出現 | Face Detection |
| speaker | 聲音出現 | ASR/Speaker Diarization |
| pose | 姿態/身體出現 | Pose Estimation |
| name_mention | 名字被提到 | ASR 文本/OCR |
### 2.3 Identity 屬性
```sql
CREATE TABLE identities (
id BIGSERIAL PRIMARY KEY,
uuid VARCHAR(36) UNIQUE NOT NULL,
name TEXT NOT NULL, -- 可識別名稱
identity_type VARCHAR(30), -- people, object, brand, concept...
description TEXT,
-- People 特有
real_name TEXT, -- 真實姓名
-- TMDB 整合
tmdb_id INTEGER, -- TMDB 人物 ID
tmdb_profile TEXT, -- TMDB 人臉照 URL
source VARCHAR(20), -- 'tmdb', 'manual', 'ai_detection'
-- 參考向量 (用於自動比對)
face_embedding VECTOR(512), -- 參考臉向量 (ArcFace)
voice_embedding VECTOR(192), -- 參考聲紋向量 (ECAPA-TDNN)
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
```
---
## 3. File 設計
### 3.1 File 屬性
```sql
CREATE TABLE files (
id BIGSERIAL PRIMARY KEY,
uuid VARCHAR(36) UNIQUE NOT NULL,
file_path TEXT NOT NULL,
file_name TEXT NOT NULL,
file_type VARCHAR(20), -- video, pdf, ppt, png, audio...
file_size BIGINT,
mime_type VARCHAR(100),
metadata JSONB, -- 類型特定元數據
tmdb_movie_id INTEGER, -- TMDB 電影 ID (可選)
imdb_id VARCHAR(20), -- IMDb ID (可選)
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
```
### 3.2 File 類型特定元數據
| 檔案類型 | 元數據內容 |
|----------|-----------|
| video | duration, width, height, fps, codec |
| audio | duration, sample_rate, channels |
| image | width, height, format |
| document | page_count, language |
---
## 4. File-Identity 關聯設計
### 4.1 關聯表
```sql
CREATE TABLE file_identities (
id BIGSERIAL PRIMARY KEY,
file_uuid VARCHAR(36) REFERENCES files(uuid),
identity_uuid VARCHAR(36) REFERENCES identities(uuid),
-- People 特有
role_name TEXT, -- 劇中角色名
costume_design TEXT, -- 定妝造型描述
presentation TEXT[], -- ['face', 'speaker', 'pose', 'name_mention']
-- 時間位置
timestamp_start FLOAT, -- 開始時間 (秒)
timestamp_end FLOAT, -- 結束時間
frame_start BIGINT, -- 開始幀
frame_end BIGINT, -- 結束幀
-- 檢測數據
face_data JSONB, -- {face_id, confidence, bbox}
speaker_data JSONB, -- {speaker_id, audio_segment}
pose_data JSONB, -- {keypoints, action}
-- 匹配資訊
match_confidence FLOAT, -- AI 匹配置信度
is_confirmed BOOLEAN DEFAULT FALSE, -- 人工確認
created_at TIMESTAMPTZ DEFAULT NOW()
);
```
### 4.2 呈現方式說明
| 呈現方式 | 說明 | 適用 Identity 類型 |
|----------|------|-------------------|
| face | 臉孔出現在畫面中 | people |
| speaker | 聲音出現在音軌中 | people |
| pose | 身體姿態出現在畫面中 | people |
| name_mention | 名字在文本中被提到 | people, brand, concept |
| object_detection | 物件被檢測到 | object, brand, logo |
| text_mention | 文字提到 | 所有類型 |
| logo_detection | 商標被檢測到 | brand, logo |
---
## 5. 分類系統設計
### 5.1 階層式編號格式
參考 IPC 但更靈活:
```
X-NNN-NNN/NNN
│ │ │ └─ 細分類 (Subgroup)
│ │ └───── 主分類 (Main Group)
│ └───────── 子分類 (Subclass)
└──────────── 大分類 (Section)
```
### 5.2 範例
```
P-001-000/000 人物 (People)
├── P-001-010/000 演員
│ ├── P-001-010/010 電影演員
│ └── P-001-010/020 電視演員
├── P-001-020/000 公眾人物
└── P-001-030/000 虛構角色
B-002-000/000 品牌 (Brand)
├── B-002-010/000 時尚品牌
│ ├── B-002-010/010 LV
│ └── B-002-010/020 Gucci
└── B-002-020/000 科技品牌
O-003-000/000 物件 (Object)
├── O-003-010/000 車輛
├── O-003-020/000 建築
└── O-003-030/000 道具
C-004-000/000 概念 (Concept)
├── C-004-010/000 情感
│ ├── C-004-010/010 愛
│ └── C-004-010/020 自由
└── C-004-020/000 思想
```
### 5.3 分類表結構
```sql
CREATE TABLE categories (
id BIGSERIAL PRIMARY KEY,
code VARCHAR(20) UNIQUE NOT NULL, -- P-001-010/010
name TEXT NOT NULL,
parent_code VARCHAR(20) REFERENCES categories(code),
description TEXT,
category_type VARCHAR(20), -- 'file', 'identity', 'both'
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- File-Category 關聯
CREATE TABLE file_categories (
file_uuid VARCHAR(36) REFERENCES files(uuid),
category_code VARCHAR(20) REFERENCES categories(code),
PRIMARY KEY (file_uuid, category_code)
);
-- Identity-Category 關聯
CREATE TABLE identity_categories (
identity_uuid VARCHAR(36) REFERENCES identities(uuid),
category_code VARCHAR(20) REFERENCES categories(code),
PRIMARY KEY (identity_uuid, category_code)
);
```
### 5.4 特點
1. **可擴充**:任何層級都可新增,不需重新編號
2. **有意義**:首字母代表大分類 (P=People, B=Brand, O=Object, C=Concept...)
3. **層級清晰**:通過編號即可知道所属分类深度
4. **靈活套用**:可套用在 File、Identity 或兩者
---
## 6. TMDB 整合設計
### 6.1 資料流
```
TMDB API → 電影資訊 + 演員名單 → 自動建立 Identity → 關聯到 File
```
### 6.2 整合流程
1. **匯入電影檔案時**
- 用戶提供 TMDB 電影 ID 或 IMDb ID
- 系統自動從 TMDB API 獲取:
- 演員名單 + 角色名
- 演員人臉照 (profile_path)
- 電影元數據
2. **建立 Identity**
- 自動建立或更新 Identity(演員)
- 儲存 TMDB ID + 人臉照 URL
- 關聯到 File(這部電影)
3. **提取參考向量**
- 下載 TMDB 人臉照
- 提取 face_embedding (512-dim)
- 儲存到 identities 表
4. **後續 AI 識別**
- 系統檢測 File 中的 Face
- 自動匹配到已有的 Identity
- 更新 file_identities 表
### 6.3 TMDB API 端點
| 端點 | 說明 |
|------|------|
| `/api/v1/tmdb/search/movie?q=關鍵字` | 搜尋電影 |
| `/api/v1/tmdb/movie/:id` | 獲取電影詳情 |
| `/api/v1/tmdb/movie/:id/cast` | 獲取演員列表 |
| `/api/v1/tmdb/person/:id` | 獲取人物詳情 |
| `/api/v1/tmdb/person/:id/images` | 獲取人物照片 |
---
## 7. 自動辨識比對設計
### 7.1 核心目標
**從 Identity (People) 的一張參考臉,自動辨識比對,找到所有出現的 File 和片段。**
### 7.2 比對流程
```
1. 建立 Identity
└── 取得參考臉 (TMDB 照片或手動上傳)
└── 提取 face_embedding (512-dim)
2. 處理 File (Video)
└── AI 檢測所有 Face → 提取每張臉的向量
└── AI 檢測所有 Speaker → 提取聲紋向量
└── AI 檢測所有 Object → 提取特徵向量
3. 自動比對匹配
└── Face 比對: 檢測臉 vs Identity face_embedding
└── Voice 比對: 檢測聲紋 vs Identity voice_embedding
└── 超過閾值 → 自動建立 file_identities 關聯
4. 人工確認 (可選)
└── 低置信度匹配標記為待確認
└── 用戶確認/修正
```
### 7.3 比對閾值
| 比對類型 | 預設閾值 | 說明 |
|----------|----------|------|
| Face | 0.85 | ArcFace 512-dim |
| Voice | 0.75 | ECAPA-TDNN 192-dim |
| Object | 0.80 | YOLO + 特徵 |
---
## 8. API 架構
### 8.1 File API
```
GET /api/v1/files # 列表
參數: ?page=1&page_size=20&type=video&category=P-001&sort=created_at
GET /api/v1/files/search?q=關鍵字 # 搜尋
GET /api/v1/files/:uuid # 詳情
GET /api/v1/files/:uuid/identities # File 有哪些 Identity
參數: ?presentation=face&role_name=蘇麗珍
POST /api/v1/files/:uuid/import-tmdb # 從 TMDB 匯入演員
Body: {"tmdb_movie_id": 12345}
```
### 8.2 Identity API
```
GET /api/v1/identities # 列表
參數: ?page=1&page_size=20&type=people&category=B-002&sort=name
GET /api/v1/identities/search?q=名字 # 搜尋
GET /api/v1/identities/:id # 詳情
GET /api/v1/identities/:id/files # Identity 在哪些 File
參數: ?presentation=face&role_name=蘇麗珍
POST /api/v1/identities # 手動建立 Identity
PUT /api/v1/identities/:id # 更新 Identity
POST /api/v1/identities/:id/reference-face # 上傳參考臉
POST /api/v1/identities/:id/scan # 掃描所有 File 比對
```
### 8.3 Category API
```
GET /api/v1/categories # 分類樹
GET /api/v1/categories/:code/children # 子分類
POST /api/v1/categories # 建立分類
PUT /api/v1/categories/:code # 更新分類
DELETE /api/v1/categories/:code # 刪除分類
```
### 8.4 TMDB API
```
GET /api/v1/tmdb/search/movie?q=關鍵字 # 搜尋電影
GET /api/v1/tmdb/movie/:id # 獲取電影詳情
GET /api/v1/tmdb/movie/:id/cast # 獲取演員列表
```
---
## 9. 搜尋範例
### 9.1 場景:找到張曼玉出現在哪些 File
```bash
# Step 1: 搜尋 Identity
GET /api/v1/identities/search?q=張曼玉
# Step 2: 獲取相關 File
GET /api/v1/identities/{identity_uuid}/files
# 返回:
{
"files": [
{
"file_uuid": "xxx",
"file_name": "花樣年華.mp4",
"role_name": "蘇麗珍",
"costume_design": "老妝+白髮頭套",
"presentation": ["face", "speaker"],
"timestamp_start": 120.5,
"timestamp_end": 135.2
}
]
}
```
### 9.2 場景:找到某 File 中所有演員
```bash
GET /api/v1/files/{file_uuid}/identities?presentation=face
# 返回:
{
"identities": [
{
"identity_uuid": "abc",
"name": "張曼玉",
"role_name": "蘇麗珍",
"presentation": ["face", "speaker"]
}
]
}
```
### 9.3 場景:通過分類瀏覽
```bash
# 所有演員相關 Identity
GET /api/v1/identities?category=P-001-010
# 所有電影相關 File
GET /api/v1/files?category=M-001-010
```
### 9.4 場景:組合搜尋
```bash
GET /api/v1/identities/search?q=&type=people&category=P-001
```
---
## 10. 執行計畫
### Phase 1: 資料庫重構
- [ ] 建立新表 (files, identities, file_identities, categories, file_categories, identity_categories)
- [ ] 資料遷移腳本 (從現有 videos/person_identities 遷移)
- [ ] 向量索引配置 (face_embedding, voice_embedding)
- [ ] 測試資料建立
### Phase 2: 核心 API
- [ ] File CRUD + 列表/搜尋/過濾
- [ ] Identity CRUD + 列表/搜尋/過濾
- [ ] Category 樹狀結構 CRUD
- [ ] File-Identity 關聯 API
- [ ] Category 關聯 API
### Phase 3: TMDB 整合
- [ ] TMDB API 串接 (搜尋電影、獲取演員、獲取照片)
- [ ] 自動建立 Identity 流程
- [ ] 人臉照下載與向量提取
- [ ] 角色名自動關聯
### Phase 4: AI 自動辨識
- [ ] Face 檢測整合 (現有)
- [ ] 向量比對匹配邏輯
- [ ] file_identities 自動建立
- [ ] 低置信度標記與人工確認流程
### Phase 5: Portal 前端
- [ ] File 列表 + 搜尋 + 過濾
- [ ] Identity 列表 + 搜尋
- [ ] 分類瀏覽
- [ ] Identity 詳情 (顯示所有相關 File)
- [ ] File 詳情 (顯示所有 Identity)
- [ ] TMDB 匯入介面
- [ ] 參考臉上傳介面
---
## 11. 待確認問題
| 編號 | 問題 | 選項 | 決策 |
|------|------|------|------|
| Q1 | 參考臉來源 | TMDB / 手動上傳 / 兩者都有 | |
| Q2 | 比對閾值 | Face: 0.85, Voice: 0.75 | |
| Q3 | 非電影檔案 | 手動建立 Identity | |
| Q4 | 分類編號格式 | P-001-010/010 | |
| Q5 | 現有系統遷移 | 需要相容層 | |
| Q6 | People 階層 | Identity → File (含角色名+造型) | |
| Q7 | 非人物件階層 | 是否需要類似造型層級? | |
| Q8 | AI 識別觸發 | 自動 / 手動 / 兩者都有 | |
---
## 12. 技術棧
| 層級 | 技術 |
|------|------|
| 後端 | Rust (momentry_core) |
| 前端 | Vue 3 + TypeScript (Portal) |
| 資料庫 | PostgreSQL + pgvector |
| 向量庫 | Qdrant |
| 快取 | Redis |
| AI 處理 | Python (Whisper, ArcFace, YOLO...) |
| TMDB | TMDB API v3 |
---
## 13. 版本歷史
| 版本 | 日期 | 目的 | 操作人 |
|------|------|------|--------|
| V1.0 | 2026-04-25 | 全新設計 (File + Identity + Category) | OpenCode |
@@ -0,0 +1,392 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Momentry Core 監控架構設計"
date: "2026-04-22"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "momentry"
- "core"
- "監控架構設計"
ai_query_hints:
- "查詢 Momentry Core 監控架構設計 的內容"
- "Momentry Core 監控架構設計 的主要目的是什麼?"
- "如何操作或實施 Momentry Core 監控架構設計?"
---
# Momentry Core 監控架構設計
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-22 |
| 文件版本 | V1.0 |
| 相關文件 | [ARCHITECTURE_OVERVIEW.md](./ARCHITECTURE_OVERVIEW.md)<br>[PERFORMANCE_AND_SCALABILITY.md](./PERFORMANCE_AND_SCALABILITY.md)<br>[SECURITY_ARCHITECTURE.md](./SECURITY_ARCHITECTURE.md) |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-04-22 | 創建監控架構設計文件 | OpenCode | OpenCode / deepseek-v3.2 |
---
## 1. 監控架構概述
### 1.1 監控目標
1. **系統健康**:確保所有服務正常運行
2. **效能監控**:追蹤系統效能指標與瓶頸
3. **業務指標**:監控關鍵業務流程與用戶行為
4. **安全監控**:偵測安全威脅與異常行為
5. **成本監控**:追蹤資源使用與成本優化
### 1.2 監控層次
```
應用層監控
├── 業務指標 (用戶行為、轉化率)
├── 應用效能 (API 響應、錯誤率)
└── 用戶體驗 (頁面載入、互動延遲)
系統層監控
├── 服務健康 (進程狀態、端口監聽)
├── 資源使用 (CPU、記憶體、磁碟)
└── 網絡流量 (帶寬、連接數)
基礎設施監控
├── 硬件狀態 (服務器、儲存)
├── 網絡設備 (路由器、交換機)
└── 電源環境 (UPS、溫度)
```
---
## 2. 監控指標體系
### 2.1 系統資源監控
#### 2.1.1 CPU 監控
| 指標 | 描述 | 告警閾值 | 測量頻率 |
|------|------|----------|----------|
| **CPU 使用率** | 總體 CPU 使用百分比 | > 80% 持續5分鐘 | 10秒 |
| **CPU 負載** | 平均負載 (1, 5, 15分鐘) | > 核心數×2 | 1分鐘 |
| **CPU 核心數** | 可用 CPU 核心數量 | 變化時告警 | 5分鐘 |
| **CPU 等待時間** | I/O 等待時間百分比 | > 20% 持續2分鐘 | 30秒 |
#### 2.1.2 記憶體監控
| 指標 | 描述 | 告警閾值 | 測量頻率 |
|------|------|----------|----------|
| **記憶體使用率** | 已用記憶體百分比 | > 85% 持續5分鐘 | 10秒 |
| **Swap 使用率** | Swap 空間使用百分比 | > 50% | 30秒 |
| **緩存使用量** | 文件緩存大小 | 監控趨勢 | 1分鐘 |
| **OOM 事件** | Out of Memory 事件 | 發生即告警 | 實時 |
#### 2.1.3 儲存監控
| 指標 | 描述 | 告警閾值 | 測量頻率 |
|------|------|----------|----------|
| **磁碟使用率** | 磁碟空間使用百分比 | > 90% | 5分鐘 |
| **磁碟 I/O** | 讀寫速度與延遲 | > 100ms 延遲 | 30秒 |
| **Inode 使用率** | Inode 使用百分比 | > 80% | 5分鐘 |
| **文件系統錯誤** | 文件系統錯誤數 | > 0 | 5分鐘 |
### 2.2 網絡監控
#### 2.2.1 網絡流量監控
| 指標 | 描述 | 告警閾值 | 測量頻率 |
|------|------|----------|----------|
| **帶寬使用率** | 網絡帶寬使用百分比 | > 80% 持續5分鐘 | 30秒 |
| **網絡錯誤率** | 錯誤包與丟包率 | > 1% | 1分鐘 |
| **TCP 連接數** | 活躍 TCP 連接數量 | > 10000 | 30秒 |
| **網絡延遲** | 網絡往返延遲 | > 100ms | 10秒 |
#### 2.2.2 端口監控
| 端口 | 服務 | 監控內容 | 告警條件 |
|------|------|----------|----------|
| **3002** | Momentry API | 端口監聽、響應時間 | 端口關閉、響應>1秒 |
| **3003** | Playground | 端口監聽、可用性 | 端口關閉、無法訪問 |
| **5432** | PostgreSQL | 連接數、查詢延遲 | 連接失敗、查詢>500ms |
| **6379** | Redis | 內存使用、命中率 | 內存>90%、命中率<80% |
| **6333** | Qdrant | 向量搜索延遲 | 搜索>100ms |
### 2.3 應用監控
#### 2.3.1 API 監控
| 端點 | 監控指標 | 告警閾值 | SLO 目標 |
|------|----------|----------|----------|
| `GET /api/health` | 響應時間、狀態碼 | 響應>200ms、非200狀態 | 99.9% 可用性 |
| `POST /api/videos/register` | 處理時間、成功率 | 處理>5分鐘、成功率<95% | 95% 成功率 |
| `GET /api/search` | 響應時間、召回率 | 響應>2秒、召回率<85% | P95 < 1.5秒 |
| `GET /api/chunks/{id}` | 緩存命中率、延遲 | 命中率<70%、延遲>500ms | 80% 緩存命中 |
#### 2.3.2 處理器監控
| 處理器 | 監控指標 | 告警閾值 | 恢復策略 |
|--------|----------|----------|----------|
| **ASR** | 處理時間、錯誤率 | 超時(3600s)、錯誤>10% | 重試、降級處理 |
| **OCR** | GPU 使用率、準確率 | GPU>90%、準確率<80% | 調整批量大小 |
| **CUT** | 算法複雜度、內存使用 | 內存泄漏、O(n²)增長 | 優化算法 |
| **YOLO** | 推理時間、檢測準確率 | 推理>100ms/幀、準確率下降 | 模型優化 |
---
## 3. 監控工具棧
### 3.1 監控系統架構
```
數據收集層
├── Prometheus (指標收集)
├── Fluentd (日誌收集)
├── OpenTelemetry (追蹤數據)
└── Filebeat (文件日誌)
數據存儲層
├── Prometheus TSDB (指標存儲)
├── Elasticsearch (日誌存儲)
├── Jaeger (追蹤存儲)
└── InfluxDB (時序數據)
可視化層
├── Grafana (儀表板)
├── Kibana (日誌分析)
└── Jaeger UI (追蹤可視化)
告警層
├── Alertmanager (告警管理)
├── PagerDuty (值班管理)
└── Slack/Email (通知渠道)
```
### 3.2 監控工具配置
#### 3.2.1 Prometheus 配置
```yaml
# prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'momentry-api'
static_configs:
- targets: ['localhost:3002']
labels:
service: 'momentry-api'
environment: 'production'
- job_name: 'postgresql'
static_configs:
- targets: ['localhost:9187'] # postgres_exporter
labels:
service: 'postgresql'
- job_name: 'redis'
static_configs:
- targets: ['localhost:9121'] # redis_exporter
labels:
service: 'redis'
- job_name: 'node'
static_configs:
- targets: ['localhost:9100'] # node_exporter
labels:
service: 'node'
```
#### 3.2.2 Grafana 儀表板
| 儀表板 | 用途 | 關鍵面板 |
|--------|------|----------|
| **系統概覽** | 整體系統健康 | CPU/記憶體/磁碟使用率 |
| **API 監控** | API 效能監控 | 響應時間、錯誤率、QPS |
| **數據庫監控** | 數據庫效能 | 查詢延遲、連接數、鎖等待 |
| **處理器監控** | 視頻處理監控 | 處理時間、隊列長度、錯誤率 |
| **業務監控** | 業務指標 | 註冊數、搜索數、用戶活躍度 |
---
## 4. 日誌管理
### 4.1 日誌分級與格式
#### 4.1.1 日誌級別
| 級別 | 描述 | 使用場景 |
|------|------|----------|
| **ERROR** | 錯誤,需要立即處理 | 系統崩潰、數據丟失 |
| **WARN** | 警告,需要注意 | 效能下降、配置問題 |
| **INFO** | 信息,正常操作 | 用戶操作、系統狀態 |
| **DEBUG** | 調試,開發使用 | 詳細調試信息 |
| **TRACE** | 追蹤,詳細追蹤 | 性能分析、調試 |
#### 4.1.2 日誌格式規範
```json
{
"timestamp": "2026-04-22T10:30:00Z",
"level": "INFO",
"service": "momentry-api",
"module": "video_processor",
"message": "Video processing completed",
"video_id": "video_123",
"duration_ms": 12345,
"user_id": "user_456",
"request_id": "req_789",
"correlation_id": "corr_abc"
}
```
### 4.2 日誌收集與分析
#### 4.2.1 日誌收集配置
```yaml
# fluentd 配置
<source>
@type tail
path /var/log/momentry/*.log
tag momentry.*
format json
</source>
<filter momentry.**>
@type record_transformer
<record>
hostname ${hostname}
environment production
</record>
</filter>
<match momentry.**>
@type elasticsearch
host elasticsearch.local
port 9200
logstash_format true
</match>
```
#### 4.2.2 日誌分析用例
| 分析場景 | 查詢語句 | 告警條件 |
|----------|----------|----------|
| **錯誤率分析** | `level:ERROR | stats count by service` | 錯誤數 > 10/分鐘 |
| **效能分析** | `message: /processing.*duration_ms/ | stats avg(duration_ms)` | 平均處理時間 > 警告閾值 |
| **用戶行為** | `message: /user.*action/ | stats count by user_id,action` | 異常行為模式 |
| **安全審計** | `message: /(login|auth|access)/ | search suspicious_pattern` | 登錄失敗 > 5次 |
---
## 5. 告警管理
### 5.1 告警策略
#### 5.1.1 告警級別
| 級別 | 響應時間 | 通知方式 | 處理流程 |
|------|----------|----------|----------|
| **P0 - 緊急** | 立即 | 電話、短信、推送 | 立即處理,全員通知 |
| **P1 - 高** | 15分鐘 | Slack、Email | 值班工程師處理 |
| **P2 - 中** | 1小時 | Email、儀表板 | 工作日處理 |
| **P3 - 低** | 24小時 | 儀表板 | 計劃性處理 |
#### 5.1.2 告警規則示例
```yaml
# alertmanager 配置
groups:
- name: momentry-critical
rules:
- alert: APIDown
expr: up{job="momentry-api"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "API service is down"
description: "{{ $labels.instance }} has been down for more than 1 minute"
- alert: HighCPUUsage
expr: rate(process_cpu_seconds_total[5m]) * 100 > 80
for: 5m
labels:
severity: warning
annotations:
summary: "High CPU usage detected"
description: "CPU usage is above 80% for 5 minutes"
```
### 5.2 值班管理
#### 5.2.1 值班排班
| 時段 | 值班人員 | 聯繫方式 | 覆蓋範圍 |
|------|----------|----------|----------|
| **工作日 9:00-18:00** | 開發團隊 | Slack、內部電話 | P0-P2 告警 |
| **工作日 18:00-9:00** | 值班工程師 | 手機、短信 | P0-P1 告警 |
| **週末/節假日** | 輪值工程師 | 手機、緊急電話 | P0 告警 |
#### 5.2.2 告警升級流程
```
檢測到告警 → 初始響應
評估嚴重程度
P0/P1: 立即通知值班人員
P2/P3: 記錄到工單系統
開始處理
問題解決
撰寫事後報告
改進預防措施
```
---
## 6. 監控最佳實踐
### 6.1 監控設計原則
1. **關鍵指標優先**:監控最重要的業務指標
2. **分層監控**:從基礎設施到應用層全面監控
3. **自動化監控**:自動發現、配置、告警
4. **可視化優先**:儀表板清晰展示關鍵信息
5. **告警有效性**:避免告警疲勞,確保告警有意義
### 6.2 效能優化建議
1. **指標採樣**:合理設置採樣頻率,平衡精度與成本
2. **日誌輪轉**:自動清理舊日誌,控制儲存成本
3. **查詢優化**:使用索引、聚合優化監控告警
4. **儲存分層**:熱數據快速訪問,冷數據歸檔存儲
### 6.3 成本控制策略
1. **監控成本分析**:定期分析監控系統成本
2. **資源優化**:根據使用模式調整資源配置
3. **數據保留策略**:設置合理的數據保留期限
4. **雲服務優化**:選擇合適的雲監控服務方案
---
## 7. 未來發展方向
### 7.1 近期改進(1-3個月)
1. **AI 異常檢測**:使用機器學習檢測異常模式
2. **預測性監控**:基於歷史數據預測潛在問題
3. **自動化修復**:簡單問題自動修復機制
### 7.2 中期規劃(3-6個月)
1. **跨區域監控**:支持多區域部署監控
2. **多租戶監控**:為不同客戶提供隔離監控
3. **移動監控**:移動端監控應用
### 7.3 長期願景(6-12個月)
1. **智能運維**AI 驅動的智能運維平台
2. **業務影響分析**:監控事件對業務影響分析
3. **自動擴展預測**:基於監控數據的自動擴展
---
## 8. 總結
Momentry Core 的監控架構設計提供:
1. **全面覆蓋**:從基礎設施到應用層的完整監控
2. **實時響應**:快速檢測問題並通知相關人員
3. **數據驅動**:基於數據的決策與優化
4. **持續改進**:不斷優化監控策略與工具
通過完善的監控體系,確保系統穩定運行,快速發現並解決問題,為用戶提供高質量的服務。
@@ -0,0 +1,192 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "監控系統實戰部署指南"
date: "2026-04-25"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "監控系統實戰部署指南"
ai_query_hints:
- "查詢 監控系統實戰部署指南 的內容"
- "監控系統實戰部署指南 的主要目的是什麼?"
- "如何操作或實施 監控系統實戰部署指南?"
---
# 監控系統實戰部署指南
## 1. 快速部署方案
### 1.1 Docker Compose 部署
創建 `docker-compose.monitoring.yml`
```yaml
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
container_name: momentry_prometheus
restart: unless-stopped
volumes:
- ./monitoring/prometheus:/etc/prometheus
ports:
- "9090:9090"
networks:
- monitoring
grafana:
image: grafana/grafana:latest
container_name: momentry_grafana
restart: unless-stopped
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- ./monitoring/grafana:/var/lib/grafana
ports:
- "3000:3000"
networks:
- monitoring
depends_on:
- prometheus
networks:
monitoring:
driver: bridge
```
### 1.2 創建配置文件
```bash
mkdir -p monitoring/prometheus
cat > monitoring/prometheus/prometheus.yml << 'EOF'
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'momentry-api'
static_configs:
- targets: ['host.docker.internal:3002']
metrics_path: '/metrics'
scrape_interval: 30s
EOF
```
### 1.3 啟動監控系統
```bash
docker-compose -f docker-compose.monitoring.yml up -d
```
**訪問地址**
- **Grafana**: http://localhost:3000 (帳號: admin, 密碼: admin)
- **Prometheus**: http://localhost:9090
---
## 2. Momentry Core 指標集成
### 2.1 添加 Prometheus 依賴
`Cargo.toml` 中添加:
```toml
[dependencies]
prometheus = "0.13"
```
### 2.2 創建指標模塊
創建 `src/core/metrics/mod.rs`
```rust
use prometheus::{self, Encoder, TextEncoder, Gauge, Counter, Registry};
lazy_static::lazy_static! {
pub static ref API_REQUESTS_TOTAL: Counter = register_counter!(
"momentry_api_requests_total",
"API 請求總數"
).unwrap();
pub static ref ACTIVE_CONNECTIONS: Gauge = register_gauge!(
"momentry_active_connections",
"活躍連接數"
).unwrap();
}
pub static REGISTRY: Lazy<Registry> = Lazy::new(|| {
let registry = Registry::new();
registry.register(Box::new(API_REQUESTS_TOTAL.clone())).unwrap();
registry.register(Box::new(ACTIVE_CONNECTIONS.clone())).unwrap();
registry
});
pub fn gather_metrics() -> String {
let metric_families = REGISTRY.gather();
let encoder = TextEncoder::new();
let mut buffer = vec![];
encoder.encode(&metric_families, &mut buffer).unwrap();
String::from_utf8(buffer).unwrap()
}
```
### 2.3 添加 API 指標端點
在 API 路由中添加:
```rust
use axum::{Router, routing::get, response::IntoResponse};
use crate::core::metrics;
pub fn metrics_routes() -> Router {
Router::new().route("/metrics", get(metrics_handler))
}
async fn metrics_handler() -> impl IntoResponse {
(
[(axum::http::header::CONTENT_TYPE, "text/plain; version=0.0.4")],
metrics::gather_metrics(),
)
}
```
---
## 3. 生產部署建議
### 3.1 安全配置
1. **更改默認密碼**
```bash
# 更改 Grafana 管理員密碼
docker exec momentry_grafana grafana-cli admin reset-admin-password newpassword
```
2. **啟用 HTTPS**
```yaml
grafana:
environment:
- GF_SERVER_PROTOCOL=https
```
### 3.2 監控項目
| 監控項目 | 指標名稱 | 告警閾值 |
|----------|----------|----------|
| API 請求數 | `momentry_api_requests_total` | N/A |
| 活躍連接數 | `momentry_active_connections` | >100 |
| 錯誤率 | `momentry_api_errors_total` | >10% |
| 響應時間 | `momentry_api_response_time` | >1s |
---
**最後更新**: 2026-04-22
**部署時間**: 10-30 分鐘
@@ -0,0 +1,381 @@
# Momentry Core 多模態語義搜尋設計文檔 V5.0 (全集)
**更新日期**: 2026-04-10
**版本**: V5.0 (Final Integration)
**狀態**: 設計完成,準備實作
---
## 1. 系統架構總覽
```mermaid
graph TD
%% 樣式定義
classDef storage fill:#e1f5fe,stroke:#01579b,stroke-width:2px;
classDef processor fill:#fff3e0,stroke:#e65100,stroke-width:2px;
classDef identity fill:#e8f5e9,stroke:#1b5e20,stroke-width:2px;
classDef search fill:#f3e5f5,stroke:#4a148c,stroke-width:2px;
subgraph "1. Input Sources (輸入源)"
Video[Video/Audio File]
end
subgraph "2. Analysis Processors (分析模組 - 模組化)"
ASR[ASR Processor\n(Whisper)]:::processor
ASRX[ASRX Processor\n(SpeechBrain)]:::processor
YOLO[YOLO Processor\n(Object Detection)]:::processor
OCR[OCR Processor\n(Text Recognition)]:::processor
FACE[Face Processor\n(Face ID/Cluster)]:::processor
POSE[Pose Processor\n(KeyPoints 33)]:::processor
SCENE[Scene Processor\n(Places365)]:::processor
AUDIO[AUDIO EVENT Processor\n(PANNs/YAMNet)]:::processor
POSE_ANALYZER[Pose Analyzer Processor\n(Action/Gesture/Sports)]:::processor
CONTEXT[Context Inference Processor\n(Rule Engine + LLM)]:::processor
SPORTS[Sports Classifier Processor\n(Rule Engine)]:::processor
end
subgraph "3. Identity & Binding (身份與綁定)"
VoiceBind[Voice Binding\n(Speaker -> Talent)]:::identity
FaceBind[Face Binding\n(Face -> Talent)]:::identity
RoleBind[Role Casting\n(Talent -> Character)]:::identity
TalentDB[(Talents DB\nVoice/Face Embeddings)]:::storage
CharDB[(Characters DB\nRoles/Multi-lang)]:::storage
end
subgraph "4. Data Storage (數據存儲)"
PG[(PostgreSQL\nChunks/Relations/Metadata)]:::storage
Qdrant[(Qdrant\nVector Search Engine)]:::storage
end
subgraph "5. Search & Query (搜尋與查詢)"
SearchProc[Search Processor\n(LLM Parser -> Hybrid Query)]:::search
User[User / API]
end
%% 數據流向
Video --> ASR
Video --> ASRX
Video --> YOLO
Video --> OCR
Video --> FACE
Video --> POSE
Video --> SCENE
Video --> AUDIO
%% 處理結果 -> 特徵提取/分析
POSE --> POSE_ANALYZER
POSE --> SPORTS
AUDIO --> AUDIO
SCENE --> CONTEXT
YOLO --> CONTEXT
YOLO --> SPORTS
ASRX --> CONTEXT
ASR --> CONTEXT
POSE_ANALYZER --> SPORTS
%% 結果寫入
ASR --> PG
ASRX --> PG
YOLO --> PG
OCR --> PG
FACE --> PG
SCENE --> PG
AUDIO --> PG
POSE_ANALYZER --> PG
CONTEXT --> PG
SPORTS --> PG
%% 綁定邏輯
ASRX -.->|Speaker ID| VoiceBind
FACE -.->|Face ID| FaceBind
VoiceBind --> TalentDB
FaceBind --> TalentDB
TalentDB --> RoleBind
CharDB --> RoleBind
RoleBind -.->|Resolve Names| PG
%% 向量同步
PG -.->|Sync Payload & Vectors| Qdrant
%% 搜尋邏輯
User --> SearchProc
SearchProc --> PG
SearchProc --> Qdrant
```
---
## 2. 核心處理模組清單 (Processor Modules)
每個模組遵循單一職責原則 (Single Responsibility Principle)。
| 模組名稱 | 職責 (Responsibility) | 核心技術/模型 | 輸出維度 (Dimension) |
|:---|:---|:---|:---|
| **ASR** | 語音轉文字 | Whisper (small/int8 + VAD) | **Text Content** (語音內容) |
| **ASRX** | 說話人分離/聲紋提取 | SpeechBrain (ECAPA-TDNN) | **Voice ID**, **Speaker Embedding** (192-dim) |
| **YOLO** | 物體檢測 | YOLOv8 (COCO 80 classes) | **Object** (車輛、武器、物品、運動裝備) |
| **OCR** | 畫面文字識別 | EasyOCR / PaddleOCR | **Text** (字幕、招牌、文件) |
| **FACE** | 人臉檢測與聚類 | RetinaFace / ArcFace | **Face ID**, **Face Embedding** |
| **POSE** | 骨架關鍵點提取 | MediaPipe / YOLO-Pose | **Keypoints** (33 點坐標) |
| **POSE ANALYZER** | 動作/手勢解碼 | Heuristics (規則引擎) | **Action** (站/坐/臥/揮手/打鬥/泳姿/旋轉) |
| **SCENE** | 場景分類 | Places365 (ResNet18) | **Location** (Macro/Semantic/Raw 三層級) |
| **AUDIO EVENT** | 環境/特效音識別 | PANNs / YAMNet | **Audio Event** (槍聲/雨聲/狗叫/樂器/哨音) |
| **CONTEXT INFERENCE** | 環境/氛圍推論 | Rule Engine + LLM | **Context** (季節/溫度/節慶/天氣) |
| **SPORTS CLASSIFIER** | 運動項目識別 | Multi-Modal Rule Engine | **Sport Type** (棒球/足球/游泳/跳水/滑冰...) |
---
## 3. 數據架構設計 (Data Architecture)
### 3.1 Chunk 定義 (Video Chunk)
**定義**: 特定視頻文件 (`uuid`) 內,從 `start_frame``end_frame` 之間的**連續畫面**。
**存儲**:
* **PostgreSQL**: 權威主數據 (Metadata, Relations, Complex Queries).
* **Qdrant**: 向量檢索與 Payload 過濾 (Fast Retrieval).
### 3.2 數據庫 Schema (PostgreSQL)
```sql
-- ==========================================
-- 1. 核心 Chunk 表
-- ==========================================
CREATE TABLE chunks (
id BIGSERIAL PRIMARY KEY,
uuid VARCHAR(32) NOT NULL, -- 視頻 ID
chunk_id VARCHAR(64) NOT NULL,
-- 物理邊界定義 (核心)
start_frame BIGINT NOT NULL,
end_frame BIGINT NOT NULL,
fps FLOAT8 NOT NULL,
duration_sec FLOAT8 GENERATED ALWAYS AS ((end_frame - start_frame) / fps) STORED,
-- 2. 人 (Who)
speaker_ids TEXT[] DEFAULT '{}', -- 觀察到的說話人 ID (Speaker X)
face_ids TEXT[] DEFAULT '{}', -- 觀察到的人臉 ID (Face Y)
-- 3. 事 (What) - 語音與行為
text_content TEXT, -- ASR 文本
action_tags TEXT[] DEFAULT '{}', -- Pose 動作 (e.g. ['running', 'fighting', 'swimming'])
audio_events TEXT[] DEFAULT '{}', -- 音頻事件 (e.g. ['gunshot', 'scream', 'whistle'])
event_tags JSONB DEFAULT '[]', -- 融合事件 (e.g. [{"tag":"gunfight", "score":0.8}])
sport_type VARCHAR(32), -- 運動項目 (e.g. 'baseball', 'diving')
sport_actions TEXT[] DEFAULT '{}', -- 運動細分動作 (e.g. ['pitching', 'smash'])
sport_sequence JSONB DEFAULT '[]', -- 動作序列 (e.g. ["takeoff", "twist", "entry"])
-- 4. 地 (Where) & 物 (Object)
scene_raw TEXT[] DEFAULT '{}', -- Places365 原始標籤
scene_semantic TEXT[] DEFAULT '{}', -- 高層語義 (e.g. ['office', 'indoor'])
object_tags TEXT[] DEFAULT '{}', -- YOLO 物件 (e.g. ['car', 'gun', 'baseball_bat'])
-- 5. 上下文 (Context)
context_season VARCHAR(16), -- 'winter', 'summer'
context_temp VARCHAR(16), -- 'hot', 'cold'
context_weather VARCHAR(16), -- 'rainy', 'snowy'
context_festivals TEXT[] DEFAULT '{}', -- ['christmas', 'halloween']
-- 向量與索引
vector_ids JSONB, -- 指向 Qdrant Point ID
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(chunk_id),
UNIQUE(uuid, chunk_id)
);
CREATE INDEX idx_chunks_uuid ON chunks(uuid);
CREATE INDEX idx_chunks_frame_range ON chunks(uuid, start_frame, end_frame);
CREATE INDEX idx_chunks_attrs ON chunks USING GIN (scene_semantic, object_tags, audio_events);
-- ==========================================
-- 6. 身份綁定表 (Identity Binding)
-- ==========================================
-- 真實人才庫 (Talent)
CREATE TABLE talents (
id BIGSERIAL PRIMARY KEY,
real_name TEXT,
voice_embedding VECTOR(192), -- 聲紋參考向量 (ECAPA-TDNN)
face_embedding VECTOR(512) -- 人臉參考向量 (ArcFace)
);
-- 劇中角色庫 (Character)
CREATE TABLE characters (
id BIGSERIAL PRIMARY KEY,
video_uuid TEXT NOT NULL,
name TEXT NOT NULL, -- 角色名
language_track TEXT DEFAULT 'original', -- 語言軌道 (dub_zh_tw, dub_en)
is_voice_only BOOLEAN DEFAULT FALSE, -- 無臉角色 (動畫/旁白/AI)
metadata JSONB DEFAULT '{}'
);
-- 飾演關係 (Casting)
CREATE TABLE castings (
talent_id BIGINT REFERENCES talents(id),
character_id BIGINT REFERENCES characters(id),
track_type TEXT DEFAULT 'original',
PRIMARY KEY (talent_id, character_id, track_type)
);
-- 綁定映射 (Signal -> Talent)
CREATE TABLE identity_bindings (
binding_type VARCHAR(32), -- 'face', 'speaker'
binding_value VARCHAR(64), -- 機器 ID (e.g. 'face_1', 'speaker_3')
talent_id BIGINT REFERENCES talents(id),
UNIQUE(binding_type, binding_value)
);
```
### 3.3 Qdrant Payload 結構 (扁平化過濾)
```json
{
"uuid": "384b0ff44aaaa1f1",
"chunk_id": "chunk_001",
"start_frame": 100,
"end_frame": 200,
"who_is_present": ["Alice", "Bob"],
"who_is_speaking": ["Alice"],
"what_happening": ["arguing", "shouting"],
"what_objects": ["person", "table"],
"what_audio": ["raised_voice"],
"sport_type": null,
"where_semantic": ["office", "indoor"],
"where_weather": null,
"context_season": null,
"context_time": "day"
}
```
---
## 4. 搜尋維度 (5W1H + Context + Sports)
### 4.1 人 (Person / Who)
* **身份解析**: `speaker_X` / `face_Y` -> `talent` -> `character`.
* **屬性過濾**: 性別、年齡、體型、五官、服裝 (VLM/Heuristics).
* **聲紋檢索**: 上傳音頻片段 -> Cosine Similarity (ECAPA-TDNN 192-dim).
### 4.2 事 (Event / What)
* **語音語義**: ASR 文本向量檢索.
* **視覺行為**: Pose Analyzer 標籤 (打架、擁抱、揮手).
* **融合事件**: `gunfight`, `romantic_scene`, `interview` (多信號規則融合).
### 4.3 時 (Time / When)
* **精確幀**: `start_frame`, `end_frame`.
* **相對時間**: "最後 5 分鐘".
### 4.4 地 (Location / Where)
* **場景語義**: Places365 -> 宏觀/語義/原始三層映射 (e.g., `beach` -> `outdoor`).
* **天氣/環境**: `rainy`, `sunny`, `night` (Context Inference).
### 4.5 物 (Object / Which)
* **YOLO 物件**: `car`, `gun`, `dog`.
* **音頻物件**: `siren`, `barking`.
### 4.6 上下文 (Context)
* **季節**: `winter` (雪/圍巾), `summer` (泳衣/太陽眼鏡).
* **節慶**: `christmas` (聖誕樹/鈴鐺聲), `cny` (鞭炮/紅燈籠).
### 4.7 運動 (Sports)
* **球類**: 棒球 (球棒/打擊聲/揮棒), 籃球 (運球聲/投籃), 足球 (哨音/踢球).
* **水上/冰上運動 (詳細特徵)**:
* **🏊 游泳 (Swimming)**:
* *場景*: `swimming_pool`, `water`.
* *物件*: `goggles`, `swim_cap`, `lane_rope`.
* *動作*: `freestyle_stroke` (自由式), `breaststroke` (蛙式), `butterfly` (蝶式), `backstroke` (仰式).
* *音頻*: `water_splash` (水花聲), `rhythmic_breathing` (規律換氣聲).
* **🤿 跳水 (Diving)**:
* *場景*: `diving_board`, `platform_10m`.
* *動作序列*: `takeoff` (起跳) → `aerial_twist` (空中翻轉) → `entry` (入水).
* *音頻*: `high_pitch_whistle` (哨音) → `massive_splash` (巨大入水聲).
* **⛸️ 滑冰 (Ice Skating)**:
* *場景*: `ice_rink`, `winter`.
* *物件*: `ice_skates`, `barrier`.
* *動作*: `gliding` (滑行), `spinning` (旋轉), `jumping` (跳躍).
* *音頻*: `blade_on_ice` (冰刀摩擦聲), `classical_music` (花滑配樂).
---
## 5. 搜尋執行流程 (Search Workflow)
### 5.1 用戶輸入
> *"找一下昨天在辦公室,那個穿西裝的男人在生氣地罵人,旁邊還有狗叫的片段。"*
### 5.2 LLM 解析 (`Search Processor`)
```json
{
"who": {
"clothing": ["suit"],
"expression": ["angry"],
"gender": "male"
},
"where": {
"semantic": ["office"]
},
"what": {
"action": ["arguing", "shouting"],
"audio_event": ["dog_bark"]
},
"when": {
"relative": "yesterday"
}
}
```
### 5.3 混合查詢 (Hybrid Query)
1. **解析身份 (Who)**:
* 查詢 `identity_bindings`,找到符合 "穿西裝男人" 的機器 ID (`face_5`).
2. **構建 SQL (PostgreSQL)**:
```sql
SELECT chunk_id, start_frame, end_frame FROM chunks
WHERE uuid = '384b0ff44aaaa1f1'
AND 'face_5' = ANY(face_ids)
AND scene_semantic @> ARRAY['office']
AND action_tags @> ARRAY['arguing', 'shouting']
AND audio_events @> ARRAY['dog_bark'];
```
3. **構建 Vector Search (Qdrant)**:
* 如果 SQL 結果為空或用戶語意模糊,切換至 Qdrant Payload Filter + Vector Similarity.
4. **返回結果**:
* Chunk 列表,包含精確的 `start_frame`, `end_frame`.
---
## 6. 實施路線圖 (Implementation Roadmap)
### Phase 1: 基礎設施與 Schema (第 1 週)
- [ ] 執行 PostgreSQL Schema V5 更新 (Chunks, Talents, Castings, Bindings, Sports).
- [ ] 建立 Qdrant Collection (`momentry_chunks`),配置 Multi-Vector 和 Payload 索引.
- [ ] 編寫 `scene_hierarchy_processor.py` (場景映射層).
- [ ] 編寫 `scene_mapping.json`.
### Phase 2: 信號提取模組 (第 2-3 週)
- [ ] 部署 `audio_event_processor.py` (PANNs/YAMNet).
- [ ] 部署 `pose_analyzer_processor.py` (基礎規則:站/坐/揮手/打鬥/泳姿).
- [ ] 部署 `context_inference_processor.py` (季節/節慶/天氣推斷).
- [ ] 部署 `sports_classifier_processor.py` (運動分類規則引擎).
- [ ] 確保所有處理器的輸出能正確映射並寫入 `chunks` 表.
### Phase 3: 身份綁定系統 (第 4 週)
- [ ] 部署 `voice_embedding_extractor.py` (聲紋提取與比對).
- [ ] 實現 `identity_resolver.py`:將機器 ID 綁定到 `talents` 和 `characters`.
- [ ] 提供 API: `POST /api/v1/person/bind`.
### Phase 4: 搜尋引擎整合 (第 5 週)
- [ ] 開發 `search_processor.py` (LLM Parser + SQL Builder).
- [ ] 實現 `POST /api/v1/search/smart` 端點.
- [ ] 測試複雜查詢 (人+事+時+地+物+上下文+運動).
### Phase 5: 優化與前端對接 (第 6 週)
- [ ] 性能優化 (索引調整、查詢緩存).
- [ ] 前端搜尋介面展示多維度過濾條件.
- [ ] 前端視頻播放器跳轉至精確 `start_frame`.
---
此設計文檔已涵蓋所有需求,確立了 Momentry Core 作為一個**高度模組化、多模態、支持深度語義搜尋**的系統架構。所有討論過的維度 (包括運動、配音、動畫、聲紋) 均已整合。
+709
View File
@@ -0,0 +1,709 @@
---
document_type: "architecture_design"
service: "N8N"
title: "n8n Video RAG Workflow - Node 設計"
date: "2026-03-22"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "workflow"
- "video"
- "node"
ai_query_hints:
- "查詢 n8n Video RAG Workflow - Node 設計 的內容"
- "n8n Video RAG Workflow - Node 設計 的主要目的是什麼?"
- "如何操作或實施 n8n Video RAG Workflow - Node 設計?"
---
# n8n Video RAG Workflow - Node 設計
| 項目 | 內容 |
|------|------|
| 建立者 | Warren |
| 建立時間 | 2026-03-22 |
| 文件版本 | V1.1 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-03-22 | 創建文件 | Warren | OpenCode / MiniMax M2.5 |
| V1.1 | 2026-03-25 | 更新API回應格式 (media_url→file_path) 與認證標頭 | OpenCode | deepseek-reasoner |
---
## 完整 Workflow 架構
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ n8n Workflow: Video RAG Demo │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Phase 1: SFTPGo 準備 (全部在 n8n Node 內執行) │ │
│ │ │ │
│ │ ① Webhook Trigger │ │
│ │ ↓ │ │
│ │ ② Set Variables (解析 file_name, query) │ │
│ │ ↓ │ │
│ │ ③ Get SFTPGo Token │ │
│ │ ↓ │ │
│ │ ④ Upload to SFTPGo │ │
│ │ ↓ │ │
│ │ ⑤ Create Share Link │ │
│ │ ↓ │ │
│ │ ⑥ Verify Upload (List Files + List Shares) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Phase 2: Momentry 註冊 (只處理 ASR, ASRX, STORY) │ │
│ │ │ │
│ │ ⑦ Register Video (modules=asr,asrx,story) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Phase 3: Progress Loop (n8n Logs 記錄) │ │
│ │ │ │
│ │ ⑧ Wait 10s ─────────────────────────────────────────────────┐ │ │
│ │ ↓ │ │
│ │ ⑨ Check Progress (API) │ │
│ │ ↓ │ │
│ │ ⑩ Log Progress (Code Node → n8n Logs) │ │
│ │ ↓ │ │
│ │ ⑪ Is Complete? (IF) │ │
│ │ │ │ │
│ │ ├── NO ──────────────────────────────── Loop Back ─────────┘ │ │
│ │ └── YES ────────────────────────────────────────────── Exit ──┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Phase 4: 搜尋與回應 │ │
│ │ │ │
│ │ ⑫ Hybrid Search (Vector + BM25) │ │
│ │ ↓ │ │
│ │ ⑬ Build Response │ │
│ │ ↓ │ │
│ │ ⑭ Respond to Webhook │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 模組說明
| 模組 | 用途 | 輸出 |
|------|------|------|
| `asr` | 語音轉文字 (Whisper) | 字幕/文字稿 |
| `asrx` | 說話者分離 (WhisperX) | 誰在什麼時候說什麼 |
| `story` | 故事線生成 (Parent-Child Chunks) | 敘事結構 + 父子區塊關聯 |
**注意**: 只處理語音和故事相關模組,跳過 YOLO、OCR、Face、Pose 等視覺分析。
┌─────────────────────────────────────────────────────────────────────────────┐
│ n8n Workflow: Video RAG Demo │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Phase 1: SFTPGo 準備 (全部在 n8n Node 內執行) │ │
│ │ │ │
│ │ ① Webhook Trigger │ │
│ │ ↓ │ │
│ │ ② Set Variables (解析 file_name, query) │ │
│ │ ↓ │ │
│ │ ③ Get SFTPGo Token │ │
│ │ ↓ │ │
│ │ ④ Upload to SFTPGo │ │
│ │ ↓ │ │
│ │ ⑤ Create Share Link │ │
│ │ ↓ │ │
│ │ ⑥ Verify Upload (List Files + List Shares) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Phase 2: Momentry 註冊 │ │
│ │ │ │
│ │ ⑦ Register Video │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Phase 3: Progress Loop (n8n Logs 記錄) │ │
│ │ │ │
│ │ ⑧ Wait 10s ─────────────────────────────────────────────────┐ │ │
│ │ ↓ │ │ │
│ │ ⑨ Check Progress (API) │ │ │
│ │ ↓ │ │ │
│ │ ⑩ Log Progress (Code Node → n8n Logs) │ │ │
│ │ ↓ │ │ │
│ │ ⑪ Is Complete? (IF) │ │ │
│ │ │ │ │ │
│ │ ├── NO ──────────────────────────────── Loop Back ─────────┘ │ │
│ │ └── YES ────────────────────────────────────────────── Exit ──┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Phase 4: 搜尋與回應 │ │
│ │ │ │
│ │ ⑫ Natural Language Search │ │
│ │ ↓ │ │
│ │ ⑬ Get File Path (含 file_path) │ │
│ │ ↓ │ │
│ │ ⑭ Build Response │ │
│ │ ↓ │ │
│ │ ⑮ Respond to Webhook │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
---
## Node 詳細配置
### Node ①: Webhook Trigger (觸發器)
```yaml
Node Name: "Webhook Trigger"
Node Type: "Webhook"
Configuration:
HTTP Method: POST
Path: "video-rag"
Response Mode: "Response Node"
Response Node: "Respond to Webhook"
Input JSON Example:
{
"file_name": "Old_Time_Movie_Show_-_Charade_1963.HD.mov",
"query": "What is the movie about?"
}
```
---
### Node ②: Set Variables (變數設定)
```yaml
Node Name: "Set Variables"
Node Type: "Set"
Configuration:
Keep Only Set: true
Variables:
- Name: "file_name"
Value: "{{ $json.body.file_name }}"
- Name: "query"
Value: "{{ $json.body.query }}"
- Name: "sftpgo_path"
Value: "/{{ $json.body.file_name }}"
- Name: "register_path"
Value: "/Users/accusys/sftpgo_test/demo/{{ $json.body.file_name }}"
```
---
### Node ③: Get SFTPGo Token (取得權杖)
```yaml
Node Name: "Get SFTPGo Token"
Node Type: "HTTP Request"
Configuration:
Method: GET
URL: "http://localhost:8080/api/v2/user/token"
Authentication: "Basic Auth"
User: "demo"
Password: "demopassword123"
Output:
{
"access_token": "eyJhbGci...",
"expires_at": "2026-03-22T07:00:00Z"
}
```
---
### Node ④: Upload to SFTPGo (上傳檔案)
```yaml
Node Name: "Upload to SFTPGo"
Node Type: "HTTP Request"
Configuration:
Method: POST
URL: "http://localhost:8080/api/v2/user/files"
Authentication: "Bearer Token"
Bearer Token: "{{ $json.access_token }}"
Body Content Type: "Form-Data Multipart"
Body:
path: /demo
mkdir_parents: true
filenames: @{{ $json.file_name }}
Output:
{"message":"Upload completed"}
```
**檔案來源選項:**
1. **Webhook 接收**: 從 Webhook 的 binary data 取得
2. **固定路徑**: 指定本地檔案路徑
3. **URL 下載**: 先下載遠端檔案再上傳
---
### Node ⑤: Create Share Link (建立分享連結)
```yaml
Node Name: "Create Share Link"
Node Type: "HTTP Request"
Configuration:
Method: POST
URL: "http://localhost:8080/api/v2/user/shares"
Authentication: "Bearer Token"
Bearer Token: "{{ $json.access_token }}"
Body Content Type: "JSON"
Body:
{
"name": "{{ $json.file_name }}_share",
"paths": ["/{{ $json.file_name }}"],
"scope": 1,
"expires_at": 0
}
Output:
{
"id": "CjmQfrkXY5qDtC46WVZY2S",
"name": "Charade_share"
}
```
---
### Node ⑥: Verify Upload (驗證上傳)
```yaml
Node Name: "Verify Upload - List Shares"
Node Type: "HTTP Request"
Configuration:
Method: GET
URL: "http://localhost:8080/api/v2/user/shares"
Authentication: "Bearer Token"
Bearer Token: "{{ $json.access_token }}"
Output:
[
{
"id": "CjmQfrkXY5qDtC46WVZY2S",
"name": "Charade_share",
"paths": ["/Old_Time_Movie_Show_-_Charade_1963.HD.mov"]
}
]
```
---
### Node ⑦: Register Video (註冊影片)
**說明**: 只註冊 ASR、ASRX、STORY 模組處理
```yaml
Node Name: "Register Video"
Node Type: "HTTP Request"
Configuration:
Method: POST
URL: "http://localhost:3002/api/v1/register"
Body Content Type: "JSON"
Body:
{
"path": "{{ $json.register_path }}",
"modules": "asr,asrx,story"
}
Output:
{
"uuid": "a1b10138a6bbb0cd",
"video_id": 7,
"file_name": "Old_Time_Movie_Show_-_Charade_1963.HD.mov",
"duration": 6879.33,
"width": 1920,
"height": 1080
}
```
**可用模組**:
| 模組 | 說明 |
|------|------|
| `asr` | 語音轉文字 (Whisper) |
| `asrx` | 說話者分離 (WhisperX) |
| `story` | 故事線生成 (Parent-Child) |
| `yolo` | 物體偵測 (可選) |
| `cut` | 場景偵測 (可選) |
| `ocr` | 文字辨識 (可選) |
| `face` | 人臉偵測 (可選) |
| `pose` | 姿態估計 (可選) |
---
### Node ⑧: Wait 10 Seconds (輪詢間隔)
```yaml
Node Name: "Wait 10 Seconds"
Node Type: "Wait"
Configuration:
Amount: 10
Unit: "Seconds"
```
---
### Node ⑨: Check Progress (檢查進度)
```yaml
Node Name: "Check Progress"
Node Type: "HTTP Request"
Configuration:
Method: GET
URL: "http://localhost:3002/api/v1/progress/{{ $('Register Video').item.json.uuid }}"
Output:
{
"uuid": "a1b10138a6bbb0cd",
"processors": [
{"name": "asr", "status": "complete", "message": "1867 segments"},
{"name": "asrx", "status": "progress", "message": "ASRX_TRANSCRIBING"},
{"name": "story", "status": "pending", "message": ""}
]
}
```
> **注意**: API 現在返回 `file_path`(檔案系統路徑)而非 `media_url`(網頁 URL)。如需在網頁中播放影片,請將檔案路徑轉換為可訪問的 URL(例如透過 SFTPGo 分享連結)。
---
### Node ⑩: Log Progress (記錄進度)
```yaml
Node Name: "Log Progress"
Node Type: "Code"
Configuration:
Language: "JavaScript"
Code:
```javascript
const progress = $input.first().json;
const processors = progress.processors;
const totalProcessors = processors.length;
const completedProcessors = processors.filter(p => p.status === 'complete').length;
const overallProgress = Math.round((completedProcessors / totalProcessors) * 100);
const currentProcessor = processors.find(p =>
p.status === 'progress' || p.status === 'info'
);
const progressMessage = `
═══════════════════════════════════════════════
📹 Video RAG Processing: ${overallProgress}%
UUID: ${progress.uuid}
${processors.map(p => {
const icon = p.status === 'complete' ? '✅' :
p.status === 'progress' || p.status === 'info' ? '🔄' : '⏳';
return ` ${icon} ${p.name.padEnd(6)} ${p.message || p.status}`;
}).join('\n')}
${currentProcessor ? `Current: ${currentProcessor.name}` : 'All complete!'}
═══════════════════════════════════════════════
`.trim();
console.log(progressMessage);
return {
json: {
uuid: progress.uuid,
overall_progress: overallProgress,
completed_processors: completedProcessors,
total_processors: totalProcessors,
current_processor: currentProcessor?.name || 'idle',
processors: processors,
log_message: progressMessage
}
};
```
Output:
{
"uuid": "a1b10138a6bbb0cd",
"overall_progress": 33,
"log_message": "📹 Video RAG Processing: 33%..."
}
```
---
### Node ⑪: Is Complete? (判斷分支)
```yaml
Node Name: "Is Complete?"
Node Type: "IF"
Configuration:
Condition:
$json.processors.every(p => p.status === 'complete')
Connections:
TRUE (完成): → Node ⑫ Natural Language Search
FALSE (未完成): → Node ⑧ Wait 10 Seconds (Loop)
```
---
### Node ⑫: Natural Language Search (RAG 搜尋)
```yaml
Node Name: "Natural Language Search"
Node Type: "HTTP Request"
Configuration:
Method: POST
URL: "http://localhost:3002/api/v1/search"
Body Content Type: "JSON"
Body:
{
"query": "{{ $('Set Variables').item.json.query }}",
"limit": 10,
"uuid": "{{ $('Register Video').item.json.uuid }}"
}
Output:
{
"results": [
{
"uuid": "a1b10138a6bbb0cd",
"chunk_id": "c_001",
"text": "Hello and welcome to the old-time movie show...",
"score": 0.92
}
]
}
```
---
### Node ⑫B: Hybrid Search (Vector + BM25)
**說明**: 使用混合搜尋,結合向量相似度和全文檢索
```yaml
Node Name: "Hybrid Search"
Node Type: "HTTP Request"
Configuration:
Method: POST
URL: "http://localhost:3002/api/v1/search/hybrid"
Body Content Type: "JSON"
Body:
{
"query": "{{ $('Set Variables').item.json.query }}",
"limit": 10,
"uuid": "{{ $('Register Video').item.json.uuid }}",
"vector_weight": 0.7,
"bm25_weight": 0.3
}
Output:
{
"query": "What is the movie about?",
"results": [
{
"uuid": "a1b10138a6bbb0cd",
"chunk_id": "c_001",
"chunk_type": "sentence",
"start_time": 0.0,
"end_time": 5.0,
"text": "Hello and welcome to the old-time movie show...",
"vector_score": 0.85,
"bm25_score": 0.75,
"combined_score": 0.80
}
]
}
```
**權重建議**:
| 查詢類型 | vector_weight | bm25_weight |
|----------|---------------|-------------|
| 主題查詢 | 0.8 | 0.2 |
| 事實查找 | 0.5 | 0.5 |
| 平衡查詢 | 0.7 | 0.3 |
---
### Node ⑬: Get Media URL (取得媒體連結)
```yaml
Node Name: "Get Media URL"
Node Type: "HTTP Request"
Configuration:
Method: POST
URL: "http://localhost:3002/api/v1/n8n/search"
Body Content Type: "JSON"
Body:
{
"query": "{{ $('Set Variables').item.json.query }}",
"limit": 10,
"uuid": "{{ $('Register Video').item.json.uuid }}"
}
Output:
{
"count": 10,
"hits": [
{
"id": "c_001",
"vid": "a1b10138a6bbb0cd",
"text": "Hello and welcome to the old-time movie show...",
"score": 0.92,
"file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/video.mp4"
}
]
}
```
---
### Node ⑭: Build Response (組合結果)
```yaml
Node Name: "Build Response"
Node Type: "Set"
Configuration:
Keep Only Set: true
Variables:
- Name: "ok"
Value: true
- Name: "uuid"
Value: "{{ $('Register Video').item.json.uuid }}"
- Name: "file_name"
Value: "{{ $('Set Variables').item.json.file_name }}"
- Name: "query"
Value: "{{ $('Set Variables').item.json.query }}"
- Name: "count"
Value: "{{ $('Get Media URL').item.json.count }}"
- Name: "results"
Value: "{{ $('Get Media URL').item.json.hits }}"
- Name: "overall_progress"
Value: "{{ $('Log Progress').item.json.overall_progress }}"
```
---
### Node ⑮: Respond to Webhook (回傳結果)
```yaml
Node Name: "Respond to Webhook"
Node Type: "Respond to Webhook"
Configuration:
Respond With: "JSON"
Response Body:
{
"ok": true,
"uuid": "{{ $json.uuid }}",
"file_name": "{{ $json.file_name }}",
"query": "{{ $json.query }}",
"count": {{ $json.count }},
"results": {{ $json.results }},
"overall_progress": {{ $json.overall_progress }},
"message": "Video RAG completed successfully"
}
```
---
## 快速複製所需資訊
### SFTPGo 設定
| 項目 | 值 |
|------|-----|
| API Base | `http://localhost:8080/api/v2` |
| Demo User | `demo` |
| Demo Password | `demopassword123` |
| Demo Home | `/Users/accusys/sftpgo_test/demo` |
| Token Endpoint | `/api/v2/user/token` |
| Upload Endpoint | `/api/v2/user/files` |
| Share Endpoint | `/api/v2/user/shares` |
### Momentry 設定
| 項目 | 值 |
|------|-----|
| API Base | `http://localhost:3002` |
| Authentication | `X-API-Key` header (所有 `/api/v1/*` 端點) |
| Register | `POST /api/v1/register` |
| Progress | `GET /api/v1/progress/{uuid}` |
| Search | `POST /api/v1/search` |
| n8n Search | `POST /api/v1/n8n/search` |
| Hybrid Search | `POST /api/v1/search/hybrid` |
| Media Base | `https://wp.momentry.ddns.net` (僅供參考,API 返回 `file_path` 而非 URL) |
### Demo 測試資料
**Charade (1963) Demo Video**
- UUID: `a1b10138a6bbb0cd`
- 位置: `/Users/accusys/test_video/Old_Time_Movie_Show_-_Charade_1963.HD.mov`
- 時長: 6872 秒 (~1.9 小時)
**已處理檔案**:
| 檔案 | 大小 | 內容 |
|------|------|------|
| `asr.json` | 210KB | 1867 語音區段 |
| `cut.json` | 220KB | 1331 場景 |
| `story.json` | 1.8MB | 641 父子區塊 |
| `transcript.txt` | 40KB | 可讀文字稿 |
**Output 目錄**: `/Users/accusys/momentry_core_0.1/output`
---
## 版本歷史
| 日期 | 版本 | 變更 |
|------|------|------|
| 2026-03-22 | v1.0 | 初始建立 |
| 2026-03-22 | v1.1 | 新增 Hybrid Search (Vector + BM25) 節點 |
| 2026-03-22 | v1.2 | 簡化為只處理 ASR、ASRX、STORY 模組 |
@@ -0,0 +1,190 @@
---
document_type: "architecture_design"
service: "N8N"
title: "Momentry Video RAG MCP Workflow"
date: "2026-03-22"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "n8n"
- "workflow"
- "rag"
- "mcp"
- "video-search"
ai_query_hints:
- "N8N Video RAG MCP 工作流程是什麼?"
- "如何配置 Momentry Video RAG Webhook"
- "Video RAG MCP 的搜尋流程如何運作?"
---
# Momentry Video RAG MCP Workflow
## 工作流程資訊
- **名稱**: Momentry Video RAG MCP
- **ID**: WlVvpX2OeKK83QOK
- **Webhook Path**: `video-rag-mcp`
- **狀態**: ✅ Active (已啟動)
- **建立時間**: 2026-03-22
## 工作流程架構
```
┌─────────────────┐ ┌──────────────────────┐ ┌───────────────────┐ ┌─────────────────┐
│ Webhook │────▶│ Search Momentry │────▶│ Process RAG │────▶│ Respond to │
│ Trigger │ │ Core │ │ Results │ │ Webhook │
└─────────────────┘ └──────────────────────┘ └───────────────────┘ └─────────────────┘
│ POST http://localhost:5678/webhook/video-rag-mcp
{
"query": "搜尋關鍵字",
"limit": 5,
"uuid": "可選的影片UUID"
}
```
## Node 說明
### 1. Webhook Trigger
- **類型**: Webhook
- **Method**: POST
- **Path**: `video-rag-mcp`
- **Response Mode**: Last Node (等待最後一個節點完成後回應)
### 2. Search Momentry Core
- **類型**: HTTP Request
- **URL**: `http://localhost:3002/api/v1/n8n/search`
- **Method**: POST
- **Body**:
```json
{
"query": "搜尋關鍵字",
"limit": 5,
"uuid": "可選的影片UUID"
}
```
- **Timeout**: 30秒
### 3. Process RAG Results
- **類型**: Code (JavaScript)
- **功能**:
- 處理 Momentry Core 搜尋結果
- 格式化 hits 為結構化資料
- 建立 RAG context(用於 LLM 問答)
- 計算相關度百分比
**輸出格式**:
```json
{
"success": true,
"query": "搜尋關鍵字",
"totalFound": 5,
"context": "[1] 文本內容... (Video: 影片標題, Time: 10s-20s)\n\n[2] ...",
"results": [
{
"index": 1,
"id": "chunk_id",
"title": "影片標題",
"text": "文本內容",
"startTime": 10,
"endTime": 20,
"relevance": "85%",
"videoUuid": "uuid",
"mediaUrl": "影片URL",
"deepLink": "影片URL#t=10,20"
}
]
}
```
### 4. Respond to Webhook
- **類型**: Respond to Webhook
- **Response**: JSON 格式結果
- **Status Code**: 200
## 使用方式
### 直接呼叫 Webhook
```bash
curl -X POST http://localhost:5678/webhook/video-rag-mcp \
-H "Content-Type: application/json" \
-d '{
"query": "charade",
"limit": 5
}'
```
### 指定特定影片搜尋
```bash
curl -X POST http://localhost:5678/webhook/video-rag-mcp \
-H "Content-Type: application/json" \
-d '{
"query": "audrey hepburn",
"limit": 3,
"uuid": "a1b10138a6bbb0cd"
}'
```
### 在 n8n 工作流程中使用
可以將此 Webhook 作為子工作流程觸發器,或使用 HTTP Request Node 呼叫:
```json
{
"name": "Call Video RAG",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "http://localhost:5678/webhook/video-rag-mcp",
"method": "POST",
"body": {
"query": "={{ $json.searchTerm }}",
"limit": 5
}
}
}
```
## RAG Context 用途
工作流程產生的 `context` 欄位可直接用於 LLM 提示:
```javascript
// Example: 使用 context 進行問答
const prompt = `
基於以下影片片段資訊回答問題:
${context}
問題:${userQuestion}
請根據上述內容提供準確的答案。
`;
```
## 相關文件
- [Momentry Core API 文件](./API_ACCESS.md)
- [n8n MCP 測試報告](./maintenance_records/changes/CHANGE_N8N_MCP_INTEGRATION_TEST_2026_03_23.md)
- [N8N_DEMO_WORKFLOW.md](./N8N_DEMO_WORKFLOW.md) - 完整工作流程設計
## MCP 建立指令
此工作流程是透過 MCP 工具建立的:
```bash
# 使用 MCP 建立工作流程
node create_workflow.js | mcp-n8n
# 使用 MCP 啟動工作流程
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"n8n_activate_workflow","arguments":{"workflowId":"WlVvpX2OeKK83QOK"}}}' | mcp-n8n
```
## 工作流程檔案
- 原始檔案: `docs/n8n_workflow_video_rag_mcp.json`
@@ -0,0 +1,709 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "影片 On-the-Fly 實時處理架構設計"
date: "2026-04-01"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "實時處理架構設計"
ai_query_hints:
- "查詢 影片 On-the-Fly 實時處理架構設計 的內容"
- "影片 On-the-Fly 實時處理架構設計 的主要目的是什麼?"
- "如何操作或實施 影片 On-the-Fly 實時處理架構設計?"
---
# 影片 On-the-Fly 實時處理架構設計
| 項目 | 內容 |
|------|------|
| 目標 | **影片上傳時即時處理完成**On-the-Fly Processing |
| 分析日期 | 2026-04-01 |
| 硬體 | M4 Mac Mini 16GB → Mac Studio 64GB |
| 部署模式 | 邊緣 AI(本地運行) |
---
## 執行摘要
### 目標定義
```
傳統流程:
上傳 (5分鐘) → 等待 → 處理 (10分鐘) → 完成
總時間: 15分鐘 ❌
On-the-Fly 目標:
上傳 (5分鐘) + 處理 (同步進行) → 完成
總時間: 5分鐘 ✅
```
### 關鍵挑戰
1. **處理速度必須快於上傳速度**
2. **邊上傳邊處理(串流處理)**
3. **資源調度優化**
4. **用戶體驗即時反饋**
---
## 上傳速度分析
### 網路環境假設
| 網路類型 | 上傳速度 | 10分鐘影片 | 1小時影片 |
|---------|---------|-----------|----------|
| **光纖 100Mbps** | 12.5 MB/s | ~1.5分鐘 | ~9分鐘 |
| **光纖 500Mbps** | 62.5 MB/s | ~18秒 | ~1.8分鐘 |
| **企業級 1Gbps** | 125 MB/s | ~9秒 | ~54秒 |
| **SFTP (區網)** | 500+ MB/s | ~2秒 | ~13秒 |
### 影片大小估算
```
1080p 30fps:
- 檔案大小: ~100MB/分鐘
- H.264 壓縮: ~50MB/分鐘
- H.265 壓縮: ~25MB/分鐘
4K 60fps:
- 檔案大小: ~400MB/分鐘
- H.264 壓縮: ~200MB/分鐘
- H.265 壓縮: ~100MB/分鐘
```
### On-the-Fly 處理時間限制
```
假設: 10分鐘影片 (1080p H.264, ~500MB)
上傳時間:
- 100Mbps: 40秒
- 500Mbps: 8秒
- 1Gbps: 4秒
處理必須在此時間內完成!
```
---
## 處理器效能 vs 上傳速度
### M4 Mac Mini 16GB(現有)
| 處理器 | 10分鐘影片 | 是否能 On-the-Fly |
|--------|-----------|------------------|
| **ASR** | 50s | ⚠️ 勉強(100Mbps |
| **ASRX** | 180s | ❌ 無法 |
| **OCR** | 150s | ❌ 無法 |
| **YOLO** | 300s | ❌ 無法 |
| **Face** | 5s | ✅ 可以 |
| **Pose** | 300s | ❌ 無法 |
| **Scene** | 15s | ✅ 可以 |
| **CUT** | 0.5s | ✅ 可以 |
**結論**M4 Mini 無法實現完整 On-the-Fly
### Mac Studio 64GB(推薦)
| 處理器 | 10分鐘影片 | 是否能 On-the-Fly |
|--------|-----------|------------------|
| **ASR** | 15s | ✅ 可以 |
| **ASRX** | 60s | ✅ 可以(100Mbps |
| **OCR** | 50s | ✅ 可以(100Mbps |
| **YOLO** | 100s | ⚠️ 勉強(500Mbps |
| **Face** | 2s | ✅ 可以 |
| **Pose** | 100s | ⚠️ 勉強(500Mbps |
| **Scene** | 5s | ✅ 可以 |
| **CUT** | 0.2s | ✅ 可以 |
**結論**Mac Studio 可實現大部分 On-the-Fly
---
## On-the-Fly 架構設計
### 方案 A:串流處理(Streaming Processing)⭐
```
上傳流程:
[SFTP 上傳] ──→ [分塊接收] ──→ [即時處理]
│ │ │
│ ├─ ASR (音頻流)
│ ├─ Scene (關鍵幀)
│ └─ Face (關鍵幀)
└─ 上傳完成 → [完整處理]
├─ OCR
├─ YOLO
└─ Pose
```
**實現**
```python
class StreamingProcessor:
"""串流處理器 - 邊上傳邊處理"""
def __init__(self):
self.buffer = VideoBuffer()
self.processors = {
"fast": [SceneProcessor(), FaceProcessor()],
"delayed": [OCRProcessor(), YOLOProcessor(), PoseProcessor()]
}
async def process_stream(self, video_stream):
"""處理串流"""
async for chunk in video_stream:
# 1. 寫入緩衝區
self.buffer.write(chunk)
# 2. 快速處理器(立即執行)
for processor in self.processors["fast"]:
await processor.process_chunk(chunk)
# 3. 更新進度
await self.update_progress()
# 4. 上傳完成,執行延遲處理器
for processor in self.processors["delayed"]:
await processor.process_full(self.buffer)
```
### 方案 B:並行管線處理(Parallel Pipeline
```
並行管線:
[上傳] ──┬─ [ASR] ──→ 結果 1 (15s)
├─ [Face] ──→ 結果 2 (2s)
├─ [Scene] ──→ 結果 3 (5s)
├─ [CUT] ──→ 結果 4 (0.2s)
└─ 上傳完成後:
├─ [OCR] ──→ 結果 5 (50s)
├─ [YOLO] ──→ 結果 6 (100s)
└─ [Pose] ──→ 結果 7 (100s)
總時間: max(上傳, ASR, Face, Scene, CUT) + max(OCR, YOLO, Pose)
= max(40s, 15s, 2s, 5s, 0.2s) + max(50s, 100s, 100s)
= 40s + 100s = 140s
```
**Mac Studio 優勢**
- 可同時運行 4-6 個處理器
- 大幅縮短總處理時間
### 方案 C:智能降級處理(Adaptive Quality
```python
class AdaptiveProcessor:
"""自適應處理器 - 根據上傳速度調整"""
def __init__(self):
self.upload_speed = self._detect_upload_speed()
self.video_duration = None
def select_processing_profile(self):
"""根據上傳速度選擇處理配置"""
estimated_upload_time = self._estimate_upload_time()
if estimated_upload_time < 30:
# 快速上傳(>500Mbps)→ 完整處理
return "professional"
elif estimated_upload_time < 120:
# 中速上傳(100-500Mbps)→ 標準處理
return "standard"
else:
# 慢速上傳(<100Mbps)→ 快速處理
return "fast"
def get_processing_config(self, profile):
"""取得處理配置"""
configs = {
"professional": {
"audio": {"model": "large-v3", "diarization": True},
"ocr": {"sample_interval": 1},
"yolo": {"sample_interval": 1},
"face": {"sample_interval": 1},
"scene": {"sample_interval": 2}
},
"standard": {
"audio": {"model": "base", "diarization": True},
"ocr": {"sample_interval": 2},
"yolo": {"sample_interval": 2},
"face": {"sample_interval": 2},
"scene": {"sample_interval": 3}
},
"fast": {
"audio": {"model": "tiny", "diarization": False},
"ocr": {"sample_interval": 5},
"yolo": {"sample_interval": 5},
"face": {"sample_interval": 3},
"scene": {"sample_interval": 5}
}
}
return configs[profile]
```
---
## 串流處理實現
### 1. 影片分塊接收
```python
class ChunkedVideoReceiver:
"""分塊影片接收器"""
def __init__(self, chunk_size_mb=10):
self.chunk_size = chunk_size_mb * 1024 * 1024
self.buffer = io.BytesIO()
self.chunk_count = 0
self.processors = []
async def receive_chunk(self, chunk_data):
"""接收影片塊"""
# 寫入緩衝區
self.buffer.write(chunk_data)
self.chunk_count += 1
# 達到塊大小時,觸發處理
if self.buffer.tell() >= self.chunk_size:
await self._process_chunk()
async def _process_chunk(self):
"""處理當前塊"""
# 提取關鍵幀
frames = await self._extract_key_frames()
# 快速處理器
for processor in self.processors:
if processor.is_fast():
await processor.process_frames(frames)
# 清空緩衝區
self.buffer = io.BytesIO()
async def finalize(self):
"""上傳完成,處理完整影片"""
# 執行完整處理
for processor in self.processors:
if not processor.is_fast():
await processor.process_full(self.temp_file)
```
### 2. 音頻串流處理
```python
class AudioStreamProcessor:
"""音頻串流處理器"""
def __init__(self):
self.audio_buffer = []
self.sample_rate = 16000
self.chunk_duration = 10 # 10秒音頻塊
async def process_audio_stream(self, audio_stream):
"""處理音頻串流"""
import whisperx
# 載入模型(預載入)
model = ModelCache.get_model("large-v3")
async for audio_chunk in audio_stream:
# 累積音頻
self.audio_buffer.append(audio_chunk)
# 達到處理長度
if self._get_buffer_duration() >= self.chunk_duration:
# 即時轉錄
result = model.transcribe(self._merge_buffer())
# 發送即時結果
await self._send_partial_result(result)
# 清空緩衝區
self.audio_buffer = []
def _get_buffer_duration(self):
"""計算緩衝區時長"""
total_samples = sum(len(chunk) for chunk in self.audio_buffer)
return total_samples / self.sample_rate
```
### 3. 關鍵幀提取與處理
```python
class KeyFrameProcessor:
"""關鍵幀處理器"""
def __init__(self, extraction_interval=2.0):
self.extraction_interval = extraction_interval
self.last_extraction_time = 0
async def process_video_stream(self, video_stream):
"""處理影片串流"""
import cv2
cap = cv2.VideoCapture(video_stream)
fps = cap.get(cv2.CAP_PROP_FPS)
frame_count = 0
key_frames = []
while True:
ret, frame = cap.read()
if not ret:
break
frame_count += 1
current_time = frame_count / fps
# 提取關鍵幀(每 N 秒)
if current_time - self.last_extraction_time >= self.extraction_interval:
key_frames.append({
"frame": frame,
"timestamp": current_time
})
self.last_extraction_time = current_time
# 達到批次大小,立即處理
if len(key_frames) >= 10:
await self._process_batch(key_frames)
key_frames = []
# 處理剩餘幀
if key_frames:
await self._process_batch(key_frames)
async def _process_batch(self, frames):
"""批次處理關鍵幀"""
# 並行運行快速處理器
tasks = [
self._run_scene(frames),
self._run_face(frames),
self._run_cut(frames)
]
await asyncio.gather(*tasks)
```
---
## Mac Studio 優化配置
### 記憶體分配策略
```python
class MemoryAllocator:
"""Mac Studio 記憶體分配"""
# 64GB Mac Studio 配置
ALLOCATION = {
"system_reserved": 4000, # 4GB 系統保留
"database": 2000, # 2GB 資料庫
"api_server": 500, # 0.5GB API
"video_buffer": 8000, # 8GB 影片緩衝
"audio_buffer": 4000, # 4GB 音頻緩衝
"model_cache": 16000, # 16GB 模型快取
"processing": 28000 # 28GB 處理器運行
}
def __init__(self):
self.total_memory = 64 * 1024 # MB
self.verify_allocation()
def verify_allocation(self):
"""驗證記憶體分配"""
total_allocated = sum(self.ALLOCATION.values())
assert total_allocated <= self.total_memory, \
f"Memory over-allocated: {total_allocated}MB > {self.total_memory}MB"
```
### 並行處理調度
```python
class ParallelScheduler:
"""並行處理調度器"""
def __init__(self, max_workers=6):
self.max_workers = max_workers
self.executor = concurrent.futures.ThreadPoolExecutor(max_workers)
async def schedule_processing(self, video_uuid):
"""調度處理任務"""
# Phase 1: 上傳時即時處理
fast_tasks = [
self.executor.submit(self.run_scene, video_uuid),
self.executor.submit(self.run_face, video_uuid),
self.executor.submit(self.run_cut, video_uuid)
]
# 等待上傳完成
await self.wait_for_upload_complete(video_uuid)
# Phase 2: 上傳完成後處理
slow_tasks = [
self.executor.submit(self.run_asr, video_uuid),
self.executor.submit(self.run_ocr, video_uuid),
self.executor.submit(self.run_yolo, video_uuid),
self.executor.submit(self.run_pose, video_uuid)
]
# 收集結果
results = await self.collect_results(fast_tasks + slow_tasks)
return results
```
---
## 用戶體驗設計
### 即時反饋 UI
```
上傳進度:
████████░░░░░░░░░░░░ 40%
即時處理結果:
✅ 場景識別: 辦公室、會議室
✅ 人臉檢測: 3 人
✅ 鏡頭切換: 5 次
⏳ 語音轉錄: 處理中...
⏳ OCR: 等待上傳完成
⏳ YOLO: 等待上傳完成
預計剩餘時間: 2分30秒
```
### WebSocket 即時更新
```python
from fastapi import WebSocket
class ProgressWebSocket:
"""即時進度推送"""
async def broadcast_progress(self, video_uuid, processor, progress):
"""廣播處理進度"""
message = {
"type": "progress",
"video_uuid": video_uuid,
"processor": processor,
"progress": progress,
"timestamp": time.time()
}
await self.websocket.send_json(message)
async def broadcast_result(self, video_uuid, processor, result):
"""廣播處理結果"""
message = {
"type": "result",
"video_uuid": video_uuid,
"processor": processor,
"result": result,
"timestamp": time.time()
}
await self.websocket.send_json(message)
```
---
## 效能基準
### Mac Studio 64GB On-the-Fly 測試
#### 測試案例 110分鐘影片(1080p)
```
上傳時間(100Mbps: 40秒
即時處理(上傳期間):
├─ Scene: 5秒 ✅
├─ Face: 2秒 ✅
└─ CUT: 0.2秒 ✅
延遲處理(上傳完成後):
├─ ASR: 15秒 ✅
├─ OCR: 50秒 ✅
├─ YOLO: 100秒 ⚠️
└─ Pose: 100秒 ⚠️
總時間: 40秒(上傳)+ 100秒(處理)= 140秒
結果: 上傳後 100 秒完成所有處理
```
#### 測試案例 21小時影片(1080p)
```
上傳時間(100Mbps: 240秒
即時處理(上傳期間):
├─ Scene: 30秒 ✅
├─ Face: 12秒 ✅
└─ CUT: 1秒 ✅
延遲處理(上傳完成後):
├─ ASR: 90秒 ✅
├─ OCR: 300秒 ⚠️
├─ YOLO: 600秒 ⚠️
└─ Pose: 600秒 ⚠️
總時間: 240秒(上傳)+ 600秒(處理)= 840秒
結果: 上傳後 10 分鐘完成所有處理
```
#### 測試案例 3:10分鐘影片(企業級網路 1Gbps)
```
上傳時間: 4秒 ✅
處理時間(Mac Studio 64GB:
├─ 快速處理器: 5秒 ✅
└─ 慢速處理器: 100秒 ⚠️
總時間: 4秒(上傳)+ 100秒(處理)= 104秒
結果: 上傳後 1.7 分鐘完成所有處理
```
---
## 優化建議
### 1. 採樣策略優化
```python
# 根據網速自動調整採樣間隔
def get_adaptive_sample_interval(upload_speed, video_duration):
"""
upload_speed: MB/s
video_duration: 秒
"""
if upload_speed > 100: # > 800Mbps
return 1.0 # 精細處理
elif upload_speed > 50: # 400-800Mbps
return 2.0 # 標準處理
elif upload_speed > 10: # 80-400Mbps
return 3.0 # 快速處理
else:
return 5.0 # 極速處理
```
### 2. 優先級處理
```python
class PriorityProcessor:
"""優先級處理器"""
PRIORITY = {
"high": ["scene", "face", "cut", "asr"], # 用戶最關心
"medium": ["ocr", "yolo"], # 次要
"low": ["pose"] # 可選
}
async def process_by_priority(self, video_uuid):
# 高優先級:立即處理
for processor in self.PRIORITY["high"]:
await self.run(processor, video_uuid)
# 中優先級:並行處理
await asyncio.gather(*[
self.run(p, video_uuid)
for p in self.PRIORITY["medium"]
])
# 低優先級:背景處理
for processor in self.PRIORITY["low"]:
asyncio.create_task(self.run(processor, video_uuid))
```
### 3. 快取預載入
```python
# Mac Studio 啟動時預載入所有模型
class PreloadManager:
"""模型預載入管理器"""
@staticmethod
def preload_all():
"""預載入所有模型到記憶體"""
models = [
("asr", "whisperx_large_v3"),
("scene", "resnet18_places365"),
("face", "face_model"),
("yolo", "yolov8x"),
("ocr", "ocr_model"),
("pose", "pose_model")
]
for name, model_path in models:
ModelCache.load(name, model_path)
print(f"[Preload] All models loaded into memory")
```
---
## 最終建議
### ✅ Mac Studio 64GB 可實現 On-the-Fly
**配置**
```
硬體:
├─ Mac Studio M4 Max 64GB
├─ 14核心 CPU
├─ 30核心 GPU
└─ 1TB SSD
軟體:
├─ 預載入所有模型(16GB
├─ 並行處理(4-6 workers
├─ 串流處理(音頻/關鍵幀)
└─ 智能降級(根據網速)
```
**預期效果**
| 影片時長 | 網速 | 上傳時間 | 處理時間 | 總時間 | On-the-Fly |
|---------|------|---------|---------|--------|-----------|
| 10分鐘 | 100Mbps | 40s | 100s | **140s** | ⚠️ 部分實現 |
| 10分鐘 | 1Gbps | 4s | 100s | **104s** | ✅ 基本實現 |
| 30分鐘 | 100Mbps | 120s | 300s | **420s** | ⚠️ 部分實現 |
| 30分鐘 | 1Gbps | 12s | 300s | **312s** | ⚠️ 部分實現 |
**結論**
- ✅ 10分鐘影片 + 企業級網路:**接近 On-the-Fly**
- ⚠️ 長影片:處理時間仍較長
- ✅ 快速處理器:**完全 On-the-Fly**
- ⚠️ 慢速處理器(YOLO/Pose):需優化
### 📋 實施步驟
1. **立即**:實現串流處理架構
2. **Mac Studio 到達**:部署並行處理
3. **第一週**:優化 YOLO/Pose 採樣
4. **第二週**:實現智能降級
5. **第三週**:用戶體驗優化(WebSocket
### 🎯 達成目標
```
目標: 上傳完成時,處理也完成
現實:
- 快速處理器: ✅ 可達成
- 慢速處理器: ⚠️ 需 1-3 分鐘額外時間
妥協方案:
- 上傳期間: 快速結果即時顯示
- 上傳完成: 1-3 分鐘後完整結果
- 用戶體驗: 良好(有即時反饋)
```
@@ -0,0 +1,120 @@
# Parent Chunk 覆蓋率分析
> **日期**: 2026-04-14 | **影片 UUID**: 384b0ff44aaaa1f1
---
## 1. 總覽
| 項目 | 數量 |
|------|------|
| ASR chunks (sentence) | 1,961 |
| parent_chunks (scene) | 17 |
| 有 parent 的 ASR chunks | 1,864 (95.1%) |
| 無 parent 的 ASR chunks | 97 (4.9%) |
---
## 2. 結論:不是每個 ASR chunk 都有 parent chunk
**95.1% 的 ASR chunks 有 parent**,但仍有 **97 個 orphan chunks** 未關聯。
---
## 3. Orphan Chunks 分佈
| 類型 | 數量 | 說明 |
|------|------|------|
| 在 parent 之間的間隙 | 93 | parent_chunks 未完全覆蓋全片 |
| 在第一個 parent 之前 | 2 | 0-1.66s (片頭) |
| 在最後一個 parent 之後 | 2 | 6849-6865s (片尾) |
### 時間覆蓋
```
0s 1.66s 6849s 6865s
|── 2 chunks ─┤────────── 17 parent_chunks ─────────┤── 2 chunks ──┤
↑ ↑
第一個 parent 最後一個 parent
```
---
## 4. 每個 Parent 涵蓋的 ASR Chunks
| Parent ID | Scene | 時間範圍 | 時長 | ASR chunks |
|-----------|-------|---------|------|:---:|
| 1 | 0 | 1.66s - 474.62s | 7.9 min | 83 |
| 3 | 1 | 474.62s - 942.86s | 7.8 min | 111 |
| 4 | 2 | 942.86s - 1395.69s | 7.5 min | 104 |
| 2 | 3 | 1395.69s - 1656.84s | 4.4 min | 97 |
| 5 | 4 | 1656.88s - 2080.90s | 7.1 min | 109 |
| 6 | 5 | 2080.90s - 2538.22s | 7.6 min | 125 |
| 7 | 6 | 2538.22s - 2889.09s | 5.9 min | 85 |
| 8 | 7 | 2889.09s - 3532.62s | 10.7 min | 136 |
| 9 | 8 | 3532.62s - 3820.90s | 4.8 min | 141 |
| 10 | 9 | 3820.90s - 4166.84s | 5.8 min | 103 |
| 11 | 10 | 4166.84s - 4430.15s | 4.4 min | 105 |
| 12 | 11 | 4430.15s - 4717.13s | 4.8 min | 103 |
| 13 | 12 | 4717.13s - 5102.38s | 6.4 min | 103 |
| 14 | 13 | 5102.38s - 5352.86s | 4.2 min | 114 |
| 15 | 14 | 5352.86s - 5851.60s | 8.3 min | 161 |
| 16 | 15 | 5851.60s - 6639.13s | 13.1 min | 114 |
| 17 | 16 | 6639.13s - 6849.01s | 3.5 min | 70 |
---
## 5. Parent Chunks 結構
```sql
CREATE TABLE parent_chunks (
id SERIAL PRIMARY KEY,
uuid TEXT NOT NULL, -- 影片 UUID
scene_order INTEGER, -- 場景順序
start_time DOUBLE PRECISION NOT NULL,
end_time DOUBLE PRECISION NOT NULL,
summary_text TEXT, -- AI 摘要
summary_vector VECTOR(768), -- 摘要嵌入
start_frame BIGINT, -- 起始幀 (精確)
end_frame BIGINT, -- 結束幀 (精確)
fps DOUBLE PRECISION,
metadata JSONB,
rule_3_markers JSONB,
created_at TIMESTAMPTZ
);
```
---
## 6. 關聯問題
### 目前狀態
```
parent_chunks: 17 筆 (scene-level)
chunks: 4,018 筆 (sentence/cut/time-level)
❌ chunks.parent_chunk_id 全部為 NULL
❌ chunks.child_chunk_ids 全部為 []
❌ 兩者未建立外鍵關聯
```
### 應建立但尚未建立的關聯
```sql
-- 應為每個 sentence chunk 設定 parent_chunk_id
UPDATE chunks c
SET parent_chunk_id = pc.id::varchar
FROM parent_chunks pc
WHERE c.uuid = pc.uuid
AND c.chunk_type = 'sentence'
AND c.start_time >= pc.start_time
AND c.end_time <= pc.end_time
AND c.parent_chunk_id IS NULL;
```
---
## 7. 建議
1. **補齊 orphan chunks 的 parent**: 為 93 個間隙 chunks 建立新的 parent_chunks
2. **建立 parent-child 關聯**: 執行上述 UPDATE 將 `parent_chunk_id` 填入
3. **dev schema 同步**: dev.parent_chunks 目前為 0 筆,需同步資料
@@ -0,0 +1,303 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Momentry Core 效能與可擴展性架構"
date: "2026-04-22"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "momentry"
- "core"
- "效能與可擴展性架構"
ai_query_hints:
- "查詢 Momentry Core 效能與可擴展性架構 的內容"
- "Momentry Core 效能與可擴展性架構 的主要目的是什麼?"
- "如何操作或實施 Momentry Core 效能與可擴展性架構?"
---
# Momentry Core 效能與可擴展性架構
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-22 |
| 文件版本 | V1.0 |
| 相關文件 | [ARCHITECTURE_OVERVIEW.md](./ARCHITECTURE_OVERVIEW.md)<br>[ARCHITECTURE_ROADMAP.md](./ARCHITECTURE_ROADMAP.md)<br>[TECHNICAL_DECISION_RECORDS.md](./TECHNICAL_DECISION_RECORDS.md) |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-04-22 | 創建效能與可擴展性架構文件 | OpenCode | OpenCode / deepseek-v3.2 |
---
## 1. 效能基準指標
### 1.1 關鍵效能指標 (KPIs)
| 指標類別 | 指標 | 目標值 | 測量方法 |
|----------|------|--------|----------|
| **響應時間** | API 響應時間 (P95) | < 500ms | 請求端到端時間 |
| | 視頻註冊處理時間 | < 5分鐘 (10分鐘影片) | 從上傳到完成 |
| | 查詢響應時間 | < 2秒 | RAG 搜索完成 |
| **吞吐量** | 併發註冊任務 | 5+ 併發 | 同時處理視頻數量 |
| | 同時查詢用戶 | 50+ 併發 | 同時 RAG 搜索 |
| | 資料庫 QPS | 1000+ QPS | 讀寫操作 |
| **資源使用** | CPU 使用率 | < 70% 平均 | 系統監控 |
| | 記憶體使用率 | < 80% 平均 | 系統監控 |
| | 儲存 I/O | < 50MB/s 讀寫 | 磁碟監控 |
| **質量指標** | 分片準確率 | > 95% | 人工抽樣驗證 |
| | 嵌入向量品質 | > 0.8 相似度 | 人工測試集 |
| | 搜索召回率 | > 90% | 標準測試集 |
### 1.2 當前效能現狀
根據現有系統分析:
1. **視頻處理管道**
- ASR: ~1-2分鐘/10分鐘影片(CPU 密集型)
- OCR: ~30秒/10分鐘影片(GPU 加速)
- CUT: ~1分鐘/10分鐘影片(算法複雜度 O(n²))
- YOLO: ~45秒/10分鐘影片(GPU 推理)
2. **記憶體消耗**
- 嵌入引擎: 500MB-1GB(取決於模型)
- 處理器: 100-300MB/任務
- 向量資料庫: 2GB+(隨資料增長)
3. **儲存需求**
- 原始視頻: 100-500MB/小時影片
- 處理結果: 50-100MB/10分鐘影片
- 向量資料: 1-2GB/100小時影片
---
## 2. 可擴展性策略
### 2.1 水平擴展 (Horizontal Scaling)
#### 2.1.1 無狀態服務擴展
| 服務類型 | 擴展策略 | 瓶頸點 |
|----------|----------|--------|
| **API Server** | 多實例 + 負載均衡 | Redis 連線數限制 |
| **處理器 Worker** | 任務隊列 + 多 Worker | 外部依賴(Python 腳本) |
| **嵌入引擎** | 模型分片 + 請求路由 | GPU 記憶體限制 |
#### 2.1.2 有狀態服務擴展
| 服務類型 | 擴展策略 | 瓶頸點 |
|----------|----------|--------|
| **PostgreSQL** | 讀寫分離 + 連接池 | 單主節點寫入 |
| **Redis** | 集群模式 + 分片 | 網絡延遲 |
| **Qdrant** | 分片 + 副本 | 向量搜索計算量 |
### 2.2 垂直擴展 (Vertical Scaling)
| 資源類型 | 升級策略 | 預期效益 |
|----------|----------|----------|
| **CPU** | 更多核心 + 更高時脈 | 提高並行處理能力 |
| **GPU** | 更高記憶體 + 更多核心 | 加速深度學習推理 |
| **記憶體** | 更大容量 + 更高頻率 | 減少磁碟交換 |
| **儲存** | NVMe SSD + RAID | 提高 I/O 吞吐量 |
---
## 3. 效能優化措施
### 3.1 計算優化
| 優化點 | 技術方案 | 預期改進 |
|--------|----------|----------|
| **向量相似度計算** | SIMD 指令集優化 | 10-100 倍加速 |
| **CUT 算法優化** | 啟發式剪枝 + 並行化 | 從 O(n²) 到 O(n log n) |
| **Python 執行器** | 進程池 + 結果緩存 | 減少啟動開銷 |
| **FFmpeg 處理** | 硬體加速 (VideoToolbox) | 2-5 倍加速 |
### 3.2 記憶體優化
| 優化點 | 技術方案 | 預期改進 |
|--------|----------|----------|
| **嵌入向量緩存** | LRU 緩存 + 分級存儲 | 減少重複計算 |
| **視頻幀緩衝** | 滑動窗口 + 智能預載 | 控制峰值記憶體 |
| **資料庫連接池** | 連接復用 + 超時釋放 | 減少連接開銷 |
| **模型量化** | INT8/FP16 量化 | 50-75% 記憶體節省 |
### 3.3 儲存優化
| 優化點 | 技術方案 | 預期改進 |
|--------|----------|----------|
| **向量索引** | HNSW 索引 + 壓縮 | 更快搜索 + 更少空間 |
| **文件存儲** | 分層存儲 + 去重 | 節省儲存空間 |
| **日誌輪轉** | 自動清理 + 壓縮 | 控制日誌增長 |
| **快照備份** | 增量備份 + 壓縮 | 減少備份窗口 |
---
## 4. 負載測試策略
### 4.1 測試場景設計
| 場景 | 目標 | 測試指標 |
|------|------|----------|
| **正常負載** | 系統日常使用 | 響應時間、成功率 |
| **峰值負載** | 節假日/活動 | 吞吐量、錯誤率 |
| **壓力測試** | 極限條件 | 崩潰點、恢復能力 |
| **耐久測試** | 長時間運行 | 記憶體泄漏、穩定性 |
### 4.2 測試工具與方法
```bash
# 使用 Apache Bench 進行 API 測試
ab -n 1000 -c 50 http://localhost:3002/api/health
# 使用 k6 進行複雜場景測試
k6 run --vus 50 --duration 30s script.js
# 自定義負載生成器
python scripts/load_test.py --scenario video_registration
```
### 4.3 性能基準測試套件
```
benchmarks/
├── api_benchmarks/ # API 效能測試
├── video_processing/ # 視頻處理測試
├── search_benchmarks/ # 搜索效能測試
├── memory_profiling/ # 記憶體分析
└── reports/ # 測試報告
```
---
## 5. 監控與告警
### 5.1 效能監控儀表板
| 監控維度 | 指標 | 告警閾值 |
|----------|------|----------|
| **系統資源** | CPU 使用率 | > 80% 持續 5分鐘 |
| | 記憶體使用率 | > 85% 持續 5分鐘 |
| | 磁碟使用率 | > 90% |
| **應用效能** | API 響應時間 | P95 > 1秒 |
| | 錯誤率 | > 1% |
| | 任務佇列長度 | > 100 |
| **業務指標** | 視頻處理成功率 | < 95% |
| | 搜索召回率 | < 85% |
| | 用戶滿意度 | < 4.0/5.0 |
### 5.2 效能分析工具
| 工具 | 用途 | 集成方式 |
|------|------|----------|
| **Prometheus** | 指標收集 | Rust 客戶端 + 暴露端點 |
| **Grafana** | 視覺化儀表板 | 預設儀表板 |
| **Jaeger** | 分佈式追蹤 | OpenTelemetry |
| **pprof** | CPU/記憶體分析 | 性能剖析端點 |
| **Valgrind** | 記憶體泄漏檢測 | 開發環境測試 |
---
## 6. 未來優化方向
### 6.1 短期優化(1-3個月)
1. **CUT 算法重構**
- 實現增量計算
- 添加啟發式剪枝
- 預期效能提升:5-10 倍
2. **Python 執行器優化**
- 進程池預熱
- 結果序列化優化
- 預期效能提升:2-3 倍
3. **向量搜索優化**
- HNSW 參數調優
- 查詢預處理
- 預期效能提升:30-50%
### 6.2 中期優化(3-6個月)
1. **異步處理管道**
- 完全異步任務調度
- 實時進度回報
- 預期吞吐量提升:2-3 倍
2. **模型壓縮與量化**
- INT8 量化支持
- 模型分片部署
- 預期記憶體節省:50-75%
3. **分散式計算**
- 多機部署支持
- 負載均衡策略
- 預期橫向擴展:線性增長
### 6.3 長期願景(6-12個月)
1. **邊緣計算集成**
- 輕量級處理器
- 離線模式支持
- 應用場景:移動端、IoT
2. **硬體加速**
- GPU 推理優化
- FPGA 加速支持
- 預期效能提升:10-100 倍
3. **智能調度**
- AI 驅動的資源分配
- 預測性擴展
- 預期成本節省:30-50%
---
## 7. 相關資源
### 7.1 效能測試數據
- [效能基準報告](./benchmarks/reports/latest.md)
- [壓力測試結果](./benchmarks/reports/stress_test.md)
- [監控儀表板](http://localhost:3000/d/momentry-performance)
### 7.2 配置參數調優
```toml
# 效能相關配置
[performance]
max_concurrent_tasks = 5
vector_cache_size = "1GB"
database_pool_size = 20
# 擴展配置
[scaling]
auto_scaling_enabled = false
min_instances = 1
max_instances = 10
```
### 7.3 參考文檔
- [Redis 效能調優指南](https://redis.io/topics/latency)
- [PostgreSQL 效能優化](https://www.postgresql.org/docs/current/performance.html)
- [向量資料庫效能最佳實踐](https://qdrant.tech/documentation/performance/)
---
## 8. 結論
Momentry Core 的效能與可擴展性設計遵循以下原則:
1. **分層優化**:從計算、記憶體、儲存多個維度進行系統性優化
2. **漸進式改進**:短期解決現有瓶頸,中期建立完善架構,長期實現智能調度
3. **數據驅動**:建立完整的監控體系,基於實際數據進行決策
4. **平衡策略**:在效能、成本、複雜度之間找到最佳平衡點
通過實施上述策略,Momentry Core 能夠支持從小型部署到大型企業級應用的各種場景,提供穩定、高效、可擴展的視頻內容分析服務。
@@ -0,0 +1,619 @@
# 人物身份整合架构设计
## 概述
将人脸识别(Face Recognition)和声纹识别(ASRX Speaker Diarization)整合,在视频块(Chunk)中标注人物身份。
## 架构设计
### 数据流
```
视频文件
┌─────────────────────────────────────────────┐
│ 并行处理 │
├─────────────────────────────────────────────┤
│ 1. Face Detection → face_detections │
│ 2. ASRX → asrx_segments (speaker_id) │
│ 3. Chunk Generation → chunks │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ 时间重叠分析 │
├─────────────────────────────────────────────┤
│ 匹配规则: │
│ - face_detections.timestamp ∈ [asrx.start, asrx.end]
│ - 提取时间重叠最大的配对 │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ 创建人物身份关联 │
├─────────────────────────────────────────────┤
│ person_identities (person_id) │
│ ├─ face_id (外键) │
│ ├─ speaker_id (字符串) │
│ ├─ confidence (关联置信度) │
│ └─ video_uuid (来源视频) │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ 更新 Chunk 元数据 │
├─────────────────────────────────────────────┤
│ chunks.metadata: { │
│ "person_identities": [ │
│ { │
│ "person_id": "person_xxx", │
│ "face_id": "face_123", │
│ "speaker_id": "SPEAKER_00", │
│ "confidence": 0.85 │
│ } │
│ ] │
│ } │
└─────────────────────────────────────────────┘
```
## 数据库表设计
### 1. person_identities(人物身份表)
```sql
CREATE TABLE person_identities (
id SERIAL PRIMARY KEY,
person_id VARCHAR(255) NOT NULL UNIQUE,
-- 身份关联
face_identity_id INTEGER REFERENCES face_identities(id) ON DELETE SET NULL,
speaker_id VARCHAR(64), -- SPEAKER_00, SPEAKER_01, etc.
-- 关联信息
video_uuid VARCHAR(255) NOT NULL,
confidence DOUBLE PRECISION DEFAULT 0.0,
-- 元数据
name VARCHAR(255), -- 人物姓名(手动标注)
metadata JSONB DEFAULT '{}'::jsonb,
-- 时间戳
first_appearance_time DOUBLE PRECISION,
last_appearance_time DOUBLE PRECISION,
total_appearance_duration DOUBLE PRECISION DEFAULT 0.0,
appearance_count INTEGER DEFAULT 0,
-- 审计字段
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
is_confirmed BOOLEAN DEFAULT FALSE, -- 用户确认的身份
-- 约束
CONSTRAINT unique_person_identity UNIQUE (video_uuid, face_identity_id, speaker_id)
);
CREATE INDEX idx_person_identities_video_uuid ON person_identities(video_uuid);
CREATE INDEX idx_person_identities_face ON person_identities(face_identity_id);
CREATE INDEX idx_person_identities_speaker ON person_identities(speaker_id);
CREATE INDEX idx_person_identities_name ON person_identities(name);
```
### 2. person_appearances(人物出场记录表)
```sql
CREATE TABLE person_appearances (
id SERIAL PRIMARY KEY,
person_id VARCHAR(255) NOT NULL REFERENCES person_identities(person_id) ON DELETE CASCADE,
-- 出场信息
video_uuid VARCHAR(255) NOT NULL,
start_time DOUBLE PRECISION NOT NULL,
end_time DOUBLE PRECISION NOT NULL,
duration DOUBLE PRECISION NOT NULL,
-- 来源信息
face_detection_id INTEGER REFERENCES face_detections(id) ON DELETE SET NULL,
asrx_segment_id INTEGER, -- 暂不设外键,ASRX 结果存储在 JSON 中
-- 元数据
confidence DOUBLE PRECISION DEFAULT 0.0,
metadata JSONB DEFAULT '{}'::jsonb,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_person_appearances_person ON person_appearances(person_id);
CREATE INDEX idx_person_appearances_video ON person_appearances(video_uuid);
CREATE INDEX idx_person_appearances_time ON person_appearances(video_uuid, start_time, end_time);
```
### 3. 增强 chunks 表
```sql
-- 在 chunks.metadata 中添加人物身份信息
-- 示例结构:
{
"person_identities": [
{
"person_id": "person_abc123",
"face_id": "face_456",
"speaker_id": "SPEAKER_00",
"confidence": 0.85,
"name": "张三"
}
],
"speaker_id": "SPEAKER_00", -- 主要说话人
"face_count": 2 //
}
```
## 核心算法
### 算法 1:时间重叠匹配
```python
def match_face_with_speaker(face_detections, asrx_segments, threshold=0.5):
"""
根据时间重叠匹配人脸和说话人
参数:
- face_detections: 人脸检测列表 [{timestamp, face_id, ...}]
- asrx_segments: ASRX 片段列表 [{start, end, speaker_id, ...}]
- threshold: 最小重叠比例阈值
返回:
- 匹配列表 [{face_id, speaker_id, confidence}]
"""
matches = []
for face in face_detections:
face_time = face['timestamp']
# 找到时间重叠的 ASRX 片段
for segment in asrx_segments:
if segment['start'] <= face_time <= segment['end']:
# 计算重叠比例
overlap_duration = min(face_time - segment['start'],
segment['end'] - face_time)
total_duration = segment['end'] - segment['start']
overlap_ratio = overlap_duration / total_duration
if overlap_ratio >= threshold:
matches.append({
'face_id': face['face_id'],
'speaker_id': segment['speaker_id'],
'confidence': overlap_ratio,
'timestamp': face_time
})
return matches
```
### 算法 2:人物身份聚类
```python
def cluster_person_identities(matches, face_embeddings, similarity_threshold=0.7):
"""
将匹配结果聚类为人物身份
参数:
- matches: 匹配列表
- face_embeddings: 人脸嵌入向量 {face_id: embedding}
- similarity_threshold: 相似度阈值
返回:
- 人物身份列表 [{person_id, face_ids, speaker_ids}]
"""
from sklearn.cluster import DBSCAN
import numpy as np
# 收集所有 face_id 和对应的嵌入向量
face_ids = list(set(m['face_id'] for m in matches))
embeddings = [face_embeddings[face_id] for face_id in face_ids]
# 聚类
clustering = DBSCAN(eps=1-similarity_threshold, min_samples=2, metric='cosine')
labels = clustering.fit_predict(embeddings)
# 按聚类分组
person_identities = {}
for face_id, label in zip(face_ids, labels):
if label == -1:
continue # 噪声
person_id = f"person_{label}"
if person_id not in person_identities:
person_identities[person_id] = {
'person_id': person_id,
'face_ids': [],
'speaker_ids': set()
}
person_identities[person_id]['face_ids'].append(face_id)
# 添加对应的 speaker_id
for match in matches:
if match['face_id'] == face_id:
person_identities[person_id]['speaker_ids'].add(match['speaker_id'])
# 转换 set 为 list
for person in person_identities.values():
person['speaker_ids'] = list(person['speaker_ids'])
return list(person_identities.values())
```
### 算法 3:更新 Chunk 人物信息
```python
def update_chunk_person_identities(chunk, person_appearances):
"""
更新 Chunk 的人物身份信息
参数:
- chunk: Chunk 对象
- person_appearances: 人物出场记录列表
返回:
- 更新后的 Chunk
"""
chunk_start = chunk['start_time']
chunk_end = chunk['end_time']
# 找到与 Chunk 时间重叠的人物出场
overlapping_persons = []
for appearance in person_appearances:
if (appearance['start_time'] <= chunk_end and
appearance['end_time'] >= chunk_start):
# 计算重叠时长
overlap_start = max(chunk_start, appearance['start_time'])
overlap_end = min(chunk_end, appearance['end_time'])
overlap_duration = overlap_end - overlap_start
overlapping_persons.append({
'person_id': appearance['person_id'],
'name': appearance.get('name'),
'overlap_duration': overlap_duration,
'confidence': appearance['confidence']
})
# 按重叠时长排序
overlapping_persons.sort(key=lambda x: x['overlap_duration'], reverse=True)
# 更新 Chunk 元数据
metadata = chunk.get('metadata', {})
metadata['person_identities'] = overlapping_persons
# 设置主要人物(重叠时长最长)
if overlapping_persons:
metadata['primary_person'] = overlapping_persons[0]['person_id']
chunk['metadata'] = metadata
return chunk
```
## API 设计
### 1. 创建人物身份关联
```http
POST /api/v1/person/identify
Content-Type: application/json
{
"video_uuid": "abc123",
"auto_match": true,
"match_threshold": 0.5
}
Response:
{
"success": true,
"message": "Identified 3 persons",
"persons": [
{
"person_id": "person_0",
"face_ids": ["face_123", "face_456"],
"speaker_ids": ["SPEAKER_00"],
"confidence": 0.85,
"appearance_count": 15,
"total_duration": 120.5
}
]
}
```
### 2. 查询人物出场时间轴
```http
GET /api/v1/person/:person_id/timeline?video_uuid=abc123
Response:
{
"success": true,
"person_id": "person_0",
"name": "",
"timeline": [
{
"start_time": 10.5,
"end_time": 25.3,
"duration": 14.8,
"confidence": 0.92
},
{
"start_time": 45.0,
"end_time": 60.2,
"duration": 15.2,
"confidence": 0.88
}
],
"statistics": {
"total_appearances": 15,
"total_duration": 120.5,
"first_appearance": 10.5,
"last_appearance": 350.2
}
}
```
### 3. 手动标注人物姓名
```http
PATCH /api/v1/person/:person_id
Content-Type: application/json
{
"name": "",
"metadata": {
"role": "",
"department": ""
}
}
Response:
{
"success": true,
"message": "Person identity updated",
"person_id": "person_0"
}
```
### 4. 查询 Chunk 中的人物
```http
GET /api/v1/chunks/:chunk_id/persons
Response:
{
"success": true,
"chunk_id": "sentence_0012",
"persons": [
{
"person_id": "person_0",
"name": "",
"confidence": 0.85,
"overlap_duration": 3.5
}
]
}
```
## 实现步骤
### Phase 1: 数据库表创建 (Day 1)
1. ✅ 创建迁移文件 `007_person_identity_tables.sql`
2. ✅ 创建 `person_identities`
3. ✅ 创建 `person_appearances`
4. ✅ 创建索引和约束
5. ✅ 运行迁移测试
### Phase 2: 核心算法实现 (Day 2-3)
1. ⏳ 实现 Rust 结构体
- `PersonIdentity`
- `PersonAppearance`
- `PersonMatch`
2. ⏳ 实现匹配算法
- `match_face_with_speaker()`
- `cluster_person_identities()`
- `update_chunk_person_identities()`
3. ⏳ 实现数据库操作
- `store_person_identity()`
- `store_person_appearance()`
- `update_chunks_with_persons()`
### Phase 3: API 实现 (Day 4)
1. ⏳ 创建 `src/api/person_identity.rs`
2. ⏳ 实现 API 端点
- `POST /api/v1/person/identify`
- `GET /api/v1/person/:person_id/timeline`
- `PATCH /api/v1/person/:person_id`
- `GET /api/v1/chunks/:chunk_id/persons`
3. ⏳ 添加路由到 `server.rs`
### Phase 4: 集成测试 (Day 5)
1. ⏳ 准备测试视频
2. ⏳ 运行完整处理流程
- Face Detection
- ASRX
- Chunk Generation
- Person Identity Creation
3. ⏳ 验证结果
- 数据库记录正确性
- API 响应正确性
- 时间轴查询正确性
### Phase 5: 文档和优化 (Day 6)
1. ⏳ 编写 API 文档
2. ⏳ 编写使用指南
3. ⏳ 性能优化
4. ⏳ 错误处理增强
## 性能优化
### 1. 批量插入
```rust
// 使用事务批量插入人物出场记录
pub async fn batch_insert_person_appearances(
db: &PostgresDb,
appearances: &[PersonAppearance],
) -> Result<()> {
let mut tx = db.pool().begin().await?;
for appearance in appearances {
sqlx::query(r#"
INSERT INTO person_appearances (
person_id, video_uuid, start_time, end_time,
duration, confidence, metadata
) VALUES ($1, $2, $3, $4, $5, $6, $7)
"#)
.bind(&appearance.person_id)
.bind(&appearance.video_uuid)
.bind(appearance.start_time)
.bind(appearance.end_time)
.bind(appearance.duration)
.bind(appearance.confidence)
.bind(&appearance.metadata)
.execute(&mut *tx)
.await?;
}
tx.commit().await?;
Ok(())
}
```
### 2. 索引优化
```sql
-- 为常用查询添加复合索引
CREATE INDEX idx_person_appearances_video_time
ON person_appearances(video_uuid, start_time, end_time);
CREATE INDEX idx_person_identities_video_face
ON person_identities(video_uuid, face_identity_id);
CREATE INDEX idx_person_identities_video_speaker
ON person_identities(video_uuid, speaker_id);
```
### 3. 缓存策略
```rust
// 使用 Redis 缓存人物时间轴查询
pub async fn get_person_timeline_cached(
redis: &RedisClient,
person_id: &str,
video_uuid: &str,
) -> Result<Vec<PersonAppearance>> {
let cache_key = format!("person_timeline:{}:{}", video_uuid, person_id);
// 尝试从缓存获取
if let Some(cached) = redis.get(&cache_key).await? {
return Ok(serde_json::from_str(&cached)?);
}
// 从数据库查询
let timeline = query_person_timeline_from_db(person_id, video_uuid).await?;
// 缓存结果(5分钟)
redis.set_ex(&cache_key, &serde_json::to_string(&timeline)?, 300).await?;
Ok(timeline)
}
```
## 错误处理
### 1. 匹配置信度过低
```rust
if confidence < MIN_MATCH_CONFIDENCE {
tracing::warn!(
"[PERSON] Low confidence match: face={}, speaker={}, confidence={}",
face_id, speaker_id, confidence
);
// 记录但不创建关联
return Ok(None);
}
```
### 2. 重复匹配
```rust
// 检查是否已存在相同关联
let existing = sqlx::query!(
"SELECT id FROM person_identities
WHERE video_uuid = $1 AND face_identity_id = $2 AND speaker_id = $3",
video_uuid, face_id, speaker_id
)
.fetch_optional(db.pool())
.await?;
if existing.is_some() {
tracing::info!("[PERSON] Identity already exists, skipping");
return Ok(());
}
```
### 3. 时间范围无效
```rust
if start_time >= end_time {
anyhow::bail!(
"Invalid time range: start={} >= end={}",
start_time, end_time
);
}
```
## 监控指标
```rust
// Prometheus 指标
lazy_static! {
static ref PERSON_IDENTITIES_CREATED: Counter =
register_counter!("person_identities_created_total").unwrap();
static ref PERSON_MATCHES_TOTAL: Counter =
register_counter!("person_matches_total").unwrap();
static ref PERSON_MATCH_CONFIDENCE: Histogram =
register_histogram!("person_match_confidence").unwrap();
}
```
## 未来扩展
### 1. 多模态融合
- 结合 OCR 文字识别(字幕、名牌)
- 结合场景分类(新闻演播室、会议室)
- 结合姿态识别(站立、坐着)
### 2. 跨视频人物追踪
- 全局人物身份库
- 人脸嵌入向量相似度匹配
- 服装、配饰特征
### 3. 实时处理
- 流式视频处理
- 实时人物识别
- WebSocket 推送更新
## 参考资料
- [InsightFace Documentation](https://github.com/deepinsight/insightface)
- [WhisperX Speaker Diarization](https://github.com/m-bain/whisperX)
- [PostgreSQL pgvector](https://github.com/pgvector/pgvector)
- [DBSCAN Clustering Algorithm](https://scikit-learn.org/stable/modules/clustering.html#dbscan)
@@ -0,0 +1,395 @@
# 人物身份整合功能使用指南
## 概述
该功能通过整合人脸识别(Face Recognition)和声纹识别(ASRX Speaker Diarization),在视频块(Chunk)中自动标注人物身份。
## 快速开始
### 1. 处理视频
首先需要处理视频以提取人脸和声纹信息:
```bash
# 处理视频,提取所有特征
cargo run -- process /path/to/video.mp4 --modules face,asrx
# 或者使用 playground 进行测试
cargo run --bin momentry_playground -- process /path/to/video.mp4 --modules face,asrx
```
这将生成:
- `face.json` - 人脸检测结果
- `asrx.json` - 说话人分离结果
### 2. 自动识别人物身份
使用 API 自动匹配人脸和声纹:
```bash
curl -X POST http://localhost:3002/api/v1/person/identify \
-H "Content-Type: application/json" \
-H "X-API-Key: your_api_key" \
-d '{
"video_uuid": "your_video_uuid",
"auto_match": true,
"match_threshold": 0.5
}'
```
响应示例:
```json
{
"success": true,
"message": "Identified 3 persons",
"persons": [
{
"person_id": "person_abc123",
"speaker_id": "SPEAKER_00",
"confidence": 0.85,
"appearance_count": 15,
"total_appearance_duration": 120.5
}
]
}
```
### 3. 查询人物时间轴
查询某个人物在视频中的出场时间:
```bash
curl -X GET "http://localhost:3002/api/v1/person/person_abc123/timeline?video_uuid=your_video_uuid" \
-H "X-API-Key: your_api_key"
```
响应示例:
```json
{
"person_id": "person_abc123",
"name": "张三",
"timeline": [
{
"start_time": 10.5,
"end_time": 25.3,
"duration": 14.8,
"confidence": 0.92
}
],
"statistics": {
"total_appearances": 15,
"total_duration": 120.5,
"first_appearance": 10.5,
"last_appearance": 350.2,
"average_confidence": 0.88
}
}
```
### 4. 手动标注人物姓名
为识别的人物添加姓名:
```bash
curl -X PATCH http://localhost:3002/api/v1/person/person_abc123 \
-H "Content-Type: application/json" \
-H "X-API-Key: your_api_key" \
-d '{
"name": "张三",
"metadata": {
"role": "主持人",
"department": "新闻部"
},
"is_confirmed": true
}'
```
### 5. 查询 Chunk 中的人物
查看某个视频块中出现的人物:
```bash
curl -X GET http://localhost:3002/api/v1/chunks/sentence_0012/persons \
-H "X-API-Key: your_api_key"
```
响应示例:
```json
{
"success": true,
"chunk_id": "sentence_0012",
"persons": [
{
"person_id": "person_abc123",
"name": "张三",
"confidence": 0.85,
"overlap_duration": 3.5
}
]
}
```
## API 端点总结
| 端点 | 方法 | 描述 |
|------|------|------|
| `/api/v1/person/identify` | POST | 自动识别人物身份 |
| `/api/v1/person/:person_id` | GET | 获取人物详情 |
| `/api/v1/person/:person_id` | PATCH | 更新人物信息 |
| `/api/v1/person/:person_id/timeline` | GET | 查询人物时间轴 |
| `/api/v1/person/:person_id/appearances` | GET | 查询人物出场记录 |
| `/api/v1/chunks/:chunk_id/persons` | GET | 查询 Chunk 中的人物 |
## 数据库表结构
### person_identities(人物身份表)
| 字段 | 类型 | 描述 |
|------|------|------|
| person_id | VARCHAR(255) | 人物唯一标识 |
| face_identity_id | INTEGER | 关联的人脸身份 ID |
| speaker_id | VARCHAR(64) | 说话人 IDSPEAKER_00, SPEAKER_01... |
| video_uuid | VARCHAR(255) | 来源视频 UUID |
| name | VARCHAR(255) | 人物姓名(手动标注) |
| confidence | DOUBLE PRECISION | 关联置信度 |
| appearance_count | INTEGER | 出场次数 |
| total_appearance_duration | DOUBLE PRECISION | 总出场时长(秒) |
| is_confirmed | BOOLEAN | 是否已确认 |
### person_appearances(人物出场记录表)
| 字段 | 类型 | 描述 |
|------|------|------|
| person_id | VARCHAR(255) | 关联的人物身份 ID |
| video_uuid | VARCHAR(255) | 视频 UUID |
| start_time | DOUBLE PRECISION | 开始时间(秒) |
| end_time | DOUBLE PRECISION | 结束时间(秒) |
| duration | DOUBLE PRECISION | 持续时间(秒) |
| face_detection_id | INTEGER | 关联的人脸检测 ID |
| confidence | DOUBLE PRECISION | 置信度 |
## 工作流程
### 完整处理流程
```
1. 视频上传
2. 并行处理
├─ Face Detection → face_detections
├─ ASRX Processing → speaker_id
└─ Chunk Generation → chunks
3. 自动匹配
├─ 时间重叠分析
├─ Face ID + Speaker ID → Person Identity
└─ 创建 person_identities 和 person_appearances
4. 更新 Chunks
└─ 在 metadata 中添加人物信息
5. 查询和使用
├─ 时间轴查询
├─ 人物搜索
└─ Chunk 标注
```
### 匹配算法
核心匹配算法基于**时间重叠**
1. 对于每个人脸检测,找到时间重叠的 ASRX 片段
2. 计算重叠比例 = overlap_duration / segment_duration
3. 如果 overlap_ratio >= threshold,则创建匹配
4. 按匹配数量和置信度聚类,形成人物身份
## 配置参数
### 匹配阈值
```rust
// 默认匹配阈值
const DEFAULT_MATCH_THRESHOLD: f64 = 0.5;
// 最小置信度
const MIN_CONFIDENCE: f64 = 0.6;
```
### 数据库索引
系统自动创建以下索引以优化查询性能:
```sql
-- 时间范围查询
CREATE INDEX idx_person_appearances_time
ON person_appearances(video_uuid, start_time, end_time);
-- 人物查询
CREATE INDEX idx_person_identities_video_uuid
ON person_identities(video_uuid);
-- 说话人查询
CREATE INDEX idx_person_identities_speaker
ON person_identities(speaker_id);
```
## 最佳实践
### 1. 视频处理顺序
```bash
# 推荐:先处理基础特征,再识别人物
cargo run -- process video.mp4 --modules asr,asrx,face
```
### 2. 批量处理
```bash
# 批量处理多个视频
for video in /path/to/videos/*.mp4; do
cargo run -- process "$video" --modules asr,asrx,face
# 获取 UUID
uuid=$(basename "$video" .mp4)
# 自动识别人物
curl -X POST http://localhost:3002/api/v1/person/identify \
-H "Content-Type: application/json" \
-H "X-API-Key: your_api_key" \
-d "{\"video_uuid\": \"$uuid\", \"auto_match\": true}"
done
```
### 3. 人物标注工作流
```bash
# 1. 列出未确认的人物
curl -X GET "http://localhost:3002/api/v1/person/list?is_confirmed=false"
# 2. 查看人物出场片段
curl -X GET "http://localhost:3002/api/v1/person/person_xxx/timeline"
# 3. 确认并标注姓名
curl -X PATCH http://localhost:3002/api/v1/person/person_xxx \
-H "Content-Type: application/json" \
-d '{"name": "张三", "is_confirmed": true}'
```
## 故障排查
### 问题 1:匹配数量过低
**原因**:匹配阈值过高
**解决**:降低阈值到 0.3-0.5
```bash
curl -X POST http://localhost:3002/api/v1/person/identify \
-H "Content-Type: application/json" \
-d '{"video_uuid": "xxx", "match_threshold": 0.3}'
```
### 问题 2:人物身份重复
**原因**:同一人物被识别为多个身份
**解决**:使用 merge API 合并
```sql
-- 直接在数据库中合并
SELECT merge_person_identities(
'person_target',
ARRAY['person_source1', 'person_source2']
);
```
### 问题 3:时间轴查询慢
**原因**:缺少索引或数据量大
**解决**
1. 确认索引已创建:`\d person_appearances`
2. 使用 EXPLAIN 分析查询
3. 考虑分区表(按 video_uuid
## 性能优化
### 1. 批量插入
```rust
// 使用事务批量插入出场记录
pub async fn batch_insert_appearances(
db: &PostgresDb,
appearances: &[PersonAppearance],
) -> Result<()> {
let mut tx = db.pool().begin().await?;
for appearance in appearances {
sqlx::query("INSERT INTO ...")
.bind(...)
.execute(&mut *tx)
.await?;
}
tx.commit().await?;
Ok(())
}
```
### 2. 缓存策略
```rust
// 使用 Redis 缓存时间轴查询
let cache_key = format!("person_timeline:{}:{}", video_uuid, person_id);
if let Some(cached) = redis.get(&cache_key).await? {
return Ok(serde_json::from_str(&cached)?);
}
// 查询数据库并缓存
let timeline = query_from_db().await?;
redis.set_ex(&cache_key, &serde_json::to_string(&timeline)?, 300).await?;
```
## 监控指标
```rust
// Prometheus 指标
lazy_static! {
static ref PERSON_IDENTITIES_CREATED: Counter =
register_counter!("person_identities_created_total").unwrap();
static ref PERSON_MATCH_CONFIDENCE: Histogram =
register_histogram!("person_match_confidence").unwrap();
}
```
## 未来扩展
### 1. 多模态融合
- 结合 OCR(字幕、名牌)
- 结合场景分类
- 结合姿态识别
### 2. 跨视频追踪
- 全局人物身份库
- 人脸嵌入相似度匹配
- 服装特征识别
### 3. 实时处理
- 流式视频处理
- 实时人物识别
- WebSocket 推送更新
## 参考资料
- [InsightFace Documentation](https://github.com/deepinsight/insightface)
- [WhisperX Speaker Diarization](https://github.com/m-bain/whisperX)
- [PostgreSQL pgvector](https://github.com/pgvector/pgvector)
- [完整架构设计文档](./PERSON_IDENTITY_INTEGRATION.md)
@@ -0,0 +1,237 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Momentry Core 全域資源與處理管線架構 (v1.0)"
date: "2026-04-21"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "momentry"
- "core"
- "全域資源與處理管線架構"
ai_query_hints:
- "查詢 Momentry Core 全域資源與處理管線架構 (v1.0) 的內容"
- "Momentry Core 全域資源與處理管線架構 (v1.0) 的主要目的是什麼?"
- "如何操作或實施 Momentry Core 全域資源與處理管線架構 (v1.0)"
---
# Momentry Core 全域資源與處理管線架構 (v1.0)
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-21 |
| 文件版本 | V1.0 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-04-21 | 創建從檔案到知識的端到端處理管線架構 | OpenCode | OpenCode / Qwen3.6-Plus |
---
## 0. 設計目標
建立一套**標準化、可追溯、可擴展**的媒體處理管線,將原始媒體檔案自動轉化為結構化知識與可檢索內容。
核心原則:
1. **一切皆資源**: 檔案、處理器、服務、產出文件皆受資料庫納管。
2. **異步與容錯**: 註冊、處理、索引全階段解耦,支援斷點續傳與失敗重試。
3. **版本精確追溯**: 從模型 GGUF Hash 到處理器 Build Time,確保結果可重現。
4. **第一階段即時可用**: ASR/文本處理完成後立即提供 BM25/向量搜尋。
---
## 1. 大框架總覽:從檔案到知識
```
[原始檔案] (SFTP/API)
┌─────────────────────────────────────────────────────────┐
│ 階段一:檔案註冊納管作業 (Onboarding Pipeline) │
│ • Hash 計算 & UUID 分配 │
│ • ffprobe 探針分析 & 分類 │
│ • Smart Thumbnail (跳過黑屏截圖) │
│ • 狀態更新: CREATED → PENDING │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 階段二:處理器調度與執行作業 (Orchestration) │
│ • 排程器取出 PENDING 任務 │
│ • 查詢 Services Registry (確認 Ollama/GPU/Qdrant 在線) │
│ • 分配 Processors (Python/Shell/CLI/Docker) │
│ • 執行 ASR / OCR / Face / Yolo / 向量嵌入 │
│ • 狀態更新: PENDING → PROCESSING → COMPLETED/FAILED │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 階段三:產出解析與索引建立 (Output & Indexing) │
│ • 解析標準化 JSON 產出 (Pre-Chunks, Frames) │
│ - Pre-Chunk: 以 frame 為基準的區間 (start_frame, end_frame) │
│ - Frame: 單幀偵測數據 (frame_number) │
│ • 參考時間換算: timestamp_sec = frame / probe_fps │
│ • 存入 Raw Data Tables (segments, detections) │
│ • Chunk 聚合: 依據 Rule 1/2/3 將 Pre-Chunk 組裝為 Chunk │
│ • 向量嵌入: 呼叫 Embedding Service (nomic-v2-moe) │
│ • 寫入 Qdrant 建立索引 │
│ • 狀態更新: INDEXING → READY (可搜尋) │
└─────────────────────────────────────────────────────────┘
[搜尋 API / Portal / N8N Webhooks]
```
---
## 2. 階段一:檔案註冊納管作業 (Onboarding)
將陌生媒體轉化為系統可識別的標準資產。
### 2.1 `assets` 表設計
```sql
CREATE TABLE assets (
id UUID PRIMARY KEY,
file_path TEXT NOT NULL,
file_hash VARCHAR(64) UNIQUE NOT NULL, -- SHA-256 防重複
asset_type VARCHAR(20), -- video, audio, image
media_info JSONB, -- ffprobe 原始輸出
status VARCHAR(20) DEFAULT 'CREATED', -- 狀態機核心欄位
metadata JSONB, -- 標題、語言、來源標籤
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
```
### 2.2 核心流程
1. **上傳/偵測**: SFTPGo 觸發 Webhook 或用戶透過 API 上傳。
2. **探針分析**: `ffprobe` 提取解析度、幀率、音軌、編碼、時長。
3. **智能預處理**: 呼叫 `Smart Thumbnail` 處理器,跳過片頭黑屏,提取正片首幀。
4. **分類標記**: 根據探針結果自動標記類型(如 `duration > 300s` 標記為 `long_form`)。
5. **入隊**: 狀態轉為 `PENDING`,寫入 Redis 任務隊列 `queue:processing`
---
## 3. 階段二:處理器調度與執行作業 (Orchestration)
排程器根據資源可用性與任務優先級,動態分配處理器。
### 3.1 排程邏輯 (Scheduler)
```sql
-- 取出可執行的任務
SELECT * FROM tasks
WHERE status = 'queued'
AND required_services <@ (SELECT id FROM services WHERE status = 'online')
ORDER BY priority DESC, created_at ASC
LIMIT 1;
```
### 3.2 執行標準化介面
所有處理器接收統一參數,確保多態兼容:
| 參數 | 說明 | 範例 |
|:---|:---|:---|
| `--uuid` | 任務唯一標識 | `--uuid 384b0ff4...` |
| `--input` | 輸入媒體路徑 | `--input /data/raw/charade.mov` |
| `--output` | 產出目錄 | `--output /data/output/384b...` |
| `--config` | (選填) 執行配置 | `--config model_config.json` |
### 3.3 資源依賴檢查
執行前,排程器驗證 `services` 表:
- ASR 需要 `llm_engine` 或本地 GPU。
- 向量嵌入需要 `embedding_engine` (Ollama nomic-v2-moe) 在線。
- 若依賴服務離線,任務自動降級或進入 `retry_queue`
*(詳細處理器註冊與多態設計請見 `PROCESSOR_REGISTRY_ARCHITECTURE.md`)*
---
## 4. 階段三:產出管理與第一階段搜尋
處理完成後,系統自動將非結構化 JSON 轉化為可檢索的結構化數據。
### 4.1 產出文件規範:Pre-Chunk 與 Frame
所有處理器產出之 JSON 皆基於 **Frame (幀)** 為時間權威單位。
- **時間計算**: `timestamp = frame_number / fps` (fps 來自 ffprobe)。
- **Pre-Chunk**: 具持續時間的片段 (如 ASR 語句),記錄 `start_frame`, `end_frame`
- **Frame**: 單幀偵測數據 (如 Face, OCR),記錄 `frame_number`
- **命名**: `{asset_uuid}_{processor_type}_{timestamp}.json`
### 4.2 數據解析與落庫
| 處理器產出 | 數據類型 | 對應 DB 表 | 搜尋能力 |
|------------|----------|------------|----------|
| `asr.json` | Pre-Chunk | `segments` | 語音關鍵字 BM25、說話者過濾 |
| `ocr.json` | Frame | `visual_texts` | 畫面文字搜尋、浮水印過濾 |
| `face.json` | Frame | `face_detections` | 人物出現時間軸、身份匹配 |
| `chunks.json` | Pre-Chunk | `chunks` + `parent_chunks` | 語意搜尋、父子關聯檢索 |
### 4.3 向量索引建立
1. 提取文本內容 (ASR + OCR + Chunk Summary)。
2. 呼叫 `embedding_engine` 服務 (`nomic-embed-text-v2-moe`) 生成 768-dim 向量。
3. 寫入 Qdrant Collection (`momentry_rule1`, `rule2`, `rule3`)。
4. 狀態更新至 `READY`,觸發 Webhook 通知使用者。
---
## 5. 底層支撐:服務與處理器註冊中心
管線的高效運行依賴於兩個註冊中心的動態協調:
### 5.1 服務註冊中心 (`services`)
管理底層基礎設施 (Ollama, Qdrant, Redis, SFTPGo)。
- **健康監控**: 定期探活 `/health`,自動標記 `offline`
- **配置動態注入**: 處理器不需寫死 IP/Key,啟動時從註冊中心讀取。
- **備份與路徑**: 統一管理 `storage_paths``backup_policy`
*(詳細服務註冊設計請見 `SERVICE_REGISTRY_ARCHITECTURE.md`)*
### 5.2 處理器註冊中心 (`processors`)
管理執行邏輯與腳本 (ASR, OCR, Face, Thumbnail)。
- **多態執行**: 支援 Python, Shell, CLI, Docker, HTTP。
- **產出驗證**: 定義 `output_spec` JSON Schema,確保下游解析不崩潰。
- **版本追溯**: 記錄 `version``build_time`,支持結果重現與比對。
---
## 6. 狀態機與異常處理 (State Machine)
```mermaid
stateDiagram-v2
[*] --> CREATED: 檔案上傳
CREATED --> PREPARING: 開始探針分析
PREPARING --> PENDING: 預處理完成
PENDING --> PROCESSING: 排程器分配處理器
PROCESSING --> INDEXING: 處理器產出 JSON
INDEXING --> READY: 向量/全文索引完成
PROCESSING --> FAILED: 超時/依賴服務離線
FAILED --> PENDING: 自動重試 (Max 3次)
READY --> [*]: 可對外提供 API
```
### 容錯機制
- **心跳超時**: 處理器每 30s 寫入 Redis `progress:{uuid}`,超時則判定為假死並 Kill。
- **依賴降級**: 若 Ollama 離線,可跳過 Vector 索引,僅保留 BM25 搜尋 (功能降級但不中斷)。
- **產出校驗**: JSON 寫入前驗證 `output_spec`,損壞檔案觸發重新處理。
---
## 7. 總結
本架構確立了 Momentry Core 的端到端資料流:
| 階段 | 核心動作 | 產出物 | 關鍵技術 |
|------|----------|--------|----------|
| **納管** | Hash / Probe / Thumbnail | `assets` 記錄 | `ffprobe`, `blackdetect` |
| **調度** | 依賴檢查 / 多態分發 | 執行進程 | Redis Queue, Service Registry |
| **處理** | AI 推論 / 特徵提取 | 標準化 JSON | WhisperX, EasyOCR, InsightFace |
| **索引** | 解析 / Embedding / 寫入 | BM25 + Vector | `nomic-v2-moe`, Qdrant, PGVector |
| **服務** | 健康檢查 / 配置注入 | 高可用叢集 | Health Check Worker, Backup Policy |
此設計將「檔案」、「處理器」、「服務」三大維度統一納管,實現了從原始媒體到智能搜尋的完全自動化與可追溯性。
@@ -0,0 +1,521 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Playground 開發架構隔離規劃"
date: "2026-03-31"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "開發架構隔離規劃"
- "playground"
ai_query_hints:
- "查詢 Playground 開發架構隔離規劃 的內容"
- "Playground 開發架構隔離規劃 的主要目的是什麼?"
- "如何操作或實施 Playground 開發架構隔離規劃?"
---
# Playground 開發架構隔離規劃
| 項目 | 內容 |
|------|------|
| 建立者 | Warren |
| 建立時間 | 2026-03-31 |
| 文件版本 | V1.0 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-03-31 | 創建 Playground 隔離架構規劃 | Warren | OpenCode |
---
## 概述
本文檔說明 Momentry Core Playground(開發環境)的隔離架構規劃,確保開發測試環境與正式生產環境的數據能夠完整隔離,避免測試數據污染生產數據。
Playground 是 `momentry` 專案的開發專用二進制文件(binary),設計用於本地開發和功能測試,與生產環境(Production)使用不同的配置和資源池。
---
## 當前狀態
| 項目 | 狀態 |
|------|------|
| Redis 隔離 | ✅ 已隔離 |
| File System 隔離 | ✅ 已隔離 |
| PostgreSQL Schema 隔離 | 🔄 待實現 |
| MongoDB Database 隔離 | 🔄 待實現 |
| Qdrant Collection 隔離 | 🔄 待實現 |
---
## 隔離架構總覽
### 當前架構(部分隔離)
```
┌─────────────────────────────────────────────────────────────────┐
│ Playground (Development) 現況 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Playground │ │ Production │ │
│ │ Server │ │ Server │ │
│ │ Port:3003 │ │ Port:3002 │ │
│ │ │ │ │ │
│ │ Redis: │ │ Redis: │ │
│ │ momentry_dev│ │ momentry: │◀── 隔離 ✅ │
│ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │
│ │ ┌───────────────┴───────────────┐ │
│ │ │ 共享資源 │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ PostgreSQL │ │ MongoDB │ │ Qdrant │ │
│ │ momentry │ │ momentry │ │ momentry_rule1 │ │
│ │ (同一DB) │ │ (同一DB) │ │ (同一collection) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
│ │ │ │ │
│ └────────────────────┴────────────────────┘ │
│ │ ❌ 未隔離 │
│ ▼ │
│ 數據混合污染風險 │
└─────────────────────────────────────────────────────────────────┘
```
### 規劃中的隔離架構
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ Playground 完整隔離架構 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────┐ ┌─────────────────────────────────┐ │
│ │ Development (Playground) │ │ Production │ │
│ │ Port: 3003 │ │ Port: 3002 │ │
│ │ Binary: debug │ │ Binary: release │ │
│ │ Worker: disabled │ │ Worker: enabled │ │
│ └──────────────┬──────────────┘ └──────────────┬────────────────┘ │
│ │ │ │
│ │ ┌──────────────────────────────────┴──────────────┐ │
│ │ │ 共享基礎設施 │ │
│ │ └──────────────────────────────────┬──────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌────────────────────┐ ┌───────────────────────────────┐ │
│ │ PostgreSQL Schema │ │ PostgreSQL Schema │ │
│ │ (dev schema) │ │ (public schema) │ │
│ ├────────────────────┤ ├───────────────────────────────┤ │
│ │ videos_dev │ │ videos │ │
│ │ chunks_dev │ │ chunks │ │
│ │ pre_chunks_dev │ │ pre_chunks │ │
│ │ frames_dev │ │ frames │ │
│ │ processor_results │ (隔離 ✅) │ processor_results │ │
│ │ file_registry_dev │ │ file_registry │ │
│ │ face_*_dev │ │ face_* │ │
│ ├────────────────────┤ ├───────────────────────────────┤ │
│ │ 可共享: │ │ 可共享: │ │
│ │ api_keys (獨立的) │ │ api_keys │ │
│ │ monitor_* │ │ monitor_* │ │
│ │ backup_* │ │ backup_* │ │
│ └────────────────────┘ └───────────────────────────────┘ │
│ │
│ ┌────────────────────┐ ┌───────────────────────────────┐ │
│ │ MongoDB │ │ MongoDB │ │
│ │ Database: │ │ Database: │ │
│ │ momentry_dev │ (隔離 ✅) │ momentry │ │
│ ├────────────────────┤ ├───────────────────────────────┤ │
│ │ - chunks │ │ - chunks │ │
│ │ - cache │ │ - cache │ │
│ └────────────────────┘ └───────────────────────────────┘ │
│ │
│ ┌────────────────────┐ ┌───────────────────────────────┐ │
│ │ Qdrant │ │ Qdrant │ │
│ │ Collection: │ │ Collection: │ │
│ │ momentry_dev_ │ (隔離 ✅) │ momentry_rule1 │ │
│ │ rule1 │ │ │ │
│ └────────────────────┘ └───────────────────────────────┘ │
│ │
│ ┌────────────────────┐ ┌───────────────────────────────┐ │
│ │ Redis │ │ Redis │ │
│ │ Prefix: │ (已有 ✅) │ Prefix: │ │
│ │ momentry_dev: │ │ momentry: │ │
│ └────────────────────┘ └───────────────────────────────┘ │
│ │
│ ┌────────────────────┐ ┌───────────────────────────────┐ │
│ │ File System │ (已有 ✅) │ File System │ │
│ │ /output_dev │ │ /output │ │
│ │ /backup_dev │ │ /backup/momentry │ │
│ └────────────────────┘ └───────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
---
## 隔離矩陣
| 資源 | Production | Development | 隔離狀態 | 隔離方式 |
|------|-----------|-------------|---------|---------|
| **API Server** | Port 3002 | Port 3003 | ✅ | 環境變數配置 |
| **Redis Prefix** | `momentry:` | `momentry_dev:` | ✅ | 環境變數配置 |
| **File Output** | `/Users/accusys/momentry/output` | `/Users/accusys/momentry/output_dev` | ✅ | 環境變數配置 |
| **File Backup** | `/Users/accusys/momentry/backup/momentry` | `/Users/accusys/momentry/backup/momentry_dev` | ✅ | 環境變數配置 |
| **PostgreSQL** | `public` schema | `dev` schema | ❌ | Schema 隔離 |
| **MongoDB** | `momentry` database | `momentry_dev` database | ❌ | Database 隔離 |
| **Qdrant** | `momentry_rule1` collection | `momentry_dev_rule1` collection | ❌ | Collection 隔離 |
---
## 需要隔離的數據表
### PostgreSQL(使用 Schema 隔離)
#### 需要隔離的表(放入 dev schema)
| 表名 | 說明 |
|------|------|
| `videos` | 視頻記錄 |
| `chunks` | 區塊數據 |
| `pre_chunks` | 預處理區塊 |
| `chunk_vectors` | 向量數據 |
| `frames` | 幀數據 |
| `processor_results` | 處理器結果 |
| `file_registry` | 文件註冊 |
| `file_lifecycle` | 文件生命周期 |
| `face_clusters` | 人臉聚類 |
| `face_detections` | 人臉檢測 |
| `face_identities` | 人臉身份 |
| `face_recognition_results` | 人臉識別結果 |
#### 可共享的表(留在 public schema
| 表名 | 說明 |
|------|------|
| `api_keys` | API 金鑰(使用獨立的 Development API Key |
| `api_key_audit_log` | API 金鑰審計日誌 |
| `api_key_anomalies` | API 金鑰異常 |
| `monitor_*` | 所有監控相關表 |
| `backup_*` | 備份記錄表 |
| `gitea_tokens` | Gitea API Token |
| `n8n_api_keys` | n8n API 金鑰 |
| `node_*` | 節點相關表 |
| `python_*` | Python 版本基線 |
| `storage_*` | 存儲統計表 |
| `v_idle_workflows` | 空閒工作流視圖 |
| `v_recent_anomalies` | 最近異常視圖 |
| `v_service_health` | 服務健康視圖 |
| `v_storage_overview` | 存儲概覽視圖 |
---
## 配置對比
### 環境變數對比
| 變數 | Production (.env) | Development (.env.development) |
|------|------------------|------------------------------|
| `MOMENTRY_SERVER_PORT` | 3002 | 3003 |
| `MOMENTRY_REDIS_PREFIX` | `momentry:` | `momentry_dev:` |
| `MOMENTRY_OUTPUT_DIR` | `/Users/accusys/momentry/output` | `/Users/accusys/momentry/output_dev` |
| `MOMENTRY_BACKUP_DIR` | `/Users/accusys/momentry/backup/momentry` | `/Users/accusys/momentry/backup/momentry_dev` |
| `DATABASE_URL` | `postgres://accusys@localhost:5432/momentr` | `postgres://accusys@localhost:5432/momentry` |
| `MONGODB_URL` | `mongodb://localhost:27017` | `mongodb://localhost:27017` |
| `QDRANT_URL` | `http://localhost:6333` | `http://localhost:6333` |
| `QDRANT_COLLECTION` | `momentry_rule1` | `momentry_dev_rule1` |
| `RUST_LOG` | info | debug |
| `MOMENTRY_WORKER_ENABLED` | true | false |
### 二進制對比
| 屬性 | Production | Playground |
|------|-----------|------------|
| Binary Name | `momentry` | `momentry_playground` |
| Build Mode | release | debug |
| Port | 3002 | 3003 |
| Config File | `.env` | `.env.development` |
---
## 實施步驟
### Step 1: 修改配置檔案
#### 更新 `.env.development`
在現有配置中添加數據庫隔離相關變數:
```bash
# Database Schema (PostgreSQL)
DATABASE_SCHEMA=dev
# MongoDB Database
MONGODB_DATABASE=momentry_dev
# Qdrant Collection
QDRANT_COLLECTION=momentry_dev_rule1
```
---
### Step 2: 修改代碼支持 Schema 切換
#### 2.1 更新 `src/core/config.rs`
添加新的配置項:
```rust
pub static DEV_SCHEMA: Lazy<String> = Lazy::new(|| {
env::var("DATABASE_SCHEMA").unwrap_or_else(|_| "dev".to_string())
});
pub static DEV_DATABASE: Lazy<String> = Lazy::new(|| {
env::var("MONGODB_DATABASE").unwrap_or_else(|_| "momentry_dev".to_string())
});
pub static DEV_QDRANT_COLLECTION: Lazy<String> = Lazy::new(|| {
env::var("QDRANT_COLLECTION").unwrap_or_else(|_| "momentry_dev_rule1".to_string())
});
```
#### 2.2 更新 `src/core/db/postgres_db.rs`
在查詢方法中添加 schema 參數支持:
```rust
// 在連接配置中使用 schema
let schema = DEV_SCHEMA.as_str();
let query = format!("SET search_path TO {}", schema);
sqlx::query(&query).execute(&pool).await?;
```
#### 2.3 更新 `src/core/db/mongodb.rs`
支持數據庫切換:
```rust
let database_name = DEV_DATABASE.as_str();
let database = client.database(database_name);
```
#### 2.4 更新 `src/core/db/qdrant_db.rs`
支持 collection 切換:
```rust
let collection_name = DEV_QDRANT_COLLECTION.as_str();
```
---
### Step 3: 創建開發環境數據庫
#### 3.1 PostgreSQL - 創建 Schema
```bash
# 連接 PostgreSQL
psql -U accusys -d momentry
# 創建 dev schema
CREATE SCHEMA IF NOT EXISTS dev;
# 將現有表的結構復製到 dev schema
CREATE TABLE dev.videos AS SELECT * FROM public.videos WHERE 1=0;
CREATE TABLE dev.chunks AS SELECT * FROM public.chunks WHERE 1=0;
-- ... 其他表
```
#### 3.2 MongoDB - 創建 Database
```bash
# 複製數據到開發數據庫
use admin
db.copyDatabase('momentry', 'momentry_dev')
```
#### 3.3 Qdrant - 創建 Collection
```bash
# 使用 Qdrant API 創建新的 collection
curl -X PUT 'http://localhost:6333/collections/momentry_dev_rule1' \
-H 'api-key: Test3200Test3200Test3200' \
-H 'Content-Type: application/json' \
-d '{
"vectors": {
"size": 1024,
"distance": "Cosine"
}
}'
```
---
### Step 4: 驗證隔離效果
#### 4.1 啟動服務驗證
```bash
# Terminal 1: 啟動 Production Server
cargo run --bin momentry -- server --port 3002
# Terminal 2: 啟動 Playground Server
cargo run --bin momentry_playground -- server --port 3003
```
#### 4.2 數據隔離驗證
```bash
# 驗證 Redis 隔離
redis-cli KEYS "momentry:job:*"
redis-cli KEYS "momentry_dev:job:*"
# 驗證 PostgreSQL Schema
psql -U accusys -d momentry -c "\dt dev.*"
psql -U accusys -d momentry -c "\dt public.*"
# 驗證 MongoDB
mongosh --eval "db.adminCommand('listDatabases')" | grep momentry
# 驗證 Qdrant
curl -s -H "api-key: Test3200Test3200Test3200" \
'http://localhost:6333/collections' | jq '.result[].name'
```
---
## 檔案位置
| 類型 | 路徑 | 說明 |
|------|------|------|
| Production Config | `/Users/accusys/momentry_core_0.1/.env` | 生產環境配置 |
| Development Config | `/Users/accusys/momentry_core_0.1/.env.development` | 開發環境配置 |
| Binary | `/Users/accusys/momentry_core_0.1/src/playground.rs` | Playground 二進制源碼 |
| Config Module | `/Users/accusys/momentry_core_0.1/src/core/config.rs` | 配置模組 |
| PostgreSQL Module | `/Users/accusys/momentry_core_0.1/src/core/db/postgres_db.rs` | PostgreSQL 模組 |
| MongoDB Module | `/Users/accusys/momentry_core_0.1/src/core/db/mongodb.rs` | MongoDB 模組 |
| Qdrant Module | `/Users/accusys/momentry_core_0.1/src/core/db/qdrant_db.rs` | Qdrant 模組 |
---
## 常用指令
### 啟動服務
```bash
# 啟動 Production Server
cargo run --bin momentry -- server
# 啟動 Playground Server
cargo run --bin momentry_playground -- server
# 指定 Port
cargo run --bin momentry_playground -- server --port 3003
# 啟動 Worker (Production)
cargo run --bin momentry -- worker --max-concurrent 2
```
### 驗證隔離
```bash
# 驗證 Redis 隔離
redis-cli KEYS "momentry:*"
redis-cli KEYS "momentry_dev:*"
# 驗證 PostgreSQL Schema
psql -U accusys -d momentry -c "\dt dev.*"
psql -U accusys -d momentry -c "\dt public.*"
# 驗證文件系統隔離
ls -la /Users/accusys/momentry/output/
ls -la /Users/accusys/momentry/output_dev/
```
### 數據庫操作
```bash
# 連接 PostgreSQL
psql -U accusys -d momentry
# 切換 Schema
SET search_path TO dev;
# 列出 Schema 表
\dt
# MongoDB 數據庫列表
mongosh --eval "db.adminCommand('listDatabases')"
# 切換 MongoDB 數據庫
use momentry_dev
db.chunks.countDocuments()
```
---
## 版本資訊
- 版本: V1.0
- 建立日期: 2026-03-31
- 文件更新: 2026-03-31
---
## 相關文件
| 文件 | 說明 |
|------|------|
| `PLAYGROUND_BINARY_IMPLEMENTATION.md` | Playground 二進制實現計劃 |
| `SERVICES.md` | 服務端口分配 |
| `MOMENTRY_CORE_REDIS_KEYS.md` | Redis Key 設計規範 |
| `AGENTS.md` | AI 代理執行指令 |
| `DOCS_STANDARD.md` | 文件創建規範 |
---
## 附錄:AI Agent 友好資訊
### 可用 Tools
| Tool | 用途 |
|------|------|
| `postgres_query` | 執行 PostgreSQL 查詢 |
| `mongodb_*` | MongoDB 操作 |
| `redis_*` | Redis 操作 |
| `qdrant_qdrant-*` | Qdrant 向量數據庫操作 |
### 數據庫 Schema
#### PostgreSQL Tables (dev schema)
```
videos, chunks, pre_chunks, chunk_vectors, frames,
processor_results, file_registry, file_lifecycle,
face_clusters, face_detections, face_identities,
face_recognition_results
```
#### MongoDB Collections
```
momentry_dev: chunks, cache
```
#### Qdrant Collections
```
momentry_dev_rule1
```
### 環境變數
```
MOMENTRY_SERVER_PORT, MOMENTRY_REDIS_PREFIX,
DATABASE_SCHEMA, MONGODB_DATABASE, QDRANT_COLLECTION,
MOMENTRY_OUTPUT_DIR, MOMENTRY_BACKUP_DIR
```
@@ -0,0 +1,392 @@
# Playground Binary Implementation Plan
| Item | Content |
|------|---------|
| Author | Warren |
| Created | 2026-03-23 |
| Document Version | V1.0 |
---
## Version History
| Version | Date | Purpose | Operator | Tool/Model |
|---------|------|---------|----------|------------|
| V1.0 | 2026-03-23 | Create implementation plan | Warren | OpenCode |
---
## Overview
Create separate `momentry_playground` binary with distinct configuration from `momentry` (production).
| Aspect | Production (`momentry`) | Development (`momentry_playground`) |
|--------|------------------------|-------------------------------------|
| **Port** | 3002 | 3003 |
| **Redis Prefix** | `momentry:` | `momentry_dev:` |
| **Worker** | Enabled | Disabled |
| **Purpose** | Production deployment | Testing/Development |
---
## Files to Modify
```
Files Changed: 6 files (+1 new)
├── src/core/config.rs ← Add server_port(), redis_key_prefix()
├── src/core/db/redis_client.rs ← Replace hardcoded prefixes
├── src/core/cache/redis_cache.rs ← Use configurable prefix
├── src/main.rs ← Update CLI defaults
├── src/playground.rs ← NEW: Development binary
├── Cargo.toml ← Add new binary
└── .env.development ← NEW: Dev environment config
```
---
## Implementation Steps
### Step 1: Update `src/core/config.rs`
Add after line 51 (after `MEDIA_BASE_URL`):
```rust
pub static SERVER_PORT: Lazy<u16> = Lazy::new(|| {
env::var("MOMENTRY_SERVER_PORT")
.unwrap_or_else(|_| "3002".to_string())
.parse()
.unwrap_or(3002)
});
pub static REDIS_KEY_PREFIX: Lazy<String> = Lazy::new(|| {
env::var("MOMENTRY_REDIS_PREFIX")
.unwrap_or_else(|_| "momentry:".to_string())
});
```
---
### Step 2: Update `src/core/db/redis_client.rs`
Replace all hardcoded `momentry:` prefixes with configurable prefix.
**Import at top:**
```rust
use crate::core::config::REDIS_KEY_PREFIX;
```
**Pattern for each method:**
```rust
let prefix = REDIS_KEY_PREFIX.as_str();
let key = format!("{}job:{}", prefix, uuid);
```
**Affected lines:**
| Line | Key Pattern |
|------|-------------|
| 47 | `job:{uuid}` |
| 81, 109 | `job:{uuid}:processor:{processor}` |
| 136, 146 | `progress:{uuid}` |
| 172 | `jobs:active` |
| 179 | `jobs:active``jobs:completed` |
| 187 | `jobs:active``jobs:failed` |
| 194 | `jobs:active` |
| 201, 208 | `health:momentry_core` |
| 214 | `monitor:job:{uuid}` |
| 242, 300 | `errors:{uuid}` |
| 258, 281 | `anomaly:alerts`, `anomaly:key:{key_id}` |
| 317, 346, 364, 392, 397 | `worker:job:{uuid}...` |
| 406, 410 | `worker:job:*` |
---
### Step 3: Update `src/core/cache/redis_cache.rs`
**Import:**
```rust
use crate::core::config::REDIS_KEY_PREFIX;
```
**Replace line 10:**
```rust
// Remove: const KEY_PREFIX: &str = "momentry:cache:";
```
**Update `prefixed_key` method (line 24):**
```rust
fn prefixed_key(&self, key: &str) -> String {
format!("{}cache:{}", REDIS_KEY_PREFIX.as_str(), key)
}
```
**Update tests (lines 161-162):**
```rust
#[test]
fn test_prefixed_key() {
// Note: This test will use the configured prefix
let cache = RedisCache::new().unwrap();
// With default prefix "momentry:"
assert_eq!(cache.prefixed_key("test"), "momentry:cache:test");
assert_eq!(cache.prefixed_key("video:abc"), "momentry:cache:video:abc");
}
```
---
### Step 4: Update `src/main.rs`
**Change CLI defaults (Lines 691-695):**
```rust
// Before:
#[arg(long, default_value = "3000")]
port: u16,
// After:
#[arg(long)]
port: Option<u16>,
```
**Update Server match arm (around line 2398):**
```rust
Commands::Server { host, port } => {
let port = port.unwrap_or_else(|| *crate::core::config::SERVER_PORT);
momentry_core::api::start_server(&host, port).await?;
Ok(())
}
```
**Update Redis key usage (Line 1098):**
```rust
// Before:
let key = format!("momentry:job:{}:processor:{}", uuid, processor);
// After:
let key = format!(
"{}job:{}:processor:{}",
crate::core::config::REDIS_KEY_PREFIX.as_str(),
uuid,
processor
);
```
---
### Step 5: Create `src/playground.rs`
```rust
use anyhow::{Context, Result};
use clap::{Parser, Subcommand};
// ... same imports as main.rs ...
fn main() -> Result<()> {
// Load development environment first
dotenv::from_filename(".env.development").ok();
tracing_subscriber::fmt::init();
tracing::info!("Starting momentry_playground (development binary)");
tracing::info!("Port: {}", *momentry_core::core::config::SERVER_PORT);
tracing::info!("Redis prefix: {}", *momentry_core::core::config::REDIS_KEY_PREFIX);
let cli = Cli::parse();
// ... rest identical to main.rs ...
}
```
---
### Step 6: Update `Cargo.toml`
**Add after line 90:**
```toml
[[bin]]
name = "momentry_playground"
path = "src/playground.rs"
```
**Add dependency (if not present):**
```toml
dotenv = "0.15"
```
---
### Step 7: Create `.env.development`
```bash
# Development Environment Configuration
# Used by: momentry_playground binary
# Server Configuration
MOMENTRY_SERVER_PORT=3003
MOMENTRY_REDIS_PREFIX=momentry_dev:
# Worker Configuration (disabled for development)
MOMENTRY_WORKER_ENABLED=false
MOMENTRY_MAX_CONCURRENT=1
MOMENTRY_POLL_INTERVAL=10
# Database (can use separate dev database)
DATABASE_URL=postgres://accusys@localhost:5432/momentry
MONGODB_URL=mongodb://accusys:Test3200Test3200@localhost:27017/admin
# Redis
REDIS_URL=redis://:accusys@localhost:6379
```
---
### Step 8: Update `.env` (Production)
Add these lines:
```bash
# Production Environment Configuration
# Used by: momentry binary
# Server Configuration
MOMENTRY_SERVER_PORT=3002
MOMENTRY_REDIS_PREFIX=momentry:
# Worker Configuration
MOMENTRY_WORKER_ENABLED=true
MOMENTRY_MAX_CONCURRENT=2
MOMENTRY_POLL_INTERVAL=5
```
---
## Testing Checklist
### 1. Build and Run Production Binary
```bash
cargo build --release --bin momentry
cargo run --bin momentry -- server
# Expected: Listening on http://127.0.0.1:3002
cargo run --bin momentry -- worker
# Expected: Worker started with momentry: prefix
```
### 2. Build and Run Development Binary
```bash
cargo build --bin momentry_playground
cargo run --bin momentry_playground -- server
# Expected: Listening on http://127.0.0.1:3003
```
### 3. Verify Redis Key Isolation
```bash
# Production data
redis-cli KEYS "momentry:*"
# Development data
redis-cli KEYS "momentry_dev:*"
# Should be separate
```
### 4. Run Both Simultaneously
```bash
# Terminal 1: Production
cargo run --bin momentry -- server
# Terminal 2: Development
cargo run --bin momentry_playground -- server
# Both should run without port conflicts
```
### 5. Unit Tests
```bash
cargo test --lib
# All tests should pass
```
---
## Redis Key Structure
### Production (`momentry:`)
```
momentry:job:{uuid} # Job status
momentry:job:{uuid}:processor:{name} # Processor progress
momentry:progress:{uuid} # Progress pub/sub
momentry:jobs:active # Active job set
momentry:jobs:completed # Completed job set
momentry:jobs:failed # Failed job set
momentry:health:momentry_core # Health status
momentry:cache:{key} # Cache entries
momentry:worker:job:{uuid} # Worker job
momentry:worker:job:{uuid}:processor:{name}
```
### Development (`momentry_dev:`)
```
momentry_dev:job:{uuid}
momentry_dev:job:{uuid}:processor:{name}
momentry_dev:progress:{uuid}
momentry_dev:jobs:active
momentry_dev:jobs:completed
momentry_dev:jobs:failed
momentry_dev:health:momentry_core
momentry_dev:cache:{key}
momentry_dev:worker:job:{uuid}
momentry_dev:worker:job:{uuid}:processor:{name}
```
---
## Potential Issues & Solutions
| Issue | Solution |
|-------|----------|
| `dotenv` crate not in dependencies | Add to Cargo.toml |
| Tests use hardcoded prefix | Update tests to use config, or use `#[cfg(test)]` defaults |
| Worker starts in playground | Check `MOMENTRY_WORKER_ENABLED=false` in `.env.development` |
| Port already in use | Graceful error message with suggestion to use `--port` flag |
| Mixed data in Redis | Ensure prefix is loaded before any Redis operations |
---
## Files Summary
| File | Lines Changed | Purpose |
|------|---------------|---------|
| `src/core/config.rs` | +15 | Add SERVER_PORT and REDIS_KEY_PREFIX |
| `src/core/db/redis_client.rs` | ~50 | Replace hardcoded prefixes |
| `src/core/cache/redis_cache.rs` | ~10 | Use configurable prefix |
| `src/main.rs` | ~15 | Update CLI defaults, Redis key usage |
| `src/playground.rs` | NEW (~2800) | Development binary |
| `Cargo.toml` | +4 | Add binary definition |
| `.env.development` | NEW (~20) | Development environment |
**Total**: ~60 lines modified + ~2800 lines new file
---
## Reference Documents
| Document | Purpose |
|----------|---------|
| `docs/SERVICES.md` | Port allocations |
| `docs/MOMENTRY_CORE_REDIS_KEYS.md` | Redis key design |
| `AGENTS.md` | Code style and conventions |
---
## Version History
| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 1.0 | 2025-03-25 | OpenCode | Initial implementation plan |
@@ -0,0 +1,318 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Video Processing Pipeline - 處理流程"
date: "2026-03-22"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "processing"
- "video"
- "pipeline"
- "處理流程"
ai_query_hints:
- "查詢 Video Processing Pipeline - 處理流程 的內容"
- "Video Processing Pipeline - 處理流程 的主要目的是什麼?"
- "如何操作或實施 Video Processing Pipeline - 處理流程?"
---
# Video Processing Pipeline - 處理流程
| 項目 | 內容 |
|------|------|
| 建立者 | Warren |
| 建立時間 | 2026-03-22 |
| 文件版本 | V1.1 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-03-22 | 創建文件 | Warren | OpenCode |
| V1.1 | 2026-03-26 | 更新流程圖文字 (media_url→file_path) | OpenCode | deepseek-reasoner |
---
## 處理流程架構
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ Video Processing Pipeline │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Stage 1: JSON 生成 (Process) │ │
│ │ │ │
│ │ video.mp4 ──→ [ASR] ──→ asr.json (語音辨識) │ │
│ │ ──→ [CUT] ──→ cut.json (場景偵測) │ │
│ │ ──→ [ASRX] ──→ asrx.json (說話者分離) │ │
│ │ ──→ [YOLO] ──→ yolo.json (物體偵測) │ │
│ │ ──→ [OCR] ──→ ocr.json (文字辨識) │ │
│ │ ──→ [Face] ──→ face.json (人臉偵測) │ │
│ │ ──→ [Pose] ──→ pose.json (姿態估計) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Stage 2: 入庫 (Import) │ │
│ │ │ │
│ │ .json files ──→ PostgreSQL (fs_json = true) │ │
│ │ ↓ │ │
│ │ pre_chunks 表 (from ASR, CUT) │ │
│ │ frames 表 (from YOLO, OCR, Face, Pose) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Stage 3: Chunk 生成 (Chunk) │ │
│ │ │ │
│ │ pre_chunks ──→ [Chunk Rule] ──→ chunks 表 │ │
│ │ ↓ │ │
│ │ 清洗 → 純文字 │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Stage 4: 向量化 (Vectorize) │ │
│ │ │ │
│ │ chunks ──→ [Embedding Model] ──→ vectors │ │
│ │ ↓ │ │
│ │ Qdrant (主要向量庫) │ │
│ │ PGVector (備份向量庫) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Stage 5: 搜尋 (Search) │ │
│ │ │ │
│ │ Natural Language Query ──→ [Embedding] ──→ [Qdrant Search] │ │
│ │ ↓ │ │
│ │ 返回結果含 file_path │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
---
## CLI 命令
### Stage 1: JSON 生成 (Process)
```bash
# 基本用法
cargo run --bin momentry -- process <uuid_or_path>
# 只處理特定模組
cargo run --bin momentry -- process <uuid> --modules asr,cut
# 強制重新處理(忽略完整性檢查)
cargo run --bin momentry -- process <uuid> --force
# 從中斷點續傳
cargo run --bin momentry -- process <uuid> --resume
# 模組使用雲端處理
cargo run --bin momentry -- process <uuid> --modules yolo,face --cloud yolo
# 完整範例
cargo run --bin momentry -- process /path/to/video.mp4 \
--modules asr,cut,yolo,ocr \
--cloud yolo
```
### Stage 2: 入庫 (Import)
```bash
# 目前入庫在 process 完成後自動執行
# 計劃新增獨立的 import 命令
# cargo run --bin momentry -- import <uuid>
```
### Stage 3: Chunk 生成
```bash
# 生成 chunks
cargo run --bin momentry -- chunk <uuid>
```
### Stage 4: 向量化
```bash
# 向量化 chunks(使用預設模型 nomic-embed-text-v2-moe:latest
cargo run --bin momentry -- vectorize <uuid>
# 明確指定模型
cargo run --bin momentry -- vectorize <uuid> --model nomic-embed-text-v2-moe:latest
```
---
## 處理模式選項
### --force (強制重新處理)
- 刪除現有的 JSON 檔案
- 從頭開始處理
- 適用於:處理失敗、模型更新、需要重新處理
```bash
# 強制重新處理 YOLO
cargo run --bin momentry -- process <uuid> --modules yolo --force
```
### --resume (續傳)
- 檢查現有 JSON 的進度
- 從中斷點繼續處理
- 適用於:處理中斷、系統崩潰後恢復
```bash
# 從上次中斷點繼續
cargo run --bin momentry -- process <uuid> --resume
```
### 預設行為 (Smart Mode)
- 如果 JSON 完全:跳過
- 如果 JSON 不完整:警告 + 跳過(需要 --resume 或 --force
- 如果 JSON 不存在:處理
```
Output:
ASR: ✓ Already complete, skipping
⚠️ Found incomplete JSON file: /path/to/yolo.json
Progress: 73800/412343 (17.9%)
Use --resume to continue from checkpoint
Use --force to reprocess from scratch
YOLO: ✓ Already complete, skipping
```
---
## 可用模組
| 模組 | 功能 | 輸出 | 用途 |
|------|------|------|------|
| asr | 自動語音辨識 | asr.json | 語音轉文字 |
| cut | 場景偵測 | cut.json | 影片分段 |
| asrx | 說話者分離 | asrx.json | 多人對話分析 |
| yolo | 物體偵測 | yolo.json | 物體辨識 |
| ocr | 文字辨識 | ocr.json | 畫面文字 |
| face | 人臉偵測 | face.json | 人臉辨識 |
| pose | 姿態估計 | pose.json | 人體姿態 |
---
## 向量化模型選擇
### 專用嵌入模型
Momentry Core 統一使用 **`nomic-embed-text-v2-moe:latest`** 作為所有規則的嵌入模型:
```bash
# 統一模型(所有 Rule 1/2/3 使用)
--model nomic-embed-text-v2-moe:latest
```
### 模型特性
| 特性 | 說明 |
|------|------|
| **模型名稱** | `nomic-embed-text-v2-moe:latest` |
| **向量維度** | 768 維 |
| **多語言支持** | ✅ 完整支持(英語、中文、日語、韓語等) |
| **模型架構** | Mixture of Experts (MoE) |
| **推理速度** | 快速,適合實時應用 |
### 使用方式
```rust
// Rust 代碼中使用
let embedder = Embedder::new("nomic-embed-text-v2-moe:latest".to_string());
// 文檔嵌入(用於儲存)
let document_vector = embedder.embed_document("文本內容").await?;
// 查詢嵌入(用於搜索)
let query_vector = embedder.embed_query("搜索查詢").await?;
```
---
## 資料庫儲存
### PostgreSQL (主要關聯式資料庫)
- 影片資訊
- Chunks 資料
- Pre-chunks 資料
- Frames 資料
- 使用者資料
### Qdrant (主要向量資料庫)
- Chunk 向量
- 相似度搜尋
### PGVector (備份向量資料庫)
- Chunk 向量副本
- 備援機制
---
## Pipeline 狀態追蹤
### PostgreSQL 狀態欄位
```sql
-- 影片處理狀態
videos.status: 'pending' | 'processing' | 'completed' | 'failed'
-- 檔案處理狀態
videos.fs_json: true/false
videos.fs_chunks: true/false
videos.fs_vectors: true/false
-- pre_chunks 狀態
pre_chunks.imported: true/false
-- frames 狀態
frames.imported: true/false
-- chunks 狀態
chunks.cleaned: true/false
chunks.vectorized: true/false
```
### 進度查詢 API
```bash
# 查詢處理進度
curl http://localhost:3002/api/v1/progress/{uuid}
# 回應範例
{
"uuid": "a1b10138a6bbb0cd",
"file_name": "video.mp4",
"overall_progress": 65,
"cpu_percent": 45.2,
"gpu_percent": 98.5,
"memory_mb": 8500,
"processors": [
{"name": "asr", "status": "complete", "progress": 100},
{"name": "cut", "status": "complete", "progress": 100},
{"name": "yolo", "status": "progress", "progress": 45},
{"name": "ocr", "status": "pending", "progress": 0}
]
}
```
---
## 下一步
1. **API 端點** - 支援 --modules 和 --cloud 參數
2. **獨立 Import 命令** - 分離入庫流程
3. **獨立 Chunk 命令** - 分離 chunk 生成
4. **獨立 Vectorize 命令** - 分離向量化流程
5. **模型管理** - 新增、選擇、預覽模型
+165
View File
@@ -0,0 +1,165 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Momentry Core 架構 5 分鐘快速入門指南"
date: "2026-04-25"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "分鐘快速入門指南"
- "momentry"
- "core"
ai_query_hints:
- "查詢 Momentry Core 架構 5 分鐘快速入門指南 的內容"
- "Momentry Core 架構 5 分鐘快速入門指南 的主要目的是什麼?"
- "如何操作或實施 Momentry Core 架構 5 分鐘快速入門指南?"
---
# Momentry Core 架構 5 分鐘快速入門指南
## 1. 系統核心概念 (60秒)
**Momentry Core** 是一個 Rust 基礎的數位資產管理系統,專注於:
1. **視訊分析**:ASR、OCR、YOLO、場景檢測等多模態處理
2. **智慧分片**:將視訊分解為不同粒度級別的內容片段
3. **向量檢索**:基於語義和視覺特徵的相似度搜索
4. **RAG 功能**:檢索增強生成,提供情境化回答
**核心設計原則**:當設計文檔與實際代碼衝突時,**以 Rust 代碼實現為準**。
## 2. 系統架構圖 (30秒)
```
輸入 → 處理管道 → 分片生成 → 向量存儲 → 檢索服務
↓ ↓ ↓ ↓
ASR Sentence Qdrant API
OCR Cut PostgreSQL Player
YOLO Story Redis CLI
CUT Trace
```
## 3. 關鍵數據結構 (60秒)
### 分片類型 (ChunkType)
```rust
pub enum ChunkType {
TimeBased, // 時間基準分片
Sentence, // 句子級分片 (基於 ASR)
Cut, // 場景分片 (基於 CUT 算法)
Trace, // 軌跡追蹤分片
Story, // 故事級分片 (基於分片聚合)
}
```
### 分片數據結構
```rust
pub struct Chunk {
pub file_id: i32,
pub uuid: String,
pub chunk_id: String,
pub chunk_type: ChunkType,
pub start_frame: i64,
pub end_frame: i64,
pub content: serde_json::Value, // 動態 JSON 內容
pub vector_id: Option<String>,
// ... 其他字段
}
```
## 4. 處理管道 (60秒)
### 標準處理流程
1. **ASR 轉錄**:語音轉文字,生成句子級分片
2. **OCR 識別**:文字區域檢測和識別
3. **YOLO 檢測**:視覺物件檢測和分類
4. **CUT 場景檢測**:基於視覺相似度的場景分割
5. **分片生成**:基於處理結果生成不同類型的分片
### 處理器特點
- 統一使用 `PythonExecutor` 執行外部腳本
- 支持超時控制和錯誤恢復
- 處理結果存儲為結構化 JSON
## 5. 數據庫架構 (60秒)
### 多數據庫系統
1. **PostgreSQL**:結構化數據存儲
- `video_records`:視訊基礎資訊
- `chunks`:分片數據
- `jobs`:處理任務
2. **Redis**:緩存和隊列
- `momentry:` 網址:生產環境
- `momentry_dev:` 網址:開發環境
3. **Qdrant**:向量數據庫
- 存儲分片嵌入向量
- 支持語義和視覺相似度搜索
4. **MongoDB**:文檔存儲
- 存儲非結構化處理結果
## 6. 開發與部署 (30秒)
### 開發環境
```bash
# 構建項目
cargo build
cargo build --release
# 運行 CLI
cargo run -- register /path/to/video.mp4
cargo run -- server --host 0.0.0.0 --port 3002
# 運行開發版
cargo run --bin momentry_playground -- server
```
### 測試
```bash
# 運行所有測試
cargo test
# 運行單個測試
cargo test test_name
# 帶輸出的測試
cargo test -- --nocapture
```
## 7. 下一步學習路徑
### 初學者 (新團隊成員)
1. 閱讀 [ARCHITECTURE_OVERVIEW.md](./ARCHITECTURE_OVERVIEW.md) - 系統概覽
2. 查看 [DESIGN_IMPLEMENTATION_GAP.md](./DESIGN_IMPLEMENTATION_GAP.md) - 設計與實現差異
3. 運行 `cargo run -- --help` 熟悉 CLI 命令
### 開發者 (功能開發)
1. 查看 [TECHNICAL_DECISION_RECORDS.md](./TECHNICAL_DECISION_RECORDS.md) - 技術決策記錄
2. 研究 [PROCESSING_PIPELINE.md](./PROCESSING_PIPELINE.md) - 處理管道詳情
3. 查看 [ARCHITECTURE_DECISION_EXECUTION_PLAN.md](./ARCHITECTURE_DECISION_EXECUTION_PLAN.md) - 執行計劃
### 架構師 (系統設計)
1. 查看 [PERFORMANCE_AND_SCALABILITY.md](./PERFORMANCE_AND_SCALABILITY.md) - 效能與擴展
2. 研究 [SECURITY_ARCHITECTURE.md](./SECURITY_ARCHITECTURE.md) - 安全架構
3. 查看 [MONITORING_ARCHITECTURE.md](./MONITORING_ARCHITECTURE.md) - 監控架構
## 8. 常見問題 (FAQ)
### Q1: 如何開始添加新的處理器?
A: 參考 `src/core/processor/` 目錄下的現有處理器,實現 `Processor` trait。
### Q2: 如何擴展分片類型?
A: 在 `src/core/chunk/types.rs` 中擴展 `ChunkType` 枚舉。
### Q3: 如何集成新的 AI 模型?
A: 通過 `PythonExecutor` 執行 Python 腳本,或直接集成到 Rust 代碼中。
### Q4: 如何優化檢索性能?
A: 調整 Qdrant 向量索引參數,優化嵌入模型,添加緩存層。
---
**更新時間**: 2026-04-22
**適用對象**: 新團隊成員、開發者、架構師
**建議閱讀時間**: 5 分鐘
@@ -0,0 +1,364 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "處理器生命週期管理"
date: "2026-04-22"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "處理器生命週期管理"
ai_query_hints:
- "查詢 處理器生命週期管理 的內容"
- "處理器生命週期管理 的主要目的是什麼?"
- "如何操作或實施 處理器生命週期管理?"
---
# 處理器生命週期管理
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-22 |
| 文件版本 | V1.0 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 |
|------|------|------|--------|
| V1.0 | 2026-04-22 | 創建處理器生命週期管理文檔 | OpenCode |
---
## 1. 處理器生命週期概覽
處理器(Processor)是 Momentry Core 中執行視頻分析任務的核心組件。完整的生命週期包括以下階段:
```
開發階段 → 測試階段 → 部署階段 → 運行階段 → 維護階段 → 退役階段
```
---
## 2. 開發階段 (Development)
### 2.1 新處理器創建流程
#### 步驟 1: 需求分析
1. **功能定義**:明確處理器要實現的功能
2. **輸入輸出規範**:定義輸入參數和輸出格式
3. **依賴分析**:識別所需的 AI 模型、庫和工具
#### 步驟 2: 技術選型
1. **執行類型**:選擇 Python、Shell、CLI App 等
2. **模型選擇**:選擇合適的 AI 模型
3. **性能評估**:評估計算資源需求
#### 步驟 3: 代碼開發
1. **腳本編寫**:編寫處理器核心邏輯
2. **錯誤處理**:實現健壯的錯誤處理機制
3. **日誌記錄**:添加詳細的日誌記錄
### 2.2 開發標準
#### Python 處理器標準:
```python
# 1. 必要的導入
import json
import sys
import argparse
from pathlib import Path
# 2. 參數解析
parser = argparse.ArgumentParser()
parser.add_argument("--uuid", required=True, help="Video UUID")
parser.add_argument("--output", required=True, help="Output path")
args = parser.parse_args()
# 3. 主處理邏輯
def process_video(video_uuid, output_path):
# 處理邏輯
result = {
"status": "success",
"metadata": {...},
"chunks": [...]
}
# 4. 結果保存
with open(output_path, "w") as f:
json.dump(result, f, indent=2)
# 5. 主函數
if __name__ == "__main__":
try:
process_video(args.uuid, args.output)
sys.exit(0)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
```
---
## 3. 測試階段 (Testing)
### 3.1 測試類型
#### 單元測試:
- 測試處理器核心邏輯
- 驗證輸入輸出格式
- 測試錯誤處理
#### 集成測試:
- 測試與其他組件的集成
- 驗證數據流完整
- 測試性能表現
#### 回歸測試:
- 確保新版本不破壞現有功能
- 測試兼容性
- 驗證性能改進
### 3.2 測試數據
#### 測試視頻:
| 類型 | 用途 | 示例 |
|------|------|------|
| 短視頻(<1分鐘) | 快速測試 | test_video.mp4 |
| 中等視頻(1-5分鐘) | 功能測試 | demo_video.mp4 |
| 長視頻(>10分鐘) | 性能測試 | long_video.mp4 |
#### 測試環境:
1. **本地開發環境**:快速迭代
2. **測試服務器**:集成測試
3. **生產模擬環境**:性能測試
---
## 4. 部署階段 (Deployment)
### 4.1 部署流程
#### 步驟 1: 版本管理
1. **版本號**:遵循語義化版本規範(SemVer
2. **構建時間**:記錄構建/部署時間戳
3. **變更日誌**:記錄版本變更內容
#### 步驟 2: 配置管理
1. **環境變量**:配置處理器運行環境
2. **模型文件**:管理 AI 模型文件
3. **依賴庫**:管理 Python 依賴
#### 步驟 3: 數據庫註冊
```sql
-- 註冊新處理器到數據庫
INSERT INTO processors (
id, name, category, execution_type,
entry_point, version, build_time,
description, technical_details,
output_spec, runtime_config, is_active
) VALUES (
'uuid', 'face_processor', 'visual', 'python',
'scripts/face_processor.py', '1.2.0', NOW(),
'人臉識別處理器,使用 InsightFace 模型',
'基於 InsightFace 的深度學習人臉識別',
'{"type": "object", "properties": {...}}'::jsonb,
'{"venv_path": "...", "timeout_secs": 3600}'::jsonb,
TRUE
);
```
### 4.2 部署檢查清單
- [ ] 處理器腳本已測試通過
- [ ] 依賴庫已正確安裝
- [ ] 模型文件已下載並配置
- [ ] 環境變量已設置
- [ ] 數據庫註冊已完成
- [ ] 權限設置正確
- [ ] 日誌配置完整
---
## 5. 運行階段 (Runtime)
### 5.1 調度與執行
#### 任務調度流程:
```
1. 任務創建 → 2. 處理器選擇 → 3. 資源分配
→ 4. 執行監控 → 5. 結果收集 → 6. 狀態更新
```
#### 執行監控:
1. **進程監控**:監控處理器進程狀態
2. **資源監控**:監控 CPU、內存、GPU 使用
3. **性能監控**:監控處理速度和進度
### 5.2 錯誤處理與恢復
#### 錯誤類型:
1. **可恢復錯誤**:臨時性問題,可重試
2. **配置錯誤**:配置問題,需要修復
3. **系統錯誤**:系統級問題,需要干預
#### 重試策略:
```rust
// Rust 中的重試機制示例
let result = run_with_retry(
|| python_executor.execute(&script, &args),
RetryConfig {
max_attempts: 3,
initial_delay: Duration::from_secs(2),
max_delay: Duration::from_secs(30),
backoff_multiplier: 2.0,
},
).await;
```
### 5.3 性能優化
#### 優化策略:
1. **並行處理**:同時處理多個視頻
2. **批處理**:批量處理相關任務
3. **緩存優化**:重用計算結果
4. **資源調度**:智能分配計算資源
---
## 6. 維護階段 (Maintenance)
### 6.1 日常維護
#### 監控項目:
1. **處理器狀態**:運行狀態、健康狀態
2. **性能指標**:處理速度、成功率
3. **資源使用**CPU、內存、存儲
4. **錯誤率**:各種錯誤的發生頻率
#### 維護任務:
1. **日誌分析**:定期分析處理器日誌
2. **性能調優**:根據監控數據進行調優
3. **安全更新**:更新依賴庫修復安全漏洞
4. **數據清理**:清理臨時文件和緩存
### 6.2 版本升級
#### 升級流程:
1. **兼容性檢查**:檢查新版本與現有系統的兼容性
2. **回滾計劃**:制定升級失敗時的回滾計劃
3. **分階段部署**:分階段逐步升級
4. **驗證測試**:升級後進行全面測試
#### 版本兼容性矩陣:
| 處理器版本 | 系統版本 | 模型版本 | 狀態 |
|------------|----------|----------|------|
| v1.0.x | v0.1.0 | insightface==0.7.3 | ✅ 兼容 |
| v1.1.x | v0.2.0 | insightface==0.7.5 | ⚠️ 需要測試 |
| v2.0.x | v0.3.0 | insightface==0.8.0 | ❌ 不兼容 |
---
## 7. 退役階段 (Retirement)
### 7.1 退役原因
1. **技術過時**:技術棧過時,需要替換
2. **功能重疊**:與其他處理器功能重疊
3. **性能問題**:性能無法滿足需求
4. **維護成本**:維護成本過高
### 7.2 退役流程
#### 步驟 1: 退役計劃
1. **替代方案**:確定替代處理器
2. **數據遷移**:計劃數據遷移方案
3. **時間安排**:安排退役時間表
#### 步驟 2: 數據遷移
1. **歷史數據**:遷移歷史處理結果
2. **配置數據**:遷移配置信息
3. **依賴關係**:處理依賴關係
#### 步驟 3: 正式退役
1. **停止服務**:停止處理器服務
2. **數據清理**:清理相關數據
3. **文檔更新**:更新系統文檔
### 7.3 退役檢查清單
- [ ] 替代處理器已部署並測試
- [ ] 數據遷移已完成
- [ ] 依賴關係已處理
- [ ] 系統配置已更新
- [ ] 用戶通知已發送
- [ ] 退役文檔已更新
---
## 8. 相關處理器示例
### 8.1 已部署處理器
| 處理器 | 類型 | 狀態 | 版本 |
|--------|------|------|------|
| asr_processor | Python | ✅ 生產 | v1.3.2 |
| face_processor | Python | ✅ 生產 | v1.1.5 |
| yolo_processor | Python | ⚠️ 測試 | v0.9.1 |
| scene_processor | Python | ⚠️ 開發 | v0.5.0 |
### 8.2 處理器開發計劃
| 處理器 | 優先級 | 預計完成時間 | 狀態 |
|--------|--------|--------------|------|
| ocr_processor | P1 | 2026-05-31 | 🚧 開發中 |
| lip_processor | P2 | 2026-06-30 | 📅 計劃中 |
| audio_classifier | P3 | 2026-07-31 | 💡 設計中 |
---
## 9. 最佳實踐
### 9.1 開發最佳實踐
1. **模塊化設計**:保持處理器模塊化和可重用
2. **配置驅動**:使用配置文件而非硬編碼
3. **完善的日誌**:記錄詳細的處理日誌
4. **錯誤處理**:實現健壯的錯誤處理機制
### 9.2 部署最佳實踐
1. **版本控制**:嚴格管理處理器版本
2. **環境隔離**:使用虛擬環境隔離依賴
3. **配置管理**:使用配置管理工具
4. **監控預警**:設置監控和預警機制
### 9.3 運維最佳實踐
1. **定期備份**:定期備份處理器配置和數據
2. **性能監控**:持續監控處理器性能
3. **安全更新**:及時更新安全補丁
4. **文檔維護**:保持文檔與實際情況一致
---
## 10. 相關文件
| 文件 | 描述 | 相關性 |
|------|------|--------|
| [PROCESSOR_REGISTRY_ARCHITECTURE.md](./PROCESSOR_REGISTRY_ARCHITECTURE.md) | 處理器資源管理架構 | 核心架構 |
| [SERVICE_REGISTRY_ARCHITECTURE.md](./SERVICE_REGISTRY_ARCHITECTURE.md) | 服務資源管理架構 | 依賴管理 |
| [ARCHITECTURE_ROADMAP.md](./ARCHITECTURE_ROADMAP.md) | 架構發展路線圖 | 發展規劃 |
---
## 11. 最後更新記錄
| 版本 | 日期 | 主要變更 | 操作人 |
|------|------|----------|--------|
| V1.0 | 2026-04-22 | 創建處理器生命週期管理文檔 | OpenCode |
**最後更新日期**: 2026-04-22
@@ -0,0 +1,330 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Momentry Core 處理器資源管理架構 (v1.0)"
date: "2026-04-21"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "momentry"
- "core"
- "處理器資源管理架構"
ai_query_hints:
- "查詢 Momentry Core 處理器資源管理架構 (v1.0) 的內容"
- "Momentry Core 處理器資源管理架構 (v1.0) 的主要目的是什麼?"
- "如何操作或實施 Momentry Core 處理器資源管理架構 (v1.0)"
---
# Momentry Core 處理器資源管理架構 (v1.0)
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-21 |
| 文件版本 | V1.0 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-04-21 | 創建處理器資源管理架構文件 | OpenCode | OpenCode / Qwen3.6-Plus |
---
## 0. 設計目標
將所有影片處理腳本與程式(Processors)視為**標準化可執行資源**,實現:
1. **插件化架構**: 支援 Python, Shell, CLI App 及未來 Docker/HTTP 擴展。
2. **版本追溯**: 精確記錄處理器版本號與構建時間 (Build Time)。
3. **產出標準化**: 定義 JSON 輸出規範,確保上下游系統相容。
4. **動態調度**: 排程器根據處理器類型與狀態分配任務。
---
## 1. 核心架構
### 1.1 處理器分類 (Execution Types)
| 類型 | 說明 | 範例 | 執行指令範例 |
|------|------|------|--------------|
| `python` | 依賴 Python 環境的腳本 | ASR (WhisperX), Face (InsightFace), OCR | `python3 script.py --uuid ...` |
| `shell` | Bash 腳本,用於系統工具串接 | Smart Thumbnail (ffmpeg) | `bash script.sh --uuid ...` |
| `cli_app` | 編譯後的二進位程式 | 高效能向量計算器 | `./bin/processor --uuid ...` |
| `docker` | 容器化執行 (未來擴展) | 隔離環境的 AI 推論 | `docker run --rm image ...` |
| `http` | 遠端 API 呼叫 (未來擴展) | 外部雲端服務 | `POST /api/process` |
### 1.2 處理器與服務的關係
```
處理器 (Processors)
├── 依賴 ──> [服務資源] (Services: Ollama, Qdrant, GPU)
├── 讀取 ──> [資產] (Assets: Video Files)
└── 產出 ──> [文件] (JSON Results in Storage)
```
---
## 2. 資料庫設計
### 2.1 `processors` 表結構
```sql
CREATE TABLE processors (
id UUID PRIMARY KEY, -- 處理器唯一標識符
name VARCHAR(100) NOT NULL, -- 顯示名稱
category VARCHAR(50) NOT NULL, -- 分類: preprocessing, audio, visual, text
execution_type VARCHAR(50) NOT NULL, -- 執行型態: python, shell, cli_app, docker, http
entry_point VARCHAR(255) NOT NULL, -- 腳本路徑或二進位檔名
version VARCHAR(20) DEFAULT '1.0.0', -- 語義化版本號
build_time TIMESTAMPTZ DEFAULT NOW(), -- 構建/部署時間
description TEXT, -- 功能說明
technical_details TEXT, -- 技術手段描述
output_spec JSONB, -- 產出規範 (JSON Schema)
runtime_config JSONB, -- 執行環境配置 (如 venv, timeout, gpu)
is_active BOOLEAN DEFAULT TRUE, -- 是否啟用
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_processors_category ON processors(category);
CREATE INDEX idx_processors_type ON processors(execution_type);
```
---
## 3. 欄位詳細說明
### 3.1 執行環境配置 (runtime_config)
根據 `execution_type` 不同,此欄位內容也會不同。
**Python**:
```json
{
"venv_path": "/Users/accusys/momentry_core_0.1/venv",
"timeout_secs": 7200,
"requirements": ["torch", "insightface", "easyocr"]
}
```
**Shell**:
```json
{
"timeout_secs": 300,
"dependencies": ["ffmpeg", "ffprobe"]
}
```
**Docker**:
```json
{
"image": "registry.gitlab.com/momentry/ocr:v1.2",
"gpu": true,
"shm_size": "4g"
}
```
### 3.2 產出規範 (output_spec)
定義處理器執行成功後應生成的 JSON 結構。
**ASR (WhisperX)**:
```json
{
"format": "json",
"structure": {
"segments": [
{
"start": "float",
"end": "float",
"text": "string",
"speaker": "string (optional)"
}
]
},
"naming_convention": "{uuid}_asr_{timestamp}.json"
}
```
**Smart Thumbnail**:
```json
{
"format": "image/jpeg",
"resolution": "320x(width/height ratio)",
"storage_path": "thumbnails/{uuid}.jpg",
"metadata_key": "thumbnail_generated_at"
}
```
---
## 4. 完整註冊範例
### 4.1 Smart Thumbnail (Shell)
```sql
INSERT INTO processors (
id, name, category, execution_type, entry_point,
description, technical_details, output_spec, runtime_config
) VALUES (
'550e8400-e29b-41d4-a716-446655440001',
'Smart Thumbnail Extractor',
'preprocessing',
'shell',
'scripts/smart_thumbnail.sh',
'Detects black screens to find the first valid frame of the main content.',
'Uses FFmpeg `blackdetect` filter to scan first 60s; applies 0.5s offset to avoid transitions.',
'{
"format": "image/jpeg",
"naming_convention": "{uuid}.jpg"
}'::jsonb,
'{
"timeout_secs": 300,
"dependencies": ["ffmpeg"]
}'::jsonb
);
```
### 4.2 ASR WhisperX (Python)
```sql
INSERT INTO processors (
id, name, category, execution_type, entry_point,
version, build_time, description, technical_details, output_spec, runtime_config
) VALUES (
'550e8400-e29b-41d4-a716-446655440002',
'WhisperX Speech Recognition',
'audio',
'python',
'scripts/asr_processor.py',
'2.1.0',
'2026-04-20 10:00:00+08', -- 真實構建時間
'High-accuracy speech-to-text with word-level timestamps and speaker diarization.',
'WhisperX (faster-whisper) + pyannote-audio for speaker diarization.',
'{
"format": "json",
"structure": {
"segments": [{"start": "f64", "end": "f64", "text": "str", "speaker": "str"}]
},
"naming_convention": "{uuid}_asr_{timestamp}.json"
}'::jsonb,
'{
"venv_path": "/Users/accusys/momentry_core_0.1/venv",
"timeout_secs": 7200,
"gpu": true
}'::jsonb
);
```
### 4.3 OCR (Python)
```sql
INSERT INTO processors (
id, name, category, execution_type, entry_point,
description, technical_details, output_spec, runtime_config
) VALUES (
'550e8400-e29b-41d4-a716-446655440003',
'EasyOCR Text Recognition',
'visual',
'python',
'scripts/ocr_processor.py',
'Extracts text blocks with coordinates from video frames.',
'Uses EasyOCR (local model) with English language support.',
'{
"format": "json",
"structure": {
"frames": [
{
"frame": "int",
"timestamp": "float",
"texts": [{"text": "str", "bbox": "object", "confidence": "float"}]
}
]
},
"naming_convention": "{uuid}_ocr_{timestamp}.json"
}'::jsonb,
'{
"venv_path": "/Users/accusys/momentry_core_0.1/venv",
"timeout_secs": 3600,
"sample_interval_frames": 30
}'::jsonb
);
```
---
## 5. 標準化執行介面 (Execution Interface)
為了讓排程器 (Scheduler) 能統一呼叫所有類型的處理器,所有處理器必須遵循以下參數規範:
| 參數 | 說明 | 範例值 |
|:---|:---|:---|
| `--uuid` | 影片/任務唯一標識符 | `--uuid 384b0ff4...` |
| `--input` | 輸入媒體檔案路徑 | `--input /data/raw/video.mp4` |
| `--output` | 產出 JSON/檔案目錄 | `--output /data/output/384b...` |
| `--config` | (選用) 額外 JSON 配置路徑 | `--config settings.json` |
**Rust 執行分發邏輯 (Dispatcher)**:
```rust
match processor.execution_type.as_str() {
"python" => {
Command::new(venv_python)
.arg(&entry_point)
.args(common_args)
.spawn()?
}
"shell" => {
Command::new("bash")
.arg(&entry_point)
.args(common_args)
.spawn()?
}
"cli_app" => {
Command::new(&entry_point)
.args(common_args)
.spawn()?
}
_ => bail!("Unsupported execution type")
}
```
---
## 6. 處理器與服務整合 (Integration)
處理器在執行時,需要查詢「服務註冊中心」來獲取依賴資源的配置。
**流程範例**:
1. 排程器啟動 `asr_processor.py`
2. Python 腳本查詢本地配置檔 (由排程器生成,內容來自 `services` 表)。
3. 腳本獲取 Ollama 的 `endpoint``model_name`
4. 腳本執行 Embedding 任務。
這樣實現了**處理器與基礎設施配置的解耦**。
---
## 7. 總結
本設計確立了 Momentry 處理器管理的標準:
| 管理維度 | 實作方式 |
|----------|----------|
| **唯一標識** | UUID (`id` 欄位) |
| **多態執行** | `execution_type` (Python/Shell/CLI/Docker...) |
| **版本控制** | `version` + `build_time` |
| **品質保證** | `output_spec` (JSON Schema 驗證) |
| **環境隔離** | `runtime_config` (Venv, Docker Image) |
| **依賴管理** | 啟動時注入 `services` 配置 |
此架構支持未來無限擴展,新的 AI 模型或工具只需編寫腳本並註冊即可納入系統管轄。
@@ -0,0 +1,120 @@
# Resource Monitoring Specification (資源監控規範)
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-25 |
| 文件版本 | V1.0 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-04-25 | 定義 Processor/Agent 的註冊與心跳協定 (僅限監控) | OpenCode | OpenCode |
---
## 1. 核心概念
本階段資源註冊機制 (Resource Registry) **僅用於監控 (Monitoring)**,不介入動態任務調度。
所有 Processor (YOLO, ASR...) 和 Agent (Translation, Summary...) 啟動時應主動註冊。
### 1.1 註冊時機
* **Processor**: 在 Python 腳本啟動時,呼叫 HTTP Endpoint 註冊。
* **Agent**: 在服務啟動時呼叫 HTTP Endpoint 註冊。
---
## 2. 註冊協定 (Registration Protocol)
### 2.1 API Endpoint
`POST /api/v1/resources/register`
### 2.2 Request Payload
```json
{
"resource_id": "unique_id",
"resource_type": "processor | agent",
"name": "Yolo Object Detector",
"capabilities": ["detect_object", "detect_face"],
"config": {
"model_version": "v8n",
"gpu_enabled": true
}
}
```
* **resource_id**: 建議格式 `{type}_{name}_{uuid}`,例如 `processor_yolo_a1b2c3`
### 2.3 Response
```json
{
"success": true,
"message": "Resource registered"
}
```
---
## 3. 心跳協定 (Heartbeat Protocol)
資源應定期發送心跳,回報當前狀態與進度。
### 3.1 API Endpoint
`POST /api/v1/resources/{resource_id}/heartbeat`
### 3.2 Request Payload
```json
{
"status": "idle | busy | error",
"job_uuid": "current_video_uuid",
"progress": 0.45,
"last_frame_index": 12500
}
```
* **progress**: 0.0 到 1.0 之間的浮點數。
* **job_uuid**: 當前正在處理的任務 ID。
---
## 4. 監控用途
系統後台 (Portal Dashboard) 可透過查詢 Registry 實現:
1. **即時儀表板**: 顯示目前有幾個 Processor 在運行 (`busy` 數量)。
2. **進度條**: 透過 `last_frame_index` 與影片總幀數計算百分比。
3. **健康檢查**: 若資源超過 60 秒未發送心跳,標記為 `offline`
---
## 5. Rust Worker 整合建議
`src/worker/processor.rs``run_processor` 函數中:
```rust
// 1. 生成唯一的 Resource ID
let resource_id = format!("processor_{}_{}", processor_type, job.uuid);
// 2. 註冊資源
register_resource(&resource_id, processor_type).await;
// 3. 執行腳本 (腳本內部應定期發送心跳,或由 Rust Wrapper 發送)
run_python_script(...);
// 4. 登出資源 (可選,或由 TTL 自動清理)
deregister_resource(&resource_id).await;
```
---
## 版本資訊
- 版本: V1.0
- 建立日期: 2026-04-25
@@ -0,0 +1,500 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Momentry Core 全域服務資源管理架構 (v1.0)"
date: "2026-04-21"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "momentry"
- "core"
- "全域服務資源管理架構"
ai_query_hints:
- "查詢 Momentry Core 全域服務資源管理架構 (v1.0) 的內容"
- "Momentry Core 全域服務資源管理架構 (v1.0) 的主要目的是什麼?"
- "如何操作或實施 Momentry Core 全域服務資源管理架構 (v1.0)"
---
# Momentry Core 全域服務資源管理架構 (v1.0)
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-21 |
| 文件版本 | V1.0 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-04-21 | 創建全域服務資源管理架構文件 | OpenCode | OpenCode / Qwen3.6-Plus |
---
## 0. 設計目標
將所有基礎設施服務(Infrastructure Services)視為**可管理資源**,實現:
1. **動態發現**: 處理器不再寫死服務 IP,而是從註冊中心查詢可用服務
2. **健康監控**: 自動探活服務狀態,故障時標記並尋找備用節點
3. **版本追溯**: 精確記錄模型檔案、配置、依賴關係,確保可重現性
4. **運維自動化**: 統一管理備份、日誌、儲存路徑,降低人工維護成本
---
## 1. 核心架構
### 1.1 服務分類 (Service Types)
| 類型 | 說明 | 範例 |
|------|------|------|
| `embedding_engine` | 語意向量生成 | Ollama (nomic-embed-text-v2-moe) |
| `llm_engine` | 文字生成/推理 | llama.cpp (gemma-4) |
| `vector_db` | 向量儲存與搜尋 | Qdrant |
| `cache` | 快取與隊列 | Redis |
| `database` | 關聯式資料庫 | PostgreSQL |
| `storage` | 檔案管理 | SFTPGo |
| `api_server` | API 閘道 | Momentry Core Server |
### 1.2 服務資源關聯圖
```
使用者/API
├──> [Momentry Core API Server] (api_server)
│ │
│ ├──> [Qdrant] (vector_db) ─── 向量搜尋
│ │
│ ├──> [Ollama] (embedding_engine) ─── 768-dim Embedding
│ │
│ ├──> [llama.cpp] (llm_engine) ─── Gemma4 推理
│ │
│ ├──> [PostgreSQL] (database) ─── 關聯資料
│ │
│ └──> [Redis] (cache) ─── 快取與隊列
└──> [SFTPGo] (storage) ─── 檔案上傳/管理
```
---
## 2. 資料庫設計
### 2.1 `services` 表結構
```sql
CREATE TABLE services (
id UUID PRIMARY KEY,
name VARCHAR(100) NOT NULL, -- 服務名稱 (e.g., ollama-embedding-nomic-v2-moe)
type VARCHAR(50) NOT NULL, -- 服務類型 (見 1.1)
endpoint VARCHAR(255), -- 基礎連接點 (e.g., http://127.0.0.1:11434)
status VARCHAR(20) DEFAULT 'unknown', -- online, offline, degraded, unknown
metadata JSONB, -- 技術細節 (模型版本、維度等)
-- 1. 網路與端口
port_config JSONB, -- 主端口、範圍、協議
-- 2. 存取控制
access_policy JSONB, -- 認證方式、允許的使用者
-- 3. 依賴關係
dependency_graph JSONB, -- 上游/下游依賴
-- 4. 業務上下文
business_purpose TEXT, -- 用途說明
reference_docs JSONB, -- 文檔連結
-- 5. 儲存與日誌
storage_paths JSONB, -- 配置、數據、log、error_log
-- 6. 備份策略
backup_policy JSONB, -- 備份週期、方法、目標
-- 7. 健康檢查
health_check_path VARCHAR(255), -- 探活路徑 (e.g., /health)
health_check_method VARCHAR(10), -- HTTP 方法 (GET/POST)
health_check_match TEXT, -- 預期回應 (Status 200 or JSON content)
check_interval_secs INT DEFAULT 60, -- 檢查頻率 (秒)
last_check_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW()
);
```
---
## 3. 欄位詳細說明
### 3.1 技術細節 (metadata)
根據服務類型記錄不同的技術參數。
**Ollama (Embedding Engine)**:
```json
{
"provider": "ollama",
"model_name": "nomic-embed-text-v2-moe",
"model_tag": "latest",
"gguf_file": "nomic-embed-text-v2-moe-Q4_0.gguf",
"gguf_sha256": "sha256:xxxxx...",
"source_url": "https://huggingface.co/nomic-ai/nomic-embed-text-v2-moe-GGUF",
"dimensions": 768,
"capabilities": ["embedding", "text-similarity", "multilingual"],
"context_length": 2048,
"architecture": "Mixture of Experts (MoE)"
}
```
**llama.cpp (LLM Engine)**:
```json
{
"provider": "llama.cpp",
"model_name": "gemma-4-12b-it",
"model_file": "gemma-4-12b-it-Q4_K_M.gguf",
"source": "https://huggingface.co/bartowski/gemma-4-12b-it-GGUF",
"sha256": "sha256:yyyyy...",
"capabilities": ["text-generation", "chat"],
"parameters": "12B",
"quantization": "Q4_K_M",
"gpu_layers": -1
}
```
### 3.2 網路與端口 (port_config)
```json
{
"main_port": 11434,
"range": "11434-11435",
"protocol": "HTTP",
"bind_address": "127.0.0.1"
}
```
### 3.3 存取控制 (access_policy)
```json
{
"auth_type": "none",
"allowed_users": ["momentry_core", "vectorize_worker"],
"api_key_env": null,
"rate_limit": "unlimited",
"cors_origin": "localhost"
}
```
### 3.4 依賴關係 (dependency_graph)
```json
{
"upstream": ["gpu_driver", "cuda_toolkit"],
"downstream": ["qdrant_ingestion", "search_api", "smart_synonym_expander"],
"criticality": "high"
}
```
### 3.5 儲存與日誌 (storage_paths)
```json
{
"data_dir": "/Users/accusys/.ollama/models",
"config_dir": "/Users/accusys/.ollama/modelfiles",
"log_file": "/Users/accusys/Library/Logs/ollama/ollama.log",
"error_log_file": "/Users/accusys/Library/Logs/ollama/ollama.error.log",
"env_file": "/Users/accusys/.ollama/.env"
}
```
### 3.6 備份策略 (backup_policy)
```json
{
"enabled": true,
"method": "rsync",
"schedule": "daily",
"destination": "/Volumes/BackupDrive/momentry_services/ollama",
"retention_days": 30,
"pre_hook": "launchctl stop com.ollama.service",
"post_hook": "launchctl start com.ollama.service",
"exclude_patterns": ["*.tmp", "logs/*"]
}
```
### 3.7 健康檢查 (health_check)
| 欄位 | 說明 | 範例 |
|------|------|------|
| `health_check_path` | 探活路徑 | `/health``/` |
| `health_check_method` | HTTP 方法 | `GET` |
| `health_check_match` | 預期回應內容 | `Ollama is running` |
| `check_interval_secs` | 檢查頻率 | `60` |
---
## 4. 完整註冊範例
### 4.1 Ollama Embedding Engine
```sql
INSERT INTO services (
id, name, type, endpoint, status, metadata,
port_config, access_policy, dependency_graph,
business_purpose, reference_docs,
storage_paths, backup_policy,
health_check_path, health_check_method, health_check_match, check_interval_secs
) VALUES (
'550e8400-e29b-41d4-a716-446655440100',
'ollama-embedding-nomic-v2-moe',
'embedding_engine',
'http://127.0.0.1:11434',
'online',
'{"provider": "ollama", "model_name": "nomic-embed-text-v2-moe", "model_tag": "latest", "dimensions": 768}'::jsonb,
'{"main_port": 11434, "protocol": "HTTP"}'::jsonb,
'{"auth_type": "none", "allowed_users": ["momentry_core", "vectorize_worker"]}'::jsonb,
'{"upstream": ["gpu_driver"], "downstream": ["qdrant_ingestion", "search_api"], "criticality": "high"}'::jsonb,
'Generate 768-dim multilingual embeddings for chunks and semantic search.',
'{"model_url": "https://ollama.com/library/nomic-embed-text-v2-moe", "wiki": "docs/PROCESSING_PIPELINE.md"}'::jsonb,
'{
"data_dir": "/Users/accusys/.ollama/models",
"config_dir": "/Users/accusys/.ollama/modelfiles",
"log_file": "/Users/accusys/Library/Logs/ollama/ollama.log",
"error_log_file": "/Users/accusys/Library/Logs/ollama/ollama.error.log"
}'::jsonb,
'{
"enabled": true,
"method": "rsync",
"destination": "/Volumes/BackupDrive/ollama_models",
"retention_days": 30
}'::jsonb,
'/', 'GET', 'Ollama is running', 60
);
```
### 4.2 llama.cpp LLM Engine
```sql
INSERT INTO services (
id, name, type, endpoint, status, metadata,
port_config, access_policy, dependency_graph,
business_purpose, reference_docs,
storage_paths, backup_policy,
health_check_path, health_check_method, health_check_match, check_interval_secs
) VALUES (
'550e8400-e29b-41d4-a716-446655440099',
'llama-server-gemma4',
'llm_engine',
'http://127.0.0.1:8081',
'online',
'{"provider": "llama.cpp", "model_name": "gemma-4-12b-it", "model_file": "gemma-4-12b-it-Q4_K_M.gguf", "capabilities": ["text-generation", "chat"], "parameters": "12B"}'::jsonb,
'{"main_port": 8081, "protocol": "HTTP"}'::jsonb,
'{"auth_type": "none", "allowed_users": ["momentry_core"]}'::jsonb,
'{"upstream": ["gpu_driver"], "downstream": ["smart_synonym_expander", "query_parser"], "criticality": "medium"}'::jsonb,
'Provide text generation and instruction following for synonym expansion and query analysis.',
'{"model_url": "https://huggingface.co/bartowski/gemma-4-12b-it-GGUF"}'::jsonb,
'{
"data_dir": "/Users/accusys/momentry/models",
"config_dir": "/Users/accusys/momentry/config",
"log_file": "/Users/accusys/momentry/logs/llama_server.log",
"error_log_file": "/Users/accusys/momentry/logs/llama_server.error.log"
}'::jsonb,
'{
"enabled": true,
"method": "rsync",
"destination": "/Volumes/BackupDrive/llama_models",
"retention_days": 30
}'::jsonb,
'/health', 'GET', 'OK', 30
);
```
### 4.3 Qdrant Vector DB
```sql
INSERT INTO services (
id, name, type, endpoint, status, metadata,
port_config, access_policy, dependency_graph,
business_purpose, reference_docs,
storage_paths, backup_policy,
health_check_path, health_check_method, health_check_match, check_interval_secs
) VALUES (
'550e8400-e29b-41d4-a716-446655440003',
'qdrant-vector-store',
'vector_db',
'http://127.0.0.1:6333',
'online',
'{"version": "1.7.0", "collections": ["momentry_rule1", "momentry_rule2", "momentry_rule3"], "vector_dim": 768, "distance": "Cosine"}'::jsonb,
'{"main_port": 6333, "grpc_port": 6334, "protocol": "HTTP/REST+gRPC"}'::jsonb,
'{"auth_type": "api_key", "api_key_env": "QDRANT_API_KEY", "allowed_users": ["momentry_core", "vectorize_worker"]}'::jsonb,
'{"upstream": ["ollama-embedding-nomic-v2-moe"], "downstream": ["search_api"], "criticality": "critical"}'::jsonb,
'Store and search 768-dim embeddings for all chunk rules.',
'{"docs": "https://qdrant.tech/documentation"}'::jsonb,
'{
"data_dir": "/opt/qdrant/storage",
"config_dir": "/opt/qdrant/config",
"log_file": "/var/log/qdrant/qdrant.log",
"error_log_file": "/var/log/qdrant/qdrant.error.log"
}'::jsonb,
'{
"enabled": true,
"method": "snapshot",
"schedule": "daily",
"destination": "/Volumes/BackupDrive/qdrant_snapshots",
"retention_days": 14
}'::jsonb,
'/healthz', 'GET', '', 30
);
```
---
## 5. 健康監控機制 (Health Monitor)
### 5.1 監控流程
```
1. Worker 掃描 services 表 (status != 'disabled')
2. 對每個服務發送 health_check
- URL: endpoint + health_check_path
- Method: health_check_method
3. 驗證回應
- HTTP Status: 200 OK?
- Content: 包含 health_check_match?
4. 更新狀態
- success → status = 'online'
- fail → status = 'offline'
- timeout → status = 'degraded'
5. 記錄 last_check_at
```
### 5.2 Rust 實作範例
```rust
pub async fn run_health_checks(pool: &PgPool) -> anyhow::Result<()> {
let services = sqlx::query!(
"SELECT id, endpoint, health_check_path, health_check_method,
health_check_match, check_interval_secs
FROM services WHERE status != 'disabled'"
)
.fetch_all(pool)
.await?;
for svc in services {
let url = format!("{}{}", svc.endpoint, svc.health_check_path);
let new_status = match check_service_health(&url, &svc.health_check_method).await {
Ok(body) => {
if let Some(expected) = &svc.health_check_match {
if body.contains(expected) { "online" } else { "degraded" }
} else { "online" }
}
Err(_) => "offline"
};
sqlx::query!(
"UPDATE services SET status = $1, last_check_at = NOW() WHERE id = $2",
new_status,
svc.id
)
.execute(pool)
.await?;
}
Ok(())
}
```
---
## 6. 依賴影響分析
### 6.1 故障傳播查詢
```sql
-- 查詢受 Ollama 故障影響的所有服務
SELECT name, type, status
FROM services
WHERE dependency_graph->'upstream' @> '["ollama-embedding-nomic-v2-moe"]';
-- 查詢 Qdrant 依賴的所有上游服務
SELECT name, type, status
FROM services
WHERE 'qdrant-vector-store' = ANY(
ARRAY(
SELECT jsonb_array_elements_text(
dependency_graph->'downstream'
)
)
);
```
### 6.2 啟動順序
根據 `dependency_graph``upstream` 字段,系統可自動計算服務啟動順序:
```
1. gpu_driver → cuda_toolkit
2. ollama-embedding-nomic-v2-moe (需要 gpu_driver)
3. llama-server-gemma4 (需要 gpu_driver)
4. qdrant-vector-store
5. redis-cache
6. postgres-main
7. momentry-core-api (依賴以上所有)
```
---
## 7. 備份管理 (Backup Manager)
### 7.1 備份排程查詢
```sql
-- 找出今日需要備份的服務
SELECT name, backup_policy
FROM services
WHERE backup_policy->>'enabled' = 'true'
AND (backup_policy->>'schedule' = 'daily'
OR backup_policy->>'schedule' LIKE '%* * *');
```
### 7.2 備份執行邏輯
```
1. Worker 掃描 backup_policy.enabled = true
2. 執行 pre_hook (如停止服務)
3. 執行備份方法
- rsync: rsync -a --exclude="*.tmp" data_dir destination
- pg_dump: pg_dump dbname > destination/dump.sql
- snapshot: qdrant CLI create-snapshot
4. 壓縮 (gzip)
5. 執行 post_hook (如重啟服務)
6. 清理超過 retention_days 的舊備份
```
---
## 8. 總結
本設計將所有基礎設施服務納管為**可發現、可監控、可備份、可追溯**的資源實體。
| 管理維度 | 實作方式 |
|----------|----------|
| **服務發現** | `services` 表 + `endpoint` 欄位 |
| **版本追溯** | `metadata` (模型檔案 SHA256, 版本號) |
| **健康監控** | `health_check_*` 欄位 + 背景 Worker |
| **依賴管理** | `dependency_graph` (upstream/downstream) |
| **存取控制** | `access_policy` (認證方式、允許使用者) |
| **儲存管理** | `storage_paths` (配置、數據、分離日誌) |
| **備份恢復** | `backup_policy` (排程、方法、保留期、Hooks) |
透過此架構,Momentry 可實現從「手動運維」到「自動化服務治理」的升級。
@@ -0,0 +1,162 @@
# 統一資源註冊架構 (Unified Resource Registry Architecture)
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-25 |
| 文件版本 | V1.0 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-04-25 | 定義 Service、Processor、Agent 為統一資源 (Resource) 的註冊與管理架構 | OpenCode | OpenCode |
---
## 1. 核心設計理念
在 Momentry Core 系統中,所有用於處理、分析和管理數據的組件,統一抽象為 **「資源 (Resource)」**。
這種設計允許系統以統一的方式發現、調度、監控和管理不同類型的組件。
### 1.1 資源三大分類 (Resource Types)
| 資源類型 | 英文代號 | 定義 | 特性 | 範例 |
|----------|----------|------|------|------|
| **服務** | **Service** | 系統運行依賴的基礎設施或長駐進程。 | 長生命週期 (Long-lived), 狀態保持。 | PostgreSQL, Redis, TMDB API |
| **處理器** | **Processor** | 執行確定性數據轉換的模組。 | 短生命週期 (Task-based), 輸入 A -> 輸出 B, 無狀態。 | FFmpeg (Probe), YOLO, Whisper |
| **智能體** | **Agent** | 依賴 LLM 進行語義推論或決策的模組。 | 短生命週期 (Task-based), 機率性輸出, 依賴 Prompt/Context。 | 5W1H Inference, Summarization, Identity Resolution |
---
## 2. 通用資源模型 (Universal Resource Model)
所有資源在註冊表中共享以下核心結構:
```json
{
"resource_id": "unique_identifier",
"resource_type": "processor | agent | service",
"category": "visual | speech | metadata | logic",
"capabilities": ["capability_1", "capability_2"],
"status": "idle | busy | offline | error",
"config": {
"model": "yolov8n",
"timeout": 60,
"gpu_required": false
},
"health_check": {
"endpoint": "/health",
"interval_seconds": 30,
"last_success": "2026-04-25T10:00:00Z"
},
"metadata": {
"version": "1.0.0",
"description": "..."
}
}
```
---
## 3. 資源生命週期 (Resource Lifecycle)
1. **註冊 (Registration)**:
* 組件啟動時向 **Resource Registry** 報到,聲明其 ID、類型和能力。
* *範例*: Agent 啟動,註冊 `resource_type: "agent"`, `capabilities: ["summarize_text"]`
2. **發現 (Discovery)**:
* 調度器 (Scheduler) 根據任務需求查詢 Registry 尋找合適的資源。
* *範例*: 任務需要「語音轉文字」,查詢 `capabilities: ["audio_to_text"]`
3. **分配與執行 (Allocation & Execution)**:
* 狀態變為 `busy`,接收任務並執行。
4. **健康檢查 (Health Monitoring)**:
* Registry 定期 Ping 資源。若無回應,標記為 `offline`
5. **登出 (Deregistration)**:
* 組件關閉或崩潰時從 Registry 移除。
---
## 4. 資源註冊表設計 (Registry Schema)
### 4.1 資料庫表結構 (SQL)
```sql
CREATE TABLE resources (
resource_id VARCHAR(64) PRIMARY KEY,
resource_type VARCHAR(20) NOT NULL, -- 'processor', 'agent', 'service'
category VARCHAR(50), -- 'visual', 'speech', 'logic'
name VARCHAR(100) NOT NULL,
description TEXT,
capabilities JSONB, -- Array of strings
config JSONB, -- Resource specific config
metadata JSONB, -- Version, author, etc.
status VARCHAR(20) DEFAULT 'offline',
last_heartbeat TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- 索引優化查詢
CREATE INDEX idx_res_type ON resources(resource_type);
CREATE INDEX idx_res_status ON resources(status);
CREATE INDEX idx_res_caps ON resources USING GIN(capabilities);
```
### 4.2 API 端點設計
| Method | Endpoint | 說明 |
|--------|----------|------|
| `POST` | `/api/v1/resources/register` | 資源啟動時註冊 |
| `POST` | `/api/v1/resources/:id/heartbeat` | 發送心跳 |
| `GET` | `/api/v1/resources` | 查詢所有資源 (支援過濾) |
| `GET` | `/api/v1/resources?capability=summarize` | 查詢具備特定能力的資源 |
| `POST` | `/api/v1/resources/:id/deregister` | 資源關閉時登出 |
---
## 5. 實作建議
### 5.1 Processor 實作 (確定性)
* 通常由 Python 腳本或 Rust 二進制執行。
* 啟動時呼叫 `POST /resources/register`,宣告如 `["video_to_frames", "detect_objects"]`
### 5.2 Agent 實作 (機率性)
* 通常封裝為具備 LLM Context 的服務。
* 啟動時呼叫 `POST /resources/register`,宣告如 `["summarize_text", "extract_5w1h"]`
* **重點**: 在 `metadata` 中記錄使用的 LLM 模型名稱 (e.g., `gpt-4o`, `llama3`)。
### 5.3 Service 實作 (基礎設施)
* 通常由 Docker Compose 或 Systemd 管理。
* 可透過 Sidecar 或定期腳本進行註冊與心跳更新。
---
## 6. 與其他架構的關係
* **Job/Task Scheduler**: 任務調度器依賴 Resource Registry 來尋找誰能執行任務。
* **Configuration Management**: 資源的詳細參數 (如 API Key, Threshold) 應存在 Config 中心,Registry 僅儲存引用或摘要。
* **Monitoring**: Prometheus/Grafana 應抓取 Registry 狀態來展示系統資源健康度儀表板。
## 7. 關聯文檔
本目錄整合了原有的 Processor 與 Service 架構,並納入新的 Agent 架構:
- `PROCESSOR_REGISTRY_ARCHITECTURE.md` - 舊版處理器註冊設計 (已整合)。
- `SERVICE_REGISTRY_ARCHITECTURE.md` - 舊版服務註冊設計 (已整合)。
- `PROCESSOR_LIFECYCLE.md` - 處理器生命週期 (資源生命週期的子集)。
---
## 版本資訊
- 版本: V1.0
- 建立日期: 2026-04-25
@@ -0,0 +1,195 @@
# API Key Management System Architecture
## System Overview
```
┌─────────────────────────────────────────────────────────────────────────────────┐
│ API Key Management System │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ CLI │ │ HTTP API │ │ Service │ │ External │ │
│ │ Layer │────▶│ Layer │────▶│ Layer │────▶│ Services │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ Core Modules │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Service │ │Validator│ │ Anomaly │ │Rotation │ │ Cleanup │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Webhook │ │Encrypt │ │Blacklist│ │ Report │ │ Error │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ PostgreSQL │ │ Redis │ │ External │ │
│ │ (Storage) │ │ (Cache) │ │ (Gitea/n8n)│ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
```
## Module Dependencies
```
┌──────────────┐
│ models.rs │
│ (Types) │
└──────┬───────┘
┌──────────────────┼──────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ service.rs │ │ error.rs │ │ validator.rs │
│ (Core CRUD) │ │ (Errors) │ │ (Cache+Rate) │
└───────┬───────┘ └───────────────┘ └───────────────┘
│ ┌───────────────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ anomaly.rs │ │ rotation.rs │ │ blacklist.rs │
│ (Detection) │ │ (Rotation) │ │ (IP Block) │
└───────────────┘ └───────────────┘ └───────────────┘
```
## Request Flow
```
Client Request
┌─────────────┐
│ CLI/API │
└──────┬──────┘
┌─────────────┐ ┌─────────────┐
│ Rate Limit │────▶│ IP Blacklist│
│ Check │ │ Check │
└──────┬──────┘ └──────┬──────┘
│ │
└─────────┬─────────┘
┌───────────────┐
│ Hash API Key │
└───────┬───────┘
┌───────────────┐ ┌───────────────┐
│ Cache Lookup │────▶│ PostgreSQL │
└───────┬───────┘ │ Lookup │
│ └───────┬───────┘
│ │
└──────────┬──────────┘
┌───────────────┐
│ Validate │
│ (Status, │
│ Expiry) │
└───────┬───────┘
┌─────────────┼─────────────┐
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Valid │ │ Invalid │ │ Error │
│ Response│ │ Response │ │ Response │
└──────────┘ └──────────┘ └──────────┘
```
## Database Schema
```
┌─────────────────────────────────────────────────────────────────┐
│ PostgreSQL │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ api_keys │ │ api_key_audit_ │ │
│ ├─────────────────┤ │ log │ │
│ │ id │ ├─────────────────┤ │
│ │ key_id │─────▶│ id │ │
│ │ key_hash │ │ key_id (FK) │ │
│ │ name │ │ action │ │
│ │ key_type │ │ ip_address │ │
│ │ status │ │ details │ │
│ │ expires_at │ └─────────────────┘ │
│ │ ... │ │
│ └─────────────────┘ ┌─────────────────┐ │
│ │ api_key_anomalies│ │
│ ┌─────────────────┐ ├─────────────────┤ │
│ │ gitea_tokens │ │ id │ │
│ ├─────────────────┤ │ key_id (FK) │ │
│ │ id │ │ anomaly_type │ │
│ │ gitea_token_id │ │ severity │ │
│ │ token_name │ │ details │ │
│ │ scopes │ └─────────────────┘ │
│ └─────────────────┘ │
│ │
│ ┌─────────────────┐ │
│ │ n8n_api_keys │ │
│ ├─────────────────┤ │
│ │ id │ │
│ │ n8n_key_id │ │
│ │ label │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```
## External Integrations
```
┌─────────────────────────────────────────────────────────────────────────────────┐
│ External Integrations │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Gitea │ │ n8n │ │ Webhook │ │
│ ├─────────────────┤ ├─────────────────┤ ├─────────────────┤ │
│ │ • Create Token │ │ • Create API Key│ │ • Key Created │ │
│ │ • List Tokens │ │ • List API Keys │ │ • Key Revoked │ │
│ │ • Delete Token │ │ • Delete API Key│ │ • Anomaly │ │
│ │ • Verify Token │ │ • Verify │ │ • Rate Limited │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
```
## Security Layers
```
┌─────────────────────────────────────────────────────────────────┐
│ Security Layers │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Layer 1: Network │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • IP Blacklist │ │
│ │ • Rate Limiting │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Layer 2: Authentication │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • API Key Hash (SHA256) │ │
│ │ • Constant-time Comparison │ │
│ │ • Key Validation (Status, Expiry) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Layer 3: Monitoring │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • Anomaly Detection │ │
│ │ • Audit Logging (Encrypted) │ │
│ │ • Webhook Notifications │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```
@@ -0,0 +1,461 @@
# Momentry API 使用流程
> **目標**: 從影片上傳到搜尋的完整流程
> **適用**: WordPress / n8n 整合
> **版本**: V1.0 | **日期**: 2026-03-25
---
## 流程總覽
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 1. 上傳 │ → │ 2. 註冊 │ → │ 3. 確認 │ → │ 4. 處理 │ → │ 5. 搜尋 │
│ SFTPGo │ │ 自動完成 │ │ UUID │ │ 查詢進度 │ │ 測試 │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
```
---
## Step 1: 上傳影片
### 方式 A: SFTP 上傳(推薦)
```bash
# 連線資訊
主機: sftpgo.momentry.ddns.net
連接埠: 2022
用戶名: demo
密碼: demopassword123
```
使用 FileZilla 或 SFTP 客戶端上傳到 `/` 目錄
### 方式 B: SFTP 命令列
```bash
sshpass -p "demopassword123" sftp -P 2022 demo@sftpgo.momentry.ddns.net
```
上傳後確認檔案在 SFTPGo 中的位置
---
## Step 2: 自動註冊
上傳後,系統會自動:
1. 偵測新檔案
2. 計算 UUIDSHA256
3. 建立資料庫記錄
**無需手動操作**
---
## Step 3: 確認註冊成功
### 查詢所有影片
```bash
curl -s -H "X-API-Key: YOUR_API_KEY" \
"https://api.momentry.ddns.net/api/v1/videos" | jq '.videos | length'
```
### 查詢特定檔案
```bash
curl -s -H "X-API-Key: YOUR_API_KEY" \
"https://api.momentry.ddns.net/api/v1/videos" | jq '.videos[] | select(.file_name | contains("你的檔案名"))'
```
### 預期回應
```json
{
"uuid": "952f5854b9febad1",
"file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/你的檔案.mp4",
"file_name": "你的檔案.mp4",
"duration": 123.45,
"width": 1920,
"height": 1080
}
```
**確認要點**:
- ✅ UUID 已產生(16位 hex
-`file_path` 正確
-`duration` > 0
---
## Step 4: 查詢處理進度
### 取得任務 UUID
```bash
# 從影片資訊取得 job_id
curl -s -H "X-API-Key: YOUR_API_KEY" \
"https://api.momentry.ddns.net/api/v1/videos" | \
jq '.videos[] | select(.file_name == "你的檔案.mp4") | {uuid, job_id}'
```
### 查詢任務狀態
```bash
curl -s -H "X-API-Key: YOUR_API_KEY" \
"https://api.momentry.ddns.net/api/v1/jobs/{uuid}"
```
### 任務狀態說明
| status | 說明 | 動作 |
|--------|------|------|
| `pending` | 等待處理 | 等待中 |
| `processing` | 處理中 | 繼續輪詢 |
| `completed` | 已完成 | 可進入 Step 5 |
| `failed` | 處理失敗 | 檢查錯誤 |
### n8n 輪詢範例
```javascript
// n8n Workflow: 檢查處理狀態
const jobUuid = $input.item.json.job_uuid;
const response = await fetch(
`https://api.momentry.ddns.net/api/v1/jobs/${jobUuid}`,
{
headers: {
"X-API-Key": "YOUR_API_KEY"
}
}
);
const job = await response.json();
// 狀態檢查
if (job.status === 'completed') {
return [{ json: { done: true, video_uuid: job.video_uuid } }];
} else {
return [{ json: { done: false, status: job.status } }];
}
```
---
## Step 5: 搜尋測試
處理完成後,資料會入庫到向量資料庫,可進行搜尋測試。
### 測試向量搜尋
```bash
curl -s -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": 5
}'
```
### 取得分段(Chunk)內容
搜尋結果會返回影片分段(Chunk),包含可播放的時間軸資訊:
```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
}
]
}
```
**Chunk 欄位說明**:
| 欄位 | 說明 |
|------|------|
| `uuid` | 影片 UUID(用於取得影片網址) |
| `chunk_id` | 分段 ID |
| `chunk_type` | 分段類型(sentence/cut/time/trace/story |
| `start_time` | 開始時間(秒) |
| `end_time` | 結束時間(秒) |
| `text` | 語音內容文字 |
| `score` | 相似度分數(0-1 |
### 播放分段
取得 Chunk 後可組合成播放網址:
```
影片網址?start={start_time}&end={end_time}
```
範例:
```
https://wp.momentry.ddns.net/video.mp4?start=5309.08&end=5311.08
```
---
## 完整 n8n Workflow 範例
```
┌──────────────┐
│ 觸發 (定時) │
└──────┬───────┘
┌──────────────┐ ┌──────────────┐
│ 查詢影片 │────►│ 比對新檔案 │
│ /videos │ │ │
└──────┬───────┘ └──────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ 等待處理 │◄────│ 輪詢任務狀態 │
│ /jobs/:uuid │ │ /jobs/:uuid │
└──────┬───────┘ └──────────────┘
▼ (completed)
┌──────────────┐
│ 搜尋測試 │
│ /search │
└──────────────┘
```
---
## 快速參考
| 步驟 | API | 用途 |
|------|-----|------|
| 查詢影片 | `GET /api/v1/videos` | 確認上傳成功 |
| 查詢任務 | `GET /api/v1/jobs/:uuid` | 查看處理進度 |
| 搜尋內容 | `POST /api/v1/search` | 測試搜尋功能 |
---
## WordPress PHP 範例
### 基本設定
```php
<?php
class Momentry_API {
private const API_URL = 'https://api.momentry.ddns.net';
private const API_KEY = 'YOUR_API_KEY';
public static function request(string $method, string $endpoint, ?array $data = null): array {
$url = self::API_URL . $endpoint;
$args = [
'method' => $method,
'headers' => [
'X-API-Key' => self::API_KEY,
'Content-Type' => 'application/json',
],
'timeout' => 30,
];
if ($data !== null) {
$args['body'] = json_encode($data);
}
$response = wp_remote_request($url, $args);
if (is_wp_error($response)) {
throw new Exception($response->get_error_message());
}
return json_decode(wp_remote_retrieve_body($response), true);
}
public static function getVideos(): array {
return self::request('GET', '/api/v1/videos');
}
public static function getVideo(string $uuid): array {
return self::request('GET', "/api/v1/videos/{$uuid}");
}
public static function getJob(string $uuid): array {
return self::request('GET', "/api/v1/jobs/{$uuid}");
}
public static function search(string $query, int $topK = 5): array {
return self::request('POST', '/api/v1/search', [
'query' => $query,
'top_k' => $topK,
]);
}
}
```
### Step 3: 確認註冊成功
```php
<?php
// 查詢所有影片
$videos = Momentry_API::getVideos();
foreach ($videos['videos'] as $video) {
echo "UUID: " . $video['uuid'] . "\n";
echo "檔案: " . $video['file_name'] . "\n";
echo "時長: " . $video['duration'] . "\n";
echo "---\n";
}
// 查詢特定影片
$video = Momentry_API::getVideo('952f5854b9febad1');
print_r($video);
```
### Step 4: 查詢處理進度
```php
<?php
// 取得任務狀態
$job = Momentry_API::getJob('9760d0820f0cf9a7');
switch ($job['status']) {
case 'pending':
echo "等待處理中...\n";
break;
case 'processing':
echo "處理中: " . $job['progress'] . "%\n";
break;
case 'completed':
echo "處理完成!\n";
break;
case 'failed':
echo "處理失敗: " . ($job['error'] ?? '未知錯誤') . "\n";
break;
}
```
### Step 5: 搜尋內容並取得 Chunk
```php
<?php
// 搜尋相關片段
$results = Momentry_API::search('測試關鍵字', 5);
foreach ($results['results'] as $result) {
echo "影片 UUID: " . $result['uuid'] . "\n";
echo "Chunk ID: " . $result['chunk_id'] . "\n";
echo "類型: " . $result['chunk_type'] . "\n";
echo "開始: " . $result['start_time'] . "s\n";
echo "結束: " . $result['end_time'] . "s\n";
echo "內容: " . ($result['text'] ?? '') . "\n";
echo "相似度: " . $result['score'] . "\n";
echo "---\n";
}
```
### WordPress Shortcode 範例(可點擊播放)
```php
<?php
// 在 functions.php 中加入
add_shortcode('momentry_search', function($atts) {
$atts = shortcode_atts([
'query' => '',
'limit' => 10,
], $atts);
if (empty($atts['query'])) {
return '<p>請輸入搜尋關鍵字</p>';
}
try {
$results = Momentry_API::search($atts['query'], $atts['limit']);
if (empty($results['results'])) {
return '<p>找不到相關結果</p>';
}
$html = '<div class="momentry-results">';
$html .= '<h3>搜尋結果: ' . esc_html($atts['query']) . '</h3>';
$html .= '<ul>';
foreach ($results['results'] as $result) {
$video_uuid = $result['uuid'];
$start = $result['start_time'] ?? 0;
$end = $result['end_time'] ?? 0;
$text = $result['text'] ?? '無文字描述';
$html .= '<li>';
$html .= '<a href="/player?uuid=' . esc_attr($video_uuid) .
'&start=' . esc_attr($start) .
'&end=' . esc_attr($end) . '">';
$html .= '播放 ' . $start . 's - ' . $end . 's';
$html .= '</a>';
$html .= '<br>';
$html .= '<small>相似度: ' . round($result['score'] * 100) . '%</small>';
$html .= '<br>';
$html .= esc_html($text);
$html .= '</li>';
}
$html .= '</ul></div>';
return $html;
} catch (Exception $e) {
return '<p>搜尋服務暫時無法使用</p>';
}
});
```
**使用方式**:
```html
[momentry_search query="關鍵字" limit="5"]
```
---
## 完整 n8n Workflow 範例
```
┌──────────────┐
│ 觸發 (定時) │
└──────┬───────┘
┌──────────────┐ ┌──────────────┐
│ 查詢影片 │────►│ 比對新檔案 │
│ /videos │ │ │
└──────┬───────┘ └──────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ 等待處理 │◄────│ 輪詢任務狀態 │
│ /jobs/:uuid │ │ /jobs/:uuid │
└──────┬───────┘ └──────────────┘
▼ (completed)
┌──────────────┐
│ 搜尋測試 │
│ /search │
└──────────────┘
```
---
**注意**:
- 處理時間視影片長度而定(1分鐘影片約需 2-5 分鐘處理)
- 大量影片時建議分批上傳
---
## 附錄:版本歷史
| 版本 | 日期 | 內容 | 操作人 |
|------|------|------|--------|
| V1.0 | 2026-03-25 | 初版建立 | OpenCode |
| V1.1 | 2026-03-25 | 新增 Chunk 取得與播放說明、Shortcode 範例 | OpenCode |
| V1.2 | 2026-03-25 | 修正 SFTPGo 主機名稱為 sftpgo.momentry.ddns.net | OpenCode |
@@ -0,0 +1,331 @@
# 架構優化待評估事項
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-03-21 |
| 文件版本 | V1.0 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 |
|------|------|------|--------|
| V1.0 | 2026-03-21 | 創建文件 | OpenCode |
| V1.1 | 2026-03-22 | 新增 TigerGraph/GraphRAG 說故事評估 | OpenCode |
---
## 架構優化項目
### 1. PostgreSQL → Redis 故障轉移
**說明**: 當 PostgreSQL 不可用時,降級到 Redis 作為臨時存儲
**複雜度**: 中
**影響範圍**:
- `src/core/db/postgres_db.rs`
- `src/core/db/redis_client.rs`
**風險**:
- 數據一致性問題
- 需要定義轉移策略
**優先級**: 待評估
---
### 2. 連接池監控
**說明**: 添加 PostgreSQL 和 Redis 連接池指標到 Prometheus
**複雜度**: 低
**影響範圍**:
- `src/core/db/postgres_db.rs`
- `src/core/db/redis_client.rs`
- `src/api/` (新增 metrics endpoint)
**風險**: 低
**優先級**: 待評估
---
### 3. Processor 重試機制
**說明**: 當 processor 失敗時自動重試
**複雜度**: 中
**影響範圍**:
- `src/core/processor/executor.rs` (新增 `run_with_retry` 方法)
- `src/core/processor/mod.rs` (導出 `RetryConfig`)
**風險**:
- 無限重試風險 → 已通過 `max_attempts` 控制
- 需要指數退避 → 已實現
**優先級**: ✅ 已完成 (2026-03-21)
**實作內容**:
- `RetryConfig` 結構體 (可配置重試次數、初始延遲、最大延遲、退避倍數)
- `run_with_retry()` 方法 (自動重試 + 指數退避)
- 單元測試覆蓋
**使用範例**:
```rust
use crate::core::processor::{PythonExecutor, RetryConfig};
let executor = PythonExecutor::new()?;
let config = RetryConfig::new(3).with_delay(1000).with_max_delay(30000);
executor.run_with_retry(
"asr_processor.py",
&["--input", "/path/to/video"],
Some(&uuid),
"asr",
Some(Duration::from_secs(3600)),
Some(config),
).await?;
```
---
### 4. PyO3 整合
**說明**: Python/Rust 直接調用,移除子進程調用
**複雜度**: 高
**影響範圍**:
- `src/core/processor/executor.rs` (重寫)
- Python 模組 (修改為可直接 import)
**風險**:
- Python GIL 問題
- 依賴版本兼容性
- 需要大量重寫
**優先級**: 低 (長期目標)
---
### 5. HTTP 健康端點
**說明**: 添加 `/health` API 用於外部監控
**複雜度**: 低
**影響範圍**:
- `src/api/server.rs` (新增路由)
**風險**: 低
**優先級**: ✅ 已完成 (2026-03-21)
**實作內容**:
- `GET /health` - 基本健康檢查 (status, version, uptime)
- `GET /health/detailed` - 詳細健康檢查 (PostgreSQL, Redis, Qdrant 狀態和延遲)
---
### 6. Gitea Actions CI/CD
**說明**: 配置 Gitea Actions 自動化 CI/CD,在合併前執行檢查
**複雜度**: 中
**影響範圍**:
- `.gitea/workflows/` (新增 workflow 文件)
**優點**:
- 強制執行檢查,無法跳過
- 跨設備一致
- PR 審查前自動檢查
**風險**: 低
**優先級**: 待評估
---
### 7. Commit Message Lint
**說明**: 規範化提交訊息格式 (Conventional Commits)
**複雜度**: 低
**影響範圍**:
- `.git/hooks/commit-msg` (新增 hook)
- `~/dotfiles/hooks/commit-msg`
**風險**: 低
**優先級**: ✅ 已完成 (2026-03-21)
**實作內容**:
- 驗證格式: `<type>(<scope>): <description>`
- 有效類型: feat, fix, docs, style, refactor, test, chore, perf, ci, build, revert
- 警告: 第一行超過 72 字符
**範例**:
```
feat(api): add health check endpoint
fix(db): resolve connection pool issue
docs: update README
```
---
### 8. 自動化安裝腳本
**說明**: 創建腳本一次安裝所有開發工具
**複雜度**: 低
**影響範圍**:
- `scripts/install-dev-tools.sh` (新增)
**風險**: 低
**優先級**: 待評估
---
## 評估標準
| 標準 | 說明 |
|------|------|
| 業務價值 | 對用戶有何幫助 |
| 技術風險 | 實現難度和潛在問題 |
| 維護成本 | 未來維護負擔 |
| 依賴性 | 對其他系統的影響 |
---
## 評估記錄
| 項目 | 評估日期 | 決策 | 原因 |
|------|----------|------|------|
| PostgreSQL → Redis 故障轉移 | 待評估 | - | - |
| 連接池監控 | 待評估 | - | - |
| Processor 重試機制 | 2026-03-21 | 已完成 | - |
| PyO3 整合 | 待評估 | - | - |
| HTTP 健康端點 | 2026-03-21 | 已完成 | - |
| Gitea Actions CI/CD | 待評估 | - | - |
| Commit Message Lint | 2026-03-21 | 已完成 | - |
| 自動化安裝腳本 | 待評估 | - | - |
---
## 9. TigerGraph / Knowledge Graph 圖譜說故事
**說明**: 使用知識圖譜 (Knowledge Graph) 增強視頻敘事 (Storytelling) 和 RAG 檢索
**複雜度**: 高
**研究來源**:
- [TigerGraph Agentic GraphRAG](https://www.tigergraph.com/blog/agentic-graphrag-gives-ai-a-playbook-for-smarter-retrieval/) (2025-12-15)
- [TigerGraph GraphRAG GitHub](https://github.com/tigergraph/graphrag) (v1.2.0, 2026-03-11)
- [GraphRAG in 2026: Practitioner's Guide](https://medium.com/graph-praxis/graph-rag-in-2026-a-practitioners-guide-to-what-actually-works-dca4962e7517) (2026-02-22)
- [GraphRAG Complete Guide](https://medium.com/@brian-curry-research/graphrag-the-complete-guide-to-graph-powered-retrieval-augmented-generation-eeb58a6bb4d1) (2026-02-11)
### 核心概念
| 概念 | 說明 |
|------|------|
| **GraphRAG** | 結合知識圖譜與 RAG,比傳統向量檢索更智能 |
| **知識圖譜** | 實體 (Entity) + 關係 (Relationship) 的結構化表示 |
| **多跳推理** | Multi-hop traversal,可連接多個相關節點 |
| **混合檢索** | Graph traversal + Vector similarity 結合 |
### 對 Momentry 的潛在應用
```
視頻場景 → 實體識別 → 關係建立 → 故事圖譜
↓ ↓ ↓ ↓
CUT [人物, 物品, 動作] [誰做了什麼, 什麼導致什麼] [敘事鏈]
```
**1. 敘事圖譜構建 (Narrative Graph)**
- 從 Story/Chunks 模組提取實體
- 建立場景之間的因果關係
- 追蹤角色互動和情節發展
**2. 故事檢索增強**
```python
# 現有: Parent-child chunks
parent_chunk: "場景描述"
child_chunks: [詳細內容]
# 加入圖譜:
場景A --led_to--> 場景B
角色X --interacted_with--> 角色Y
主題Y --related_to--> 主題Z
```
**3. 查詢模式**
| 查詢類型 | 傳統 RAG | GraphRAG |
|----------|----------|----------|
| 事實查找 | ✅ "這個場景在說什麼" | ✅ |
| 主題推理 | ❌ "這個視頻的主要情節" | ✅ Global search |
| 多跳關係 | ❌ | ✅ "A導致BB導致C" |
| 可解釋性 | ❌ | ✅ 關係路徑可追溯 |
### 實作方案
**方案 A: TigerGraph Cloud (推薦)**
- ✅ 原生 Graph + Vector 混合查詢
- ✅ GraphRAG 官方支援
- ✅ 200GB 免費額度
- ❌ 雲端依賴,延遲敏感場景需考慮
**方案 B: Neo4j + Qdrant**
- ✅ 成熟開源生態
- ✅ LangChain/LlamaIndex 整合
- ❌ 需要維護兩個系統
**方案 C: 自建混合架構**
- PostgreSQL + Neo4j (或Typesense)
- 利用現有 BM25 + 向量檢索基礎
- ❌ 開發成本高
### 技術棧整合建議
```rust
// 現有架構
Vector Search (Qdrant) BM25 (PostgreSQL)
// 加入 GraphRAG
Knowledge Graph (TigerGraph/Neo4j)
Vector + Graph traversal
```
### 優先級: 待評估
**考慮因素**:
- 用戶是否需要複雜的故事情節查詢?
- 實體識別 (NER) 成本是否可以接受?
- 與現有 BM25 + Vector 混合搜索的比較優勢?
---
## 10. LazyGraphRAG / FastGraphRAG 成本優化
**說明**: GraphRAG 索引成本高昂,LazyGraphRAG 推遲圖譜構建到查詢時
**來源**: [GraphRAG in 2026](https://medium.com/graph-praxis/graph-rag-in-2026-a-practitioners-guide-to-what-actually-works-dca4962e7517)
**Microsoft GraphRAG 問題**: $33K 索引大型數據集
**替代方案**:
- **LazyGraphRAG**: 按需構建,查詢時再建立子圖
- **FastGraphRAG**: 優化索引管道,10-90% 成本節省
- **HippoRAG**: 使用 Personalised PageRank 優化遍歷
**優先級**: 待評估 (作為 GraphRAG 的一部分)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,682 @@
# Job Worker 實作計畫
| 項目 | 內容 |
|------|------|
| 建立者 | Warren / OpenCode |
| 建立時間 | 2026-03-24 |
| 文件版本 | V1.1 |
| 狀態 | ✅ 已實作 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 |
|------|------|------|--------|
| V1.0 | 2026-03-24 | 建立實作計畫 | OpenCode |
| V1.1 | 2026-03-25 | 實作完成,更新狀態 | OpenCode |
---
## 實作狀態
### ✅ 已完成
| 元件 | 檔案 | 狀態 |
|------|------|------|
| MonitorJob 結構 | `src/core/db/postgres_db.rs` | ✅ |
| ProcessorResult 結構 | `src/core/db/postgres_db.rs` | ✅ |
| Worker 配置 | `src/worker/config.rs` | ✅ |
| Job Worker | `src/worker/job_worker.rs` | ✅ |
| Processor Pool | `src/worker/processor.rs` | ✅ |
| Worker 模組 | `src/worker/mod.rs` | ✅ |
| PostgreSQL 表格 | `monitor_jobs`, `processor_results` | ✅ |
| 類型修復 | `i32`, `NaiveDateTime` | ✅ |
### 待整合
| 項目 | 說明 |
|------|------|
| Worker 服務啟動 | 需要加入 launchd plist |
| 監控整合 | 需要加入 MOMENTRY_CORE_MONITORING.md |
| 備份涵蓋 | 需要確認備份包含新表格 |
---
## 1. 設計決策
### 1.1 確認的設計決策
| 項目 | 決策 | 理由 |
|------|------|------|
| 觸發方式 | 輪詢(Job Worker) | 暫無可靠的 API 觸發機制 |
| 並行處理 | 最多 2 個 | 可根據 CPU/GPU 能力調整 |
| 失敗處理 | 獨立模組,部分完成可接續 | 任何模組失敗都產出狀態記錄 |
| Worker 啟動 | 獨立進程 | 隔離、易管理 |
| 並行上限調整 | 環境變數 + 預設值 | 靈活、可調整 |
| 狀態同步 | PostgreSQL + Redis | 可靠 + 即時 |
### 1.2 環境變數
| 變數 | 預設值 | 說明 |
|------|--------|------|
| `MOMENTRY_MAX_CONCURRENT` | 2 | 最大並行 processor 數 |
| `MOMENTRY_POLL_INTERVAL` | 5 | 輪詢間隔(秒) |
| `MOMENTRY_WORKER_ENABLED` | true | 是否啟用 worker |
---
## 2. 系統架構
### 2.1 完整流程圖
```
┌─────────────────────────────────────────────────────────────────────────┐
│ 檔案註冊觸發處理流程 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. SFTPGo 上傳 │
│ │ │
│ ▼ │
│ 2. Hook 呼叫 Register API │
│ │ │
│ ▼ │
│ 3. Register API │
│ ├─► ffprobe 提取 metadata │
│ ├─► 寫入 videos 表 │
│ └─► 建立 monitor_jobs 記錄 (status=pending) │
│ │ │
│ ▼ │
│ 4. Job Worker (獨立進程,輪詢機制) │
│ ├─► 輪詢 pending jobs │
│ ├─► 檢查 videos 表 fs_json 決定需要處理什麼 │
│ ├─► 並行執行 processors (最多 2 個) │
│ └─► 更新 videos, monitor_jobs, processor_results 表 │
│ │ │
│ ▼ │
│ 5. 處理結果 │
│ ├─► 更新 videos 表 (fs_json, psql_chunk, qvector_chunk) │
│ ├─► 更新 monitor_jobs 表 (status, progress) │
│ ├─► 更新 processor_results 表 (每個模組狀態) │
│ └─► Redis Pub/Sub 即時進度 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
```
### 2.2 Job Worker 架構
```
┌─────────────────────────────────────────────────────────────────────┐
│ Job Worker 架構 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ PostgreSQL │ ───▶ │ Worker │ ───▶ │ Processor │ │
│ │ Job Queue │ │ Loop │ │ Pool │ │
│ └─────────────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Video State │ │ Processor 1 │ │
│ │ Check │ │ (ASR/YOLO) │ │
│ └─────────────┘ ├─────────────┤ │
│ │ Processor 2 │ │
│ │ (CUT/OCR) │ │
│ └─────────────┘ │
│ │
│ Redis ──── Pub/Sub ──── 即時進度 │
│ │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 3. 資料庫結構
### 3.1 Migration 檔案
**檔案**: `migrations/003_job_worker.sql`
```sql
-- ================================================================
-- Migration 003: Job Worker System
-- ================================================================
-- 3.1.1 更新 videos 表
ALTER TABLE videos ADD COLUMN IF NOT EXISTS status VARCHAR(20) DEFAULT 'pending';
ALTER TABLE videos ADD COLUMN IF NOT EXISTS user_id BIGINT;
ALTER TABLE videos ADD COLUMN IF NOT EXISTS job_id INTEGER REFERENCES monitor_jobs(id);
COMMENT ON COLUMN videos.status IS 'pending, processing, completed, failed';
COMMENT ON COLUMN videos.user_id IS 'WordPress user ID';
COMMENT ON COLUMN videos.job_id IS 'Associated monitor_jobs ID';
-- 3.1.2 更新 monitor_jobs 表
ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS video_id BIGINT REFERENCES videos(id);
ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS user_id BIGINT;
ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS processors VARCHAR(20)[];
ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS completed_processors VARCHAR(20)[];
ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS failed_processors VARCHAR(20)[];
COMMENT ON COLUMN monitor_jobs.processors IS 'Processors to run: asr, cut, yolo, ocr, face, pose, asrx';
COMMENT ON COLUMN monitor_jobs.completed_processors IS 'Successfully completed processors';
COMMENT ON COLUMN monitor_jobs.failed_processors IS 'Failed processors';
-- 3.1.3 新增 processor_results 表
CREATE TABLE IF NOT EXISTS processor_results (
id SERIAL PRIMARY KEY,
job_id INTEGER REFERENCES monitor_jobs(id) ON DELETE CASCADE,
video_id BIGINT REFERENCES videos(id) ON DELETE CASCADE,
processor VARCHAR(20) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'pending',
output_path TEXT,
started_at TIMESTAMP,
completed_at TIMESTAMP,
error_message TEXT,
progress_total INT DEFAULT 0,
progress_current INT DEFAULT 0,
last_checkpoint JSONB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(job_id, processor)
);
CREATE INDEX IF NOT EXISTS idx_processor_results_job ON processor_results(job_id);
CREATE INDEX IF NOT EXISTS idx_processor_results_video ON processor_results(video_id);
CREATE INDEX IF NOT EXISTS idx_processor_results_status ON processor_results(status);
COMMENT ON TABLE processor_results IS 'Tracks individual processor execution status';
COMMENT ON COLUMN processor_results.status IS 'pending, running, completed, failed, skipped';
-- 3.1.4 更新 videos 表標記欄位用途
COMMENT ON COLUMN videos.fs_video IS 'Video file exists on filesystem';
COMMENT ON COLUMN videos.fs_json IS 'All processor JSON files generated';
COMMENT ON COLUMN videos.fs_chunks IS 'Chunk files generated';
COMMENT ON COLUMN videos.fs_vectors IS 'Vector files generated';
COMMENT ON COLUMN videos.psql_chunk IS 'Chunks stored in PostgreSQL';
COMMENT ON COLUMN videos.pvector_chunk IS 'Vectors stored in PostgreSQL';
COMMENT ON COLUMN videos.qvector_chunk IS 'Vectors stored in Qdrant';
```
### 3.2 表關係圖
```
videos monitor_jobs
┌──────────────────────┐ ┌──────────────────────┐
│ id (PK) │◄────────│ video_id (FK) │
│ uuid │ │ user_id │
│ status │ │ processors[] │
│ fs_video │ │ completed_processors[]│
│ fs_json │ │ failed_processors[] │
│ job_id (FK)─────────┼────────►│ status │
│ user_id │ │ id (PK) │
└──────────────────────┘ └──────────────────────┘
processor_results
┌──────────────────────┐
│ job_id (FK) │
│ video_id (FK) │
│ processor │
│ status │
│ progress_current │
│ last_checkpoint │
│ id (PK) │
└──────────────────────┘
```
---
## 4. 模組並行策略
### 4.1 模組分類
| 模組 | 資源需求 | 獨立性 | 建議並行 |
|------|----------|--------|----------|
| ASR | GPU/CPU | 高 | ✅ 可並行 |
| CUT | CPU | 高 | ✅ 可並行 |
| YOLO | GPU | 中 | ✅ 可並行 |
| OCR | GPU/CPU | 高 | ✅ 可並行 |
| Face | GPU | 中 | ✅ 可並行 |
| Pose | GPU | 中 | ✅ 可並行 |
| ASRX | GPU/CPU | 高 | ✅ 可並行 |
### 4.2 建議並行組合
| 組合 | 模組 1 | 模組 2 | 說明 |
|------|---------|---------|------|
| GPU+CPU | YOLO/Pose/Face | ASR/CUT/OCR | 平衡負載 |
| 雙GPU | YOLO | Pose | 雙 GPU 卡片 |
| 雙CPU | ASR | CUT/OCR | 無 GPU 時 |
### 4.3 Worker 配置
```rust
// src/worker/config.rs
#[derive(Debug, Clone)]
pub struct WorkerConfig {
pub max_concurrent: usize, // 預設 2
pub poll_interval_secs: u64, // 預設 5
pub enabled: bool, // 預設 true
}
impl Default for WorkerConfig {
fn default() -> Self {
Self {
max_concurrent: 2,
poll_interval_secs: 5,
enabled: true,
}
}
}
impl WorkerConfig {
pub fn from_env() -> Self {
Self {
max_concurrent: std::env::var("MOMENTRY_MAX_CONCURRENT")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(2),
poll_interval_secs: std::env::var("MOMENTRY_POLL_INTERVAL")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(5),
enabled: std::env::var("MOMENTRY_WORKER_ENABLED")
.ok()
.map(|v| v != "false")
.unwrap_or(true),
}
}
}
```
---
## 5. 失敗處理機制
### 5.1 設計原則
```
每個模組獨立處理:
- 成功 → 產出完整 .jsonstatus=completed
- 失敗 → 產出 .json 包含 error 狀態,status=failed
- 部分完成 → 可從 checkpoint 繼續,status=running
```
### 5.2 Processor 輸出格式
```json
{
"processor": "asr",
"status": "completed|failed|partial",
"completed_at": "2026-03-24T12:00:00Z",
"result": { ... },
"error": null,
"last_checkpoint": {
"frame": 5000,
"timestamp": 180.5
}
}
```
### 5.3 失敗處理流程
```rust
async fn run_processor(&self, module: &str, video: &Video) -> Result<()> {
let output_path = self.get_output_path(video, module);
match self.execute_processor(module, video, &output_path).await {
Ok(result) => {
// 成功:更新狀態
self.db.update_processor_status(job_id, module, "completed").await?;
self.publish_progress(job_id, module, 100).await?;
}
Err(e) => {
// 失敗:仍然保存部分結果
let partial_result = self.get_partial_result(&output_path);
self.db.update_processor_status(job_id, module, "failed").await?;
self.db.save_error_message(job_id, module, &e.to_string()).await?;
// 記錄錯誤但不中斷其他模組
tracing::warn!("Processor {} failed: {}", module, e);
}
}
Ok(())
}
```
---
## 6. 實作結構
### 6.1 目錄結構
```
src/
├── worker/
│ ├── mod.rs # Worker 模組導出
│ ├── config.rs # Worker 配置
│ ├── worker.rs # Worker 主邏輯
│ ├── processor.rs # Processor 執行器
│ ├── queue.rs # Job 佇列管理
│ └── progress.rs # 進度追蹤
├── api/
│ └── server.rs # 更新 Register API
└── main.rs # 新增 worker 命令
```
### 6.2 核心模組
#### 6.2.1 Worker Config (`src/worker/config.rs`)
```rust
pub struct WorkerConfig {
pub max_concurrent: usize,
pub poll_interval_secs: u64,
pub enabled: bool,
}
impl WorkerConfig {
pub fn from_env() -> Self { ... }
}
```
#### 6.2.2 Worker Loop (`src/worker/worker.rs`)
```rust
pub struct JobWorker {
db: PostgresDb,
redis: RedisCache,
config: WorkerConfig,
semaphore: Arc<Semaphore>,
}
impl JobWorker {
pub async fn run(&self) -> Result<()> {
loop {
if self.config.enabled {
self.process_pending_jobs().await?;
}
tokio::time::sleep(Duration::from_secs(self.config.poll_interval_secs)).await;
}
}
async fn process_pending_jobs(&self) -> Result<()> {
// 1. 檢查並發數
// 2. 取得 pending jobs
// 3. 分配給 worker pool
// 4. 並行執行 processors
}
}
```
#### 6.2.3 Processor Pool (`src/worker/processor.rs`)
```rust
pub struct ProcessorPool {
max_concurrent: usize,
}
impl ProcessorPool {
pub async fn execute(&self, job: &Job, video: &Video) -> Result<ProcessorResult> {
// 根據 videos 表決定需要執行哪些 processor
// 並行執行最多 2 個
// 處理失敗但不中斷其他 processor
}
}
```
---
## 7. API 端點設計
### 7.1 新增端點
| 端點 | 方法 | 說明 |
|------|------|------|
| `/api/v1/jobs` | GET | 列出所有 jobs |
| `/api/v1/jobs/:uuid` | GET | 取得特定 job 詳細 |
| `/api/v1/jobs/:uuid/retry` | POST | 重試失敗的 processor |
| `/api/v1/jobs/:uuid/cancel` | POST | 取消 job |
### 7.2 端點詳情
#### GET /api/v1/jobs
```json
Response:
{
"jobs": [
{
"id": 1,
"uuid": "abc123def456",
"status": "running",
"progress": 60,
"processors": ["asr", "cut", "yolo", "ocr", "face", "pose"],
"completed": ["asr", "cut", "yolo"],
"failed": []
}
]
}
```
#### GET /api/v1/jobs/:uuid
```json
Response:
{
"id": 1,
"uuid": "abc123def456",
"video_id": 10,
"status": "running",
"processors": {
"asr": {"status": "completed", "progress": 100},
"cut": {"status": "completed", "progress": 100},
"yolo": {"status": "running", "progress": 45, "current": 5000, "total": 11000},
"ocr": {"status": "pending"},
"face": {"status": "pending"},
"pose": {"status": "pending"}
},
"created_at": "2026-03-24T12:00:00Z",
"started_at": "2026-03-24T12:01:00Z"
}
```
---
## 8. Redis Key 設計
### 8.1 現有 Key 保持
```bash
momentry:job:{uuid} # Job Hash
momentry:job:{uuid}:processor:{name} # Processor Hash
momentry:progress:{uuid} # Pub/Sub Channel
momentry:jobs:active # Set: 運行中 UUIDs
momentry:jobs:completed # Set: 完成 UUIDs
momentry:jobs:failed # Set: 失敗 UUIDs
```
### 8.2 進度更新時序
```
Processor 執行
├─► 每秒更新 Redis Hash (即時)
├─► 每 10% 或完成時更新 PostgreSQL (持久)
└─► 失敗時立即更新 PostgreSQL (錯誤記錄)
```
---
## 9. 實作順序
### Phase 1: 資料庫遷移
| 任務 | 說明 |
|------|------|
| 1.1 | 建立 `migrations/003_job_worker.sql` |
| 1.2 | 更新 `postgres_db.rs` 對應的 struct |
| 1.3 | 執行 migration 驗證 |
### Phase 2: Worker 框架
| 任務 | 說明 |
|------|------|
| 2.1 | 建立 `src/worker/mod.rs` |
| 2.2 | 建立 `src/worker/config.rs` |
| 2.3 | 建立 `src/worker/worker.rs` |
| 2.4 | 建立 `src/worker/processor.rs` |
### Phase 3: Register API 整合
| 任務 | 說明 |
|------|------|
| 3.1 | 修改 `src/api/server.rs` 的 register 函數 |
| 3.2 | 加入建立 monitor_jobs 的邏輯 |
| 3.3 | 更新 videos 表 status 欄位 |
### Phase 4: Processor 執行
| 任務 | 說明 |
|------|------|
| 4.1 | 實作 processor 並行執行(最多 2 個) |
| 4.2 | 實作失敗處理(保存部分結果) |
| 4.3 | 實作 checkpoint 恢復 |
### Phase 5: 進度追蹤
| 任務 | 說明 |
|------|------|
| 5.1 | Redis Pub/Sub 整合 |
| 5.2 | PostgreSQL 定期同步 |
| 5.3 | API 進度端點更新 |
### Phase 6: API 端點
| 任務 | 說明 |
|------|------|
| 6.1 | GET /api/v1/jobs |
| 6.2 | GET /api/v1/jobs/:uuid |
| 6.3 | POST /api/v1/jobs/:uuid/retry |
| 6.4 | POST /api/v1/jobs/:uuid/cancel |
### Phase 7: CLI 命令
| 任務 | 說明 |
|------|------|
| 7.1 | `cargo run -- worker` 命令 |
| 7.2 | Worker 啟動/停止/狀態顯示 |
| 7.3 | launchd plist 設定 |
### Phase 8: 測試
| 任務 | 說明 |
|------|------|
| 8.1 | 單元測試 |
| 8.2 | 端到端測試 |
| 8.3 | 失敗處理測試 |
| 8.4 | 並行執行測試 |
---
## 10. CLI 命令
### 10.1 Worker 命令
```bash
# 啟動 worker
cargo run -- worker
# 顯示 worker 幫助
cargo run -- worker --help
```
### 10.2 環境變數
```bash
# Worker 配置
export MOMENTRY_MAX_CONCURRENT=2
export MOMENTRY_POLL_INTERVAL=5
export MOMENTRY_WORKER_ENABLED=true
# 現有環境變數
export DATABASE_URL=postgres://accusys@localhost:5432/momentry
export REDIS_URL=redis://:accusys@localhost:6379
```
---
## 11. 預估工時
| Phase | 任務 | 預估工時 |
|-------|------|----------|
| 1 | 資料庫遷移 | 2h |
| 2 | Worker 框架 | 4h |
| 3 | Register API 整合 | 2h |
| 4 | Processor 執行 | 4h |
| 5 | 進度追蹤 | 2h |
| 6 | API 端點 | 3h |
| 7 | CLI 命令 | 2h |
| 8 | 測試 | 4h |
| **總計** | | **23h** |
---
## 12. 參考文件
| 文件 | 用途 |
|------|------|
| `docs/MOMENTRY_CORE_MONITORING.md` | 監控系統規範 |
| `docs/MOMENTRY_CORE_REDIS_KEYS.md` | Redis Key 設計 |
| `docs/PROCESSING_PIPELINE.md` | 處理流程 |
| `docs/CHUNK_DESIGN.md` | 資料庫設計 |
| `docs/API_REFERENCE.md` | API 參考 |
---
## 13. 附錄
### A. 狀態機
```
┌──────────────┐
│ PENDING │
└──────┬───────┘
│ register 後
┌──────────────┐
┌─────▶│ PROCESSING │◀──────┐
│ └──────┬───────┘ │
│ │ │
部分失敗 all completed 全部失敗
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ PARTIAL │ │COMPLETED │ │ FAILED │
└──────────┘ └──────────┘ └──────────┘
```
### B. videos 表 status 欄位
| 值 | 說明 |
|------|------|
| `pending` | 已註冊,等待處理 |
| `processing` | 處理中 |
| `completed` | 所有處理完成 |
| `failed` | 處理失敗 |
### C. processor_results 表 status 欄位
| 值 | 說明 |
|------|------|
| `pending` | 等待執行 |
| `running` | 執行中 |
| `completed` | 執行成功 |
| `failed` | 執行失敗 |
| `skipped` | 跳過(如檔案已存在) |
@@ -0,0 +1,782 @@
# Momentry 系統自動化安裝計劃
> **計劃階段** - 僅供討論,尚未執行
> **建立時間**: 2026-03-23
> **目標**: Thunderbolt NVMe 外開機完整安裝
---
## 系統概述
### 當前環境
| 項目 | 內容 |
|------|------|
| **主控機** | Mac mini (M4, 16GB RAM) |
| **作業系統** | macOS 26.3.1 (Tahoe) |
| **儲存** | Thunderbolt NVMe (2TB) |
| **用途** | 開機碟 + 完整 Momentry 系統 |
### 目標環境
| 項目 | 內容 |
|------|------|
| **目標主機** | 其他 Mac (Intel 或 Apple Silicon) |
| **安裝方式** | Thunderbolt NVMe 外接開機 |
| **連接方式** | Thunderbolt 3/4 |
| **控制方式** | SSH 遠端管理 |
---
## 系統架構
### 服務列表
| 服務 | 版本 | 用途 | Port |
|------|------|------|------|
| **PostgreSQL** | 18.1 | 主資料庫、n8n 資料庫 | 5432 |
| **MongoDB** | 8.0 | 文件資料庫 | 27017 |
| **MariaDB** | 11.4 | WordPress 資料庫 | 3306 |
| **Redis** | 7.x | 快取、佇列 | 6379 |
| **Qdrant** | 1.7.x | 向量資料庫 | 6333 |
| **Ollama** | 0.13.5 | 本地 LLM | 11434 |
| **Caddy** | 2.x | 反向代理 | 80/443 |
| **Gitea** | 1.21 | Git 服務 | 3000 |
| **PHP-FPM** | 8.5 | WordPress | 9000 |
| **n8n** | 2.3.5 | 工作流程自動化 | 5678 |
| **RustDesk** | hbbs/hbbr | 遠端桌面 | 21115-21119 |
| **SFTPGo** | 2.x | SFTP 服務 | 2022 |
| **Momentry Core** | 0.1.0 | 影片處理核心 | 3002 |
| **Prometheus** | 3.9.1 | 監控 | 9090 |
### 目錄結構
```
/Volumes/Momentry/
├── System/
│ └── macOS/ # macOS 系統
├── Applications/
│ └── Homebrew/ # Homebrew 應用程式
├── momentry/
│ ├── var/ # 資料目錄
│ │ ├── postgresql/ # PostgreSQL 資料
│ │ ├── mongodb/ # MongoDB 資料
│ │ ├── mariadb/ # MariaDB 資料
│ │ ├── redis/ # Redis 資料
│ │ ├── qdrant/ # Qdrant 資料
│ │ ├── n8n/ # n8n 資料
│ │ ├── ollama/ # Ollama 模型
│ │ └── ...
│ ├── etc/ # 配置檔案
│ │ ├── Caddyfile
│ │ ├── gitea/
│ │ ├── php/
│ │ └── ...
│ ├── log/ # 日誌
│ ├── scripts/ # 管理腳本
│ └── backup/ # 備份
├── momentry_core/ # Rust 原始碼
└── momentry_dashboard/ # Web Dashboard
```
---
## 階段一:前置準備
### 1.1 收集目標主機資訊
```bash
# 需要收集的資訊
- Mac 型號 (Intel/Apple Silicon)
- macOS 版本
- Thunderbolt 版本 (3/4)
- 可用記憶體
- 目標磁碟代號 (diskX)
- 網路配置 (DHCP/固定 IP)
```
### 1.2 準備 Thunderbolt NVMe
```bash
# 檢查 Thunderbolt NVMe
diskutil list external
# 預期輸出:
# /dev/diskX (external, physical):
# NAME TYPE SIZE
# Thunderbolt NVMe ...
```
### 1.3 準備主控機腳本
```bash
# 主控機需要準備的腳本
~/momentry/setup/
├── 01_prepare_disk.sh
├── 02_install_macos.sh
├── 03_install_homebrew.sh
├── 04_install_dependencies.sh
├── 05_install_services.sh
├── 06_install_momentry.sh
├── 07_configure_network.sh
├── 08_start_services.sh
└── utils/
├── common.sh
├── backup.sh
└── monitor.sh
```
---
## 階段二:Thunderbolt NVMe 準備
### 2.1 分割磁碟方案 A(推薦)
```bash
# 磁碟分割配置
diskutil partitionDisk /dev/diskX \
GPT \
"APFS System" APFS "Momentry System" 200G \
"APFS Data" APFS "Momentry Data" 1.8T
```
### 2.2 分割磁碟方案 B(最小化)
```bash
# 統一 APFS 容器
diskutil partitionDisk /dev/diskX \
GPT \
APFS "Momentry" 100%
```
---
## 階段三:安裝 macOS
### 3.1 建立 macOS 安裝碟
```bash
# 下載 macOS Sonoma (或最新版本)
softwareupdate --fetch-full-installer --full-installer-version 14.0
# 建立可開機安裝碟
sudo /Applications/Install\ macOS\ Sonoma.app/Contents/Resources/createinstallinstmedi \
--volume /Volumes/Momentry \
--nointeraction
```
### 3.2 安裝 macOS 到 Thunderbolt NVMe
**兩種方法:**
#### 方法 A: 復原模式安裝
1. 連接 Thunderbolt NVMe
2. 重啟目標主機,按住Option鍵
3. 選擇 Thunderbolt NVMe 開機
4. 進入 Recovery Mode (Command+R)
5. 使用 Disk Utility 格式化目標磁碟
6. 安裝 macOS
#### 方法 B: ASR 複製(建議)
```bash
# 從主控機執行
# 將現有系統複製到目標磁碟
sudo asr restore \
--source /Volumes/Macintosh\ HD \
--target /Volumes/Momentry \
--erase --noprompt
```
### 3.3 設定 macOS
```bash
# 自動化設定腳本
./setup/scripts/03_install_homebrew.sh
```
**設定項目:**
- 電腦名稱:`momentry-<serial>`
- 使用者帳號:`momentry` (管理員)
- SSH 遠端登入:啟用
- 螢幕鎖定:關閉
- 節能設定:永不休眠
---
## 階段四:安裝 Homebrew
### 4.1 安裝 Homebrew
```bash
#!/bin/bash
# 04_install_homebrew.sh
# 檢查架構
ARCH=$(uname -m)
if [ "$ARCH" = "arm64" ]; then
# Apple Silicon
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [ "$ARCH" = "x86_64" ]; then
# Intel
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
echo 'eval "$(/usr/local/bin/brew shellenv)"' >> ~/.zprofile
eval "$(/usr/local/bin/brew shellenv)"
fi
# 驗證
brew --version
```
### 4.2 安裝基礎工具
```bash
# 基礎開發工具
brew install \
git \
curl \
wget \
jq \
yq \
tree \
htop \
tmux \
zsh \
zsh-completions
```
---
## 階段五:安裝服務
### 5.1 安裝資料庫服務
```bash
#!/bin/bash
# 05_install_services.sh
# PostgreSQL
brew install postgresql@18
brew services start postgresql@18
# MongoDB
brew tap mongodb/brew
brew install mongodb-community
brew services start mongodb-community
# MariaDB
brew install mariadb
brew services start mariadb
# Redis
brew install redis
brew services start redis
# Qdrant (需要 Cargo)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo install qdrant
```
### 5.2 安裝應用服務
```bash
# Ollama
brew install ollama
brew services start ollama
# Caddy
brew install caddy
brew services start caddy
# Gitea
brew install gitea
brew services start gitea
# PHP
brew install php
brew services start php
# n8n
brew install n8n
brew services start n8n
```
### 5.3 Launchd 服務配置
```xml
<!-- /Library/LaunchDaemons/com.momentry.postgresql.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.momentry.postgresql</string>
<key>UserName</key>
<string>momentry</string>
<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/opt/postgresql@18/bin/postgres</string>
<string>-D</string>
<string>/Volumes/Momentry/momentry/var/postgresql</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/Volumes/Momentry/momentry/log/postgresql.log</string>
<key>StandardErrorPath</key>
<string>/Volumes/Momentry/momentry/log/postgresql.error.log</string>
</dict>
</plist>
```
---
## 階段六:安裝 Momentry Core
### 6.1 複製原始碼
```bash
#!/bin/bash
# 06_install_momentry.sh
# 建立 Momentry 目錄
mkdir -p /Volumes/Momentry/momentry/{var,etc,log,scripts,backup}
mkdir -p /Volumes/Momentry/momentry_core
# 複製原始碼
rsync -av \
--exclude 'target' \
--exclude '.git' \
--exclude 'node_modules' \
/Users/accusys/momentry_core_0.1/ \
/Volumes/Momentry/momentry_core/
# 編譯 Rust 專案
cd /Volumes/Momentry/momentry_core
cargo build --release
```
### 6.2 初始化資料庫
```bash
# 建立 PostgreSQL 資料庫
psql -U postgres <<EOF
CREATE DATABASE momentry;
CREATE DATABASE n8n;
CREATE DATABASE video_register;
CREATE USER momentry WITH PASSWORD 'momentry_password';
CREATE USER n8n WITH PASSWORD 'n8n_password';
GRANT ALL PRIVILEGES ON DATABASE momentry TO momentry;
GRANT ALL PRIVILEGES ON DATABASE n8n TO n8n;
EOF
# 執行 migration
cd /Volumes/Momentry/momentry_core
sqlx migrate run
```
### 6.3 配置環境變數
```bash
# ~/.zshrc 或 ~/.bash_profile
export DATABASE_URL="postgres://momentry:momentry_password@localhost:5432/momentry"
export REDIS_URL="redis://:momentry_password@localhost:6379"
export QDRANT_URL="http://localhost:6333"
export MONGODB_URI="mongodb://localhost:27017/momentry"
export MOMENTRY_OUTPUT_DIR="/Volumes/Momentry/momentry/var/output"
export MOMENTRY_LOG_LEVEL="info"
```
---
## 階段七:網路配置
### 7.1 設定固定 IP(可選)
```bash
# 網路配置腳本
#!/bin/bash
# 07_configure_network.sh
# 取得網路介面
INTERFACE=$(networksetup -listallnetworkservices | grep "Thunderbolt")
# 設定固定 IP
networksetup -setmanual "$INTERFACE" \
192.168.1.100 \
255.255.255.0 \
192.168.1.1
# 設定 DNS
networksetup -setdnsservers "$INTERFACE" \
8.8.8.8 \
8.8.4.4
```
### 7.2 配置防火牆
```bash
# 開放服務端口
# 使用 macOS Firewall 或 pfctl
```
### 7.3 設定 SSH 金鑰
```bash
# 產生 SSH 金鑰對
ssh-keygen -t ed25519 -C "momentry@$(hostname)"
# 複製公鑰到目標主機
ssh-copy-id momentry@target-host
# 主控機 SSH 配置
# ~/.ssh/config
Host momentry-target
HostName 192.168.1.100
User momentry
IdentityFile ~/.ssh/id_ed25519
```
---
## 階段八:啟動服務
### 8.1 啟動順序
```bash
#!/bin/bash
# 08_start_services.sh
# 1. 基礎服務
launchctl load /Library/LaunchDaemons/com.momentry.postgresql.plist
launchctl load /Library/LaunchDaemons/com.momentry.mongodb.plist
launchctl load /Library/LaunchDaemons/com.momentry.mariadb.plist
launchctl load /Library/LaunchDaemons/com.momentry.redis.plist
sleep 10
# 2. 向量資料庫
launchctl load /Library/LaunchDaemons/com.momentry.qdrant.plist
sleep 5
# 3. 應用服務
launchctl load /Library/LaunchDaemons/com.momentry.ollama.plist
launchctl load /Library/LaunchDaemons/com.momentry.caddy.plist
sleep 5
# 4. 其他服務
launchctl load /Library/LaunchDaemons/com.momentry.gitea.plist
launchctl load /Library/LaunchDaemons/com.momentry.php.plist
launchctl load /Library/LaunchDaemons/com.momentry.n8n.main.plist
launchctl load /Library/LaunchDaemons/com.momentry.n8n.worker.plist
# 5. Momentry Core
launchctl load /Library/LaunchDaemons/com.momentry.sftpgo.plist
launchctl load /Library/LaunchDaemons/com.momentry.rustdesk.hbbs.plist
launchctl load /Library/LaunchDaemons/com.momentry.rustdesk.hbbr.plist
```
### 8.2 驗證服務
```bash
# 檢查所有服務狀態
function check_services() {
services=(
"postgresql"
"mongodb"
"mariadb"
"redis"
"qdrant"
"ollama"
"caddy"
"gitea"
"php"
"n8n"
"sftpgo"
)
for service in "${services[@]}"; do
if launchctl list | grep "$service" | grep -q "running"; then
echo "$service: Running"
else
echo "$service: Not running"
fi
done
}
check_services
```
---
## 階段九:備份與還原
### 9.1 備份策略
```bash
#!/bin/bash
# 備份腳本
BACKUP_DIR="/Volumes/Momentry/backup/$(date +%Y%m%d)"
# 1. PostgreSQL 備份
pg_dump -U momentry momentry > "$BACKUP_DIR/momentry.sql"
pg_dump -U n8n n8n > "$BACKUP_DIR/n8n.sql"
# 2. MongoDB 備份
mongodump --out "$BACKUP_DIR/mongodb"
# 3. Redis 備份
redis-cli BGSAVE
cp /Volumes/Momentry/var/redis/dump.rdb "$BACKUP_DIR/redis.rdb"
# 4. Qdrant 備份
curl -X POST http://localhost:6333/collections/accusysdb/snapshots
# 5. 配置檔案備份
tar -czf "$BACKUP_DIR/config.tar.gz" \
/Volumes/Momentry/momentry/etc/
```
### 9.2 自動備份 Cron
```bash
# crontab -e
0 2 * * * /Volumes/Momentry/scripts/backup.sh
0 3 * * 0 /Volumes/Momentry/scripts/backup_full.sh
```
---
## 階段十:監控與維護
### 10.1 健康檢查腳本
```bash
#!/bin/bash
# health_check.sh
# 檢查所有服務
check_postgresql() {
pg_isready -q && echo "✅ PostgreSQL" || echo "❌ PostgreSQL"
}
check_mongodb() {
mongosh --eval "db.stats()" > /dev/null 2>&1 && echo "✅ MongoDB" || echo "❌ MongoDB"
}
check_redis() {
redis-cli ping > /dev/null 2>&1 && echo "✅ Redis" || echo "❌ Redis"
}
check_qdrant() {
curl -s http://localhost:6333/health && echo "✅ Qdrant" || echo "❌ Qdrant"
}
check_n8n() {
curl -s http://localhost:5678/api/v1/workflows > /dev/null 2>&1 && echo "✅ n8n" || echo "❌ n8n"
}
check_momentry() {
curl -s http://localhost:3002/api/v1/videos > /dev/null 2>&1 && echo "✅ Momentry" || echo "❌ Momentry"
}
```
### 10.2 日誌輪替
```bash
# 新聞日誌配置
/Volumes/Momentry/momentry/log/*.log {
daily
rotate 7
compress
missingok
notifempty
create 644 momentry staff
}
```
---
## 自動化腳本架構
### 主控腳本:部署控制器
```bash
#!/bin/bash
# deploy_controller.sh
# 用於從主控機部署到目標主機
set -e
# 配置
TARGET_HOST="momentry@192.168.1.100"
TARGET_DISK="/dev/disk2"
# 顏色定義
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
function log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
function log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
function log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 階段執行
function run_stage() {
local stage=$1
local script=$2
log_info "執行階段: $stage..."
ssh "$TARGET_HOST" "bash /Volumes/Momentry/scripts/$script"
if [ $? -eq 0 ]; then
log_info "✅ 階段完成: $stage"
else
log_error "❌ 階段失敗: $stage"
exit 1
fi
}
# 主程序
log_info "開始 Momentry 系統部署..."
# 執行各階段
run_stage "磁碟準備" "01_prepare_disk.sh"
run_stage "macOS 安裝" "02_install_macos.sh"
run_stage "Homebrew 安裝" "03_install_homebrew.sh"
run_stage "依賴安裝" "04_install_dependencies.sh"
run_stage "服務安裝" "05_install_services.sh"
run_stage "Momentry 安裝" "06_install_momentry.sh"
run_stage "網路配置" "07_configure_network.sh"
run_stage "啟動服務" "08_start_services.sh"
log_info "✅ 部署完成!"
```
---
## 待確認事項
### 需要與使用者確認
1. **目標主機型號**
- Intel Mac 或 Apple Silicon
- Thunderbolt 版本 (3/4)
2. **網路配置**
- DHCP 或固定 IP
- 目標 IP 網段?
3. **磁碟配置**
- 分割方案 A (200G 系統 + 1.8T 資料)
- 分割方案 B (統一磁碟區)
4. **服務需求**
- 需要安裝全部服務?
- 還是選擇性安裝?
5. **備份策略**
- 本地備份?
- 遠端備份?
- 備份頻率?
6. **監控需求**
- Prometheus + Grafana
- 簡單腳本監控?
---
## 預估時間
| 階段 | 預估時間 | 備註 |
|------|---------|------|
| 前置準備 | 30 分鐘 | 收集資訊、準備腳本 |
| 磁碟準備 | 10 分鐘 | 分割格式化 |
| macOS 安裝 | 30-60 分鐘 | 視 USB 速度 |
| Homebrew 安裝 | 15 分鐘 | 下載速度 |
| 服務安裝 | 60-90 分鐘 | 多個服務 |
| Momentry 安裝 | 20 分鐘 | 編譯 Rust |
| 網路配置 | 10 分鐘 | 固定 IP |
| 服務啟動 | 15 分鐘 | 依序啟動 |
| 驗證測試 | 30 分鐘 | 完整測試 |
| **總計** | **3-4 小時** | 自動化後可縮短 |
---
## 風險與應對
| 風險 | 機率 | 影響 | 應對措施 |
|------|------|------|---------|
| Thunderbolt 不相容 | 低 | 高 | 準備多種驅動 |
| macOS 安裝失敗 | 低 | 高 | 準備還原方案 |
| 服務啟動失敗 | 中 | 中 | 日誌診斷腳本 |
| 網路連線問題 | 中 | 中 | 有線網路備援 |
| 儲存空間不足 | 低 | 高 | 磁碟空間檢查 |
---
## 下一步行動
1. ✅ 確認目標主機規格
2. ✅ 確認 Thunderbolt NVMe 容量
3. ✅ 確認網路配置
4. ✅ 選擇服務清單
5. ✅ 準備安裝腳本
6. ✅ 測試腳本執行
7. ✅ 正式部署
---
## 附錄
### A. 服務端口對照表
| 服務 | Port | 協議 |
|------|------|------|
| PostgreSQL | 5432 | TCP |
| MongoDB | 27017 | TCP |
| MariaDB | 3306 | TCP |
| Redis | 6379 | TCP |
| Qdrant API | 6333 | HTTP |
| Qdrant gRPC | 6334 | gRPC |
| Ollama | 11434 | HTTP |
| Caddy HTTP | 80 | HTTP |
| Caddy HTTPS | 443 | HTTPS |
| Gitea | 3000 | HTTP |
| PHP-FPM | 9000 | FastCGI |
| n8n | 5678 | HTTP |
| SFTPGo | 2022 | SFTP |
| RustDesk hbbs | 21115 | TCP |
| RustDesk hbbr | 21117 | TCP |
| Momentry | 3002 | HTTP |
| Prometheus | 9090 | HTTP |
### B. 環境變數清單
`.env` 範例檔案或 `docs/MOMENTRY_CORE_MONITORING.md`
### C. 疑難排解
`docs/PENDING_ISSUES.md`
---
**計劃狀態**: 📝 草稿 - 等待使用者確認後執行
**負責人**: OpenCode AI Assistant
**最後更新**: 2026-03-23
@@ -0,0 +1,169 @@
# Momentry Video RAG MCP Workflow
## 工作流程資訊
- **名稱**: Momentry Video RAG MCP
- **ID**: WlVvpX2OeKK83QOK
- **Webhook Path**: `video-rag-mcp`
- **狀態**: ✅ Active (已啟動)
- **建立時間**: 2026-03-22
## 工作流程架構
```
┌─────────────────┐ ┌──────────────────────┐ ┌───────────────────┐ ┌─────────────────┐
│ Webhook │────▶│ Search Momentry │────▶│ Process RAG │────▶│ Respond to │
│ Trigger │ │ Core │ │ Results │ │ Webhook │
└─────────────────┘ └──────────────────────┘ └───────────────────┘ └─────────────────┘
│ POST http://localhost:5678/webhook/video-rag-mcp
{
"query": "搜尋關鍵字",
"limit": 5,
"uuid": "可選的影片UUID"
}
```
## Node 說明
### 1. Webhook Trigger
- **類型**: Webhook
- **Method**: POST
- **Path**: `video-rag-mcp`
- **Response Mode**: Last Node (等待最後一個節點完成後回應)
### 2. Search Momentry Core
- **類型**: HTTP Request
- **URL**: `http://localhost:3002/api/v1/n8n/search`
- **Method**: POST
- **Body**:
```json
{
"query": "搜尋關鍵字",
"limit": 5,
"uuid": "可選的影片UUID"
}
```
- **Timeout**: 30秒
### 3. Process RAG Results
- **類型**: Code (JavaScript)
- **功能**:
- 處理 Momentry Core 搜尋結果
- 格式化 hits 為結構化資料
- 建立 RAG context(用於 LLM 問答)
- 計算相關度百分比
**輸出格式**:
```json
{
"success": true,
"query": "搜尋關鍵字",
"totalFound": 5,
"context": "[1] 文本內容... (Video: 影片標題, Time: 10s-20s)\n\n[2] ...",
"results": [
{
"index": 1,
"id": "chunk_id",
"title": "影片標題",
"text": "文本內容",
"startTime": 10,
"endTime": 20,
"relevance": "85%",
"videoUuid": "uuid",
"mediaUrl": "影片URL",
"deepLink": "影片URL#t=10,20"
}
]
}
```
### 4. Respond to Webhook
- **類型**: Respond to Webhook
- **Response**: JSON 格式結果
- **Status Code**: 200
## 使用方式
### 直接呼叫 Webhook
```bash
curl -X POST http://localhost:5678/webhook/video-rag-mcp \
-H "Content-Type: application/json" \
-d '{
"query": "charade",
"limit": 5
}'
```
### 指定特定影片搜尋
```bash
curl -X POST http://localhost:5678/webhook/video-rag-mcp \
-H "Content-Type: application/json" \
-d '{
"query": "audrey hepburn",
"limit": 3,
"uuid": "a1b10138a6bbb0cd"
}'
```
### 在 n8n 工作流程中使用
可以將此 Webhook 作為子工作流程觸發器,或使用 HTTP Request Node 呼叫:
```json
{
"name": "Call Video RAG",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "http://localhost:5678/webhook/video-rag-mcp",
"method": "POST",
"body": {
"query": "={{ $json.searchTerm }}",
"limit": 5
}
}
}
```
## RAG Context 用途
工作流程產生的 `context` 欄位可直接用於 LLM 提示:
```javascript
// Example: 使用 context 進行問答
const prompt = `
基於以下影片片段資訊回答問題:
${context}
問題:${userQuestion}
請根據上述內容提供準確的答案。
`;
```
## 相關文件
- [Momentry Core API 文件](./API_ACCESS.md)
- [n8n MCP 測試報告](./N8N_MCP_TEST_REPORT.md)
- [N8N_DEMO_WORKFLOW.md](./N8N_DEMO_WORKFLOW.md) - 完整工作流程設計
## MCP 建立指令
此工作流程是透過 MCP 工具建立的:
```bash
# 使用 MCP 建立工作流程
node create_workflow.js | mcp-n8n
# 使用 MCP 啟動工作流程
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"n8n_activate_workflow","arguments":{"workflowId":"WlVvpX2OeKK83QOK"}}}' | mcp-n8n
```
## 工作流程檔案
- 原始檔案: `docs/n8n_workflow_video_rag_mcp.json`
@@ -0,0 +1,292 @@
# Video Processing Pipeline - 處理流程
| 項目 | 內容 |
|------|------|
| 建立者 | Warren |
| 建立時間 | 2026-03-22 |
| 文件版本 | V1.1 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-03-22 | 創建文件 | Warren | OpenCode |
| V1.1 | 2026-03-26 | 更新流程圖文字 (media_url→file_path) | OpenCode | deepseek-reasoner |
---
## 處理流程架構
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ Video Processing Pipeline │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Stage 1: JSON 生成 (Process) │ │
│ │ │ │
│ │ video.mp4 ──→ [ASR] ──→ asr.json (語音辨識) │ │
│ │ ──→ [CUT] ──→ cut.json (場景偵測) │ │
│ │ ──→ [ASRX] ──→ asrx.json (說話者分離) │ │
│ │ ──→ [YOLO] ──→ yolo.json (物體偵測) │ │
│ │ ──→ [OCR] ──→ ocr.json (文字辨識) │ │
│ │ ──→ [Face] ──→ face.json (人臉偵測) │ │
│ │ ──→ [Pose] ──→ pose.json (姿態估計) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Stage 2: 入庫 (Import) │ │
│ │ │ │
│ │ .json files ──→ PostgreSQL (fs_json = true) │ │
│ │ ↓ │ │
│ │ pre_chunks 表 (from ASR, CUT) │ │
│ │ frames 表 (from YOLO, OCR, Face, Pose) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Stage 3: Chunk 生成 (Chunk) │ │
│ │ │ │
│ │ pre_chunks ──→ [Chunk Rule] ──→ chunks 表 │ │
│ │ ↓ │ │
│ │ 清洗 → 純文字 │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Stage 4: 向量化 (Vectorize) │ │
│ │ │ │
│ │ chunks ──→ [Embedding Model] ──→ vectors │ │
│ │ ↓ │ │
│ │ Qdrant (主要向量庫) │ │
│ │ PGVector (備份向量庫) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Stage 5: 搜尋 (Search) │ │
│ │ │ │
│ │ Natural Language Query ──→ [Embedding] ──→ [Qdrant Search] │ │
│ │ ↓ │ │
│ │ 返回結果含 file_path │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
---
## CLI 命令
### Stage 1: JSON 生成 (Process)
```bash
# 基本用法
cargo run --bin momentry -- process <uuid_or_path>
# 只處理特定模組
cargo run --bin momentry -- process <uuid> --modules asr,cut
# 強制重新處理(忽略完整性檢查)
cargo run --bin momentry -- process <uuid> --force
# 從中斷點續傳
cargo run --bin momentry -- process <uuid> --resume
# 模組使用雲端處理
cargo run --bin momentry -- process <uuid> --modules yolo,face --cloud yolo
# 完整範例
cargo run --bin momentry -- process /path/to/video.mp4 \
--modules asr,cut,yolo,ocr \
--cloud yolo
```
### Stage 2: 入庫 (Import)
```bash
# 目前入庫在 process 完成後自動執行
# 計劃新增獨立的 import 命令
# cargo run --bin momentry -- import <uuid>
```
### Stage 3: Chunk 生成
```bash
# 生成 chunks
cargo run --bin momentry -- chunk <uuid>
```
### Stage 4: 向量化
```bash
# 向量化 chunks(使用預設模型 nomic-embed-text-v2-moe:latest
cargo run --bin momentry -- vectorize <uuid>
# 明確指定模型
cargo run --bin momentry -- vectorize <uuid> --model nomic-embed-text-v2-moe:latest
```
---
## 處理模式選項
### --force (強制重新處理)
- 刪除現有的 JSON 檔案
- 從頭開始處理
- 適用於:處理失敗、模型更新、需要重新處理
```bash
# 強制重新處理 YOLO
cargo run --bin momentry -- process <uuid> --modules yolo --force
```
### --resume (續傳)
- 檢查現有 JSON 的進度
- 從中斷點繼續處理
- 適用於:處理中斷、系統崩潰後恢復
```bash
# 從上次中斷點繼續
cargo run --bin momentry -- process <uuid> --resume
```
### 預設行為 (Smart Mode)
- 如果 JSON 完全:跳過
- 如果 JSON 不完整:警告 + 跳過(需要 --resume 或 --force
- 如果 JSON 不存在:處理
```
Output:
ASR: ✓ Already complete, skipping
⚠️ Found incomplete JSON file: /path/to/yolo.json
Progress: 73800/412343 (17.9%)
Use --resume to continue from checkpoint
Use --force to reprocess from scratch
YOLO: ✓ Already complete, skipping
```
---
## 可用模組
| 模組 | 功能 | 輸出 | 用途 |
|------|------|------|------|
| asr | 自動語音辨識 | asr.json | 語音轉文字 |
| cut | 場景偵測 | cut.json | 影片分段 |
| asrx | 說話者分離 | asrx.json | 多人對話分析 |
| yolo | 物體偵測 | yolo.json | 物體辨識 |
| ocr | 文字辨識 | ocr.json | 畫面文字 |
| face | 人臉偵測 | face.json | 人臉辨識 |
| pose | 姿態估計 | pose.json | 人體姿態 |
---
## 向量化模型選擇
### 統一嵌入模型
Momentry Core 統一使用 **`nomic-embed-text-v2-moe:latest`** 作為所有規則的嵌入模型:
```bash
# 統一模型(所有 Rule 1/2/3 使用)
--model nomic-embed-text-v2-moe:latest
```
### 模型特性
| 特性 | 說明 |
|------|------|
| **模型名稱** | `nomic-embed-text-v2-moe:latest` |
| **向量維度** | 768 維 |
| **多語言支持** | ✅ 完整支持(英語、中文、日語、韓語等) |
| **模型架構** | Mixture of Experts (MoE) |
| **推理速度** | 快速,適合實時應用 |
### 使用方式
```bash
# 向量化命令
cargo run --bin momentry -- vectorize <uuid> --model nomic-embed-text-v2-moe:latest
```
---
## 資料庫儲存
### PostgreSQL (主要關聯式資料庫)
- 影片資訊
- Chunks 資料
- Pre-chunks 資料
- Frames 資料
- 使用者資料
### Qdrant (主要向量資料庫)
- Chunk 向量
- 相似度搜尋
### PGVector (備份向量資料庫)
- Chunk 向量副本
- 備援機制
---
## Pipeline 狀態追蹤
### PostgreSQL 狀態欄位
```sql
-- 影片處理狀態
videos.status: 'pending' | 'processing' | 'completed' | 'failed'
-- 檔案處理狀態
videos.fs_json: true/false
videos.fs_chunks: true/false
videos.fs_vectors: true/false
-- pre_chunks 狀態
pre_chunks.imported: true/false
-- frames 狀態
frames.imported: true/false
-- chunks 狀態
chunks.cleaned: true/false
chunks.vectorized: true/false
```
### 進度查詢 API
```bash
# 查詢處理進度
curl http://localhost:3002/api/v1/progress/{uuid}
# 回應範例
{
"uuid": "a1b10138a6bbb0cd",
"file_name": "video.mp4",
"overall_progress": 65,
"cpu_percent": 45.2,
"gpu_percent": 98.5,
"memory_mb": 8500,
"processors": [
{"name": "asr", "status": "complete", "progress": 100},
{"name": "cut", "status": "complete", "progress": 100},
{"name": "yolo", "status": "progress", "progress": 45},
{"name": "ocr", "status": "pending", "progress": 0}
]
}
```
---
## 下一步
1. **API 端點** - 支援 --modules 和 --cloud 參數
2. **獨立 Import 命令** - 分離入庫流程
3. **獨立 Chunk 命令** - 分離 chunk 生成
4. **獨立 Vectorize 命令** - 分離向量化流程
5. **模型管理** - 新增、選擇、預覽模型
@@ -0,0 +1,165 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Momentry Core 安全架構設計"
date: "2026-04-22"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "momentry"
- "core"
- "安全架構設計"
ai_query_hints:
- "查詢 Momentry Core 安全架構設計 的內容"
- "Momentry Core 安全架構設計 的主要目的是什麼?"
- "如何操作或實施 Momentry Core 安全架構設計?"
---
# Momentry Core 安全架構設計
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-22 |
| 文件版本 | V1.0 |
| 相關文件 | [ARCHITECTURE_OVERVIEW.md](./ARCHITECTURE_OVERVIEW.md)<br>[API_KEY_ARCHITECTURE.md](./API_KEY_ARCHITECTURE.md)<br>[PERFORMANCE_AND_SCALABILITY.md](./PERFORMANCE_AND_SCALABILITY.md) |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-04-22 | 創建安全架構設計文件 | OpenCode | OpenCode / deepseek-v3.2 |
---
## 1. 安全設計原則
### 1.1 核心安全原則
1. **最小權限原則**:每個組件只擁有完成其功能所需的最小權限
2. **縱深防禦**:多層安全防護,單一防護失效不導致系統被攻破
3. **默認安全**:系統默認配置為最安全狀態
4. **審計與日誌**:所有安全相關操作皆有記錄,可追溯
5. **安全更新**:定期安全評估與更新,及時修補漏洞
### 1.2 安全等級分類
| 安全等級 | 描述 | 適用場景 |
|----------|------|----------|
| **L1 - 公開** | 無需認證,信息公開 | 健康檢查、文檔頁面 |
| **L2 - 內部** | 內部網絡訪問,基本認證 | 管理面板、監控系統 |
| **L3 - 受控** | API Key 認證,訪問控制 | 客戶端 API 調用 |
| **L4 - 敏感** | 多因素認證,加密傳輸 | 用戶數據、管理操作 |
| **L5 - 機密** | 硬件級保護,審計追蹤 | 加密密鑰、認證數據 |
---
## 2. 認證與授權
### 2.1 API Key 管理系統
#### 2.1.1 API Key 類型
| 類型 | 格式 | 使用場景 | 權限範圍 |
|------|------|----------|----------|
| **管理員金鑰** | `madmin_<uuid>_<timestamp>_<hash>` | 系統管理 | 完全權限 |
| **用戶金鑰** | `muser_<uuid>_<timestamp>_<hash>` | 普通用戶 | 受限制權限 |
| **服務金鑰** | `mservice_<uuid>_<timestamp>_<hash>` | 服務間通信 | 特定服務權限 |
| **臨時金鑰** | `mtemp_<uuid>_<timestamp>_<hash>` | 臨時訪問 | 時間限制權限 |
### 2.2 訪問控制策略
#### 2.2.1 基於角色的訪問控制 (RBAC)
| 角色 | 權限描述 | API 端點 |
|------|----------|----------|
| **系統管理員** | 完整系統管理權限 | 所有端點 |
| **內容管理員** | 視頻內容管理 | `/api/videos/*`, `/api/chunks/*` |
| **分析師** | 數據查詢與分析 | `/api/search/*`, `/api/analytics/*` |
| **普通用戶** | 基本查詢功能 | `/api/search/*` (僅限公開內容) |
---
## 3. 數據安全
### 3.1 數據加密策略
#### 3.1.1 靜態數據加密
| 數據類型 | 加密方式 | 密鑰管理 | 存儲位置 |
|----------|----------|----------|----------|
| **用戶數據** | AES-256-GCM | KMS | PostgreSQL |
| **視頻文件** | 文件系統加密 | 系統級密鑰 | SFTPGo |
| **API Keys** | bcrypt 哈希 + 鹽值 | 應用內管理 | Redis |
#### 3.1.2 傳輸中數據加密
| 傳輸通道 | 加密協議 | 證書管理 | 強制性 |
|----------|----------|----------|--------|
| **HTTP API** | TLS 1.3 | Let's Encrypt | 是 |
| **數據庫連接** | SSL/TLS | 自簽證書 | 是 |
| **Redis 連接** | TLS | 自簽證書 | 是 |
---
## 4. 網絡安全
### 4.1 網絡隔離策略
```
外部網絡 (Internet)
└──> [邊緣層] - 防火牆 + WAF
└──> [應用層] - API Gateway
├──> [服務層] - 內部服務
└──> [數據層] - 隔離網絡
```
### 4.2 攻擊防護
| 攻擊類型 | 防護措施 | 監控指標 |
|----------|----------|----------|
| **DDoS 攻擊** | 速率限制 + CDN | 請求速率 |
| **SQL 注入** | 參數化查詢 | SQL 錯誤 |
| **XSS 攻擊** | 輸入驗證 | 可疑字符 |
| **API 濫用** | 速率限制 | API 使用模式 |
---
## 5. 合規與審計
### 5.1 安全合規要求
| 法規 | 適用範圍 | Momentry 遵循措施 |
|------|----------|-------------------|
| **GDPR** | 歐盟用戶數據 | 數據匿名化、刪除權 |
| **CCPA** | 加州居民數據 | 數據訪問權、刪除權 |
| **數據安全法** | 中國數據 | 數據分類、安全審計 |
### 5.2 審計日誌要求
| 日誌類別 | 保留期限 | 審計要求 |
|----------|----------|----------|
| **認證日誌** | 90天 | 所有登錄嘗試 |
| **訪問日誌** | 180天 | 所有數據訪問 |
| **操作日誌** | 365天 | 管理操作記錄 |
---
## 6. 應急響應
### 6.1 安全事件分類
| 等級 | 描述 | 響應時間 | 通知對象 |
|------|------|----------|----------|
| **L1 - 緊急** | 系統被入侵 | 立即 | 管理層 |
| **L2 - 高** | 嚴重漏洞 | 2小時 | 安全團隊 |
| **L3 - 中** | 配置錯誤 | 24小時 | 相關團隊 |
---
## 7. 總結
Momentry Core 的安全架構設計遵循業界最佳實踐,包括:
1. **多層防護**:從網絡、應用、數據多個層面進行保護
2. **最小權限**:嚴格控制每個組件的訪問權限
3. **持續監控**:實時監控安全事件,快速響應
4. **合規要求**:符合 GDPR、CCPA 等隱私法規
通過上述安全措施,確保系統在提供強大功能的同時,保持高度的安全性與合規性。
@@ -0,0 +1,247 @@
# Momentry Core 多維度自然語言搜尋設計文檔
**版本**: V1.0
**日期**: 2026-04-10
**狀態**: 設計階段
---
## 1. 概述
本設計文檔旨在定義 Momentry Core 的**多維度自然語言搜尋 (Multi-Dimensional Semantic Search)** 系統架構與實施規範。該系統旨在突破傳統關鍵詞匹配的限制,通過解析用戶的「人事時地物」(5W1H) 意圖,結合多模態數據 (ASR, YOLO, Pose, Scene, Face),實現高精度的語義檢索。
### 1.1 設計原則
1. **模組化 (Modularity)**: 搜尋功能作為獨立的 `Search Processor` 模塊,依賴但不侵入其他數據生產模塊 (如 Pose, ASR)。
2. **多模態融合 (Multi-Modal Fusion)**: 結合結構化數據 (SQL 過濾) 與非結構化向量數據 (Vector 檢索)。
3. **本地優先 (Local First)**: 核心解析與檢索邏輯盡可能在本地完成,僅 LLM 意圖解析可調用雲端或本地 LLM。
---
## 2. 搜尋維度定義 (5W1H Schema)
我們將用戶的自然語言查詢解析為以下結構化維度:
### 2.1 人 (Person / Who)
基於 `person_identities` 表及 `face` / `pose` / `asrx` 分析結果擴展。
| 屬性 | 數據類型 | 獲取來源 | 示例值 | 備註 |
| :--- | :--- | :--- | :--- | :--- |
| **性別** | `Enum` | VLM / 推斷 | `male`, `female` | |
| **年齡段** | `Enum` | VLM / 推斷 | `child`, `teen`, `young`, `middle`, `senior` | |
| **體型** | `Enum` | Pose (骨架寬高比) | `slim`, `average`, `muscular`, `heavy` | |
| **五官特徵** | `String[]` | VLM / Face | `["glasses", "beard", "long_hair"]` | |
| **表情** | `String[]` | Face / VLM | `["smiling", "angry", "crying"]` | |
| **服裝** | `String[]` | YOLO / VLM | `["red_shirt", "suit", "helmet"]` | |
| **動作/手勢** | `String[]` | **Pose Analyzer** | `["waving", "pointing", "hands_up", "fighting"]` | 核心新增 |
| **戲內角色** | `String` | 元數據 / 手動 | "Detective", "Doctor" | |
| **演員/真實身份** | `String` | 註冊資料庫 | "Tom Hanks", "User_001" | |
| **聲紋特徵** | `Enum` | ASRX | `deep_male`, `high_female` | |
### 2.2 事 (Event / Action / What)
基於 `ASR` (語音語義) 和 `Pose Analyzer` (行為語義)。
* **語音內容**: "他在解釋量子力學" -> 向量檢索 ASR 文本。
* **視覺行為**: "他在跑步", "兩人在擁抱" -> 檢索 `pose_analysis` 標籤或向量。
### 2.3 時 (Time / When)
基於 `chunks` 的時間戳。
* **絕對時間**: `10:05 - 10:15`
* **相對時間**: "最後 5 分鐘", "剛開始"。
### 2.4 地 (Location / Where)
基於 `Scene` (Places365) 分類結果。
* **標籤**: "beach", "office", "living_room"。
* **映射**: 用戶說 "戶外" -> 映射為 `["beach", "forest", "street", ...]`
### 2.5 物 (Object / Which)
基於 `YOLO` (物件檢測) 和 `OCR` (文字識別)。
* **物件**: `car`, `dog`, `knife`
* **文字**: 路牌、標題中的關鍵詞。
---
## 3. 系統架構
### 3.1 數據流向圖
```mermaid
graph TD
User[用戶自然語言查詢] --> API[API Gateway]
API --> SearchProc[Search Processor]
subgraph "Search Processor (Python)"
Parser[Intent Parser (LLM)]
Translator[Query Translator]
Executor[Search Executor]
Parser -->|JSON 結構化| Translator
Translator -->|SQL + Vector Query| Executor
end
Executor -->|Filter: Who, Where, Object| PG[(PostgreSQL)]
Executor -->|Search: Event (Text/Action)| Vec[(Qdrant / pgvector)]
subgraph "Data Producers"
PoseProc[Pose Analyzer Processor] -.->|Pose Tags| PG
FaceProc[Face Processor] -.->|Face Attributes| PG
ASRProc[ASR Processor] -.->|Transcript| PG
end
PG -->|Results| Executor
Vec -->|Results| Executor
Executor -->|Aggregated JSON| API
```
### 3.2 模組職責
1. **Pose Analyzer Processor**: 負責讀取 Pose 座標與 YOLO 數據,生成行為標籤 (Tags),寫入數據庫。
2. **Search Processor**: 負責將自然語言轉為查詢語句並執行檢索。
---
## 4. 資料庫 Schema 擴展
為支持多維度搜尋,需擴展現有表結構。
### 4.1 擴展 `person_identities` (增加屬性 JSONB)
```sql
ALTER TABLE person_identities
ADD COLUMN IF NOT EXISTS attributes JSONB DEFAULT '{}';
-- 建立 GIN 索引加速屬性搜索
CREATE INDEX IF NOT EXISTS idx_person_attrs ON person_identities USING GIN (attributes);
```
*示例數據*: `{"gender": "male", "age": "middle", "clothing": ["suit"], "pose_action": ["standing"]}`
### 4.2 擴展 `chunks` (增加行為標籤與語義向量)
```sql
ALTER TABLE chunks
ADD COLUMN IF NOT EXISTS action_tags TEXT[] DEFAULT '{}',
ADD COLUMN IF NOT EXISTS scene_tags TEXT[] DEFAULT '{}',
ADD COLUMN IF NOT EXISTS object_tags TEXT[] DEFAULT '{}';
-- 使用數組索引加速標籤查詢
CREATE INDEX IF NOT EXISTS idx_chunk_actions ON chunks USING GIN (action_tags);
```
### 4.3 新增 `pose_analytics` 表 (可選,用於存儲詳細分析)
如果 `chunks` 存儲標籤不夠,可存儲詳細的動作序列。
```sql
CREATE TABLE pose_analytics (
id SERIAL PRIMARY KEY,
uuid TEXT NOT NULL,
chunk_id TEXT REFERENCES chunks(chunk_id),
person_id INTEGER, -- 關聯 person_identities
start_time FLOAT,
end_time FLOAT,
action_label TEXT, -- 如 "waving"
action_score FLOAT,
keypoints_snapshot JSONB -- 關鍵幀骨架 (用於 Debug)
);
```
---
## 5. 查詢解析機制 (LLM Intent Parser)
### 5.1 Prompt 設計
System Prompt 將指示 LLM 輸出標準化的 JSON 格式,映射到上述維度。
### 5.2 JSON 輸出示例
用戶輸入:"找一下昨天在辦公室,那個戴眼鏡穿西裝,正在生氣地罵人的男人。"
```json
{
"who": {
"gender": "male",
"facial_features": ["glasses"],
"clothing": ["suit"],
"expression": "angry",
"action": ["shouting", "arguing"]
},
"where": ["office"],
"when": { "relative": "yesterday" },
"what": "shouting at someone",
"limit": 10
}
```
---
## 6. 搜索執行器邏輯 (Query Translator)
Translator 將上述 JSON 轉換為混合查詢 (Hybrid Query)。
### 6.1 結構化過濾 (SQL)
針對精確匹配字段使用 SQL `WHERE` 子句。
```sql
SELECT c.* FROM chunks c
JOIN person_identities pi ON ...
WHERE
pi.attributes->>'gender' = 'male'
AND pi.attributes->'facial_features' ? 'glasses'
AND c.scene_tags @> ARRAY['office']
AND c.start_time >= :yesterday_start;
```
### 6.2 語義檢索 (Vector)
針對模糊描述 (What) 使用向量相似度。
* 將 "shouting at someone" 編碼為向量。
* 在 Qdrant 中檢索與此向量相似的 `chunks` (基於 ASR 語義) 或 `pose_events` (基於動作語義)。
### 6.3 結果融合 (Re-ranking)
* 取 SQL 過濾結果與 Vector 檢索結果的交集。
* 若無交集,優先展示滿足 Filter (Who/Where) 的結果,按 Vector 分數排序。
---
## 7. Pose Analyzer Processor 實施細節
這是支持「事 (Event)」和「人 (Person Action)」維度的核心前置模塊。
### 7.1 處理流程
1. **輸入**: 原始 `pose.json` (座標) + `yolo.json` (物體框)。
2. **特徵工程**:
* 計算關節角度 (Angle): 手肘、膝蓋。
* 計算速度 (Velocity): 手腕、身體中心點位移。
* 計算交互 (Interaction): 人手框與 YOLO 物體框 IoU。
3. **規則分類 (Rule-based)**:
* 手部高於頭頂 -> `hands_up`
* 雙手交叉於胸前 -> `arms_crossed`
* 快速靠近另一人 -> `approaching`
4. **輸出**: 更新 `chunks` 表的 `action_tags``person_identities` 表的 `attributes`
---
## 8. 實施路線圖
### Phase 1: 基礎設施 (Day 1-2)
* [ ] 更新數據庫 Schema (增加 `attributes`, `action_tags` 等字段與索引)。
* [ ] 創建 `scripts/pose_analyzer_processor.py` (基礎規則版:站/坐/臥/手勢)。
* [ ] 運行 Pose Analyzer 對現有數據進行標記。
### Phase 2: 搜尋解析器 (Day 3-4)
* [ ] 創建 `scripts/search_processor.py`
* [ ] 實現 LLM Intent Parser (Qwen3.6-plus)。
* [ ] 實現 Query Translator (生成動態 SQL)。
### Phase 3: 執行與整合 (Day 5-6)
* [ ] 實現 Search Executor (PostgreSQL 查詢邏輯)。
* [ ] 開發 `POST /api/v1/search/smart` API。
* [ ] 前端對接與測試。
### Phase 4: 優化 (Day 7+)
* [ ] 引入向量檢索 (Vector Search) 支持模糊語義。
* [ ] 優化 Pose 分析算法 (引入 ST-GCN 等輕量模型)。
---
## 9. 風險與對策
| 風險 | 影響 | 對策 |
| :--- | :--- | :--- |
| **LLM 解析不穩定** | 提取的屬性錯誤 (如把 "蘋果" 當作物體而非公司名) | 在 Prompt 中增加 Context (提供當前視頻的 YOLO/Scene 標籤列表供 LLM 選擇)。 |
| **Pose 標籤稀疏** | 複雜動作無法識別 (如 "打太極") | 初期僅支持基礎動作庫;複雜動作依賴語義向量搜索 (ASR 內容補充)。 |
| **查詢性能** | 多條件 JOIN 與 JSONB 查詢慢 | 嚴格要求 GIN 索引;限制搜尋範圍 (如先過濾 Video UUID 和 Time)。 |
@@ -0,0 +1,698 @@
# Momentry 服務添加規範 v2.1
| 項目 | 內容 |
|------|------|
| 建立者 | Warren |
| 建立時間 | 2026-03-16 |
| 更新時間 | 2026-03-24 |
| 文件版本 | V2.1 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-03-16 | 創建文件 | Warren | OpenCode / MiniMax M2.5 |
| V2.1 | 2026-03-24 | 更新 launchctl 命令,使用 bootstrap | OpenCode | OpenCode / big-pickle |
---
## 一、概述
本文檔定義在 Momentry 系統中添加新服務的標準流程和規範。
**重要原則**
- 使用 `launchctl` 管理服務,勿使用 `brew services`
- 所有服務使用 `com.momentry.*` 作為 plist Label
- 數據存放於 `/Users/accusys/momentry/` 目錄
- 每個服務需提供完整的監控腳本
- 所有服務 Plist 存放於 `/Library/LaunchDaemons/`
- 所有服務以 `accusys` 用戶運行,確保 accusys 可以管理
---
## 二、服務運行方式
### 2.1 運行分類
| 類型 | 說明 | 示例 |
|------|------|------|
| **開機自動運行** | 電腦開機後立即自動啟動 | PostgreSQL, Redis, n8n, Caddy 等核心服務 |
| **登入時運行** | 用戶登入後才啟動 | 開發工具、臨時服務 |
**當前所有服務**:均為開機自動運行
### 2.2 Plist 存放位置
所有 Momentry 服務統一存放於:
```
/Library/LaunchDaemons/com.momentry.{service_name}.plist
```
---
## 三、服務命名規範
### 3.1 Plist 文件命名
```
com.momentry.{service_name}.plist
```
示例:
- `com.momentry.redis.plist`
- `com.momentry.n8n.main.plist`
- `com.momentry.rustdesk.hbbs.plist`
### 3.2 目錄命名
服務相關目錄統一放置於:
```
/Users/accusys/momentry/
├── var/{service_name}/ # 服務數據
├── etc/{service_name}/ # 服務配置
├── log/{service_name}.log # 服務日誌 (stdout)
└── log/{service_name}.error.log # 錯誤日誌 (stderr)
```
---
## 四、Plist 文件模板
### 4.1 標準服務模板
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.momentry.{service_name}</string>
<key>UserName</key>
<string>accusys</string>
<key>WorkingDirectory</key>
<string>/Users/accusys/momentry/var/{service_name}</string>
<key>ProgramArguments</key>
<array>
<string>/path/to/executable</string>
<string>--arg1</string>
<string>value1</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
<!-- 其他環境變數 -->
</dict>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/Users/accusys/momentry/log/{service_name}.log</string>
<key>StandardErrorPath</key>
<string>/Users/accusys/momentry/log/{service_name}.error.log</string>
</dict>
</plist>
```
### 4.2 日誌文件規範
每個服務必須創建兩個日誌文件:
| 文件 | 說明 | 路徑 |
|------|------|------|
| StandardOutPath | 標準輸出日誌 | `/Users/accusys/momentry/log/{service_name}.log` |
| StandardErrorPath | 錯誤輸出日誌 | `/Users/accusys/momentry/log/{service_name}.error.log` |
**創建日誌文件**
```bash
touch /Users/accusys/momentry/log/{service_name}.log
touch /Users/accusys/momentry/log/{service_name}.error.log
chmod 644 /Users/accusys/momentry/log/{service_name}.log
chmod 644 /Users/accusys/momentry/log/{service_name}.error.log
```
---
## 五、添加服務步驟
### 步驟 1:創建目錄結構
```bash
# 創建服務目錄
mkdir -p /Users/accusys/momentry/var/{service_name}
mkdir -p /Users/accusys/momentry/etc/{service_name}
# 創建日誌文件
touch /Users/accusys/momentry/log/{service_name}.log
touch /Users/accusys/momentry/log/{service_name}.error.log
```
### 步驟 2:創建 Plist 文件
```bash
# 複製模板並編輯
cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/template.service.plist \
/Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.{service_name}.plist
# 編輯 plist 文件
vim /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.{service_name}.plist
```
### 步驟 3:複製到系統 LaunchDaemons
```bash
# 複製到 /Library/LaunchDaemons/
sudo cp /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.{service_name}.plist \
/Library/LaunchDaemons/
```
### 步驟 4:載入服務
```bash
# 載入服務
sudo launchctl load /Library/LaunchDaemons/com.momentry.{service_name}.plist
# 驗證服務狀態
launchctl list | grep momentry
```
### 步驟 5:添加監控
`monitor/config/monitor_config.yaml` 中添加服務配置:
```yaml
service:
services:
- name: "{service_name}"
type: "http" # 或 "process", "tcp"
port: {port_number}
host: "localhost"
check_url: "http://localhost:{port}/health"
timeout: 5
enabled: true
```
### 步驟 6:添加文檔
`docs/INSTALL_{SERVICE_NAME}.md` 中記錄:
- 安裝步驟
- 配置說明
- 健康檢查命令
- 故障排除
---
## 六、服務分類
### 按功能分類
| 類別 | 服務 |
|------|------|
| 資料庫 | PostgreSQL, Redis, MariaDB, MongoDB |
| 應用 | n8n, Gitea, SFTPGo |
| 網頁 | Caddy, PHP-FPM |
| AI/ML | Ollama, Qdrant |
| 遠程 | RustDesk |
### 按運行方式分類
| 運行方式 | 數量 | 服務 |
|----------|------|------|
| 開機自動運行 | 15 | PostgreSQL, Redis, n8n, Caddy, Gitea, SFTPGo, Ollama, Qdrant, MariaDB, PHP-FPM, RustDesk, MongoDB, Agent |
| 登入時運行 | 0 | (暫無) |
---
## 七、監控要求
每個服務必須提供:
### 7.1 健康檢查
`monitor/service/health_check.sh` 中添加檢查函數:
```bash
check_{service_name}() {
local start=$(date +%s%N)
if nc -z localhost {port} > /dev/null 2>&1; then
local end=$(date +%s%N)
local ms=$(( (end - start) / 1000000 ))
echo -e "${GREEN}${NC} {service_name} ({port}) - ${ms}ms"
record_service "{service_name}" "up" "$ms" ""
return 0
else
echo -e "${RED}${NC} {service_name} ({port}) - Down"
record_service "{service_name}" "down" "0" "Connection failed"
return 1
fi
}
```
### 7.2 數據庫記錄
```sql
-- 添加服務監控記錄函數
record_service() {
local service=$1
local status=$2
local response_time=$3
local error_msg=$4
psql -U accusys -h localhost -d momentry << EOF
INSERT INTO monitor_services (service_name, service_type, status, response_time_ms, error_message, checked_at)
VALUES ('$service', 'service', '$status', $response_time, '$error_msg', NOW());
EOF
}
```
---
## 八、服務管理命令
### 8.1 基本操作
```bash
# 啟動服務 (使用 launchctl bootstrap)
sudo launchctl bootstrap system /Library/LaunchDaemons/com.momentry.{service}.plist
# 停止服務 (使用 launchctl bootout)
sudo launchctl bootout system/com.momentry.{service}.plist
# 重新載入服務
sudo launchctl bootout system/com.momentry.{service}.plist
sudo launchctl bootstrap system /Library/LaunchDaemons/com.momentry.{service}.plist
# 查看服務狀態
launchctl list | grep com.momentry
# 查看特定服務狀態
launchctl list | grep com.momentry.{service}
# 查看服務日誌
tail -f /Users/accusys/momentry/log/{service}.log
tail -f /Users/accusys/momentry/log/{service}.error.log
```
### 8.2 批量管理
```bash
# 啟動所有 Momentry 服務
for plist in /Library/LaunchDaemons/com.momentry.*.plist; do
sudo launchctl bootstrap system "$plist"
done
# 停止所有 Momentry 服務
for svc in $(launchctl list | grep com.momentry | awk '{print $3}'); do
sudo launchctl bootout system/$svc 2>/dev/null
done
# 查看所有 Momentry 服務狀態
launchctl list | grep com.momentry
```
### 8.2 故障排除
```bash
# 檢查服務是否運行
pgrep -f "{service_process_name}"
# 檢查端口是否監聽
lsof -i :{port}
# 檢查錯誤日誌
tail -100 /Users/accusys/momentry/log/{service}.error.log
```
---
## 九、服務備份作業
### 9.1 備份內容
每個服務需要備份的內容:
| 類別 | 路徑 | 說明 |
|------|------|------|
| 數據 | `/Users/accusys/momentry/var/{service}/` | 服務運行數據 |
| 配置 | `/Users/accusys/momentry/etc/{service}/` | 服務配置文件 |
| Plist | `/Library/LaunchDaemons/com.momentry.{service}.plist` | 啟動配置 |
| 日誌 | `/Users/accusys/momentry/log/{service}.log` | 運行日誌 |
### 9.2 備份命名規範
**格式**: `{service}_{type}_{YYYYMMDD}_{HHMMSS}[_{suffix}].{ext}`
**組成部分**:
| 位置 | 說明 | 範例 |
|------|------|------|
| `{service}` | 服務名稱 (小寫) | `postgresql`, `redis`, `n8n` |
| `{type}` | 備份類型 | `full`, `db`, `cfg`, `data` |
| `{YYYYMMDD}` | 備份日期 | `20260315` |
| `{HHMMSS}` | 備份時間 (24小時制) | `030000` |
| `{suffix}` | 可選標記 | `incremental`, `verified` |
| `{ext}` | 檔案擴展名 | `sql.gz`, `tar.gz`, `rdb`, `zip` |
**類型說明**:
| 類型 | 說明 | 包含內容 |
|------|------|---------|
| `full` | 完整備份 | 數據 + 配置 + 日誌 |
| `db` | 數據庫備份 | 資料庫導出 (sql, rdb) |
| `cfg` | 配置備份 | 配置文件 |
| `data` | 數據備份 | var 目錄 |
**範例**:
```
postgresql_db_20260315_030000.sql.gz # PostgreSQL 完整資料庫 (壓縮)
redis_rdb_20260315_030000.rdb # Redis RDB 快照
n8n_full_20260315_030000.tar.gz # n8n 完整備份
mariadb_db_wordpress_20260315_030000.sql.gz # MariaDB WP 資料庫
gitea_full_20260315_030000.zip # Gitea 完整備份
qdrant_snapshot_20260315_030000.tar.gz # Qdrant 向量庫
ollama_cfg_20260315_030000.tar.gz # Ollama 配置
caddy_cfg_20260315_030000.tar.gz # Caddy 配置
```
**可信斷點標記**:
- 檔名本身即為可信時間點
- 還原時直接使用檔名中的時間戳
- 建議配合 `backup_registry` 資料庫記錄完整元數據
**校驗和命名**:
```
postgresql_db_20260315_030000.sql.gz.sha256
```
### 9.3 備份腳本
```bash
#!/bin/bash
# 標準化備份腳本範本
# 遵循命名規範: {service}_{type}_{YYYYMMDD}_{HHMMSS}.{ext}
set -e
SERVICE_NAME="{service_name}"
BACKUP_TYPE="{type}" # full, db, cfg, data
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/Users/accusys/momentry/backup/${SERVICE_NAME}"
mkdir -p "$BACKUP_DIR"
# 根據類型執行備份
case "$BACKUP_TYPE" in
full)
echo "[$TIMESTAMP] 執行 $SERVICE_NAME 完整備份..."
tar -czf "$BACKUP_DIR/${SERVICE_NAME}_full_${TIMESTAMP}.tar.gz" \
/Users/accusys/momentry/var/${SERVICE_NAME}/ \
/Users/accusys/momentry/etc/${SERVICE_NAME}/ 2>/dev/null
;;
db)
echo "[$TIMESTAMP] 執行 $SERVICE_NAME 資料庫備份..."
if [ "$SERVICE_NAME" = "postgresql" ]; then
pg_dump -U accusys ${SERVICE_NAME} | gzip > \
"$BACKUP_DIR/${SERVICE_NAME}_db_${TIMESTAMP}.sql.gz"
elif [ "$SERVICE_NAME" = "mariadb" ]; then
mysqldump -u root -p --all-databases | gzip > \
"$BACKUP_DIR/${SERVICE_NAME}_db_${TIMESTAMP}.sql.gz"
elif [ "$SERVICE_NAME" = "redis" ]; then
redis-cli -a accusys SAVE
cp /opt/homebrew/var/db/redis/dump.rdb \
"$BACKUP_DIR/${SERVICE_NAME}_rdb_${TIMESTAMP}.rdb"
fi
;;
cfg)
echo "[$TIMESTAMP] 執行 $SERVICE_NAME 配置備份..."
tar -czf "$BACKUP_DIR/${SERVICE_NAME}_cfg_${TIMESTAMP}.tar.gz" \
/Users/accusys/momentry/etc/${SERVICE_NAME}/ 2>/dev/null
;;
data)
echo "[$TIMESTAMP] 執行 $SERVICE_NAME 數據備份..."
tar -czf "$BACKUP_DIR/${SERVICE_NAME}_data_${TIMESTAMP}.tar.gz" \
/Users/accusys/momentry/var/${SERVICE_NAME}/ 2>/dev/null
;;
esac
# 生成校驗和
if [ -f "$BACKUP_DIR/${SERVICE_NAME}_${BACKUP_TYPE}_${TIMESTAMP}"* ]; then
sha256sum "$BACKUP_DIR/${SERVICE_NAME}_${BACKUP_TYPE}_${TIMESTAMP}"* > \
"$BACKUP_DIR/${SERVICE_NAME}_${BACKUP_TYPE}_${TIMESTAMP}.sha256"
fi
# 清理舊備份 (保留 30 天)
find "$BACKUP_DIR" -name "*_${TIMESTAMP%%_*}_*.tar.gz" -mtime +30 -delete 2>/dev/null
find "$BACKUP_DIR" -name "*_${TIMESTAMP%%_*}_*.sql.gz" -mtime +30 -delete 2>/dev/null
find "$BACKUP_DIR" -name "*_${TIMESTAMP%%_*}_*.rdb" -mtime +30 -delete 2>/dev/null
find "$BACKUP_DIR" -name "*.sha256" -mtime +30 -delete 2>/dev/null
echo "備份完成: ${SERVICE_NAME}_${BACKUP_TYPE}_${TIMESTAMP}"
```
### 9.4 備份排程
建議使用 cron 進行自動備份:
```bash
# 編輯 crontab
crontab -e
# 添加備份任務 (每天凌晨 3 點)
0 3 * * * /Users/accusys/momentry/scripts/backup_{service}.sh >> /Users/accusys/momentry/log/backup.log 2>&1
# 每週日凌晨 3 點執行完整備份
0 3 * * 0 /Users/accusys/momentry/scripts/backup_{service}.sh full >> /Users/accusys/momentry/log/backup.log 2>&1
```
### 9.5 備份驗證
```bash
# 查看備份列表 (按時間排序)
ls -lt /Users/accusys/momentry/backup/{service}/
# 驗證備份完整性
# 1. 檢查校驗和
sha256sum -c /Users/accusys/momentry/backup/{service}/*.sha256
# 2. 驗證 tar 壓縮
tar -tzf /Users/accusys/momentry/backup/{service}/{service}_full_20260315_030000.tar.gz
# 3. 驗證 SQL 備份
zcat /Users/accusys/momentry/backup/{service}/{service}_db_20260315_030000.sql.gz | head -5
# 驗證備份完整性
tar -tzf /Users/accusys/momentry/backup/{service}/{service}_var_20260315.tar.gz
```
---
## 十、服務完整刪除作業
### 10.1 刪除前確認
**警告**:此操作不可逆,請確保已完成備份!
- [ ] 確認服務已停止運行
- [ ] 確認數據已備份
- [ ] 確認無其他服務依賴此服務
### 10.2 刪除步驟
**步驟 1:停止服務**
```bash
# 停止服務
sudo launchctl unload /Library/LaunchDaemons/com.momentry.{service}.plist
# 驗證服務已停止
launchctl list | grep momentry.{service}
```
**步驟 2:刪除 Plist**
```bash
# 刪除系統 Plist
sudo rm /Library/LaunchDaemons/com.momentry.{service}.plist
# 刪除專案 Plist
rm /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.{service}.plist
```
**步驟 3:刪除數據和配置**
```bash
# 刪除數據目錄
sudo rm -rf /Users/accusys/momentry/var/{service}/
# 刪除配置目錄
sudo rm -rf /Users/accusys/momentry/etc/{service}/
# 刪除日誌
rm -f /Users/accusys/momentry/log/{service}.log
rm -f /Users/accusys/momentry/log/{service}.error.log
```
**步驟 4:清理監控配置**
```bash
# 從監控配置中移除服務
vim /Users/accusys/momentry_core_0.1/monitor/config/monitor_config.yaml
# 刪除該服務的監控配置
# 從監控腳本中移除
vim /Users/accusys/momentry_core_0.1/monitor/service/health_check.sh
# 移除該服務的檢查函數
```
**步驟 5:清理監控數據(可選)**
```bash
# 保留歷史數據還是刪除?
# 刪除監控數據
psql -U accusys -h localhost -d momentry -c "
DELETE FROM monitor_services WHERE service_name = '{service}';
"
```
### 10.3 驗證刪除
```bash
# 確認服務已停止
launchctl list | grep momentry.{service}
# 確認目錄已刪除
ls /Users/accusys/momentry/var/{service}/ 2>/dev/null || echo "已刪除"
# 確認 Plist 已刪除
ls /Library/LaunchDaemons/com.momentry.{service}.plist 2>/dev/null || echo "已刪除"
```
### 10.4 完整刪除腳本
```bash
#!/bin/bash
SERVICE_NAME="{service_name}"
echo "========== 服務完整刪除 =========="
echo "服務: $SERVICE_NAME"
echo "警告:此操作不可逆!"
read -p "確認繼續 (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
echo "取消刪除"
exit 0
fi
# 停止服務
echo "[1/6] 停止服務..."
sudo launchctl unload /Library/LaunchDaemons/com.momentry.${SERVICE_NAME}.plist 2>/dev/null
# 刪除 Plist
echo "[2/6] 刪除 Plist..."
sudo rm -f /Library/LaunchDaemons/com.momentry.${SERVICE_NAME}.plist
rm -f /Users/accusys/momentry_core_0.1/momentry_runtime/plist/com.momentry.${SERVICE_NAME}.plist
# 刪除數據
echo "[3/6] 刪除數據..."
sudo rm -rf /Users/accusys/momentry/var/${SERVICE_NAME}/
# 刪除配置
echo "[4/6] 刪除配置..."
sudo rm -rf /Users/accusys/momentry/etc/${SERVICE_NAME}/
# 刪除日誌
echo "[5/6] 刪除日誌..."
rm -f /Users/accusys/momentry/log/${SERVICE_NAME}.log
rm -f /Users/accusys/momentry/log/${SERVICE_NAME}.error.log
# 清理監控數據
echo "[6/6] 清理監控數據..."
psql -U accusys -h localhost -d momentry -c "
DELETE FROM monitor_services WHERE service_name = '${SERVICE_NAME}';
" 2>/dev/null
echo "========== 刪除完成 =========="
```
---
## 十一、檢查清單
添加新服務時,請確認以下項目:
- [ ] 創建服務目錄 (`var/`, `etc/`)
- [ ] 配置日誌文件 (`.log` + `.error.log`)
- [ ] 創建 plist 文件,UserName 設為 `accusys`
- [ ] 複製到 `/Library/LaunchDaemons/`
- [ ] 使用 launchctl 載入服務
- [ ] 驗證服務運行
- [ ] 添加監控配置
- [ ] 測試監控腳本
- [ ] 創建安裝文檔
- [ ] 更新 SERVICES.md 服務清單
- [ ] 更新 MOMENTRY_INTEGRATION_GUIDE.md
---
## 十二、模板文件
### Plist 模板位置
```
/Users/accusys/momentry_core_0.1/momentry_runtime/plist/
├── template.service.plist # 服務模板
├── com.momentry.redis.plist # 服務示例
└── com.momentry.n8n.main.plist # 複雜服務示例
```
### 創建模板命令
```bash
# 創建服務模板
cat > /Users/accusys/momentry_core_0.1/momentry_runtime/plist/template.service.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.momentry.SERVICE_NAME</string>
<key>UserName</key>
<string>accusys</string>
<key>WorkingDirectory</key>
<string>/Users/accusys/momentry/var/SERVICE_NAME</string>
<key>ProgramArguments</key>
<array>
<string>/path/to/executable</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/Users/accusys/momentry/log/SERVICE_NAME.log</string>
<key>StandardErrorPath</key>
<string>/Users/accusys/momentry/log/SERVICE_NAME.error.log</string>
</dict>
</plist>
EOF
```
---
## 十一、版本歷史
| 版本 | 日期 | 內容 |
|------|------|------|
| 1.0 | 2026-03-15 | 初始版本 |
| 2.0 | 2026-03-15 | 統一 Plist 位置、移除 root/用戶區分、加入運行方式分類 |
| 2.1 | 2026-03-15 | 新增服務備份作業、服務完整刪除作業 |
| 2.1 | 2026-03-24 | 更新 launchctl 命令,使用 `bootstrap`/`bootout` 替代 `load`/`unload` | |
@@ -0,0 +1,668 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "技術決策記錄 (Technical Decision Records)"
date: "2026-04-22"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "decision"
- "技術決策記錄"
ai_query_hints:
- "查詢 技術決策記錄 (Technical Decision Records) 的內容"
- "技術決策記錄 (Technical Decision Records) 的主要目的是什麼?"
- "如何操作或實施 技術決策記錄 (Technical Decision Records)"
---
# 技術決策記錄 (Technical Decision Records)
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-22 |
| 文件版本 | V1.0 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 |
|------|------|------|--------|
| V1.0 | 2026-04-22 | 創建技術決策記錄文件 | OpenCode |
---
## 1. 什麼是技術決策記錄 (TDR)
技術決策記錄是一種文檔化方法,用於記錄重要的技術決策、其背景、評估選項、選擇理由以及後果。每條記錄都應包含:
1. **決策標題**:簡要描述決策內容
2. **決策狀態**:已採納、待定、廢棄等
3. **決策日期**:做出決策的日期
4. **決策背景**:為什麼需要這個決策
5. **評估選項**:考慮過的各種方案
6. **選擇理由**:為什麼選擇這個方案
7. **後果**:預期的正面和負面影響
8. **相關鏈接**:相關的文檔、代碼或討論
---
## 2. 架構決策
### TDR-001: 分層分片架構設計
| 項目 | 內容 |
|------|------|
| **決策標題** | 採用四層分片架構設計 |
| **決策狀態** | ✅ 已採納(設計階段) |
| **決策日期** | 2026-04-21 |
| **最後更新** | 2026-04-22 |
#### 2.1 決策背景
Momentry Core 需要將連續視頻轉化為可檢索的知識單元。需要一個架構來支持不同粒度的檢索和分析。
#### 2.2 評估選項
**選項 A: 單層分片架構**
- 所有內容都存儲在同一層級
- 簡單實現,維護成本低
- 但檢索粒度單一,無法支持多層級分析
**選項 B: 兩層分片架構**
- 句子級 + 場景級分片
- 適中的複雜度
- 但缺乏視覺和摘要層級
**選項 C: 四層分片架構(選擇方案)**
- Rule 1: 句子級 (`sentence`)
- Rule 2: 視覺物件級 (`visual`)
- Rule 3: 場景級 (`scene`)
- Rule 4: 摘要級 (`summary`)
#### 2.3 選擇理由
選擇四層架構的原因:
1. **粒度靈活性**:支持從單詞到故事的各種檢索需求
2. **理解深度**:從細節到整體的多層次理解
3. **未來擴展**:為更複雜的分析提供基礎
4. **用戶體驗**:不同用戶可以選擇合適的檢索粒度
#### 2.4 後果
**正面影響**
- 豐富的檢索能力
- 支持多層級內容分析
- 更好的用戶體驗
**負面影響**
- 實現複雜度增加
- 需要更多計算資源
- 數據存儲需求增加
#### 2.5 實現狀態
| 分片層級 | 設計狀態 | 實現狀態 | 備註 |
|----------|----------|----------|------|
| Rule 1 (Sentence) | ✅ 已定義 | ✅ 已實現 | `src/core/chunk/rule1_ingest.rs` |
| Rule 2 (Visual) | ✅ 已定義 | ❌ 未實現 | 需要集成 YOLO 物件檢測 |
| Rule 3 (Scene) | ✅ 已定義 | ⚠️ 部分實現 | 基於 CUT 數據,需要完善 |
| Rule 4 (Summary) | ✅ 已定義 | ❌ 未實現 | 需要集成 LLM 摘要生成 |
#### 2.6 相關鏈接
- [CHUNKING_ARCHITECTURE.md](./chunking/CHUNKING_ARCHITECTURE.md)
- 代碼實現:`src/core/chunk/`
---
### TDR-002: 數據庫技術選型
| 項目 | 內容 |
|------|------|
| **決策標題** | 多數據庫混合架構 |
| **決策狀態** | ✅ 已採納並實現 |
| **決策日期** | 2026-03-15 |
| **最後更新** | 2026-04-22 |
#### 2.1 決策背景
需要選擇合適的數據存儲方案來支持不同類型的數據和查詢需求。
#### 2.2 評估選項
**選項 A: 單一關係型數據庫**
- 使用 PostgreSQL 存儲所有數據
- 簡單統一,但可能不適合所有數據類型
**選項 B: 單一 NoSQL 數據庫**
- 使用 MongoDB 存儲所有數據
- 靈活的 schema,但關係查詢能力有限
**選項 C: 多數據庫混合架構(選擇方案)**
- **PostgreSQL**: 主數據存儲,關係型數據
- **Redis**: 緩存和隊列管理
- **MongoDB**: 文檔緩存
- **Qdrant**: 向量數據庫,語義搜索
#### 2.3 選擇理由
選擇混合架構的原因:
1. **專業化存儲**:每個數據庫處理最適合的數據類型
2. **性能優化**:向量搜索用 Qdrant,緩存用 Redis
3. **靈活性**:不同類型的數據有不同的存儲需求
4. **可擴展性**:可以獨立擴展各個組件
#### 2.4 後果
**正面影響**
- 各組件性能最優化
- 支持複雜的查詢需求
- 良好的可擴展性
**負面影響**
- 系統複雜度增加
- 需要管理多個數據庫
- 數據一致性挑戰
#### 2.5 實現狀態
| 數據庫 | 用途 | 實現狀態 |
|--------|------|----------|
| PostgreSQL | 主數據存儲,關係型數據 | ✅ 已實現 |
| Redis | 緩存和隊列管理 | ✅ 已實現 |
| MongoDB | 文檔緩存 | ✅ 已實現 |
| Qdrant | 向量數據庫,語義搜索 | ✅ 已實現 |
#### 2.6 相關鏈接
- 代碼實現:`src/core/db/`
---
### TDR-003: 編程語言選擇
| 項目 | 內容 |
|------|------|
| **決策標題** | 使用 Rust 作為核心開發語言 |
| **決策狀態** | ✅ 已採納並實現 |
| **決策日期** | 2026-03-10 |
| **最後更新** | 2026-04-22 |
#### 3.1 決策背景
需要選擇一個高性能、安全、可維護的語言來構建視頻處理系統。
#### 3.2 評估選項
**選項 A: Python**
- 生態豐富,AI 庫完善
- 開發速度快
- 但性能較低,不適合高並發
**選項 B: Go**
- 性能好,並發支持好
- 簡單易學
- 但生態不如 Rust 豐富
**選項 C: Rust(選擇方案)**
- 高性能,接近 C++ 的性能
- 內存安全,無 GC
- 強大的類型系統和錯誤處理
**選項 D: Java/Kotlin**
- 企業級生態
- 性能良好
- 但內存佔用大,啟動慢
#### 3.3 選擇理由
選擇 Rust 的原因:
1. **性能需求**:視頻處理需要高性能
2. **安全性**:內存安全避免潛在的崩潰和安全問題
3. **並發處理**:強大的並發支持適合高並發 API
4. **生態系統**:豐富的網絡和數據庫庫
5. **長期維護**:嚴格的編譯器檢查減少 bug
#### 3.4 後果
**正面影響**
- 高性能和低延遲
- 高可靠性和安全性
- 良好的可維護性
**負面影響**
- 學習曲線陡峭
- 開發速度相對較慢
- 某些 AI 庫需要通過 Python 橋接
#### 3.5 實現狀態
- ✅ 核心系統使用 Rust 實現
- ✅ Python 用於 AI 模型處理
- ✅ 通過子進程調用橋接 Rust 和 Python
#### 3.6 相關鏈接
- 代碼庫:`src/` 目錄
- [RUST_DEVELOPMENT.md](../REFERENCE/RUST_DEVELOPMENT.md)
---
### TDR-004: 分片規則分析與未來規劃
| 項目 | 內容 |
|------|------|
| **決策標題** | 視覺/場景/摘要分片的設計意義與實現規劃 |
| **決策狀態** | 📝 設計階段(未實現) |
| **提出日期** | 2026-04-22 |
| **最後更新** | 2026-04-22 |
#### 4.1 視覺分片 (Visual Chunk) 的意義
**核心價值**
1. **物件級搜索**:支持「看到了什麼」的搜索
2. **跨模態橋接**:連接視覺與語音/文本內容
3. **場景理解基礎**:通過物件組合理解場景
**好處**
- 實現「視覺第一」的搜索體驗
- 支持基於物件出現的視頻分析
- 為場景分析提供基礎數據
#### 4.2 場景分片 (Scene Chunk) 的意義
**核心價值**
1. **語義聚合**:將相關句子/物件組成有意義場景
2. **上下文保留**:保持對話和行為的連貫性
3. **高效檢索**:直接定位到場景而非單句
**好處**
- 支持語義級搜索(如「會議對話」、「爭吵場景」)
- 保留完整上下文
- 為故事摘要提供基礎
#### 4.3 摘要分片 (Summary Chunk) 的意義
**核心價值**
1. **高層級理解**:提供視頻整體概括
2. **5W1H 結構化**:提取關鍵信息
3. **敘事壓縮**:將長視頻精簡為可快速理解的摘要
**好處**
- 用戶無需觀看整個視頻即可了解內容
- 提供清晰的結構化信息
- 支持視頻內容快速評估和比較
#### 4.4 實現優先級與挑戰
**實現優先級**
1.**Rule 1 (句子級)** - 已實現
2. ⚠️ **Rule 3 (場景級)** - 部分實現(基於 CUT 數據)
3.**Rule 2 (視覺級)** - 待實現
4.**Rule 4 (摘要級)** - 待實現
**技術挑戰**
1. **視覺分片**:物件檢測準確性與性能平衡
2. **場景分片**:場景邊界智能識別
3. **摘要分片**LLM 摘要質量與一致性
4. **數據融合**:多模態信息有效整合
#### 4.5 遷移計劃
**短期 (1-2個月)**
- 完善 Rule 3 (場景級分片)
- 集成 Places365 場景分類
- 完善基於視覺和語音的場景識別
**中期 (3-6個月)**
- 實現 Rule 2 (視覺分片)
- 集成 YOLO 物件檢測
- 創建物件標籤索引
**長期 (6-12個月)**
- 實現 Rule 4 (摘要分片)
- 集成 LLM 摘要生成
- 實現5W1H結構化提取
#### 4.6 相關鏈接
- [CHUNKING_ARCHITECTURE.md](./chunking/CHUNKING_ARCHITECTURE.md))
- Rule 1 實現:`src/core/chunk/rule1_ingest.rs`
- Rule 3 實現:`src/core/chunk/rule3_ingest.rs`
---
## 3. 設計與實現差異分析
### 設計目標 vs 實際實現
#### 差異點1: chunk_type 定義
| 設計文件 | 實際代碼 | 狀態分析 |
|----------|----------|----------|
| `sentence` | `"sentence"` | ✅ 一致 |
| `visual` | 未實現 | ❌ 缺失設計功能 |
| `scene` | `"cut"` + 部分實現 | ⚠️ 部分實現(名稱差異) |
| `summary` | 未實現 | ❌ 缺失設計功能 |
| - | `"time"`, `"trace"`, `"story"` | 🔄 代碼中的額外類型 |
#### 差異點2: 分片規則實現
| 規則 | 設計描述 | 實現狀態 | 問題分析 |
|------|----------|----------|----------|
| Rule 1 | 句子級檢索 | ✅ 已實現 | 完整功能 |
| Rule 2 | 視覺物件級檢索 | ❌ 未實現 | 缺乏物件檢測集成 |
| Rule 3 | 場景級檢索 | ⚠️ 部分實現 | 僅基於CUT數據,缺少場景分類 |
| Rule 4 | 摘要級檢索 | ❌ 未實現 | 缺少LLM集成和結構化摘要 |
#### 差異點3: 數據庫結構
| 設計目標 | 實現現狀 | 分析 |
|----------|----------|------|
| 通用分片結構 | 已實現基本結構 | ✅ |
| 視覺物件索引 | 未實現 | ❌ |
| 場景聚合表 | 部分實現 | ⚠️ |
| 摘要生成表 | 未實現 | ❌ |
---
## 4. 建議實現路徑與計劃
### 優先級1: 完善現有實現
**短期目標 (1-2週)**
1. **統一 `chunk_type` 枚舉**
- 更新 `src/core/chunk/types.rs` 中的 `ChunkType` 枚舉
- 確保與數據庫中存儲的字符串值一致
2. **擴展Rule 3實現**
- 集成Places365模型進行場景分類
- 結合視覺和語音數據的場景邊界識別
- 創建 `chunks_rule3` 表的完整結構
### 優先級2: 實現視覺分片
**中期目標 (1-2個月)**
1. **YOLO集成**
- 創建 `yolo_processor.py` 腳本
- 實現基於關鍵幀的物件檢測
- 物件標籤標準化和索引建立
2. **視覺分片生成**
- 創建 `visual_ingest.rs` 處理器
- 實現物件聚合和標籤生成
- 創建 `chunks_rule2` 表結構
### 優先級3: 實現摘要分片
**長期目標 (3-6個月)**
1. **LLM集成**
- 集成Gemma4或類似LLM
- 實現視頻內容摘要生成
- 5W1H結構化信息提取
2. **摘要分片生成**
- 創建 `summary_ingest.rs` 處理器
- 實現跨場景的敘事壓縮
- 創建 `chunks_rule4` 表結構
---
## 5. 關鍵決策點總結
### 決策1: 分層架構設計
**設計目標**
- 四層分片架構:句子 → 視覺 → 場景 → 摘要
- 多粒度檢索:從細節到整體的不同層次理解
**實現現狀**
- 句子級分片(Rule 1)完整實現
- 場景級分片(Rule 3)部分實現
- 視覺和摘要分片未實現
### 決策2: 數據庫混合架構
**設計目標**
- PostgreSQL: 主數據存儲
- Redis: 緩存和隊列
- MongoDB: 文檔緩存
- Qdrant: 向量搜索
**實現現狀**
- ✅ 所有數據庫均已集成
- ✅ 多數據庫協同工作
- ⚠️ 數據一致性管理需要完善
### 決策3: 技術棧選擇
**設計目標**
- Rust: 核心系統語言
- Python: AI模型處理
- Axum: Web框架
- Tokio: 異步運行時
**實現現狀**
- ✅ Rust核心系統完整實現
- ✅ Python AI模型集成
- ✅ Axum + Tokio 穩定運行
- ⚠️ Python-Rust 橋接效率需優化
---
## 6. 未來改進方向
### 短期改進 (1-2個月)
1. **統一API設計**
- 標準化所有列表API的分頁參數
- 統一回應結構格式
- 完善錯誤處理和文檔
2. **優化性能**
- 改進數據庫查詢效率
- 優化Python子進程調用
- 改善並發處理能力
### 中期改進 (3-6個月)
1. **完善分片規則**
- 實現視覺分片(Rule 2
- 實現摘要分片(Rule 4
- 完善場景分片(Rule 3
2. **擴展功能**
- 支持更多視頻格式
- 集成更多AI模型
- 提供更多分析維度
### 長期改進 (6-12個月)
1. **系統架構升級**
- 微服務化架構
- 雲原生部署支持
- 大規模視頻處理能力
2. **平台化發展**
- 多租戶支持
- 可擴展插件架構
- 雲端協同工作流
---
## 7. 最後更新記錄
| 版本 | 日期 | 主要變更 | 操作人 |
|------|------|----------|--------|
| V1.0 | 2026-04-22 | 創建技術決策記錄文件 | OpenCode |
| V1.1 | 2026-04-22 | 添加設計與實現差異分析 | OpenCode |
| V1.2 | 2026-04-22 | 完善實現計劃和改進方向 | OpenCode |
**最後更新日期**: 2026-04-22
@@ -0,0 +1,309 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "術語對照表 (Terminology Mapping)"
date: "2026-04-22"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "術語對照表"
ai_query_hints:
- "查詢 術語對照表 (Terminology Mapping) 的內容"
- "術語對照表 (Terminology Mapping) 的主要目的是什麼?"
- "如何操作或實施 術語對照表 (Terminology Mapping)"
---
# 術語對照表 (Terminology Mapping)
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-22 |
| 文件版本 | V1.0 |
| 相關文件 | [DESIGN_IMPLEMENTATION_GAP.md](./DESIGN_IMPLEMENTATION_GAP.md)<br>[ARCHITECTURE_OVERVIEW.md](./ARCHITECTURE_OVERVIEW.md)<br>[CHUNKING_ARCHITECTURE.md](./CHUNKING_ARCHITECTURE.md) |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-04-22 | 創建術語對照表 | OpenCode | OpenCode / deepseek-v3.2 |
---
## 1. 核心原則
**當設計與實現出現矛盾時,以實際的 Rust 代碼實現為最高權威。**
本文檔提供設計文檔中的術語與實際 Rust 代碼實現之間的對照關係,用於:
1. 統一所有架構文檔的術語使用
2. 指導新文檔的撰寫
3. 作為代碼審查的參考標準
---
## 2. 分片類型 (Chunk Type) 對照
### 2.1 設計與實現對照表
| 設計概念 | 設計值 | 實現值 | 實現狀態 | 說明 |
|----------|--------|--------|----------|------|
| **時間基準分片** | `time` | `TimeBased` | ✅ 已實現 | 基於固定時間間隔的分片 |
| **句子級分片** | `sentence` | `Sentence` | ✅ 已實現 | 基於 ASR 轉錄的句子邊界 |
| **場景級分片** | `scene` | `Cut` | ⚠️ 部分實現 | 基於 CUT 算法的場景邊界檢測 |
| **視覺物件級分片** | `visual` | (未實現) | ❌ 未實現 | 基於 YOLO 的物件檢測分片 |
| **摘要級分片** | `summary` | `Story` | ⚠️ 概念調整 | 基於分片聚合的敘事重建 |
| **軌跡追蹤分片** | (未定義) | `Trace` | ✅ 已實現 | 人物/物件軌跡追蹤分片 |
### 2.2 實際 Rust 代碼定義
```rust
// src/core/chunk/mod.rs 中的 ChunkType 枚舉
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum ChunkType {
TimeBased, // 時間基準分片
Sentence, // 句子級分片
Cut, // 場景級分片 (基於 CUT 算法)
Trace, // 軌跡追蹤分片
Story, // 敘事分片 (原設計的摘要分片)
}
```
### 2.3 文檔撰寫指南
1. **新文檔撰寫**:一律使用實現值 (`TimeBased`, `Sentence`, `Cut`, `Trace`, `Story`)
2. **舊文檔更新**:將設計值替換為實現值,並添加註釋說明
3. **狀態標記**:對於未實現或部分實現的功能,使用狀態標記 (✅, ⚠️, ❌)
---
## 3. 分片規則 (Chunk Rule) 對照
### 3.1 設計與實現對照表
| 規則編號 | 設計名稱 | 實現名稱 | 實現狀態 | 對應 ChunkType |
|----------|----------|----------|----------|----------------|
| **Rule 1** | 句子級分片 | Rule 1 (句子分片) | ✅ 已實現 | `Sentence` |
| **Rule 2** | 視覺物件級分片 | (未實現) | ❌ 未實現 | (未實現) |
| **Rule 3** | 場景級分片 | Rule 3 (場景分片) | ⚠️ 部分實現 | `Cut` |
| **Rule 4** | 摘要級分片 | Rule 4 (敘事分片) | ⚠️ 概念調整 | `Story` |
### 3.2 實際實現狀態
1. **Rule 1**: 完整實現於 `src/core/chunk/rule1_ingest.rs`
2. **Rule 2**: 未實現,僅有設計概念
3. **Rule 3**: 部分實現,使用 CUT 算法檢測場景邊界
4. **Rule 4**: 概念調整,實現為基於分片聚合的敘事重建
---
## 4. 數據模型對照
### 4.1 設計中的數據模型
```json
{
"chunk_type": "sentence|visual|scene|summary", // 設計值
"content": {
"text": "轉錄文本",
"visual_objects": ["person", "car", "dog"],
"scene_context": "辦公室會議",
"summary": "會議討論項目進度"
}
}
```
### 4.2 實際實現的數據模型
```rust
// src/core/chunk/mod.rs 中的 Chunk 結構
pub struct Chunk {
pub id: i64,
pub uuid: String,
pub video_record_id: i64,
pub chunk_type: ChunkType, // 實現值: TimeBased|Sentence|Cut|Trace|Story
pub start_time: f64,
pub end_time: f64,
pub content: serde_json::Value, // 動態 JSON 內容
pub embedding: Option<Vec<f32>>,
pub created_at: DateTime<Utc>,
}
```
### 4.3 關鍵差異
1. **類型系統**:設計使用字符串枚舉,實現使用 Rust 枚舉
2. **內容結構**:設計有固定字段,實現使用動態 JSON
3. **時間表示**:設計使用時間戳+時長,實現使用開始/結束時間
---
## 5. 處理管道對照
### 5.1 設計管道
```
ASR → OCR → YOLO → CUT → LLM → 分片生成
```
### 5.2 實際管道
```
ASR → OCR → YOLO → CUT → 分片生成
LLM(尚未集成)
```
### 5.3 關鍵差異點
1. **LLM 集成**:設計中有完整 LLM 階段,實際尚未集成
2. **處理順序**:實際實現根據技術依賴關係調整了順序
3. **並行處理**:實際實現有更多並行處理優化
---
## 6. 文檔更新指南
### 6.1 更新原則
1. **優先級**:以實際 Rust 代碼實現為準
2. **一致性**:所有文檔使用相同的術語
3. **狀態標記**:明確標記功能實現狀態
4. **版本控制**:記錄術語變更歷史
### 6.2 具體更新操作
#### 6.2.1 分片類型更新
| 舊術語 | 新術語 | 更新說明 |
|--------|--------|----------|
| `chunk_type: "sentence"` | `chunk_type: "Sentence"` | 保持 PascalCase |
| `chunk_type: "visual"` | `chunk_type: (未實現)` | 標記為未實現 |
| `chunk_type: "scene"` | `chunk_type: "Cut"` | 使用實際實現值 |
| `chunk_type: "summary"` | `chunk_type: "Story"` | 使用實際實現值 |
#### 6.2.2 規則名稱更新
| 舊術語 | 新術語 | 更新說明 |
|--------|--------|----------|
| `Rule 2 (visual)` | `Rule 2 (未實現)` | 標記為未實現 |
| `Rule 3 (scene)` | `Rule 3 (場景分片)` | 使用中文描述 |
| `Rule 4 (summary)` | `Rule 4 (敘事分片)` | 使用中文描述 |
### 6.3 狀態標記系統
| 標記 | 含義 | 使用場景 |
|------|------|----------|
| ✅ | 已完整實現 | 功能完全按照設計實現 |
| ⚠️ | 部分實現 | 功能部分實現,有差異 |
| ❌ | 未實現 | 功能尚未實現 |
| 🔄 | 概念調整 | 設計概念在實現中調整 |
---
## 7. 使用示例
### 7.1 正確示例
```markdown
## 分片類型
Momentry Core 支持以下分片類型:
1. **TimeBased** (時間基準分片) ✅ 已實現
2. **Sentence** (句子級分片) ✅ 已實現
3. **Cut** (場景級分片) ⚠️ 部分實現
4. **Trace** (軌跡追蹤分片) ✅ 已實現
5. **Story** (敘事分片) ⚠️ 概念調整
**注意**:設計中的 `visual` 分片尚未實現,設計中的 `summary` 分片已調整為 `Story` 分片。
```
### 7.2 錯誤示例
```markdown
## 分片類型
Momentry Core 支持以下分片類型:
1. sentence (句子級分片)
2. visual (視覺物件級分片)
3. scene (場景級分片)
4. summary (摘要級分片)
```
---
## 8. 維護與更新
### 8.1 更新流程
1. **代碼變更**:當 Rust 代碼中的類型定義變更時
2. **文檔更新**:根據本文檔更新所有相關文檔
3. **一致性檢查**:運行 `scripts/check_architecture_docs.py` 驗證
4. **版本更新**:更新本文檔的版本歷史
### 8.2 審查要點
1. **術語一致性**:所有文檔是否使用相同的術語
2. **狀態準確性**:功能實現狀態是否準確標記
3. **文檔完整性**:所有重要概念是否都有對照說明
### 8.3 自動化檢查
```bash
# 運行架構文檔一致性檢查
python3 scripts/check_architecture_docs.py --check-terminology
```
---
## 9. 結論
本文檔作為 Momentry Core 架構文檔的術語標準,確保:
1. **設計與實現一致性**:文檔準確反映實際代碼狀態
2. **文檔統一性**:所有文檔使用相同的術語體系
3. **可維護性**:提供明確的更新和維護指南
**核心原則重申**:在出現矛盾時,實際的 Rust 代碼實現是最高權威,設計文檔應反映實際實現狀態並指導未來改進方向。
---
## 附錄 A:快速參考
### A.1 分片類型快速參考
| 使用場景 | 推薦術語 | 狀態 |
|----------|----------|------|
| 時間基準分片 | `TimeBased` | ✅ |
| 句子級分片 | `Sentence` | ✅ |
| 場景級分片 | `Cut` | ⚠️ |
| 軌跡追蹤分片 | `Trace` | ✅ |
| 敘事分片 | `Story` | ⚠️ |
| 視覺物件分片 | (標記為未實現) | ❌ |
### A.2 規則名稱快速參考
| 規則 | 推薦名稱 | 狀態 |
|------|----------|------|
| Rule 1 | 句子分片規則 | ✅ |
| Rule 2 | (標記為未實現) | ❌ |
| Rule 3 | 場景分片規則 | ⚠️ |
| Rule 4 | 敘事分片規則 | ⚠️ |
### A.3 狀態標記快速參考
- ✅:使用 `chunk_type: "Sentence"` (已實現)
- ⚠️:使用 `chunk_type: "Cut"` ⚠️ 部分實現 (部分實現)
- ❌:標記為 "未實現" 或 "設計概念" (未實現)
- 🔄:說明概念調整原因 (概念調整)
---
**文件版本**: V1.0
**最後更新**: 2026-04-22
**維護者**: OpenCode
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,443 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "統一會員系統 + 影片歸屬追蹤實作計畫"
date: "2026-03-24"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
- "影片歸屬追蹤實作計畫"
- "統一會員系統"
ai_query_hints:
- "查詢 統一會員系統 + 影片歸屬追蹤實作計畫 的內容"
- "統一會員系統 + 影片歸屬追蹤實作計畫 的主要目的是什麼?"
- "如何操作或實施 統一會員系統 + 影片歸屬追蹤實作計畫?"
---
# 統一會員系統 + 影片歸屬追蹤實作計畫
| 項目 | 內容 |
|------|------|
| 建立者 | Warren |
| 建立時間 | 2026-03-24 |
| 文件版本 | V1.0 |
| 狀態 | 待確認 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 |
|------|------|------|--------|
| V1.0 | 2026-03-24 | 創建實作計畫 | OpenCode |
---
## 1. 背景與目標
### 1.1 現有問題
目前 Momentry 生態系統中,各服務有獨立的用戶管理:
| 服務 | 用戶系統 | 問題 |
|------|----------|------|
| WordPress | wp_users (2 admin) | 無會員系統,無 API 認證 |
| SFTPGo | users 表 (3 users) | 獨立管理 |
| n8n | users 表 | 獨立管理 |
| Gitea | `user` 表 | 獨立管理 |
| Momentry Core | api_keys (未啟用) | 無 user 關聯 |
**問題**
1. 無法追蹤影片歸屬(誰上傳的影片)
2. 無法實作 per-user 配額管理
3. API 端點全部公開,無認證
4. 用戶創建需要多處操作
### 1.2 目標
建立統一的會員系統,讓 WordPress 成為唯一登入入口:
```
┌─────────────────────────────────────────────────────────────────┐
│ 目標架構 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ WordPress (會員系統) │
│ │ │
│ ├─► SFTPGo (檔案上傳) │
│ ├─► Momentry Core (影片處理) │
│ └─► n8n (自動化流程) │
│ │
│ 統一的 user_id 追蹤 │
│ │ │
│ └─► videos 表關聯 user_id │
│ └─► monitor_jobs 表關聯 user_id │
│ └─► per-user 配額管理 │
│ │
└─────────────────────────────────────────────────────────────────┘
```
---
## 2. 現有系統分析
### 2.1 WordPress
| 項目 | 狀態 |
|------|------|
| 安裝插件 | Elementor, Akismet, Code Snippets, All-in-One WP Migration |
| 用戶表 | wp_users (2 users: wp_user, sc_demo) |
| 會員插件 | 無 |
| REST API | 標準端點 (`/wp-json/wp/v2/users`) |
| 認證方式 | Cookie / Application Passwords |
| JWT | 無 |
### 2.2 SFTPGo
| 項目 | 值 |
|------|-----|
| 用戶數 | 3 (demo, warren, momentry) |
| API | REST API v2 (`/api/v2/users`) |
| Admin | admin:Test3200Test3200 |
| Hook | `/Users/accusys/sftpgo_test/register_hook.sh` |
### 2.3 Momentry Core
| 項目 | 狀態 |
|------|------|
| api_keys 表 | 已存在 |
| users 表 | 不存在 |
| videos.user_id | 不存在 |
| API 認證 | 未啟用(所有端點公開) |
---
## 3. 實作計畫
### Phase 1: WordPress 認證機制啟用
#### 1.1 啟用 Application Passwords
**WordPress 5.6+ 內建功能**,無需額外插件。
```php
// wp-config.php (如需自訂設定)
define('WP APPLICATION_PASSWORDS_ENABLED', true);
```
**使用方式**
```bash
# Basic Auth 格式
curl -X POST "https://wp.momentry.ddns.net/wp-json/wp/v2/users" \
-u "username:application_password" \
-H "Content-Type: application/json" \
-d '{"username": "newuser", "email": "user@example.com", "password": "password"}'
```
#### 1.2 測試 WordPress REST API
```bash
# 取得用戶列表(需要 admin 權限)
curl -s -u "wp_user:xxxx xxxx xxxx xxxx xxxx xxxx" \
"https://wp.momentry.ddns.net/wp-json/wp/v2/users"
# 創建新用戶
curl -X POST "https://wp.momentry.ddns.net/wp-json/wp/v2/users" \
-u "wp_user:xxxx xxxx xxxx xxxx xxxx xxxx" \
-H "Content-Type: application/json" \
-d '{
"username": "testuser",
"email": "test@example.com",
"password": "TestPass123!",
"roles": ["subscriber"]
}'
```
---
### Phase 2: 資料庫結構調整
#### 2.1 新增 users 表(Momentry Core
```sql
-- migrations/002_user_management.sql
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
wordpress_id BIGINT UNIQUE NOT NULL,
username VARCHAR(60) NOT NULL,
email VARCHAR(100) NOT NULL,
api_key_hash VARCHAR(64),
quota_size BIGINT DEFAULT 10737418240, -- 10GB
quota_used BIGINT DEFAULT 0,
sftpgo_username VARCHAR(60),
status VARCHAR(20) DEFAULT 'active', -- active, suspended, deleted
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_users_wordpress_id ON users(wordpress_id);
CREATE INDEX idx_users_username ON users(username);
-- videos 表新增 user_id
ALTER TABLE videos ADD COLUMN user_id BIGINT REFERENCES users(id);
CREATE INDEX idx_videos_user_id ON videos(user_id);
-- monitor_jobs 表新增 user_id
ALTER TABLE monitor_jobs ADD COLUMN user_id BIGINT REFERENCES users(id);
CREATE INDEX idx_monitor_jobs_user_id ON monitor_jobs(user_id);
-- api_keys 表新增 user_id
ALTER TABLE api_keys ADD COLUMN user_id BIGINT REFERENCES users(id);
```
#### 2.2 更新 api_keys 表結構
```sql
-- 新增欄位
ALTER TABLE api_keys ADD COLUMN user_id BIGINT REFERENCES users(id);
ALTER TABLE api_keys ADD COLUMN wordpress_id BIGINT;
ALTER TABLE api_keys ADD COLUMN sftpgo_username VARCHAR(60);
```
---
### Phase 3: API 認證中介層
#### 3.1 中介層設計
```rust
// src/api/middleware/auth.rs
#[derive(Clone)]
pub struct AuthState {
pub db: Arc<PostgresDb>,
pub cache: Arc<RedisCache>,
}
pub async fn auth_middleware(
req: Request,
next: Next,
state: AuthState,
) -> Result<Response, StatusCode> {
// 1. 從 Header 提取 API Key
// Header: X-API-Key: muser_xxx
// 或: Authorization: Bearer muser_xxx
// 2. 驗證並取得 user_id
let user_id = validate_api_key(&req, &state).await?;
// 3. 附加到 request extensions
req.extensions_mut().insert(UserContext { user_id });
// 4. 執行 handler
next.call(req).await
}
#[derive(Clone)]
pub struct UserContext {
pub user_id: i64,
}
```
#### 3.2 API Key 格式更新
```
新格式: muser_{uuid}_{timestamp}_{random}_{user_id_hash}
```
| 欄位 | 說明 |
|------|------|
| 前綴 | `muser_` = User 類型 |
| uuid | 唯一識別碼 |
| timestamp | 創建時間戳 |
| random | 隨機字串 |
| user_id_hash | 壓縮的 user_id |
---
### Phase 4: 更新 Register API
#### 4.1 修改 register 端點
```rust
// POST /api/v1/register
pub async fn register(
State(state): State<ApiState>,
Json(req): Json<RegisterRequest>,
Extension(ctx): Extension<UserContext>, // 新增
) -> Result<Json<RegisterResponse>, StatusCode> {
// ... 現有邏輯 ...
// 驗證用戶配額
let user = state.db.get_user(ctx.user_id).await?;
if user.quota_used + file_size > user.quota_size {
return Err(StatusCode::FORBIDDEN);
}
// 關聯 user_id 到影片
let video_uuid = state.db.create_video(req, Some(ctx.user_id)).await?;
// 建立 processing job(帶 user_id
state.db.create_monitor_job(
job_type: "auto_ingestion",
video_uuid,
user_id: Some(ctx.user_id),
processors: vec!["asr", "cut", "yolo", "ocr", "face", "pose"],
).await?;
Ok(Json(RegisterResponse { uuid: video_uuid }))
}
```
---
### Phase 5: n8n 自動化流程
#### 5.1 用戶註冊 Workflow
```
┌─────────────────────────────────────────────────────────────────┐
│ WordPress 用戶註冊自動化流程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Trigger: Webhook (或 WordPress Plugin) │
│ │
│ Step 1: 驗證管理員權限 │
│ └─► 檢查 WordPress REST API 憑證 │
│ │
│ Step 2: 在 Momentry Core 建立用戶記錄 │
│ └─► POST /api/v1/admin/users │
│ └─► 產生 API Key │
│ │
│ Step 3: 在 SFTPGo 建立用戶 │
│ └─► POST /api/v2/users (SFTPGo API) │
│ └─► 設定 home_dir: /data/{username} │
│ │
│ Step 4: 更新用戶記錄 │
│ └─► 關聯 sftpgo_username │
│ │
│ Step 5: 發送歡迎 email │
│ └─► 包含 SFTP 登入資訊 │
│ └─► 包含 API Key │
│ │
└─────────────────────────────────────────────────────────────────┘
```
#### 5.2 SFTPGo Hook 更新
```bash
# /Users/accusys/sftpgo_test/register_hook.sh
# 修改為傳遞 user_id
curl -X POST "http://localhost:3002/api/v1/register" \
-H "X-API-Key: ${SFTPGO_USER_API_KEY}" \
-H "X-SFTPGo-User: ${SFTPGO_USERNAME}" \
-d "{\"path\": \"${SFTPGO_FILE_PATH}\"}"
```
---
## 4. 實作優先順序
| Phase | 任務 | 複雜度 | 優先級 | 預估工時 |
|-------|------|--------|--------|----------|
| 1.1 | 測試 WordPress Application Passwords | 低 | P0 | 1h |
| 1.2 | 為 WordPress 產生 Application Password | 低 | P0 | 0.5h |
| 2.1 | 建立 users 表 migration | 中 | P0 | 2h |
| 2.2 | 更新 videos, monitor_jobs 表 | 低 | P0 | 1h |
| 3.1 | 實作 API auth middleware | 中 | P0 | 4h |
| 3.2 | 更新 register API 接受 user_id | 低 | P0 | 2h |
| 4 | 建立 admin users API | 中 | P1 | 4h |
| 5.1 | 建立 n8n 用戶註冊 workflow | 中 | P1 | 6h |
| 5.2 | 更新 SFTPGo hook | 低 | P1 | 2h |
| 6 | 實作配額管理 | 中 | P2 | 4h |
| 7 | 測試與驗證 | 中 | P2 | 4h |
**總預估工時**: ~30.5h
---
## 5. 待確認事項
### 5.1 WordPress 用戶建立方式
- [ ] 手動在 wp-admin 建立?還是透過 Elementor 表單?
- [ ] 是否需要 email 驗證?
- [ ] 初始角色設定(subscriber / contributor)?
### 5.2 API Key 格式
- [ ] 維持現有 `muser_` 前綴格式?
- [ ] 還是建立新的用戶專用 key 格式?
- [ ] 是否需要 JWT token
### 5.3 SFTPGo 整合
- [ ] 每個 WordPress 用戶對應一個 SFTPGo 用戶?
- [ ] home_dir 命名規則?(如 `data/{wordpress_username}`
- [ ] SFTPGo 配額是否同步?
### 5.4 配額管理
- [ ] 每人預設 10GB 空間?
- [ ] 超出配額如何處理?(阻止上傳 / 警告)
- [ ] 配額用完後是否暫停 SFTPGo 用戶?
### 5.5 資料同步
- [ ] WordPress 用戶刪除時是否同步刪除其他系統?
- [ ] 用戶停權時的處理流程?
---
## 6. 參考文件
### 內部文件
| 文件 | 用途 |
|------|------|
| `docs_v1.0/REFERENCE/PENDING_ISSUES.md` | 待解決問題追蹤 |
| `docs_v1.0/REFERENCE/API_KEY_MANAGEMENT.md` | API Key 管理系統 |
| `docs_v1.0/REFERENCE/API_REFERENCE.md` | API 端點參考 |
| `docs_v1.0/IMPLEMENTATION/SFTPGO_DEMO_USER.md` | SFTPGo 用戶設定 |
| `docs_v1.0/IMPLEMENTATION/N8N_INTEGRATION_GUIDE.md` | n8n 整合指南 |
| `docs_v1.0/IMPLEMENTATION/INSTALL_WORDPRESS.md` | WordPress 安裝指南 |
### 外部資源
| 資源 | URL |
|------|-----|
| WordPress REST API | https://developer.wordpress.org/rest-api/ |
| WordPress Application Passwords | https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/#authentication-plugins |
| SFTPGo REST API | https://docs.sftpgo.com/latest/rest-api/ |
---
## 7. 附錄
### A. 現有使用者資料
#### WordPress (wp_users)
| ID | user_login | user_email | display_name |
|----|------------|------------|--------------|
| 1 | wp_user | marketing@accusys.com.tw | wp_user |
| 2 | sc_demo | susan.cheng@accusys.com.tw | Susan Cheng |
#### SFTPGo (users)
| username | email | home_dir | status |
|----------|-------|----------|--------|
| demo | demo@momentry.local | /Users/accusys/momentry/var/sftpgo/data/demo | Active |
| warren | warren@momentry.local | /Users/accusys/momentry/var/sftpgo/data/warren | Active |
| momentry | system@momentry.local | /Users/accusys/momentry/var/sftpgo/data/momentry | Active |
### B. 服務端口
| 服務 | Port | URL |
|------|------|-----|
| WordPress | 9000 (PHP-FPM) | https://wp.momentry.ddns.net |
| SFTPGo | 8080 | http://localhost:8080 |
| Momentry API | 3002 | http://localhost:3002 |
| n8n | 5678 | http://localhost:5678 |
@@ -0,0 +1,498 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Identity 系統設計規範"
date: "2026-04-24"
version: "V1.0"
status: "deprecated"
owner: "Warren"
created_by: "OpenCode"
tags:
- "deprecated"
- "identity"
- "系統設計規範"
ai_query_hints:
- "查詢 Identity 系統設計規範 的內容"
- "Identity 系統設計規範 的主要目的是什麼?"
- "如何操作或實施 Identity 系統設計規範?"
---
> [!WARNING] **檔案已過時 (Deprecated)**
>
> **原因**: 此文件定義的 `face_identities` 和舊版 `file_identities` 結構已被新的 `FILE_IDENTITY_API_DESIGN.md` 取代。新設計統一了 File、Identity 和 Candidate 的概念,並移除了複雜的 IPC 分類系統。
>
> **狀態**: 僅供歷史參考,不應用於新功能的開發。
>
> **搬移日期**: 2026-04-25
# Identity 系統設計規範
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-24 |
| 文件版本 | V1.0 |
| 目的 | 定義全域身份 (Identity) 與泛型檔案 (File) 雙核心架構 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 |
|------|------|------|--------|
| V1.0 | 2026-04-24 | 初始設計規範,定義全域 Identity 與 File 雙核心架構、IPC 分類系統、關係分類 | OpenCode |
---
## 1. 核心概念
### 1.1 全域操作物件
| 物件 | 唯一識別碼 | 說明 |
|------|-----------|------|
| **File** | `file_uuid` | 泛型檔案(影片、圖片、PDF、PPT、Logo 圖檔等任何媒體類型) |
| **Identity** | `identities_id` | 全域唯一實體,涵蓋所有可被識別、命名、追蹤的對象 |
### 1.2 Identity 的涵蓋範圍
Identity 不限於人類,任何可被系統識別且擁有意義的實體皆屬於此範疇:
| 類別 | 範例 |
|------|------|
| **人物 (Person)** | 演員、導演、真實人物 |
| **角色 (Character)** | 虛構角色(如《無間道》的劉建明) |
| **吉祥物 (Mascot)** | Hello Kitty、皮卡丘 |
| **品牌 (Brand/Logo)** | 公司商標、產品 Logo |
| **物件 (Object)** | 特定道具、車輛 |
| **動物 (Animal)** | 寵物、野生動物 |
### 1.3 設計原則
1. **Identity 全域唯一性**`identities_id` 在全域範圍內唯一,同一個 Identity 可出現在多個不同檔案中。
2. **File 泛型性**`file_uuid` 不限於影片類型,支援任何媒體格式。
3. **多特徵支援 (Multi-Face/Feature)**:一個 Identity 可擁有多個 **Face Identity (定妝/特徵群集)**。Face 明確屬於特定檔案(如:同一演員在不同影片中的不同造型)。
4. **槽狀關聯結構 (Slot-based Association)**:檔案與身份的關係透過槽位表管理,紀錄檔案層級的專屬資訊(角色名稱、時間軸、位置等)。
5. **關係分類支援**:支援人物間的親屬、社交、專業關係,應用於社交親屬關係圖譜。
---
## 2. IPC 風格分類系統
### 2.1 分類碼結構
採用 **IPC (International Patent Classification)** 標準格式:
```
[小類 Subclass] [主組 Main Group]/[分組 Subgroup]
範例: A61B 17/02
↑ ↑ ↑
| | └─ 分組 (Subgroup) - 點號數量表示層級深度
| └──── 主組 (Main Group)
└───────── 小類 (Subclass)
```
### 2.2 部分類定義 (Section)
| 部代碼 | 名稱 | 說明 |
|--------|------|------|
| **A** | PERSONS (人物) | 真實人物、演員、導演、公眾人物 |
| **B** | CHARACTERS (角色) | 虛構角色、動漫角色、戲劇人物 |
| **C** | BRANDING (品牌) | 公司 Logo、產品商標、品牌識別 |
| **D** | MASCOTS (吉祥物) | 商業吉祥物、活動吉祥物、IP 角色 |
| **E** | OBJECTS (物件) | 車輛、武器、特定道具、建築物 |
| **F** | ANIMALS (動物) | 寵物、野生動物、神話生物 |
| **G** | LOCATIONS (場景) | 特定地點、地標、場景元素 |
| **H** | AUDIO-VISUAL (視聽) | 特定音樂、音效、視覺效果模式 |
### 2.3 關係分類系統 (R-Section)
採用相同 IPC 格式,以 **R** 開頭表示「Relationship」:
| 關係碼 | 關係名稱 | 說明 |
|--------|---------|------|
| **R01** | 親屬關係 (Kinship) | 血親、姻親 |
| **R01 01/02** | . 父母/子女 | 血親關係 |
| **R01 02/02** | . 配偶 | 姻親關係 |
| **R02** | 社交關係 (Social) | 朋友、同事、師生 |
| **R02 01/04** | . 摯友 | 深度友誼 |
| **R02 02/04** | . 上下屬關係 | 職場關係 |
| **R03** | 專業關係 (Professional) | 導演/演員、製片/演員、經紀人/藝人 |
| **R04** | 創作關係 (Creative) | 作者/角色、原型人物/虛構角色 |
### 2.4 多重分類
一個 Identity 可擁有多個分類碼:
**範例:劉德華**
| 分類碼 | 分類名稱 | 主要/次要 |
|--------|---------|----------|
| `A61B 17/02` | 電影演員 | 主要 |
| `B61A 17/04` | 電影主角 | 次要 |
**範例:Hello Kitty**
| 分類碼 | 分類名稱 | 主要/次要 |
|--------|---------|----------|
| `D01A 13/02` | 商業吉祥物 | 主要 |
| `B61A 17/10` | 動漫角色 | 次要 |
---
## 3. API 路由設計
### 3.1 全域身份管理 (`/api/v1/identities`)
| 方法 | 路徑 | 說明 |
|------|------|------|
| GET | `/api/v1/identities` | 全域查找身份(搜尋名稱、別名、類型) |
| GET | `/api/v1/identities/:id` | 獲取身份詳情(包含所有特徵群集、出現檔案軌跡) |
| GET | `/api/v1/identities/:id/files` | 查找該身份出現過的所有檔案(跨類型) |
| GET | `/api/v1/identities/:id/relationships` | 獲取該身份的社會關係網絡 |
| POST | `/api/v1/identities` | 建立新身份 |
| PATCH | `/api/v1/identities/:id` | 更新身份資訊(名稱、類型、描述、別名) |
| DELETE | `/api/v1/identities/:id` | 刪除身份 |
### 3.2 檔案層級身份槽位 (`/api/v1/files/{file_uuid}/identities`)
| 方法 | 路徑 | 說明 |
|------|------|------|
| GET | `/api/v1/files/{file_uuid}` | 獲取檔案詳情與元數據 |
| GET | `/api/v1/files/{file_uuid}/identities` | 列出此檔案中所有出現的身份 |
| GET | `/api/v1/files/{file_uuid}/identities/:id` | 獲取該身份在此檔案中的詳細資訊 |
| POST | `/api/v1/files/{file_uuid}/identities/:id/bind` | 綁定訊號(Face/Speaker/Text)到身份 |
| DELETE | `/api/v1/files/{file_uuid}/identities/:id` | 移除檔案中的身份關聯 |
### 3.3 檔案管理 (`/api/v1/files`)
| 方法 | 路徑 | 說明 |
|------|------|------|
| GET | `/api/v1/files` | 列出所有檔案(支援類型篩選) |
| POST | `/api/v1/files/register` | 註冊新檔案 |
| GET | `/api/v1/files/{file_uuid}` | 獲取檔案詳情 |
| PATCH | `/api/v1/files/{file_uuid}` | 更新檔案元數據 |
### 3.4 分類辭典 API
| 方法 | 路徑 | 說明 |
|------|------|------|
| GET | `/api/v1/classifications/ipc` | 獲取 IPC 分類辭典 |
| GET | `/api/v1/classifications/ipc/{ipc_code}/children` | 獲取子分類 |
| GET | `/api/v1/identities?ipc_code=A61B 17/02` | 按分類碼查找身份 |
| GET | `/api/v1/identities?ipc_code=A61B 17&include_children=true` | 包含子分類查找 |
---
## 4. API 回應結構範例
### 4.1 全域身份詳情
```
GET /api/v1/identities/101
```
```json
{
"success": true,
"data": {
"identities_id": 101,
"name": "劉德華",
"type": "person",
"aliases": ["Andy Lau", "華仔"],
"ipc_classifications": [
{
"ipc_code": "A61B 17/02",
"title": "電影演員",
"is_primary": true,
"confidence": 0.95,
"assigned_by": "manual"
}
],
"files": [
{
"file_uuid": "abc123",
"file_type": "video",
"file_name": "無間道.mp4",
"role_name": "劉建明",
"appearance_count": 45,
"faces": [
{
"face_id": "face_001",
"description": "古裝造型",
"thumbnail_url": "..."
},
{
"face_id": "face_002",
"description": "現代造型",
"thumbnail_url": "..."
}
]
}
],
"relationships": [
{
"target_id": 202,
"target_name": "朱麗倩",
"ipc_code": "R01 02/02",
"title": "配偶",
"description": "妻子",
"is_bidirectional": true,
"metadata": { "marriage_year": 2008 }
}
]
}
}
```
### 4.2 檔案內身份列表
```
GET /api/v1/files/{file_uuid}/identities
```
```json
{
"success": true,
"data": [
{
"identities_id": 101,
"name": "劉德華",
"role_name": "劉建明",
"type": "person",
"appearance_count": 45,
"total_duration": 3600,
"thumbnail_url": "..."
}
]
}
```
---
## 5. 資料庫設計
### 5.1 核心表格
#### `identities` (全域身份表)
```sql
CREATE TABLE identities (
identities_id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
type VARCHAR(50),
aliases JSONB,
metadata JSONB,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
```
#### `ipc_taxonomy` (IPC 分類辭典表)
```sql
CREATE TABLE ipc_taxonomy (
ipc_code VARCHAR(20) PRIMARY KEY,
parent_code VARCHAR(20),
section CHAR(1),
class VARCHAR(3),
subclass CHAR(1),
main_group VARCHAR(10),
subgroup VARCHAR(10),
indent_level INTEGER,
title_en VARCHAR(255),
title_zh VARCHAR(255),
definition TEXT,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_ipc_parent ON ipc_taxonomy(parent_code);
CREATE INDEX idx_ipc_section ON ipc_taxonomy(section);
```
#### `identity_ipc_classifications` (身份-IPC 關聯表)
```sql
CREATE TABLE identity_ipc_classifications (
identities_id INTEGER REFERENCES identities(identities_id),
ipc_code VARCHAR(20) REFERENCES ipc_taxonomy(ipc_code),
is_primary BOOLEAN DEFAULT FALSE,
confidence NUMERIC(3,2),
assigned_by VARCHAR(50),
metadata JSONB,
created_at TIMESTAMPTZ DEFAULT NOW(),
PRIMARY KEY (identities_id, ipc_code)
);
```
#### `identity_relationships` (關係圖譜表)
```sql
CREATE TABLE identity_relationships (
relationship_id BIGSERIAL PRIMARY KEY,
source_id INTEGER REFERENCES identities(identities_id),
target_id INTEGER REFERENCES identities(identities_id),
ipc_code VARCHAR(20) REFERENCES ipc_taxonomy(ipc_code),
description TEXT,
context_file_uuid VARCHAR(64),
confidence NUMERIC(3,2),
is_bidirectional BOOLEAN DEFAULT FALSE,
start_date DATE,
end_date DATE,
metadata JSONB,
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(source_id, target_id, ipc_code)
);
CREATE INDEX idx_rel_source ON identity_relationships(source_id);
CREATE INDEX idx_rel_target ON identity_relationships(target_id);
CREATE INDEX idx_rel_ipc ON identity_relationships(ipc_code);
```
#### `file_registry` (檔案註冊表)
```sql
CREATE TABLE file_registry (
file_uuid VARCHAR(64) PRIMARY KEY,
file_path TEXT NOT NULL,
file_type VARCHAR(50),
mime_type VARCHAR(100),
file_size BIGINT,
duration_seconds NUMERIC,
metadata JSONB,
created_at TIMESTAMPTZ DEFAULT NOW()
);
```
#### `face_identities` (檔案層級定妝表)
```sql
CREATE TABLE face_identities (
face_id VARCHAR(64) PRIMARY KEY,
file_uuid VARCHAR(64) REFERENCES file_registry(file_uuid),
identities_id INTEGER REFERENCES identities(identities_id),
embedding VECTOR(512),
description TEXT,
thumbnail_path TEXT,
cluster_metadata JSONB,
created_at TIMESTAMPTZ DEFAULT NOW()
);
```
#### `file_identities` (檔案-身份關聯槽位表)
```sql
CREATE TABLE file_identities (
file_uuid VARCHAR(64) REFERENCES file_registry(file_uuid),
identities_id INTEGER REFERENCES identities(identities_id),
role_name VARCHAR(255),
appearance_count INTEGER DEFAULT 0,
total_duration_seconds NUMERIC,
first_appearance NUMERIC,
last_appearance NUMERIC,
metadata JSONB,
PRIMARY KEY (file_uuid, identities_id),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
```
---
## 6. 關係圖
```
identities (全域身份表)
├── identities_id (PK)
├── name
├── type
├── aliases
└── metadata
ipc_taxonomy (分類辭典表)
├── ipc_code (PK)
├── parent_code (FK → code)
├── title_en/zh
├── indent_level
└── is_active
identity_ipc_classifications (身份-IPC 關聯表)
├── identities_id (FK → identities)
├── ipc_code (FK → taxonomy)
├── is_primary
└── metadata
identity_relationships (關係圖譜表)
├── relationship_id (PK)
├── source_id (FK → identities)
├── target_id (FK → identities)
├── ipc_code (FK → taxonomy)
├── is_bidirectional
└── metadata
file_registry (檔案表)
├── file_uuid (PK)
├── file_type
└── metadata
face_identities (檔案層級定妝表)
├── face_id (PK)
├── file_uuid (FK → file_registry)
├── identities_id (FK → identities)
├── embedding
└── thumbnail_path
file_identities (檔案-身份槽位表)
├── file_uuid (FK)
├── identities_id (FK)
├── role_name
└── metadata
```
---
## 7. 應用場景
### 7.1 電影角色關係圖
當用戶觀看《無間道》時,系統可呈現:
- 劉德華 (角色:劉建明) → 曾志偉 (角色:韓琛):`R02 04/00` (敵人/競爭對手)
- 劉德華 (角色:劉建明) → 陳慧琳 (角色:心理醫生):`R02 03/00` (醫患關係)
### 7.2 演員現實關係
- 劉德華 → 朱麗倩:`R01 02/02` (配偶)
- 周星馳 → 吳孟達:`R02 01/04` (摯友) + `R03 01/02` (長期合作演員)
### 7.3 品牌與代言人關係
- Nike (品牌) → 劉德華 (代言人):`R03 04/00` (品牌/代言人)
---
## 8. 前端影響範圍
| 檔案 | 變更內容 |
|------|---------|
| `portal/src/api/client.ts` | API URL 路徑更新為 `/api/v1/files/...``/api/v1/identities/...` |
| `portal/src/router.ts` | 路由路徑更新 (`/persons``/identities`) |
| `portal/src/App.vue` | 導航連結與文案更新 (`人物管理``身份管理`) |
| `portal/src/views/HomeView.vue` | 連結與文案更新 |
| `portal/src/views/PersonsView.vue` | 更名為 `IdentitiesView.vue` 或整合 |
| `portal/src/components/PersonThumbnail.vue` | 更名為 `IdentityThumbnail.vue` |
### UI 文案變更
| 舊文案 | 新文案 |
|--------|--------|
| 人物管理 | 身份管理 |
| Person | Identity |
| 人物 | 身份/實體 |
---
## 9. 待評估項目
1. **IPC 編碼格式**:空格分隔 (`A61B 17/02`) 還是緊湊格式 (`A61B17/02`)
2. **部的數量**:目前設計 A-H + R 共 9 個部,是否需要增減?
3. **分類深度**:IPC 通常支援到 3-4 層分組,系統是否需要限制最大深度?
4. **自訂擴展**:是否允許用戶在標準 IPC 之外新增自訂分類碼?
5. **關係時間軸**:是否需要記錄關係的開始/結束時間?
6. **關係方向性**:除 `is_bidirectional` 外,是否需要支援更複雜的關係方向表達?
---
## 相關文件
| 文件 | 說明 |
|------|------|
| `ARCHITECTURE_OVERVIEW.md` | 架構總覽 |
| `PROCESSING_PIPELINE.md` | 處理流程 |
| `DESIGN_IMPLEMENTATION_GAP.md` | 設計與實現差異分析 |
@@ -0,0 +1,195 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Momentry Core 語音特徵與人物識別整合架構 (Speaker-AudioVisual Integration) (v1.0)"
date: "2026-04-21"
version: "V1.0"
status: "deprecated"
owner: "Warren"
created_by: "OpenCode"
tags:
- "deprecated"
- "momentry"
- "core"
- "語音特徵與人物識別整合架構"
ai_query_hints:
- "查詢 Momentry Core 語音特徵與人物識別整合架構 (Speaker-AudioVisual Integration) (v1.0) 的內容"
- "Momentry Core 語音特徵與人物識別整合架構 (Speaker-AudioVisual Integration) (v1.0) 的主要目的是什麼?"
- "如何操作或實施 Momentry Core 語音特徵與人物識別整合架構 (Speaker-AudioVisual Integration) (v1.0)"
---
> [!WARNING] **檔案已過時 (Deprecated)**
>
> **原因**: 此文件依賴舊版 `global_person_identities` 和 `person_identities` 表結構。新的 `FILE_IDENTITY_API_DESIGN.md` 已將聲紋、臉部等所有特徵統一歸納至 `identities` 表中,不再區分全域/本地人物表。
>
> **狀態**: 僅供歷史參考,不應用於新功能的開發。
>
> **搬移日期**: 2026-04-25
# Momentry Core 語音特徵與人物識別整合架構 (Speaker-AudioVisual Integration) (v1.0)
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-21 |
| 文件版本 | V1.0 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-04-21 | 定義語音特徵 (Speaker Diarization & Embedding) 與視覺識別的融合邏輯 | OpenCode | OpenCode / Qwen3.6-Plus |
---
## 0. 設計目標
單純依賴臉部識別 (Face Recognition) 在側臉、遮擋、遠景或黑暗環境下容易失敗。**語音特徵整合** 提供了強大的互補邏輯,透過「誰在說話」與「誰在畫面中」的時空關聯,實現 **多模態人物身分決議 (Multimodal Person Identity Resolution)**
- **核心目標**: 利用 ASRX (說話者日誌化) 產出的時間軸與聲紋特徵,自動綁定臉部聚類 (Face Clusters)。
- **資料豐富**: 建立 `voice_print` (語音特徵向量) 與 `speaker_id` 關聯,支援跨影片聲音重識別 (Speaker Re-Identification)。
- **魯棒性**: 當臉部識別置信度低時,以語音時間重疊率 (Temporal Overlap) 作為主要判斷依據。
---
## 1. 核心關聯邏輯 (Association Logic)
系統採用 **「時空共現 (Spatio-Temporal Co-occurrence)」 + 「特徵交叉驗證 (Cross-Modal Verification)」** 雙重機制。
### 1.1 時空共現原理
在大多數影視內容中,當一個人說話時,鏡頭通常會聚焦於該人。
- **假設**: 若 `SPEAKER_00` 說話的 80% 時間內,`FACE_01` 都出現在畫面中心,則 `SPEAKER_00``FACE_01` 極可能為同一人。
### 1.2 語音特徵向量 (Speaker Embedding)
ASRX 處理時,同時提取每個 `speaker_id`**ECAPA-TDNN x-vector** (通常為 192 或 256 維)。
- **用途**: 用於跨影片聲音比對 (例如:同一配音員在不同影片中出現)。
- **儲存**: 寫入 `global_person_identities.voice_print`
---
## 2. 資料庫結構擴展 (Schema Extension)
為支援語音整合,需對全域人物表與本地關聯表進行欄位擴展。
### 2.1 全域人物身分表 (`global_person_identities`)
```sql
ALTER TABLE global_person_identities
ADD COLUMN voice_print vector(256), -- 聲紋特徵向量 (ECAPA-TDNN)
ADD COLUMN primary_speaker_id VARCHAR(50), -- 主要關聯的 Speaker ID
ADD COLUMN match_strategy VARCHAR(30); -- 'tmdb_face', 'audio_visual_overlap', 'manual'
```
### 2.2 本地人物出現表 (`person_identities`)
```sql
ALTER TABLE person_identities
ADD COLUMN speaker_id VARCHAR(50), -- 關聯的 ASRX Speaker ID
ADD COLUMN temporal_overlap_score FLOAT, -- 時間重疊率 (0.0 - 1.0)
ADD COLUMN audio_visual_confidence FLOAT; -- 融合置信度
```
---
## 3. 時空對齊演算法 (Temporal Alignment Algorithm)
系統如何精確計算「說話者」與「臉部」的關聯?
### 3.1 演算法步驟
1. **時間切片**: 將影片以 `1秒` 為單位劃分時間窗。
2. **標籤映射**:
- 若該秒有 ASRX 輸出,標記為 `ActiveSpeaker = SPEAKER_XX`
- 若該秒 Face Processor 偵測到臉部,標記為 `ActiveFace = FACE_YY` (取信心值最高且面積最大者)。
3. **共現矩陣 (Co-occurrence Matrix)**: 統計每對 `(SPEAKER_XX, FACE_YY)` 同時出現的秒數。
4. **計算重疊率**:
```math
Overlap(S_x, F_y) = \frac{\text{Count}(S_x \cap F_y)}{\text{Count}(S_x)}
```
5. **決策**:
- 若 `Overlap > 0.60` → 建立強關聯 (High Confidence)。
- 若 `0.30 <= Overlap <= 0.60` → 建立建議關聯 (Medium Confidence)。
- 若 `Overlap < 0.30` → 忽略 (可能是畫外音或群體場景)。
### 3.2 偽代碼範例
```python
# 輸入: speaker_timeline, face_timeline
co_occurrence = defaultdict(int)
speaker_duration = defaultdict(int)
for sec in range(total_seconds):
if speaker_timeline[sec]:
s_id = speaker_timeline[sec]
speaker_duration[s_id] += 1
if face_timeline[sec]:
f_id = face_timeline[sec] # 取最大臉
co_occurrence[(s_id, f_id)] += 1
# 計算關聯強度
for (s_id, f_id), overlap_count in co_occurrence.items():
score = overlap_count / speaker_duration[s_id]
if score > 0.6:
link_speaker_to_face(s_id, f_id, score)
```
---
## 4. 融合識別流程 (Integration Pipeline)
此流程與 TMDB 臉部比對並行執行,最終匯入同一個 `Global Identity Resolver`。
```mermaid
graph TD
A[ASRX Processor] -->|Speaker IDs + x-vectors| B(Speaker-Face Aligner)
C[Face Processor] -->|Face Clusters + BBoxes| B
D[TMDB Service] -->|Actor Names + Photos| E[Identity Resolver]
B -->|Audio-Visual Pairs| E
E -->|Merge & Deduplicate| F[(Global Person DB)]
F -->|Enrich Chunks| G[Rule 3/4 Chunking]
```
### 4.1 執行時機
1. `ASRX` 與 `Face` 處理器均完成。
2. 觸發 `audio_visual_binding_worker`。
3. 產出 `speaker_face_mapping.json`。
4. 寫入資料庫,並更新 `person_identities` 表。
---
## 5. 衝突處理與置信度評分 (Conflict & Confidence)
### 5.1 常見衝突情境
| 情境 | 現象 | 處理策略 |
|:---|:---|:---|
| **畫外音 (Voice-Over)** | Speaker 出現時間長,但對應 Face 為空或 constantly changing | 降低權重,標記為 `narration`,不強制綁定單一 Face |
| **多人對話重疊** | 畫面有 3 張臉,但只有 1 個 Speaker | 優先綁定畫面中心/最大臉,其餘標記為 `audience/background` |
| **TMDB 與 Speaker 衝突** | TMDB 匹配為 A,但 Speaker 重疊指向 B | 以 **高置信度 Speaker 重疊** 為優先 (因為是動態實測),TMDB 降為候補參考 |
### 5.2 融合置信度計算
```math
FinalConfidence = (W_{face} \times FaceScore) + (W_{voice} \times OverlapScore) + (W_{tmdb} \times TMDBScore)
```
預設權重:`Face: 0.4`, `Voice: 0.4`, `TMDB: 0.2` (可依影片類型動態調整)。
---
## 6. 與 TMDB 的協同效應 (Synergy)
| 維度 | TMDB 整合 | 語音特徵整合 | 綜合效益 |
|:---|:---|:---|:---|
| **資料來源** | 外部資料庫 (靜態) | 影片內容本身 (動態) | 靜態+動態互補 |
| **解決問題** | "這部片有誰?" | "現在說話的是誰?" | 精準定位時間軸 |
| **失敗情境** | 電影元資料錯誤/小眾片 | 畫外音/環境音干擾 | 一方失敗時另一方補位 |
| **輸出結果** | 演員名單與照片 | 說話者時間軸與聲紋 | 完整多模態人物畫像 |
---
## 7. 總結
引入 **Speaker 特徵整合** 後,Momentry Core 的人物識別從「單點視覺比對」升級為 **「聽視覺時空融合」**。
- **召回率提升**: 解決側臉、背光、遠景下的臉部識別失敗問題。
- **時間軸精準**: 不僅知道「誰在片中」,更知道「誰在何時說了什麼」。
- **聲紋累積**: 跨影片建立 `voice_print` 庫,未來可實現「聽聲辨人」的檢索能力。
此架構確保了人物資料的完整性與高可用性,為後續的 Chunk Rule 3/4 (場景與劇情分析) 提供了堅實的實體基礎。
@@ -0,0 +1,212 @@
---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "Momentry Core TMDB 人物識別整合架構 (TMDB Character Integration) (v1.0)"
date: "2026-04-21"
version: "V1.0"
status: "deprecated"
owner: "Warren"
created_by: "OpenCode"
tags:
- "deprecated"
- "character"
- "tmdb"
- "momentry"
- "core"
ai_query_hints:
- "查詢 Momentry Core TMDB 人物識別整合架構 (TMDB Character Integration) (v1.0) 的內容"
- "Momentry Core TMDB 人物識別整合架構 (TMDB Character Integration) (v1.0) 的主要目的是什麼?"
- "如何操作或實施 Momentry Core TMDB 人物識別整合架構 (TMDB Character Integration) (v1.0)"
---
> [!WARNING] **檔案已過時 (Deprecated)**
>
> **原因**: 此文件定義了舊版 `person_identities` 和 `global_person_identities` 表結構。新的架構設計已採用 `identities` (全域實體) 和 `file_identities` (出現紀錄) 的通用模型,詳見 `FILE_IDENTITY_API_DESIGN.md`。
>
> **狀態**: 僅供歷史參考,不應用於新功能的開發。
>
> **搬移日期**: 2026-04-25
# Momentry Core TMDB 人物識別整合架構 (TMDB Character Integration) (v1.0)
| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-04-21 |
| 文件版本 | V1.0 |
---
## 版本歷史
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-04-21 | 定義基於 TMDB API 的自動化全域人物識別與資料建檔流程 | OpenCode | OpenCode / Qwen3.6-Plus |
---
## 0. 設計目標
本規範旨在透過整合 **TMDB (The Movie Database) API**,解決影片處理中「臉部聚類 (Face Clustering)」後無法得知真實身分的問題。
- **核心目標**: 實現電影類型檔案的 **零人工干預 (Zero-Touch)** 人物識別。
- **資料豐富**: 自動獲取 **演員本名 (Actor Name)**、**角色名 (Character Name)** 及 **大頭照 (Profile Photo)**
- **全域身分**: 建立跨影片的全域人物庫 (`global_person_identities`),而非僅限於單一影片的標籤。
---
## 1. 整體架構流程 (Workflow)
整合流程發生在影片處理管線的 **「臉部處理 (Face Processing)」** 階段之後,**「內容聚合 (Chunking)」** 階段之前。
```mermaid
graph LR
A[影片資產] -->|Metadata (Title/Year)| B(TMDB Query Service)
B -->|Cast List + Photos| C[Cast Local DB]
D[Face Processor] -->|Face Clusters + Embeddings| E(Face Matcher)
C -->|Actor Profile Embeddings| E
E -->|Match Result| F[Identity Resolver]
F -->|Create/Update| G[(Global Person Identity)]
G -->|Link| H[Local Person Appearance]
```
### 1.1 關鍵步驟
1. **Metadata 解析**: 從檔名或 `ffprobe` 資訊中提取電影名稱與年份。
2. **TMDB 查詢**: 呼叫 API 獲取 Top Cast (通常前 10-15 名) 及其照片 URL。
3. **照片下載與特徵提取**: 下載演員照片並生成 Face Embedding (512-dim)。
4. **向量比對**: 將演員照片向量與影片內偵測到的 **Face Cluster Centroids** 進行相似度比對 (Cosine Similarity)。
5. **身分決議**: 若相似度超過閾值 (如 0.6),則自動建立全域身分並標記。
---
## 2. 資料結構設計 (Schema Design)
為了支持此流程,需擴展資料庫以儲存外部資料來源與比對結果。
### 2.1 全域人物身分表 (Global Person Identities)
此表用於存放已確認的真實演員資料,跨影片共享。
```sql
CREATE TABLE global_person_identities (
id UUID PRIMARY KEY,
tmdb_id INT, -- TMDB Actor ID (唯一索引)
name VARCHAR(255) NOT NULL, -- 演員姓名 (e.g., "Cary Grant")
profile_path VARCHAR(255), -- 照片路徑 (本地或 URL)
embedding vector(512), -- 照片的人臉特徵向量
source VARCHAR(20) DEFAULT 'tmdb', -- 來源標記
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(tmdb_id)
);
```
### 2.2 本地人物出現紀錄 (Local Person Appearances)
此表記錄特定人物在特定影片中的具體表現 (角色名)。
```sql
CREATE TABLE person_identities (
id UUID PRIMARY KEY,
asset_uuid UUID NOT NULL, -- 所屬影片
global_person_id UUID REFERENCES global_person_identities(id), -- 關聯全域身分
character_name VARCHAR(255), -- 角色名 (e.g., "Peter Joshua")
face_cluster_id VARCHAR(50), -- 對應的臉部聚類 ID
match_score FLOAT, -- 匹配信心度 (0.0 - 1.0)
appearance_count INT DEFAULT 0, -- 出現次數
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_person_asset ON person_identities(asset_uuid);
CREATE INDEX idx_person_global ON person_identities(global_person_id);
```
---
## 3. 處理邏輯細節 (Implementation Details)
### 3.1 TMDB 服務註冊 (Service Registry)
根據 `SERVICE_REGISTRY_ARCHITECTURE.md`TMDB 服務定義如下:
```json
{
"name": "tmdb-cast-api",
"type": "external_api",
"endpoint": "https://api.themoviedb.org/3",
"metadata": {
"api_key_env": "TMDB_API_KEY",
"language": "zh-TW",
"image_base_url": "https://image.tmdb.org/t/p/w185"
}
}
```
### 3.2 臉部比對策略 (Face Matching Strategy)
系統如何決定「畫面中的臉」就是「Cary Grant」?
1. **參考集準備 (Reference Set)**:
* 從 TMDB 獲取演員照片 URL。
* 下載並使用 InsightFace 提取向量 $V_{actor}$。
2. **目標集 (Target Set)**:
* 從影片 Face Processor 獲取每個 Cluster 的中心向量 $V_{cluster}$。
3. **計算相似度**:
* $Score = 1 - \text{CosineDistance}(V_{actor}, V_{cluster})$
4. **決策閾值**:
* **High Confidence (> 0.70)**: 自動確認身分 (Auto-Confirm)。
* **Medium Confidence (0.55 - 0.70)**: 標記為 "Suggestion" (建議),需人工確認。
* **Low Confidence (< 0.55)**: 忽略,保持為 "Unknown Cluster"。
### 3.3 角色名關聯 (Role Mapping)
TMDB 返回的結構包含 `character` 字段:
```json
{
"id": 389, // Actor ID
"name": "Cary Grant",
"character": "Peter Joshua", // 角色名
"profile_path": "/path/to/image.jpg"
}
```
當比對成功時,系統將 **"Peter Joshua"** 寫入 `person_identities.character_name`,並將 **"Cary Grant"** 寫入 `global_person_identities.name`
---
## 4. 自動化流程腳本 (Automation Pipeline)
此流程被打包為一個獨立的 **Post-Face-Processing Job**
1. **Trigger**: `face_processor` 完成,產生 `face_clusters`
2. **Action**: 系統檢查 `asset_type == 'movie'``title` 存在。
3. **Execution**: 執行 `tmdb_cast_ingestion.py`
* 查詢 TMDB。
* 下載圖片 -> 計算向量 -> 存入 `global_person_identities` (若不存在)。
* 執行比對 -> 更新 `person_identities`
4. **Output**: 資料庫中充滿了真實姓名與角色名的紀錄,供 Rule 3/4 Chunking 使用。
---
## 5. 容錯與異常處理 (Error Handling)
- **找不到電影**: 若檔名模糊導致 TMDB 無結果,則跳過此步驟,保留原始 Face Cluster ID。
- **無演員照片**: 若某演員在 TMDB 無照片,無法進行向量比對,僅記錄名字 (若 ASR 有提及)。
- **多人飾演一角**: 若臉部特徵同時匹配多個演員 (極罕見),取 Confidence 最高者,其餘列入候補。
---
## 6. 總結
透過引入 **TMDB API**Momentry Core 將具備**好萊塢級別的自動標記能力**。
| 特性 | 實作方式 |
|------|----------|
| **資料來源** | TMDB API (Cast Endpoint) |
| **識別方式** | Face Embedding Similarity (Vector Match) |
| **儲存活用** | 建立 `global_person_identities` 實現跨片共享 |
| **元數據豐富** | 同時獲取演員名、角色名、大頭照 |
| **自動化** | 處理管線自動觸發,無需人工介入 |
此機制確保了用戶在搜尋 "Cary Grant" 或 "Peter Joshua" 時,系統都能精確返回對應的影片片段。