# Momentry N8n Search API 技術說明書

> **適用對象**: n8n 自動化流程開發者、前端開發者  
> **版本**: V1.0 | **日期**: 2026-04-17  
> **更新重點**: 統一欄位名稱 (`start_time`/`end_time`)，新增底層邏輯說明

---

## 1. API 概覽

此 API 專為 **n8n 工作流**設計，提供影片內容的向量搜尋（語意搜尋）與關鍵字搜尋（BM25）。  
其回應格式已針對自動化腳本優化，直接提供影片路徑、時間軸與 5W1H 結構化摘要。

### 基本資訊

| 項目 | 值 |
|------|-----|
| **Vector Search** | `POST /api/v1/n8n/search` |
| **Keyword Search** | `POST /api/v1/n8n/search/bm25` |
| **Smart Search (LLM)**| `POST /api/v1/n8n/search/smart` |
| **認證方式** | Header `X-API-Key` |

---

## 2. 請求格式 (Request)

適用於 `/api/v1/n8n/search` 與 `/api/v1/n8n/search/bm25`。

### Headers
```http
Content-Type: application/json
X-API-Key: muser_68600856036340bcafc01930eb4bd839
```

### Body (JSON)

| 參數 | 類型 | 必填 | 說明 |
|------|------|------|------|
| `query` | string | **是** | 搜尋關鍵字或句子 |
| `uuid` | string | 否 | 限定搜尋特定影片 (16碼 hex) |
| `limit` | int | 否 | 回傳筆數，預設 10 |

### 範例
```json
{
  "query": "主角開車離開的場景",
  "uuid": "384b0ff44aaaa1f14cb2cd63b3fea966",
  "limit": 5
}
```

---

## 3. 回應格式 (Response)

```json
{
  "query": "主角開車離開的場景",
  "count": 1,
  "hits": [
    {
      "id": "sentence_0790",
      "vid": "384b0ff44aaaa1f14cb2cd63b3fea966",
      "start_frame": 187296,
      "end_frame": 187356,
      "fps": 59.94,
      "start_time": 3124.72,
      "end_time": 3125.73,
      "title": "Chunk sentence_0790",
      "text": "I'm trying to prove it.",
      "score": 0.28,
      "file_path": "/Users/accusys/momentry/var/sftpgo/data/demo/video.mp4",
      "metadata": {
        "structured_summary": {
           "who": "...",
           "what": "..."
        }
      }
    }
  ]
}
```

### 欄位說明 (N8nSearchHit)

| 欄位 | 類型 | 說明 |
|------|------|------|
| `id` | string | Chunk ID (例如 `sentence_0790`) |
| `vid` | string | Video UUID |
| `start_time` | float | **開始時間 (秒)** (V1.5 修正) |
| `end_time` | float | **結束時間 (秒)** (V1.5 修正) |
| `start_frame` | int | 開始幀號 (精準定位用) |
| `end_frame` | int | 結束幀號 (精準定位用) |
| `text` | string | 該分段轉錄文字 (已處理繁簡統一與標點) |
| `score` | float | 相關性分數 (0.0 - 1.0) |
| `file_path` | string | **影片絕對路徑** (n8n 可直接呼叫 ffplayer 播放) |
| `metadata` | object | **5W1H 結構化摘要** (來自 LLM 分析) |

---

## 4. 底層操作邏輯 (Underlying Logic)

為了讓開發者理解效能與資料來源，以下是 `/api/v1/n8n/search` (Vector) 的完整執行流程：

### 步驟 1: 認證與快取 (Auth & Cache)
1. **API Key 驗證**: 檢查 Header 中的 `X-API-Key`。
2. **Query Hash**: 計算 `SHA256(query + uuid + limit)` 作為快取 Key。
3. **MongoDB Cache 檢查**:
    * 若命中快取：直接返回 JSON，**跳過**後續繁重的向量運算。
    * 若未命中：進入步驟 2。

### 步驟 2: 向量化與搜尋 (Embedding & Search)
1. **Embedding**: 呼叫 Ollama (Nomic-Embed-Text) 將 Query 轉換為向量 (Vector)。
2. **Qdrant 搜尋**:
    * 若有 `uuid`: 在該影片的 Collection 中搜尋最相似的 Chunk。
    * 若無 `uuid`: 進行全域搜尋。
    * 返回 Top-N 個包含 `chunk_id` 與 `uuid` 的候选結果。

### 步驟 3: 資料豐富化 (Enrichment via PostgreSQL)
拿到 Qdrant 結果後，系統會**逐筆**向 PostgreSQL 查詢詳細資訊：

1. **取得 Chunk 內容**: 
    * 查詢 `chunks` 表格，獲取原始 JSON 內容、時間、幀號等。
2. **取得影片路徑**: 
    * 利用 `uuid` 查詢 `videos` 表格，獲取 `file_path`。
3. **取得 5W1H 摘要**:
    * 檢查 Chunk 是否有 `parent_chunk_id` (所屬的故事段落)。
    * 若有，查詢 `parent_chunks` 表格的 `metadata` 欄位。
    * 該欄位包含由 Gemma4 LLM 生成的結構化摘要 (Who, What, Where, When, Why, Key Events)。

### 步驟 4: 格式化與回傳 (Formatting)
1. **Text Processing**: 將 Chunk 原始內容中的文字提取，並進行繁簡轉換與分詞處理 (Tokenization)。
2. **建構 Hit 物件**: 組合上述所有資料為 `N8nSearchHit`。
3. **寫入快取**: 將最終結果寫入 MongoDB 以便下次秒回。
4. **回應 JSON**: 返回給 n8n。

---

## 5. 進階搜尋模式

除了標準的 Vector Search，還有兩種變體：

### 5.1 BM25 Keyword Search
* **Endpoint**: `/api/v1/n8n/search/bm25`
* **邏輯**: 跳過向量運算，直接使用 PostgreSQL 的全文檢索 (Full Text Search) 功能。適合精確匹配專有名詞或關鍵字。

### 5.2 Smart Search (LLM 分析)
* **Endpoint**: `/api/v1/n8n/search/smart`
* **邏輯**: 
  1. 將 Query 送至 Llama-server (Port 8081) 進行意圖分析 (5W1H)。
  2. 提取出關鍵實體 (人名、地點、動作)。
  3. 將提取出的實體轉換為更精確的 BM25 查詢語句進行搜尋。
  4. 適合自然語言提問 (例如：「誰在辦公室裡生氣了？」)。

---

## 6. 版本歷史

| 版本 | 日期 | 內容 |
|------|------|------|
| V1.0 | 2026-04-17 | 建立完整技術說明書，包含底層邏輯與 5W1H 機制說明 |
