5 分鐘建立第一個外掛
先從最小可運作骨架開始,再依需求加入設定頁、背景工作與商城能力。
目錄與打包規範
建議目錄
tynvr_module_example/
├── manifest.json
├── plugin.py
├── config.example.yml
├── README.md
└── assets/
└── plugin.css
打包要求
- ZIP 最上層只放一個外掛根目錄。
manifest.json與plugin.py必須存在。- 一般外掛 ZIP 建議不超過 16 MB。
- 大型模型、PyTorch、CUDA 等執行環境不要塞進一般外掛包。
manifest.json
描述外掛身分、版本、設定 UI、選單掛載與可執行操作。
{
"id": "tynvr_module_example",
"name": "Example Plugin",
"version": "1.0.0",
"description": "Example Securex Nvr plugin",
"enabled": true,
"kind": "tynvr_core_module",
"module_id": "example",
"order": 50,
"config_apply": "hot",
"first_install_restart": true,
"navigation_user_toggle": true,
"navigation_default_visible": true,
"actions": [
{"id": "reload", "label": "Reload"}
],
"navigation": {
"key": "example",
"mount": "settings.sidebar.plugins",
"label": "Example Plugin",
"url": "/api/example/?embed=1",
"view": "iframe",
"order": 50,
"icon": "puzzle"
}
}id穩定唯一 ID;建議 tynvr_module_xxx。version每次商城升級必須遞增。navigation選單由 manifest 動態宣告;建議明確提供穩定 key。navigation_user_toggle允許使用者控制側欄顯示;升級必須保留使用者選擇。config_apply建議 hot:一般設定儲存後立即套用,不要求重啟 Frigate。first_install_restart首次安裝/程式碼升級可要求一次重載;一般設定儲存不應要求重啟。actions提供給外掛管理頁的明確操作。plugin.py / class Plugin
目前 Universal 外掛以 FrigatePlugin 為基底類別。建議把路由、設定、背景執行緒與停止邏輯都封裝在外掛實例內。
from pathlib import Path
from typing import Any
from fastapi import APIRouter, Depends
from frigate.api.auth import require_role
from frigate.plugins.base import FrigatePlugin
class Plugin(FrigatePlugin):
def __init__(self, frigate_config: Any, plugin_dir: Path, stop_event=None):
super().__init__(frigate_config, plugin_dir, stop_event)
self._router = APIRouter(tags=["example"])
self._build_routes()
@property
def router(self):
return self._router
def _build_routes(self):
@self._router.get(
"/api/example/status",
dependencies=[Depends(require_role(["admin"]))],
)
def status():
return {"ok": True}
def get_public_config(self):
return {"enabled": True}
def update_config(self, payload):
return {"success": True}
def run_action(self, action, payload):
return {"success": action == "reload"}
def stop(self):
pass設定、狀態與使用者資料
權限、Secret 與敏感操作
最小權限:讀取使用已登入權限;修改設定、Token、模型部署、硬體控制等使用管理員權限。
Secret:完整 Token、密碼、金鑰只保留在伺服器端。UI 只顯示「已設定」或遮罩值。
CSRF / POST:變更狀態不可使用 GET。Frigate 同源 POST/PUT/PATCH/DELETE 應明確送出 X-CSRF-TOKEN: 1(建議同時 X-CACHE-BYPASS: 1);Universal 雖有通用橋接,外掛本身仍應正確實作。
輸入驗證:路徑、URL、命令參數、上傳檔名都要白名單/正規化,避免把使用者輸入直接拼進 shell。
背景工作、網路與恢復
不要阻塞請求
訓練、下載、同步、掃描等長工作放入背景執行緒/Worker,並提供狀態、進度、停止與錯誤資訊。
非同步路由不要做同步回環 HTTP
async FastAPI 路由內不要直接用 urllib/requests 同步呼叫 Frigate 自己的 127.0.0.1 API,否則可能造成事件迴圈自鎖到 timeout。請使用執行緒池/非同步客戶端或重用既有資料。
網路操作必須可恢復
設定合理 timeout;斷網後退避重試;上傳大型檔案使用分塊與校驗;重複請求盡量做到冪等。
日誌與執行環境需可維護
日誌清理應使用原地 truncate,不停止 Worker/訓練;大型 runtime 與 artifacts 應與外掛程式碼分離,升級只替換外掛本體。
官方 AI 外掛參考
以下為目前正式基線,可用來驗證第三方外掛是否符合平台約定。
Securex AI Cloud v1.1.7
- Shadow A/B 在同一畫面比較生產與候選模型,不切換生產 detector。
- Explore 人工確認按「是/否」即提交;只有 Store 雲端確認 correct/incorrect 後才顯示「已提交」。
- 人工確認樣本使用 sample_reason=manual,並在圖片頁顯示「正確/錯誤 · 人工確認」。
- 人工提交讀取 Frigate event/snapshot 時必須在線程池執行,避免 async 路由自鎖。
Securex AI Training Worker v1.0.11
- 訓練 runtime 與外掛程式碼分離,升級/重啟不刪除訓練環境與 artifacts。
- 支援重新附著正在執行的 Job,不重複訓練。
- 安裝日誌與 Worker 日誌可原地清空,不停止安裝器/Worker。
- 獨立頁面跟隨 Frigate 主題,狀態操作遵循 Frigate CSRF 規則。
簡體 / 繁體 / English 與響應式
商城中的外掛名稱、描述、按鈕、錯誤、設定欄位都應完整提供三種語言;不要只翻譯標題。
- 英文通常更長,按鈕與卡片不能依賴固定中文寬度。
- 在 1366px、平板寬度與窄側欄嵌入場景下測試。
- 日誌、長 ID、URL 使用換行/省略規則,避免撐破版面。
版本、升級與移除
升級覆蓋外掛程式碼時,應保留使用者設定、側欄顯示偏好與持久資料;一般設定儲存採熱套用。移除時要區分「刪除外掛程式碼」與「刪除使用者資料」;破壞性清理必須明確提示。
發布前檢查
ZIP 結構正確manifest.json / plugin.py
安裝與啟用正常全新安裝測試
重啟自動恢復Frigate 重啟後狀態正確
升級保留資料config / db / status
移除後無殘留選單動態選單正常
三語言完整简 / 繁 / EN
窄螢幕不溢出1366 / tablet / embed
網路失敗可恢復timeout / retry / resume
Secret 不洩漏瀏覽器與日誌檢查
寫入請求 CSRF 正確X-CSRF-TOKEN / POST / PUT / DELETE
熱儲存不需重啟config_apply=hot
升級保留側欄偏好navigation_visible
非同步路由無阻塞回環threadpool / async client
版本與商城資料一致manifest / catalog / ZIP
外掛準備好了?
完成檢查後上傳 ZIP。商城審核重點包括安全、相容性、升級保留、多語言與介面完整性。