# 工程師交接說明 ## 後臺方案更換建議:Streamlit 若未來認為 Rocket.Chat 部署過重或整合不便,可轉用 **Streamlit** 開發自定義管理後台。此方案能針對 Open WebUI 的資料結構進行 100% 客製化。 ### 核心優勢 1. **極簡開發**:純 Python 即可構建前端,約 200 行程式碼可完成完整後台。 2. **超輕量級**:單一容器(~100MB 記憶體),無需額外資料庫(直接讀取現有 Postgres)。 3. **完全客製**:可完美呈現「用戶 → 對話 → 訊息」的三層結構,不受限於聊天軟體的頻道邏輯。 4. **部署簡單**:標準 Docker image `python:3.11-slim` + `pip install streamlit`。 ### 實作架構 * **前端**:Streamlit Web App (Port 8501) * **後端邏輯**:直連 PostgreSQL `reply_queue` 表格 * **功能**:自動刷新、用戶篩選、歷史回覆查詢 ### 程式碼範例 (admin.py) ```python import streamlit as st import psycopg2 import pandas as pd # 自動刷新設定 (每 5 秒) from streamlit_autorefresh import st_autorefresh st_autorefresh(interval=5000, key="msg_refresh") st.set_page_config(layout="wide", page_title="TobiichiGPT Admin") # 1. 連接資料庫 conn = psycopg2.connect("postgresql://user:pass@postgres:5432/tobiichiGPT") # 2. 側邊欄:用戶列表 st.sidebar.title("用戶列表") users = pd.read_sql("SELECT DISTINCT user_id FROM reply_queue", conn) selected_user = st.sidebar.radio("選擇用戶", users['user_id']) # 3. 主畫面:顯示該用戶的對話 if selected_user: st.header(f"用戶: {selected_user}") # 撈取該用戶訊息 msgs = pd.read_sql( f"SELECT * FROM reply_queue WHERE user_id='{selected_user}' ORDER BY created_at DESC", conn ) for _, row in msgs.iterrows(): with st.expander(f"對話 {row['chat_id']} ({row['status']})", expanded=True): st.info(f"用戶: {row['user_message']}") if row['status'] == 'pending': with st.form(key=f"form_{row['id']}"): reply = st.text_area("回覆內容") if st.form_submit_button("送出"): # 更新資料庫 cur = conn.cursor() cur.execute( "UPDATE reply_queue SET admin_reply=%s, status='replied' WHERE id=%s", (reply, row['id']) ) conn.commit() st.success("已回覆") st.rerun() else: st.success(f"管理員: {row['admin_reply']}") ``` ### 部署配置 (Docker) **Dockerfile**: ```dockerfile FROM python:3.11-slim WORKDIR /app RUN pip install streamlit psycopg2-binary pandas streamlit-autorefresh COPY admin.py . CMD ["streamlit", "run", "admin.py", "--server.port=8501", "--server.address=0.0.0.0"] ``` **docker-compose.yml**: ```yaml admin-ui: build: ./admin-ui ports: ["8501:8501"] environment: - DB_HOST=postgres - DB_PASSWORD=${DB_PASSWORD} networks: - tobiichiGPT-network ``` ### 與 Rocket.Chat/Chatwoot比較 | 特性 | Streamlit (自建) | Rocket.Chat | Chatwoot | | :--- | :--- | :--- | :--- | | **對應 Open WebUI 結構** | ⭐⭐⭐⭐⭐ (完全貼合) | ⭐⭐⭐ (需用頻道模擬) | ⭐ (結構扁平) | | **即時性** | ⭐⭐ (輪詢刷新) | ⭐⭐⭐⭐⭐ (WebSocket) | ⭐⭐⭐⭐⭐ (WebSocket) | | **手機 App** | ⭐ (網頁版) | ⭐⭐⭐⭐⭐ (原生 App) | ⭐⭐⭐⭐⭐ (原生 App) | | **資源消耗** | 低 (~100MB) | 中 (~500MB) | 高 (~1GB) | | **適用場景** | 單人/少數管理員,追求輕量與精準管理 | 多人團隊協作,需要 App 通知 | 專業客服團隊 | ### 建議切換時機 若遇到以下情況,建議切換至 Streamlit 方案: 1. Rocket.Chat 的頻道/執行緒管理變得混亂,難以追蹤用戶對話。 2. 伺服器資源不足,無法負擔 Rocket.Chat + MongoDB。 3. 需要針對特定業務邏輯(如:查看用戶餘額、審核特定關鍵字)進行客製化開發。 ## Rocket.Chat 實作紀錄 ### 實作日期 2026年2月1日 ### 系統架構 ``` ┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ │ Open WebUI │────▶│ API 轉接層 │────▶│ Rocket.Chat │ │ (Port 10060) │ │ (Port 18000) │ │ (Port 13000) │ │ 用戶前端 │◀────│ FastAPI │◀────│ 管理員後台 │ └─────────────────┘ └──────────────────┘ └─────────────────┘ │ │ ▼ ▼ ┌──────────────────┐ ┌─────────────────┐ │ PostgreSQL │ │ MongoDB │ │ (Port 5432) │ │ (Port 27017) │ └──────────────────┘ └─────────────────┘ ``` ### 工作流程 1. **用戶發送訊息** → Open WebUI 呼叫 `/v1/chat/completions` 2. **API 轉接層接收** → 提取用戶資訊 (user_name, chat_id) 3. **創建 Rocket.Chat 頻道** → 頻道名稱: `{用戶名}-{對話ID前8位}` 4. **發送用戶訊息** → 顯示格式: `💬 用戶名: 訊息內容` 5. **輪詢等待回覆** → 每 2 秒檢查是否有管理員新訊息 6. **回傳給用戶** → 以 OpenAI 格式回傳管理員的回覆 ### 已完成的修改 #### 1. docker-compose.yml **新增服務:** - `mongo`: MongoDB 7.0 (Rocket.Chat 8.0.1 需要 7.0+) - `mongo-init-replica`: 初始化 MongoDB Replica Set - `rocketchat`: Rocket.Chat 8.0.1 **修改服務:** - `openwebui`: 新增 `ENABLE_FORWARD_USER_INFO_HEADERS=True` 環境變數 **關鍵配置:** ```yaml mongo: image: mongo:7.0 # 從 5.0 升級,因為 Rocket.Chat 8.0.1 不支援 5.0 command: mongod --oplogSize 128 --replSet rs0 rocketchat: image: registry.rocket.chat/rocketchat/rocket.chat:latest ports: - "13000:3000" environment: MONGO_URL: mongodb://mongo:27017/rocketchat?replicaSet=rs0 MONGO_OPLOG_URL: mongodb://mongo:27017/local?replicaSet=rs0 openwebui: environment: - ENABLE_FORWARD_USER_INFO_HEADERS=True # 轉發用戶資訊到 API ``` #### 2. api/server.py **新增 imports:** ```python import json import hashlib ``` **核心函數重寫:** | 函數名稱 | 功能說明 | |---------|---------| | `rocketchat_login()` | 使用帳密登入 Rocket.Chat,取得 Auth Token | | `get_or_create_chat_channel()` | 為每個對話創建專屬頻道 (不使用 Thread) | | `send_user_message()` | 發送用戶訊息到頻道,回傳訊息 ID | | `wait_for_admin_reply()` | 輪詢等待管理員回覆,過濾機器人訊息 | **Headers 提取邏輯:** ```python # Open WebUI 轉發的 Headers user_id = headers_dict.get("x-openwebui-user-id") chat_id = headers_dict.get("x-openwebui-chat-id") user_name = headers_dict.get("x-openwebui-user-name") user_email = headers_dict.get("x-openwebui-user-email") ``` **系統任務過濾:** ```python # 跳過 Open WebUI 的標題/標籤/後續問題生成請求 if user_message.strip().startswith("### Task:"): return {"choices": [{"message": {"content": "{}"}}], ...} ``` ### 遇到的問題與解決方案 #### 問題 1: MongoDB 版本不相容 - **錯誤**: `MongoServerSelectionError` - **原因**: Rocket.Chat 8.0.1 需要 MongoDB 7.0+,但配置的是 5.0 - **解決**: 將 `mongo:5.0` 升級為 `mongo:7.0` #### 問題 2: postMessage 返回 400 錯誤 - **錯誤**: `alias` 參數需要特殊權限 - **原因**: Rocket.Chat API 的 `alias` 欄位需要 bot 權限 - **解決**: 移除 `alias` 參數,改用訊息內文標註用戶名 #### 問題 3: Open WebUI 不發送用戶資訊 Headers - **錯誤**: `user_name` 始終為 `None` - **原因**: Open WebUI 預設不轉發用戶資訊 - **解決**: 設置環境變數 `ENABLE_FORWARD_USER_INFO_HEADERS=True` #### 問題 4: 奇怪的系統訊息被發送到 Rocket.Chat - **錯誤**: `### Task: Generate a concise title...` 等訊息出現 - **原因**: Open WebUI 會額外發送標題/標籤/後續問題生成請求 - **解決**: 過濾以 `### Task:` 開頭的訊息,直接回傳空 JSON #### 問題 5: 重複回傳相同的管理員回覆 - **錯誤**: 每次用戶訊息都收到同一個回覆 - **原因**: Thread 架構複雜,難以正確追蹤新回覆 - **解決**: 改用簡化架構 (每個對話一個 Channel,不用 Thread) ### 最終架構決策 **放棄 Thread 架構,改用 Channel 架構:** | 項目 | Thread 架構 (放棄) | Channel 架構 (採用) | |-----|-------------------|-------------------| | 結構 | 用戶→頻道→多個Thread | 對話→專屬頻道 | | 追蹤 | 需要追蹤 Thread ID | 只需追蹤訊息 ID | | 複雜度 | 高 | 低 | | 可讀性 | 中 (Thread 內對話) | 高 (直接看頻道) | **頻道命名規則:** ``` {用戶名小寫}-{chat_id前8位} 例: ckliu-67b4341e ``` ### 待辦事項 - [ ] 實作管理員回覆後的通知機制 - [ ] 處理超時後的重試邏輯 - [ ] 新增管理員身份驗證 (目前使用單一 admin 帳號) - [ ] 考慮切換到 Streamlit 方案 (更輕量、完全客製化) ### 相關檔案 ``` tobiichiGPT/ ├── docker-compose.yml # 容器編排配置 ├── api/ │ ├── server.py # API 轉接層主程式 │ └── requirements.txt # Python 依賴 └── exchange.md # 本文件 ``` ### 環境變數清單 | 變數名稱 | 用途 | 預設值 | |---------|------|-------| | `ROCKETCHAT_URL` | Rocket.Chat API 位址 | `http://rocketchat:3000` | | `ROCKETCHAT_USER` | 登入帳號 | `admin` | | `ROCKETCHAT_PASSWORD` | 登入密碼 | `admin` | | `DB_HOST` | PostgreSQL 主機 | `postgres` | | `DB_PASSWORD` | 資料庫密碼 | (必填) | ### 測試指令 ```bash # 重建並重啟 API 容器 cd /mnt/data/External/tobiichiGPT sudo docker-compose up -d --build api # 查看 API 日誌 sudo docker logs tobiichiGPT-api --tail 100 # 重啟 Open WebUI (套用 Headers 設定) sudo docker-compose up -d openwebui ```