---
document_type: "spec"
service: "MOMENTRY_CORE"
title: "Processor 選型與資源預估 V1.0.0"
date: "2026-05-02"
version: "V1.1"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
  - "momentry"
  - "core"
  - "processor"
  - "model-selection"
  - "resource-estimation"
  - "v1.0.0"
ai_query_hints:
  - "processor 的選型原因與實驗報告"
  - "各 processor 的資源預估與模型資訊"
  - "processor 之間的依賴關係"
  - "模型選擇的比較與決策"
  - "processor 檔案狀態後綴規則（json/tmp/err）"
  - "Job 完成條件與必要 processor 定義"
related_documents:
  - "PROCESSORS/ASR_V1.0.0.md"
  - "PROCESSORS/FACE_V1.0.0.md"
  - "PROCESSORS/YOLO_V1.0.0.md"
  - "PROCESSORS/CUT_V1.0.0.md"
  - "CHUNK_DEFINITION_V1.0.0.md"
---

# Processor 選型與資源預估 V1.0.0

| 項目 | 內容 |
|------|------|
| 建立者 | OpenCode |
| 建立時間 | 2026-05-02 |
| 文件版本 | V1.1 |

---

## 關鍵術語定義

| 術語 | 定義 |
|------|------|
| Processor | 處理器，負責特定類型媒體分析的 Python 腳本 |
| Pipeline | 處理管線，定義 processor 的執行順序與依賴關係 |
| PythonExecutor | 統一執行 Python 腳本的 Rust 封裝層 |
| real-time factor | 即時倍率，處理時間與影片時長的比值 |
| resource estimation | 資源預估，包含 CPU/記憶體/GPU 的使用量 |
| Job | 處理任務，包含多個 processor 的執行與狀態管理 |

## 總覽

| Processor | 狀態 | 模型 | 依賴 | GPU | CPU | 記憶體 | 文件 |
|-----------|------|------|------|-----|-----|--------|------|
| ASR | ✅ 100% | faster-whisper (small) | 無 | 否 | 1.0 | 2048 MB | [詳細](./PROCESSORS/ASR_V1.0.0.md) |
| CUT | ✅ 100% | PySceneDetect | 無 | 否 | 0.5 | 512 MB | [詳細](./PROCESSORS/CUT_V1.0.0.md) |
| YOLO | ✅ 100% | YOLOv5n (CoreML ANE) | 無 | 是 | 0.1 | 512 MB | [詳細](./PROCESSORS/YOLO_V1.0.0.md) |
| OCR | ✅ 100% | Swift Vision VNRecognizeTextRequest | 無 | 是 (ANE) | 0.1 | 64 MB | [詳細](./PROCESSORS/OCR_V1.0.0.md) |
| Face | ✅ 100% | InsightFace + CoreML FaceNet | 無 | 是 (ANE) | 0.3 | 512 MB | [詳細](./PROCESSORS/FACE_V1.0.0.md) |
| Pose | ✅ 100% | Swift Vision VNDetectHumanBodyPoseRequest | 無 | 是 (ANE) | 0.1 | 64 MB | [詳細](./PROCESSORS/POSE_V1.0.0.md) |
| ASRX | ⚠️ 80% | SpeechBrain ECAPA-TDNN | ASR | 否 | 0.8 | 2048 MB | [詳細](./PROCESSORS/ASRX_V1.0.0.md) |
| Scene | ✅ 100% | MIT Places365 | CUT | 否 | 0.3 | 512 MB | [詳細](./PROCESSORS/SCENE_V1.0.0.md) |
| VisualChunk | ✅ 整合 | 規則聚合（無模型） | YOLO | 否 | 0.3 | 512 MB | [詳細](./PROCESSORS/VISUAL_CHUNK_V1.0.0.md) |
| Caption | ✅ 100% (本地化) | Moondream2 | Scene | 否 | - | - | [詳細](./PROCESSORS/CAPTION_V1.0.0.md) |
| Story | ✅ 100% (本地化) | 模板聚合 | Scene, Caption | 否 | - | - | [詳細](./PROCESSORS/STORY_V1.0.0.md) |

---

## Processor 依賴關係圖 （V4.1）

```
CUT ───→ Scene
  │
ASR ───→ ASRX
  │
YOLO ─→ VisualChunk
```

> **註（V4.1）**：CUT 和 Scene 在 register 階段同步執行，Worker pipeline 中 Scene 依賴僅 CUT（已移除 ASR）。長影片（scene ≤ 3, max > 600s）時 Face 動態移到 ASR 前。

## 檔案狀態後綴

所有 processor 輸出檔案使用統一的後綴規則：

