iT邦幫忙

2026 iThome 鐵人賽

DAY 11
0
Build on Google AI

打造零成本企業級 AI Agent:以 Gemini 2.5 Flash 構建金融分析助手與維運實戰系列 第 11

【Day 11】前端互動介面:極簡前端與獨立單元測試驗證模組 (static/validation.js)

  • 分享至 

  • xImage
  •  

「一個生產級的自建 AI Agent,除了需要強健的後端服務,還需要一個獨立、輕量且具備前後端雙重校驗(Double Validation)機制的數據驗證模組。」

在先前,我們建構了自動化資料 pipeline(Google Drive 同步、每日盤後分析推播與 Google Sheets 追蹤)。今天我們將進入專案的——前端互動介面、系統全監控與生產部署!

我們將探討 app/main.py 如何透過 FastAPI 的 StaticFiles 機制掛載前端 static/ 靜態目錄,剖析專門用於單元測試與前端訊息校驗的 static/validation.js,以及後端如何透過 Pydantic 與自訂指令(/learn、/fetch-url)進行訊息接收與防禦。

本篇重點摘要

  1. 為什麼選擇無框架(No-Framework Vanilla Web)與獨立 Validation 模組設計呢?
  2. 拆解 app/main.py 中 StaticFiles 的靜態目錄掛載位置與順序守則。
  3. 剖析 static/validation.js 前端驗證機制(空白拒絕、2000 字元限制與 Node.js 測試兼容)。
  4. 解析前後端縱深防禦:後端 HTTP 422 空白字元過濾與內建指令處理。

一、前端選型與 FastAPI 靜態檔案掛載

在 Self-hosted RHEL 環境下,為了追求極致的輕量與系統穩定,我們捨棄了繁重的 React/Vue 構建流程,選擇採用原生的 Vanilla JavaScript 進行驗證與對接。

靜態檔案掛載順序守則 (app/main.py)

  在 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")

二、訊息驗證與 Node.js 單元測試相容設計 (static/validation.js)

為了避免使用者發送無效訊息或超長文本衝擊後端,我們在前端 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 };
}

三、前後端縱深防禦:後端 API 訊息過濾 (app/main.py)

前端的 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 巡檢整合


上一篇
【Day 10】數據追蹤與績效評估:Google Sheets 數據寫入與預測準確率追蹤 (sheets_tracker.py)
下一篇
【Day 12】系統全監控:/health 與 /stats API 實作與 Ansible 巡檢整合
系列文
打造零成本企業級 AI Agent:以 Gemini 2.5 Flash 構建金融分析助手與維運實戰12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言