「一個生產級的自建 AI Agent,除了需要強健的後端服務,還需要一個獨立、輕量且具備前後端雙重校驗(Double Validation)機制的數據驗證模組。」
在先前,我們建構了自動化資料 pipeline(Google Drive 同步、每日盤後分析推播與 Google Sheets 追蹤)。今天我們將進入專案的——前端互動介面、系統全監控與生產部署!
我們將探討 app/main.py 如何透過 FastAPI 的 StaticFiles 機制掛載前端 static/ 靜態目錄,剖析專門用於單元測試與前端訊息校驗的 static/validation.js,以及後端如何透過 Pydantic 與自訂指令(/learn、/fetch-url)進行訊息接收與防禦。
在 Self-hosted RHEL 環境下,為了追求極致的輕量與系統穩定,我們捨棄了繁重的 React/Vue 構建流程,選擇採用原生的 Vanilla JavaScript 進行驗證與對接。
在 FastAPI 中,靜態檔案目錄 static/ 的掛載(Mounting)必須置於 所有 API 路由宣告之後,否則靜態檔案路由會優先攔截 /chat、/health、/stats 等 API 請求:
Python
# app/main.py 靜態檔案掛載邏輯
# 注意:靜態檔案必須掛載於最後,避免覆蓋 API 路由
_static_dir = Path(__file__).resolve().parent.parent / "static"
if _static_dir.is_dir():
app.mount("/", StaticFiles(directory=str(_static_dir), html=True), name="static")
為了避免使用者發送無效訊息或超長文本衝擊後端,我們在前端 static/ 目錄下實作了獨立的驗證模組 static/validation.js。
這段模組具備高度的工程品質:
1. 空白字元過濾:拒絕發送空字串或僅含空白的訊息。
2. 長度上限防禦:精準限制發送字數不得超過 2000 字元(對齊後端 ChatRequest 規格)。
3. 前後端/測試兼融性:撰寫 typeof module !== 'undefined' 判斷,使同一份前端 JS 代碼可以直接被 Node.js CI/CD 單元測試(Jest/Mocha)引用。
JavaScript
/**
* Chat UI Validation Module
* Extracted for independent testing.
*
* validateMessage(message) checks:
* 1. Empty or whitespace-only messages are rejected.
* 2. Messages exceeding 2000 characters are rejected.
* 3. All other messages are accepted.
*/
function validateMessage(message) {
if (!message || message.trim() === '') {
return { valid: false, error: 'Please enter a valid message.' };
}
if (message.length > 2000) {
return { valid: false, error: 'Message exceeds 2000 character limit.' };
}
return { valid: true, error: null };
}
// Export for Node.js testing (when available)
if (typeof module !== 'undefined' && module.exports) {
module.exports = { validateMessage };
}
前端的 validateMessage 是第一道防線,而後端在 app/main.py 的 /chat Endpoint 中則進行了雙重校驗(Double Validation):
Python
@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest) -> ChatResponse:
session_id = request.session_id
message = request.message
language = request.language
# 空白字元過濾:若全是空白則拋出 HTTP 422 異常
if not message.strip():
raise HTTPException(
status_code=422,
detail="Message cannot be empty or contain only whitespace characters.",
)
此外,app.py 中也直接解析前端或自動化腳本送入的特殊指令,無須經過 LLM 推理即可快速處理:
1. /learning-stats:讀取 LearningModule 學習統計數據。
2. /learn :動態將文本切分為 Paragraph Chunk 並加入 ChromaDB。
3. /fetch-url :使用 httpx 非同步抓取網頁 HTML、清除 / 標籤並分塊存入向量庫。
透過前端 static/validation.js 驗證機制與後端 app/main.py 的實作,我們完成了用戶互動介面與資料驗證的完整 cycle:
1. 第一道防線:透過 validateMessage 在發出 API 請求前阻擋空訊息與超長文本,降低後端非必要負載。
2. 測試驅動開發 (TDD) 友好:驗證邏輯導出 CommonJS 介面,方便加入自動化 CI/CD 單元測試。
3. 縱深防禦:前後端均對無效輸入與空訊息進行精準攔截,確保 API 接口的安全性與穩定度。
明天(Day 12)我們將進入 app/main.py 中的健康檢查與指標系統,探討 /health 與 /stats API 實作,以及如何與 Ansible status.yml 自動化巡檢進行深度整合!
明日預告:【Day 12】系統全監控:/health 與 /stats API 實作與 Ansible 巡檢整合