# Momentry Core API 安裝指南

| 項目 | 內容 |
|------|------|
| 建立者 | Warren |
| 建立時間 | 2026-03-18 |
| 文件版本 | V1.3 |

---

## 版本歷史

| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|------|------|------|--------|-----------|
| V1.0 | 2026-03-18 | 創建文件 | Warren | OpenCode / MiniMax M2.5 |
| V1.1 | 2026-03-23 | 更新端點與實際一致 | OpenCode | - |
| V1.2 | 2026-03-25 | 新增快取/刪除 API | OpenCode | - |
| V1.3 | 2026-03-26 | 修正認證聲明與API回應格式 | OpenCode | - |

---

## Base URL

| 環境 | URL | 說明 |
|------|-----|------|
| **本地開發** | `http://localhost:3002` | 直接訪問 API，繞過反向代理 |
| **外部訪問** | `https://api.momentry.ddns.net` | 通過 Caddy 反向代理訪問，需網路可達 |

> **Note:** Port 3000 is used by Gitea. Momentry API server runs on **port 3002**.

### URL 使用時機

| 情境 | 建議 URL |
|------|----------|
| 本地開發/測試 | `http://localhost:3002` |
| n8n workflow | `https://api.momentry.ddns.net` |
| 外部系統整合 | `https://api.momentry.ddns.net` |
| 反向代理有問題時 | `http://localhost:3002` (繞過代理) |

## Authentication

**API Key 認證：**

所有 `/api/v1/*` 端點需要 `X-API-Key` header 進行認證。

**公開端點：**
- `GET /health` - 健康檢查
- `GET /health/detailed` - 詳細健康檢查

**認證格式：**
```bash
curl -H "X-API-Key: YOUR_API_KEY" http://localhost:3002/api/v1/videos
```

**API Key 管理：**
- 使用 `/api/v1/api-keys` 端點管理 API Keys
- 詳細說明請參考 [API Key Management Guide](../docs/API_KEY_MANAGEMENT.md)

---

## Endpoints

### 1. Register Video
Register a video file to the system.

**Endpoint:** `POST /api/v1/register`

**Request Body:**
```json
{
  "path": "/path/to/video.mp4"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `path` | string | Yes | Absolute path to video file |

**Response (200):**
```json
{
  "uuid": "5dea6618a606e7c7",
  "video_id": 1,
  "job_id": 10,
  "file_name": "video.mp4",
  "duration": 120.5,
  "width": 1920,
  "height": 1080,
  "already_exists": false
}
```

**Example:**
```bash
curl -X POST http://localhost:3002/api/v1/register \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{"path": "/Users/accusys/test_video/BigBuckBunny_320x180.mp4"}'
```

---

### 2. Process Video (CLI)
Process video to generate ASR, CUT, YOLO, OCR, Face, Pose data.

**Note:** This is a CLI command, not an HTTP endpoint.

```bash
# Process video by UUID
cargo run --bin momentry -- process 5dea6618a606e7c7

