# Architect Round 1 — 技術可行性分析與重大決策 > 目的:visionA-local 第一輪技術評估。不寫完整 TDD,只列架構方向、關鍵風險、待決問題。 > 作者:Architect Agent | 日期:2026-04-10 ## 1. 整體架構方案 **採用「Wails 殼 + Go Server 子程序 + Python sidecar」三層結構**,而非 single binary。理由: 原 `edge-ai-platform` 已經跑通 `installer/`(Wails)把 `edge-ai-server`(Go binary,內含 go:embed 的 Next.js)作為「payload」解壓到使用者目錄後啟動。這個拆分是**對的**,不該改成單一 binary: - Go server 本身要長時間持續跑(serve HTTP、WebSocket、管理 USB 裝置),Wails 前端則是 UI 殼;把兩者綁在同一個行程會讓 UI 當掉時連服務也一起掛。 - Python KneronPLUS SDK 必須由獨立 `python3` interpreter 執行,無法塞進 Go binary,註定要用 sidecar(`os/exec` 叫 `scripts/kneron_bridge.py`),Go server 仍是中介。 - Wails 本來就適合做「啟動器 + 控制台」,現有 `installer/app.go` 已有 894 行成熟程式碼、含系統資訊偵測、進度回報、裝置偵測、瀏覽器開啟等——**幾乎可以直接改名沿用**。 **建議架構:** ``` visionA-local.app (Wails 二進位) ├─ 內嵌 payload(go:embed installer/payload/...) │ ├─ edge-ai-server ← Go binary(含 embedded Next.js) │ ├─ data/ ← models.json + 預置 .nef (~73MB) │ └─ scripts/ │ ├─ kneron_bridge.py │ ├─ requirements.txt │ ├─ KneronPLUS-*.whl ← 每平台一份 wheel │ └─ (ffmpeg binary — 新增) ├─ 首次執行 → 解壓到 ~/.visiona-local/ ├─ 建立 venv + pip install requirements + KneronPLUS wheel └─ 啟動 edge-ai-server 子行程 → 開啟內嵌 WebView 指向 http://127.0.0.1:3721 ``` Wails 殼同時扮演:首次安裝精靈、Tray/常駐、啟動/停止 server、查看 log。第二次執行直接 detect 到已安裝、跳過解壓。 ## 2. 依賴內嵌策略(關鍵) ### 2.1 Python Runtime **結論:不要內嵌 Python runtime,改為「偵測 + 自動安裝系統 Python」。** | 平台 | 策略 | |------|------| | macOS | 首選:使用者系統已有的 `python3`(macOS 12+ 幾乎都有)。無則呼叫 Homebrew 安裝(現有程式碼已有 `brew install python@3.12` 流程) | | Windows | 首選:`winget install Python.Python.3.12`。備援:從 python.org 下載 embedded zip | | Ubuntu | `apt-get install python3 python3-venv python3-pip`(需 sudo polkit 提權) | **不採用 python-build-standalone / PyInstaller 的原因:** - KneronPLUS wheel 綁定 `pyusb` + 原生 libusb,用 embedded Python 時 site-packages 的 C extension 常踩到 ABI 問題 - 每平台都內嵌完整 Python 會讓安裝檔大約 +40MB,且升級 Python 需要重發整包 - 現有 `installer/app.go` 的 `setupPythonVenv()` 邏輯已在 macOS/Windows/Linux 跑通,包含 linux 缺 `ensurepip` 的 fallback **代價:** 使用者需要能連網做一次 `pip install`。如需完全離線,第二階段可改為 bundle wheels + `pip install --no-index --find-links`(requirements.txt 只有 numpy / opencv-python-headless / pyusb 三個,加上 KneronPLUS 共 ~80MB wheels)。**建議採「離線 wheel」路線**——完全符合「一鍵安裝不需連網」的要求。 ### 2.2 KneronPLUS SDK **結論:每平台打包對應的 wheel,透過 `pip install` 解壓到 venv。原 `installer/wheels/` 已有三平台的 wheel(共 3.9MB)。** | 平台 | wheel 狀態 | 原生函式庫 | 注意事項 | |------|-----------|-----------|---------| | macOS | `KneronPLUS-2.0.0-*.whl`(含 `.dylib`) | kp/lib/*.dylib | 需要 **ad-hoc codesign**(已有程式碼)否則 Gatekeeper 擋 | | Linux | `KneronPLUS-2.0.0 / 3.1.2-*.whl`(含 `.so`) | kp/lib/*.so | 需要 libusb-1.0(`apt-get install libusb-1.0-0`)+ udev rule 讓非 root 使用者能存取 USB | | Windows | `KneronPLUS-3.1.2-*.whl`(含 `.dll`) | kp/lib/*.dll + libusb-1.0.dll | 需要安裝 WinUSB driver(已有 `installer/drivers/kneron_winusb.inf`)— **這一步可能需要使用者手動同意 UAC** | **USB driver 是風險點:** Windows 必須裝 WinUSB driver 才能讓 libusb 存取裝置,現有程式碼透過 `pnputil` 或類似方式自動安裝,會彈 UAC。Linux 需要寫入 `/etc/udev/rules.d/99-kneron.rules` 也要 sudo。macOS 完全不需要 driver(IOUSB 直接用)。**這點要在 PRD 裡寫成「首次啟動需管理員權限」。** ### 2.3 ffmpeg **結論:內嵌靜態 binary,不要走 brew/winget。** | 平台 | 來源 | 大小 | 授權 | |------|------|------|------| | macOS (Intel + ARM) | evermeet.cx 的 static build,或 BtbN GitHub Release | ~40MB | LGPL build(**不要用 GPL 版**,避免產品須開源) | | Windows | gyan.dev 或 BtbN 的 essentials_build | ~50MB | LGPL | | Linux | johnvansickle.com 或 BtbN static build | ~50MB | LGPL | **做法:** 在 `installer/payload/ffmpeg/{platform}/ffmpeg` 放靜態檔,解壓後 Go server 用絕對路徑呼叫,不依賴 PATH。原 `stepInstallFfmpeg()` 是 fallback 去系統 PATH 找,新版應改為**一律用內嵌版**確保可重現。 **必須使用 LGPL build 而非 GPL build**——否則整個產品就被 GPL 感染。授權聲明要寫在 About 頁。 ### 2.4 預置模型 .nef **結論:放在 payload 中一起解壓到 `~/.visiona-local/data/nef/`,不塞進 Go binary。** 現狀 nef 總量 **73MB**。理由: - go:embed 會把 73MB 直接吃進 Go binary,link 時記憶體吃緊、IDE debug 變慢 - 解壓後使用者可手動管理、刪除、增加自訂模型(符合既有 `custom-models` 流程) - 沿用現有 `stepExtractData` 的做法 ## 3. 打包輸出格式 | 平台 | 格式 | 簽章 | |------|------|------| | **macOS** | `.app` 內包 Universal Binary(arm64 + amd64 用 `lipo` 合併)→ 再包成 `.dmg` | **強烈建議做 Developer ID + notarization**;否則使用者第一次開啟要右鍵 → 開啟。Wails 支援 `wails build -platform darwin/universal`。Notarization 需要 Apple Developer 帳號($99/年) | | **Windows** | `.exe`(NSIS / Inno Setup 都可,推薦 **Inno Setup**,UI 較現代) | **Authenticode 簽章**否則 SmartScreen 會狂擋新下載。EV 憑證 $300-500/年 | | **Ubuntu** | **`.AppImage`(首選)+ `.deb`(次選)** | 無強制簽章 | **為何選 AppImage:** 單檔、不需安裝、不需 sudo、攜帶性最高,最符合「像一般 app」的體驗。`.deb` 需要 `apt install`、需要 sudo、只能跑 Debian 系;AppImage 跨所有 glibc ≥2.28 發行版。`.snap` / Flatpak 需要發到 store,發行流程重。 **Universal Binary 是否做?** 建議做。現在 M1/M2 使用者已經是主流,若只發 Intel 版,M 系 Mac 要走 Rosetta,效能不穩(KneronPLUS dylib 如果是 x86_64-only 更糟)。需先確認 KneronPLUS macOS wheel 是否支援 arm64——**這是風險點 R3**。 ## 4. 預估安裝檔大小(壓縮後) | 平台 | Wails shell | Go server | Next.js embed | Python wheels | ffmpeg | NEF 模型 | WinUSB driver | 合計 | |------|------------|-----------|--------------|---------------|--------|---------|--------------|------| | macOS (Universal) | ~12MB | ~25MB (x2 架構 ~50MB) | ~5MB | ~40MB | ~35MB | ~73MB | - | **~215MB** | | Windows | ~10MB | ~20MB | ~5MB | ~40MB | ~45MB | ~73MB | ~1MB | **~195MB** | | Ubuntu (AppImage) | ~12MB | ~20MB | ~5MB | ~40MB | ~45MB | ~73MB | - | **~195MB** | 以上為**壓縮後**大小。主要體積來自 ffmpeg + Python wheels + 預置模型。若要瘦身:可將 .nef 改為首次啟動時線上下載(-73MB),但違反「完全離線一鍵安裝」原則。建議接受 ~200MB。 ## 5. 既有程式碼取用策略 | 目錄/檔案 | 策略 | 說明 | |-----------|------|------| | `installer/` | **直接複製改名** | 改為 `visiona-local/`,`app.go` 刪除 relay/dashboard 欄位,其餘流程沿用 | | `installer/wheels/` | **直接複製** | 三平台 KneronPLUS wheel | | `installer/drivers/` | **直接複製** | WinUSB driver 檔案 | | `server/main.go` | **改寫** | 刪除 cluster / tunnel / relay-token / gitea-url 相關參數與初始化 | | `server/internal/api/` | **改寫** | 刪除 cluster、tunnel handler 與 route | | `server/internal/camera` `device` `model` `inference` `flash` `config` `deps` | **直接複製** | 核心業務邏輯全保留 | | `server/internal/cluster` | ❌ **刪除** | | | `server/internal/tunnel` | ❌ **刪除** | | | `server/cmd/relay-server` | ❌ **刪除** | | | `server/tray/` | **直接複製** | 保留 macOS tray + Windows `--gui` web controller | | `server/scripts/` | **直接複製** | kneron_bridge.py + firmware update | | `server/data/` | **直接複製** | models.json + 預置 nef | | `server/web/` + `frontend/` | **改寫** | 移除 relay 模式切換、cluster 管理 UI | | `docker/` `scripts/deploy-*` | ❌ **刪除** | 不需要部署腳本 | | `tools/` | 視情況 | 多數是開發腳本 | ## 6. 要砍掉的程式碼清單(具體路徑) ``` server/internal/cluster/ ← 整包刪 server/internal/tunnel/ ← 整包刪 server/cmd/relay-server/ ← 整包刪 server/pkg/hwid/ ← relay token 用的,可刪 docker/ ← 整包刪 scripts/deploy-aws.sh scripts/deploy-ec2.sh frontend/app/.../cluster/ ← 前端 cluster 頁面(待 Design Agent 確認) frontend/app/.../relay/ ← 前端 relay 模式切換 UI ``` `server/main.go` 需移除的 import 與初始化: - `internal/cluster`, `internal/tunnel`, `pkg/hwid` - `cfg.RelayURL / RelayToken / GiteaURL` 相關 flag - `tunnelClient.Start()`、`clusterMgr`、`relayWebURL()` 等 - `config.go` 中的 `RelayURL / RelayToken / TrayMode`(tray 保留)`GUIMode`、`GiteaURL` 砍掉 ## 7. 重大技術風險(Top 5) | # | 風險 | 可能性 | 影響 | 緩解 | |---|------|-------|------|------| | **R1** | **KneronPLUS Linux wheel 只有特定 glibc/ABI,無法在所有 Ubuntu 跑** | 高 | 高 | 先實測 Ubuntu 22.04/24.04 x64,若不過則限定支援版本;訴求 AppImage 內帶 libusb | | **R2** | **Windows WinUSB driver 安裝需要 UAC,使用者拒絕就裝不起來** | 中 | 高 | 首次啟動明確說明;提供「手動安裝 driver」的後援流程 | | **R3** | **KneronPLUS macOS wheel 可能只有 x86_64**(M 系 Mac 要走 Rosetta,dylib 會抗議) | 中 | 高 | 第二輪前必須驗證:`lipo -info` 檢查 .dylib 架構;若只有 x86_64,Universal Binary 就沒意義 | | **R4** | **離線 wheel 安裝在沒有 pip 的 Python 環境會炸**(macOS 系統 Python 有 pip,但 Ubuntu 沒有 `python3-venv` 是常態) | 中 | 中 | 已有 `installPython3Venv()` fallback,但需要 sudo;考慮改為引導使用者手動裝 | | **R5** | **預置 .nef 模型授權可能限制重新發布** | 低 | 中 | 請 PM 確認 Kneron 預置模型的 re-distribution license | ## 8. 需要 PM / Design 回答的問題 **給 PM:** 1. 目標使用者是「開發者 / ML 工程師」還是「一般使用者」?影響 UI 的技術密度(要不要顯示 log、要不要 advanced mode) 2. 是否必須支援**完全離線**一鍵安裝?還是可以在首次啟動時連網下載 wheels?影響 R4 緩解方案 3. 預置模型清單要保留哪些?現狀 KL520/KL720 各有 5-6 個,73MB;可否精簡到 30MB? 4. 是否支援**多裝置連接**(一台電腦插兩顆 Kneron dongle)?影響裝置列表 UI 5. 要不要保留**韌體更新**功能(`update_kl720_firmware.py`)? **給 Design:** 1. Wails 殼的 UI 要走「安裝精靈風格」還是「Dashboard 風格」?原 installer 是精靈式,但 local 版應該常駐後是 Dashboard 2. 需要 Dark Mode 嗎? 3. 首次安裝流程的進度條樣式(現有是 0-100% 橫條,可否保留?) 4. 系統列(Tray)菜單要放哪些項目?至少:開啟儀表板 / 啟動/停止 / 結束 ## 9. 需要使用者確認的問題 1. **Apple 簽章與 notarization**:是否有 Apple Developer 帳號?沒有就只能 ad-hoc sign(使用者第一次要右鍵打開) 2. **Windows Authenticode**:是否願意採購 EV 簽章憑證(~$300/年)?沒有就會被 SmartScreen 警告,但仍可使用 3. **最低 OS 版本**:建議 macOS 12+、Windows 10 (1809)+、Ubuntu 22.04+,可接受? 4. **ARM Linux(Raspberry Pi 之類)**:暫不支援?(KneronPLUS 的 arm64 Linux 支援度不明) 5. **Bundle ID**:`com.innovedus.visiona-local` 可以用嗎?(progress.md 已記錄但標記待確認) 6. **離線 vs 線上安裝**:追求完全離線(~200MB 安裝檔)還是接受首次連網(~120MB 安裝檔)? 7. **預置模型**:是否需要精簡清單? 8. **應用程式名稱顯示**:visionA-local 還是 VisionA Local?品牌字風格? --- **下一步:** 等待 PM / Design / 使用者對上述問題的回覆。回覆後進入第二輪——產出完整 Design Doc 與 TDD,拆分為模組化檔案(`04-architecture/design-doc.md` 索引 + `api/`、`database.md`、`infra.md` 等子檔)。