# 功能介紹 ## 核心概念 TobiichiGPT 將 Open WebUI 這類 AI 對話系統的後端改造成由真人管理員回覆的系統。 ### 基本原理 1. **API 中間層** - 提供 OpenAI API 相容端點(`/v1/chat/completions`) 2. **訊息轉發** - 將用戶訊息轉發到 Rocket.Chat 頻道 3. **管理員介面** - 使用 Rocket.Chat 讓真人管理員查看並回覆 4. **輪詢機制** - API 使用時間戳比較等待管理員在 Rocket.Chat 中回覆 ### 技術架構 ``` 用戶 → Open WebUI → API (FastAPI) → Rocket.Chat ← 管理員 ↓ ↓ 等待回覆 管理員查看訊息 ↓ ↓ 輪詢檢查 管理員回覆訊息 ↓ ↓ 返回給用戶 ←─────────┘ (PostgreSQL 用於記錄追蹤) ``` ## 需求分析 ### Open WebUI 的對話結構 Open WebUI 採用**雙層結構**來組織對話: ``` 用戶 A (user_id: abc123) ├── 對話 1 (chat_id: chat_001) - "教我 Python" ├── 對話 2 (chat_id: chat_002) - "推薦餐廳" └── 對話 3 (chat_id: chat_003) - "旅遊攻略" 用戶 B (user_id: def456) ├── 對話 1 (chat_id: chat_004) - "程式問題" └── 對話 2 (chat_id: chat_005) - "健康諮詢" ``` **關鍵特性**: - 一個用戶(user_id)可以創建多個對話(chat_id) - 每個對話有獨立的主題和訊息串 - 管理員需要能夠明確追蹤「哪個用戶的哪個對話」 ### 管理後台需求 理想的管理介面應該呈現: ``` 📂 所有對話(每個對話獨立頻道) ├── 💬 張三-chat001 (教我 Python) │ ├── 💬 張三: "Python 怎麼學?" │ └── 💬 管理員: "建議從基礎開始..." │ ├── 💬 張三-chat002 (推薦餐廳) │ ├── 💬 張三: "台北有什麼好吃的?" │ └── 💬 管理員: "推薦鼎泰豐..." │ └── 💬 李四-chat004 (程式問題) ⚠️ 待回覆 └── 💬 李四: "React Hook 怎麼用?" ``` **核心需求**: - ✅ 對話隔離 - 每個對話一個獨立頻道 - ✅ 用戶識別 - 頻道名稱包含用戶名和對話 ID - ✅ 簡單直觀 - 不使用 Thread,直接在頻道內問答 - ✅ 狀態管理 - 清楚標示哪些對話待回覆 ## Rocket.Chat 整合架構 ### 系統架構圖 ``` ┌─────────────┐ │ Open WebUI │ │ 用戶介面 │ └──────┬──────┘ │ 1. Chat Request │ Headers: X-OpenWebUI-User-Id, X-OpenWebUI-Chat-Id │ X-OpenWebUI-User-Name ▼ ┌─────────────────────────────────────────────────────────┐ │ API (FastAPI - server.py) │ ├─────────────────────────────────────────────────────────┤ │ 2. 解析 Headers 提取 user_id, chat_id, user_name │ │ 3. 登入 Rocket.Chat 取得認證 Token │ │ 4. 創建/取得對話頻道 ({user_name}-{chat_id[:8]}) │ │ 5. 發送用戶訊息到頻道,記錄時間戳 │ │ 6. 輪詢頻道訊息,用時間戳比較等待管理員回覆 │ │ 7. 將管理員回覆返回給 Open WebUI │ └──────┬──────────────────────────┬───────────────────────┘ │ │ ▼ ▼ ┌─────────────┐ ┌─────────────────────────┐ │ PostgreSQL │ │ Rocket.Chat + MongoDB │ │ reply_queue │ ├─────────────────────────┤ │ (記錄追蹤) │ │ 頻道: ckliu-68a77282 │ └─────────────┘ │ ├── 💬 ckliu: 測試訊息│ │ └── 💬 管理員: ... │ │ │ │ 頻道: ckliu-a8224bcf │ │ ├── 💬 ckliu: 測試訊息 │ │ └── 💬 管理員: ... │ └─────────────────────────┘ ▲ │ 8. 管理員直接在頻道回覆 │ ┌─────┴──────┐ │ 管理員瀏覽器│ └────────────┘ ``` ### 資料映射關係 | Open WebUI | Rocket.Chat | 說明 | |-----------|-------------|------| | 對話 (chat_id) | 頻道 (Channel) | 每個對話一個專屬頻道 `{user_name}-{chat_id[:8]}` | | 訊息 (message) | 訊息 (Message) | 直接在頻道中發送,不使用 Thread | | 用戶 (user_name) | 頻道名稱前綴 | 用於識別是誰的對話 | **設計理念**: - 簡化架構,不使用 Thread(執行緒) - 每個對話完全獨立,避免複雜的層級結構 - 頻道名稱直接顯示用戶和對話 ID,方便識別 ### Rocket.Chat 呈現效果 ``` Rocket.Chat 介面: ├── 📂 頻道列表 │ ├── ckliu-68a77282 (最近活躍) │ ├── ckliu-a8224bcf │ ├── alice-3f91c2e1 │ └── bob-7d4e9a23 │ └── 📂 ckliu-68a77282 頻道內容 ├── 💬 **💬 ckliu:** │ NPU能吃嗎... ├── 💬 管理員回覆: │ NPU 是神經處理單元,不能吃喔 😄 ├── 💬 **💬 ckliu:** │ 那有什麼用途? └── 💬 管理員回覆: 主要用於 AI 運算加速... ``` **特點**: - 每個頻道 = 一個完整對話 - 訊息直接在頻道中,不用點開 Thread - 管理員看到新頻道就知道有新對話 - 頻道名稱清楚標示用戶和對話 ID ### 資料庫結構 `reply_queue` 表格結構(用於記錄追蹤): ```sql CREATE TABLE reply_queue ( id SERIAL PRIMARY KEY, conversation_id VARCHAR(50) UNIQUE NOT NULL, user_id VARCHAR(255), chat_id VARCHAR(255), user_name VARCHAR(255), user_message TEXT NOT NULL, admin_reply TEXT, status VARCHAR(20) DEFAULT 'pending', created_at TIMESTAMP DEFAULT NOW(), replied_at TIMESTAMP, rocketchat_room_id VARCHAR(100), -- 儲存頻道 ID rocketchat_thread_id VARCHAR(100) -- 保留欄位(目前未使用) ); ``` **說明**: - PostgreSQL 僅用於記錄追蹤,非主要邏輯 - 實際對話內容和回覆檢測都在 Rocket.Chat 中進行 - 使用時間戳比較來判斷是否有新的管理員回覆 ### 服務列表 | 服務 | 容器名 | Port | 說明 | |------|-------|------|------| | **PostgreSQL** | tobiichiGPT-postgres | 5432 | 資料庫(記錄追蹤) | | **MongoDB** | tobiichiGPT-mongo | 27017 | Rocket.Chat 資料庫 | | **API** | tobiichiGPT-api | 18000 | OpenAI API 相容端點 | | **Open WebUI** | tobiichiGPT-ui | 10060 | 用戶對話介面 | | **Rocket.Chat** | tobiichiGPT-rocketchat | 13000 | 管理員對話介面 | ### 技術特點 1. **一對一映射** - 每個 Open WebUI 對話對應一個 Rocket.Chat 頻道 2. **簡化架構** - 不使用 Thread,減少複雜度和潛在問題 3. **時間戳比較** - 使用 ISO 格式時間戳判斷新訊息,簡單可靠 4. **即時通知** - Rocket.Chat 支援桌面和手機推送 5. **輕量部署** - 共 5 個容器(含初始化容器) 6. **可擴展性** - 支援多管理員協作回覆