# Or process by file path
cargo run --bin momentry -- process /path/to/video.mp4
```

---

### 3. Get Progress
Get real-time processing progress via Redis.

**Endpoint:** `GET /api/v1/progress/:uuid`

| Parameter | Type | Description |
|-----------|------|-------------|
| `uuid` | path | Video UUID (16 characters) |

**Response (200):**
```json
{
  "uuid": "5dea6618a606e7c7",
  "processors": [
    {
      "name": "asr",
      "status": "complete",
      "current": 0,
      "total": 0,
      "message": "7 segments"
    },
    {
      "name": "cut",
      "status": "complete",
      "current": 134,
      "total": 134,
      "message": "134 scenes"
    },
    {
      "name": "yolo",
      "status": "progress",
      "current": 5000,
      "total": 14315,
      "message": "frame 5000"
    },
    {
      "name": "ocr",
      "status": "pending",
      "current": 0,
      "total": 0,
      "message": ""
    }
  ]
}
```

**Processor Status Values:**
- `pending` - Not started
- `info` - Starting/info message
- `progress` - In progress
- `complete` - Finished
- `error` - Failed

**Example:**
```bash
# Get progress for specific video
curl -H "X-API-Key: YOUR_API_KEY" http://localhost:3002/api/v1/progress/5dea6618a606e7c7
```

---

### 4. Natural Language Search
Search video chunks using natural language queries (RAG).

**Endpoint:** `POST /api/v1/search`

**Request Body:**
```json
{
  "query": "What is the person saying about machine learning?",
  "limit": 10,
  "uuid": "5dea6618a606e7c7"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `query` | string | Yes | Natural language search query |
| `limit` | integer | No | Max results (default: 10) |
| `uuid` | string | No | Filter by specific video UUID |

**Response (200):**
```json
{
  "results": [
    {
      "uuid": "5dea6618a606e7c7",
      "chunk_id": "0",
      "chunk_type": "sentence",
      "start_time": 5.5,
      "end_time": 8.2,
      "text": "Machine learning is a subset of artificial intelligence...",
      "score": 0.85
    }
  ],
  "query": "What is the person saying about machine learning?"
}
```

**Example:**
```bash
curl -X POST http://localhost:3002/api/v1/search \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{"query": "machine learning", "limit": 5}'
```

---

### 4a. N8N Search (n8n Workflow Integration)
N8n-compatible search endpoint with standardized response format for direct workflow integration.

**Endpoint:** `POST /api/v1/n8n/search`

**Request Body:**
```json
{
  "query": "sunset",
  "limit": 10,
  "uuid": "5dea6618a606e7c7"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `query` | string | Yes | Natural language search query |
| `limit` | integer | No | Max results (default: 10) |
| `uuid` | string | No | Filter by specific video UUID |

**Response (200):**
```json
{
  "query": "sunset",
  "count": 2,
  "hits": [
    {
      "id": "c_001",
      "vid": "5dea6618a606e7c7",
      "start": 5.5,
      "end": 8.2,
      "title": "Sunset Scene",
      "text": "The sun slowly sets over the ocean...",
      "score": 0.92,
      "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/video.mp4"
    }
  ]
}
```

| Field | Type | Description |
|-------|------|-------------|
| `query` | string | Original search query |
| `count` | integer | Number of results |
| `hits[].id` | string | Chunk ID |
| `hits[].vid` | string | Video UUID |
| `hits[].start` | number | Start time in seconds |
| `hits[].end` | number | End time in seconds |
| `hits[].title` | string | Chunk title (from metadata or auto-generated) |
| `hits[].text` | string | Text content |
| `hits[].score` | number | Relevance score (0-1) |
| `hits[].file_path` | string | Full file path to video file |

**Example:**
```bash
curl -X POST http://localhost:3002/api/v1/n8n/search \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{"query": "sunset", "limit": 5}'
```

**Environment Variables:**
| Variable | Default | Description |
|----------|---------|-------------|
| `MOMENTRY_MEDIA_BASE_URL` | `https://wp.momentry.ddns.net` | Base URL for constructing media URLs |

---

### 5. Lookup Video
Lookup video UUID by path or get video details by UUID.

**Endpoint:** `GET /api/v1/lookup`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `path` | query | No* | Video file path |
| `uuid` | query | No* | Video UUID |

*One of `path` or `uuid` is required.

**Response (200):**
```json
{
  "uuid": "5dea6618a606e7c7",
  "file_path": "/path/to/video.mp4",
  "file_name": "video.mp4",
  "duration": 120.5
}
```

**Example:**
```bash
# Lookup by path
curl -H "X-API-Key: YOUR_API_KEY" "http://localhost:3002/api/v1/lookup?path=/path/to/video.mp4"

# Lookup by UUID
curl -H "X-API-Key: YOUR_API_KEY" "http://localhost:3002/api/v1/lookup?uuid=5dea6618a606e7c7"
```

---

### 6. List Videos
List all registered videos.

**Endpoint:** `GET /api/v1/videos`

**Response (200):**
```json
{
  "videos": [
    {
      "uuid": "5dea6618a606e7c7",
      "file_path": "/path/to/video.mp4",
      "file_name": "video.mp4",
      "duration": 120.5,
      "width": 1920,
      "height": 1080
    }
  ]
}
```

**Example:**
```bash
curl -H "X-API-Key: YOUR_API_KEY" http://localhost:3002/api/v1/videos
```

---

## Data Flow

```
┌─────────────────────────────────────────────────────────────────────┐
│                         完整工作流程                                   │
└─────────────────────────────────────────────────────────────────────┘

1. Register Video
   POST /api/v1/register
   └── UUID: 5dea6618a606e7c7

2. Process Video (CLI)
   cargo run -- process 5dea6618a606e7c7
   ├── ASR (WhisperX)        → 7 segments
   ├── CUT (PySceneDetect)   → 134 scenes
   ├── YOLO (YOLOv8)         → 10483 frames with objects
   ├── OCR (EasyOCR)         → 40 frames with text
   ├── Face (OpenCV)         → 44 frames with faces
   └── Pose (YOLOv8-Pose)    → 14315 frames

3. Monitor Progress (Real-time)
   GET /api/v1/progress/:uuid
   └── Redis Pub/Sub + Hash

4. Chunk (CLI)
   cargo run -- chunk 5dea6618a606e7c7
   └── Create chunks in database

5. Vectorize (CLI)
   cargo run -- vectorize 5dea6618a606e7c7
   └── Generate embeddings in Qdrant

6. Search (API)
   POST /api/v1/search
   └── Natural language query
```

---

## Processor Reference

| Processor | Model | Description |
|-----------|-------|-------------|
| **ASR** | WhisperX (faster-whisper) | Speech recognition + diarization |
| **CUT** | PySceneDetect | Scene detection/segmentation |
| **ASRX** | WhisperX | Speaker diarization |
| **YOLO** | YOLOv8n | Object detection |
| **OCR** | EasyOCR | Text recognition |
| **Face** | OpenCV Haar Cascade | Face detection |
| **Pose** | YOLOv8n-Pose | Pose estimation |

---

## Cache Toggle

Toggle caching at runtime.

**Endpoint:** `POST /api/v1/config/cache`

**Request Body:**
```json
{
  "enabled": true
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `enabled` | boolean | Yes | Enable (true) or disable (false) cache |

**Response (200):**
```json
{
  "cache_enabled": true,
  "message": "Cache toggled successfully"
}
```

---

## Unregister Video

Delete a video and all associated data (chunks, processor results, thumbnails).

**Endpoint:** `POST /api/v1/unregister`

**Request Body:**
```json
{
  "uuid": "5dea6618a606e7c7"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `uuid` | string | Yes | Video UUID (16 character hex) |

**Response (200):**
```json
{
  "success": true,
  "message": "Video unregistered successfully",
  "uuid": "5dea6618a606e7c7"
}
```

**Warning:** This operation is irreversible and will delete all associated chunks, processor results, and thumbnails.

---

## Error Responses

**400 Bad Request**
```json
{
  "error": "Invalid request body"
}
```

**404 Not Found**
```json
{
  "error": "Resource not found"
}
```

**500 Internal Server Error**
```json
{
  "error": "Internal server error"
}
```

---

## Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `DATABASE_URL` | `postgres://accusys@localhost:5432/momentry` | PostgreSQL connection |
| `REDIS_URL` | `redis://localhost:6379` | Redis connection |
| `REDIS_PASSWORD` | `accusys` | Redis password |
| `QDRANT_URL` | `http://localhost:6333` | Qdrant vector DB URL |
| `QDRANT_API_KEY` | - | Qdrant API key |
| `QDRANT_COLLECTION` | `chunks` | Qdrant collection name |
| `MOMENTRY_MEDIA_BASE_URL` | `https://wp.momentry.ddns.net` | Base URL for n8n search media URLs |

---

## Starting the Server

```bash
# Default (port 3002, since 3000 is Gitea)
cargo run --bin momentry -- server

# Custom host and port
cargo run --bin momentry -- server --host 127.0.0.1 --port 3002
```

---

## Quick Reference

| Task | Command |
|------|---------|
| Register video | `POST /api/v1/register` |
| Process video | `cargo run -- process <uuid>` |
| Check progress | `GET /api/v1/progress/<uuid>` |
| Search | `POST /api/v1/search` |
| List videos | `GET /api/v1/videos` |
| Lookup | `GET /api/v1/lookup?uuid=<uuid>` |
| Toggle cache | `POST /api/v1/config/cache` |
| Delete video | `POST /api/v1/unregister` |