| 後綴 | 意義 | 行為 |
|------|------|------|
| `.json` | 完成 | 直接載入使用 |
| `.json.tmp` | 執行中 | 跳過、等待 |
| `.json.err` | 失敗 | 跳過、不重試 |

此規則由 `PythonExecutor` 統一處理（`executor.rs:150-279`）。

## Job 完成條件（V4.1）

| 條件 | 結果 |
|------|------|
| 所有 processor 完成 | ✅ Job completed |
| 必要 processor (cut/asr/yolo) 完成，其餘失敗 | ✅ Job completed（非必要失敗不卡住） |
| 必要 processor 任一失敗 | ❌ Job failed |

## 版本歷史

| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-05-02 | 初始版本，含選型實驗報告與資源預估 | OpenCode | deepseek-chat |
| V1.1 | 2026-05-03 | CUT 新增 cut_count/cut_max_duration；Scene 移除 ASR 依賴；長影片 Face 動態調度；Job 完成條件放寬 | OpenCode | deepseek-chat |

---

## Frame Scheduling 架構（V4.1）

### 問題

目前每個 processor 各自獨立呼叫 ffmpeg 從影片中萃取 frames，導致重複的 ffmpeg 解碼開銷：

```
YOLO: ffmpeg extract → detect → write
OCR:  ffmpeg extract → OCR    → write  ← ffmpeg again
Face: ffmpeg extract → detect → write  ← ffmpeg again
Pose: ffmpeg extract → detect → write  ← ffmpeg again
```

對長片（6879s），每個 processor 的 ffmpeg overhead 約 15~30s，總計浪費 ~75s。

### 解決方案：共享 Frame Cache + 並發調度

```
Pipeline Phase 1 (順序):
  CUT → Scene → ASR → ASRX

Frame Cache Phase (一次 ffmpeg):
  ffmpeg extract → shared frame directory
    ├── frame_00001.jpg
    ├── frame_00002.jpg
    └── ...

Pipeline Phase 2 (並發 on shared frames):
  tokio::join!(
    OCR  (Swift Vision → frame dir)
    Face (CoreML FaceNet → frame dir)
    Pose (Swift Vision → frame dir)
    YOLO (CoreML → frame dir)
  )
```

### 實作模組

| 模組 | 檔案 | 說明 |
|------|------|------|
| `FrameManager` | `src/core/frame_cache.rs` | 負責 ffmpeg extract、管理 frame 目錄生命週期 |
| `ProcessorTask.frame_dir` | `src/worker/processor.rs` | 傳遞共享 frame 目錄路徑給 child process |
| `MOMENTRY_FRAME_DIR` | env var | Worker 設此 env var，processor 讀取後跳過 ffmpeg |

### V1 實作狀態

| 項目 | 狀態 |
|------|------|
| `FrameManager::extract()` | ✅ 完成 — 一次 ffmpeg 產出 shared frame directory |
| `MOMENTRY_FRAME_DIR` 環境變數傳遞 | ✅ `start_processor` 在 spawn 前設定 |
| Swift OCR (`swift_ocr.swift`) | ✅ 若 `MOMENTRY_FRAME_DIR` 有值則跳過 ffmpeg |
| Swift Pose (`swift_pose.swift`) | ✅ 同上 |
| Python Face (`face_processor.py`) | ⏳ 待實作 |
| Python YOLO (`yolo_processor.py`) | ⏳ 待實作 |

### 流程

```rust
// job_worker.rs
let frame_needed = [OCR, Face, Pose, Yolo].any_in(processors_to_run);
if frame_needed {
    let fm = FrameManager::extract(video, sample_interval).await;
    // fm.dir → /tmp/frames_{hash}/ 含全部 .jpg
}
// processor.rs
start_processor(task) {
    if let Some(dir) = task.frame_dir {
        std::env::set_var("MOMENTRY_FRAME_DIR", dir);
    }
    tokio::spawn(async move { run_processor(...) });
}
```

### 效益

| 指標 | 改善 |
|------|------|
| ffmpeg 呼叫次數 | 4次 → **1次** |
| 累積 extract overhead | ~75s → **~15s** |
| OCR/Face/Pose/YOLO 總執行時間 | 順序 N 倍 → **約等於最慢的 processor** |

---

## 版本歷史

| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-05-02 | 初始版本 | OpenCode | deepseek-chat |
| V1.1 | 2026-05-03 | CUT 新增 cut_count/cut_max_duration；Scene 移除 ASR 依賴；長影片 Face 動態調度；Job 完成條件放寬 | OpenCode | deepseek-chat |
| V1.2 | 2026-05-04 | 新增 Frame Scheduling 架構 + V1 實作（FrameManager、env var 傳遞、Swift OCR/Pose 支援） | OpenCode | deepseek-chat |
