visionA/local-tool/.autoflow/04-architecture/architect-analysis-round1.md
jim800121chen c54f16fca0 Initial commit: visionA monorepo with local-tool subproject
local-tool/: visionA-local desktop app
- M1: Wails shell + Go server + Next.js UI + Mock mode (macOS dmg ready)
- M2: i18n (zh-TW/en) + Settings 4-tab refactor
- M3: Embedded Python 3.12 runtime (python-build-standalone) + KneronPLUS wheels
- M4: Windows Inno Setup script (build on Windows runner)
- M5: Linux AppImage script + udev rule (build on Linux runner)
- M6: ffmpeg (GPL, pending legal review) + yt-dlp bundled
- Lifecycle: watchServer health check, fatal native dialog,
            Wails IPC raise endpoint, stale process cleanup

.autoflow/: full PRD / Design Spec / Architecture / Testing docs
            (4 rounds tri-party discussion + cross review)
.github/workflows/: macOS / Windows / Linux build CI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:10:38 +08:00

190 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 二進位)
├─ 內嵌 payloadgo: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 完全不需要 driverIOUSB 直接用)。**這點要在 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 binarylink 時記憶體吃緊、IDE debug 變慢
- 解壓後使用者可手動管理、刪除、增加自訂模型(符合既有 `custom-models` 流程)
- 沿用現有 `stepExtractData` 的做法
## 3. 打包輸出格式
| 平台 | 格式 | 簽章 |
|------|------|------|
| **macOS** | `.app` 內包 Universal Binaryarm64 + 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 要走 Rosettadylib 會抗議) | 中 | 高 | 第二輪前必須驗證:`lipo -info` 檢查 .dylib 架構;若只有 x86_64Universal 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 LinuxRaspberry 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` 等子檔)。