docs(local-tool): 功能規格文件 LOCAL-TOOL-SPEC.md

涵蓋:
- 概述(三平台 + 完全離線安裝)
- Wails 控制台(5 階段啟動進度、timeout 機制、控制台功能、single-instance)
- Web UI(頁面路由、推論來源、結果顯示、模型管理、裝置管理、離線覆蓋層)
- 預設模型清單(KL520 × 4 + KL720 × 3)
- 內嵌依賴(Python/numpy/opencv/KneronPLUS/ffmpeg LGPL)
- Server API 摘要(系統/模型/裝置/媒體/WebSocket)
- M8 重構變更紀錄(15 個 commit 的完整 changelog)
- 資料目錄結構(三平台路徑 + 檔案說明)
- Build 指引(macOS/Windows/Linux)
- 除錯指引(Windows 啟動問題 + 常見問題)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
jim800121chen 2026-04-16 14:46:09 +08:00
parent 9793a2efc1
commit 61f9b8bf6b

View File

@ -0,0 +1,355 @@
# visionA Local Tool — 功能規格文件
> 版本v0.1.0-dev | 最後更新2026-04-16 | 對應 commit`9793a2e`
## 概述
visionA Local Tool 是 Kneron KL520 / KL720 邊緣 AI 推論硬體的**本機桌面應用**,讓使用者在完全離線的環境下,透過 USB 連接 Kneron 裝置,進行影像 / 影片 / 攝影機即時推論。
架構為 **Wails 桌面 AppGo + Vanilla JS 控制台)+ Go HTTP Server + Next.js Web UI瀏覽器**。Wails 控制台負責 server lifecycle 管理,瀏覽器 Web UI 負責裝置操作、模型管理、推論工作區。
### 三平台支援
| 平台 | 安裝格式 | Build target |
|------|---------|-------------|
| macOS (x86_64) | `.dmg` | `make dmg` |
| Windows (x64) | `.exe` (Inno Setup) | `make exe` |
| Linux (x86_64) | `.AppImage` | `make appimage` |
### 完全離線安裝
所有依賴Python runtime、wheels、ffmpeg、ffprobe、.nef 模型)全部 vendor 進 installer安裝和執行過程**不需要網路連線**。
---
## 1. Wails 控制台(桌面應用程式視窗)
### 1.1 啟動流程 — 5 階段進度面板
| 階段 | 名稱 | 做什麼 |
|------|------|--------|
| 1 | 初始化控制台 | 建立 dataDir、舊資料遷移、single-instance lock、IPC server、首次啟動 seed複製內建模型到 user dataDir |
| 2 | 檢查 Python 執行環境 | 偵測系統 Python → 或解壓內建 Python runtime首次啟動 ~1-3 分鐘)→ 建 venv → pip install wheelsnumpy/opencv/KneronPLUS 等 9 個套件) |
| 3 | 啟動本機伺服器 | spawn `visiona-local-server` subprocess → 等 health check 通過(首次啟動 Windows Defender 掃描可能需 1-2 分鐘) |
| 4 | 偵測 Kneron 裝置 | 對 `/api/devices` 發一次 GET 確認 server 可 serve 業務 endpoint |
| 5 | 開啟瀏覽器 | 自動開啟系統預設瀏覽器到 `http://127.0.0.1:3721`(可在設定中關閉) |
- **全屏 splash**app 啟動最一開始顯示 logo + spinner 全屏 overlay收到第一個 stage event 後切換到 5 階段面板
- **每階段細步文案**Go 端在每個 sub-step emit `startup:stage-detail` event前端即時顯示當前正在做什麼例如「正在解壓 Python runtime」「等待伺服器健康檢查通過」
- **啟動完成自動收合**5 階段全部完成後面板收合成一行 summary「✓ 啟動完成 · 點此展開檢視」,使用者點擊可展開歷史紀錄
- **重啟 / 重試時重新展開**:按「重新啟動伺服器」或「重試」會重置面板並完整重跑 5 階段
- **前端 snapshot 補漏**:前端 init 完成後呼叫 `GetStartupSnapshot()` 補上 race window 中漏掉的 stage events避免順序亂跳
- **Web UI 連線指示燈**Stage 6「等待 Web UI 連線」從面板隱藏,改為 header 的 Web UI 連線指示燈(綠燈 = 已連線、黃燈 pulse = 等待中)
### 1.2 Timeout 機制
| 類型 | 時長 | 行為 |
|------|------|------|
| 每階段 soft timeout | 20 秒 | emit「正在重試...」提示,**不中斷流程** |
| 整體 hard timeout | 5 分鐘300 秒) | 超過則 fail 進 Error state |
| 首次 bootstrap pause | 無上限 | Stage 1 seed / Stage 2 Python bootstrap / Stage 3 waitHealthy 期間暫停 hard timeout 計時,不算進 5 分鐘 budget |
### 1.3 控制台功能
- **狀態列**:顯示 server 狀態(閒置 / 啟動中 / 執行中 / 停止中 / 已停止 / 錯誤、port、PID、uptime、Web UI 連線狀態
- **主要控制**:在瀏覽器開啟 / 啟動 / 管理(停止 / 重新啟動 / 開啟 log 資料夾)
- **Log 面板**server 即時 log 顯示、自動跟隨最新、關鍵字過濾、層級過濾All / INFO / WARN / ERROR、清空 / 複製 / 匯出 / 開啟 log 資料夾
- **Settings**啟動時自動開啟瀏覽器macOS/Windows 預設 ON、Linux 預設 OFF、語言切換繁體中文 / English / Auto、關於資訊
- **Shutdown modal**server 停止時顯示「正在停止伺服器…」overlay15 秒 watchdog 自動 hide可用 Esc / 點 backdrop 手動關閉
- **Error 處理**server 啟動失敗 → 紅 banner「伺服器無法啟動」+ 重試按鈕runtime crash → OS 原生通知 + Error state
- **i18n 雙語**:繁體中文 + English全 UI 元素(含 stage 細步文案、設定、錯誤訊息)
### 1.4 Single-instance 保護
- 用 `visiona-local.lock` 檔案鎖 + PID 存活檢查
- 第二次啟動偵測到已有 instance → 嘗試 IPC raise 把現有視窗提到前景 → 自己 quietly exit
- Stale lockPID 已死)自動清理並取得新 lock
---
## 2. Web UI瀏覽器介面
### 2.1 頁面路由
| 路由 | 功能 |
|------|------|
| `/` | 儀表板 — 已連接裝置列表、活動時間軸、統計卡片 |
| `/devices` | 裝置列表 — 掃描 / 連接 / 斷開 Kneron USB 裝置 |
| `/devices/[id]` | 裝置詳細 — 狀態、健康度、韌體版本、連線日誌、設定 |
| `/models` | 模型庫 — 7 個預設 .nef 模型KL520 × 4 + KL720 × 3+ 上傳自訂模型 |
| `/models/[id]` | 模型詳細 — metadata、支援硬體、效能數據 |
| `/workspace` | 工作區 — 選裝置 → 選模型 → 選來源 → 推論 |
| `/workspace/[deviceId]` | 單一裝置工作區 — 推論操作主介面 |
| `/settings` | 設定 — 語言、主題、其他偏好 |
### 2.2 推論來源
| 來源 | 說明 |
|------|------|
| 攝影機 (Camera) | USB / IP Camera 即時串流推論 |
| 圖片 (Image) | 上傳單張 JPG/PNG 做單次推論 |
| 影片 (Video) | 上傳 MP4/AVI/MOV/MPEG/MPG 做逐幀推論ffmpeg 解碼) |
| 批次圖片 (Batch Images) | 上傳多張圖片逐張推論 |
### 2.3 推論結果顯示
- **MJPEG 即時串流**`/api/camera/stream` 提供多客戶端 multipart MJPEG 串流
- **Canvas overlay**bounding box + label + confidence 即時疊加
- **推論面板**FPS、平均延遲、信心度門檻調整、分類結果展示
- **影片進度**:目前幀 / 總幀、seek 跳轉
- **批次進度**:已處理 / 總張數、縮圖預覽
### 2.4 模型管理
- **7 個預設模型**NEF 格式、INT8 量化)
- **上傳自訂 .nef 模型**`POST /api/models/upload`
- **刪除已上傳模型**`DELETE /api/models/:id`
- **模型篩選**按任務類型object_detection / classification、硬體KL520 / KL720、關鍵字
- **模型對比工具**:並排比較兩個模型的規格
### 2.5 裝置管理
- **掃描 USB 裝置**:偵測已連接的 Kneron KL520 / KL720
- **連接 / 斷開**:連接時自動載入 firmwareKL520 USB Boot 流程)
- **韌體更新**flash .nef 到裝置 + 進度 WebSocket 即時回報
- **WinUSB 驅動安裝**Windows only首次啟動自動透過 KneronPLUS SDK libwdi 安裝,需 UAC 提權
### 2.6 離線覆蓋層
- Server 關閉 / 崩潰時,瀏覽器 tab 顯示 Offline Overlay
- `role=alertdialog` + focus trap + WebSocket 重連機制
- `boot-id` 偵測 server restart → 自動 reload含 reload loop guard
---
## 3. 預設模型
### KL5204 個)
| 模型 ID | 名稱 | 任務 | 輸入 | FPS |
|---------|------|------|------|-----|
| kl520-yolov5-detection | YOLOv5 Detection | 物件偵測 | 640×640 | ~20 |
| kl520-fcos-detection | FCOS Detection | 物件偵測 | 512×512 | ~22 |
| kl520-ssd-face-detection | SSD Face Detection | 人臉偵測 | 320×240 | ~100 |
| kl520-tiny-yolov3 | Tiny YOLOv3 | 物件偵測 | 416×416 | ~28 |
### KL7203 個)
| 模型 ID | 名稱 | 任務 | 輸入 | FPS |
|---------|------|------|------|-----|
| kl720-yolov5-detection | YOLOv5 Detection | 物件偵測 | 640×640 | ~33 |
| kl720-resnet18-classification | ResNet18 Classification | 分類1000 類)| 224×224 | ~100 |
| kl720-fcos-detection | FCOS Detection | 物件偵測 | 512×512 | ~33 |
---
## 4. 內嵌依賴
| 依賴 | 版本 | 用途 | 授權 |
|------|------|------|------|
| Python | 3.12.9 (python-build-standalone) | Kneron Python bridge | PSF |
| numpy | 2.4.4 | 影像處理 | BSD |
| opencv-python-headless | 4.10.0 | 影像處理 | Apache-2.0 |
| KneronPLUS | 2.0.0 | Kneron SDK Python binding | Kneron |
| pyusb | 1.3.1 | USB 裝置存取 | BSD |
| requests | 2.33.1 | HTTP 工具 | Apache-2.0 |
| ffmpeg | 自建 LGPL v3 decoder-only | 影片解碼mp4/avi/mov/mpeg/mpg| LGPL v3 |
| ffprobe | 同上 | 影片 metadata 提取 | LGPL v3 |
### ffmpeg LGPL 合規
macOS 版為自行編譯的最小 decoder-only build~5.7MB),只啟用必要的 demuxer/decoder/parser/filter**無 --enable-gpl / libx264 / libx265**,符合 LGPL v3。Windows/Linux 使用 BtbN 官方 LGPL 預編譯 binary。
---
## 5. Server API 摘要
### 系統
| Method | Path | 說明 |
|--------|------|------|
| GET | `/api/system/health` | 健康檢查(高頻輪詢用,無 log |
| GET | `/api/system/info` | 版本、平台、uptime |
| GET | `/api/system/metrics` | Go runtime 記憶體統計 |
| GET | `/api/system/deps` | 外部依賴檢查python/ffmpeg/ffprobe |
| GET | `/api/system/boot-id` | server 啟動 ID偵測 restart 用) |
| POST | `/api/system/restart` | 重啟 server |
| POST | `/api/system/install-driver` | 安裝 Kneron USB 驅動Windows only |
| POST | `/api/system/shutdown-notify` | 廣播關機通知到 WebSocket clients |
### 模型
| Method | Path | 說明 |
|--------|------|------|
| GET | `/api/models` | 列出所有模型(支援 filter |
| GET | `/api/models/:id` | 取得單一模型詳細 |
| POST | `/api/models/upload` | 上傳自訂 .nef 模型 |
| DELETE | `/api/models/:id` | 刪除已上傳模型 |
### 裝置
| Method | Path | 說明 |
|--------|------|------|
| GET | `/api/devices` | 列出已偵測裝置 |
| POST | `/api/devices/scan` | 掃描 USB 裝置 |
| GET | `/api/devices/:id` | 取得裝置詳細 |
| POST | `/api/devices/:id/connect` | 連接裝置 |
| POST | `/api/devices/:id/disconnect` | 斷開裝置 |
| POST | `/api/devices/:id/flash` | 燒錄韌體 |
| POST | `/api/devices/:id/inference/start` | 啟動推論 |
| POST | `/api/devices/:id/inference/stop` | 停止推論 |
### 媒體
| Method | Path | 說明 |
|--------|------|------|
| GET | `/api/camera/list` | 列出可用攝影機 |
| POST | `/api/camera/start` | 啟動攝影機推論 pipeline |
| POST | `/api/camera/stop` | 停止 pipeline |
| GET | `/api/camera/stream` | MJPEG 即時串流 |
| POST | `/api/media/upload/image` | 上傳單張圖片推論 |
| POST | `/api/media/upload/video` | 上傳影片逐幀推論 |
| POST | `/api/media/upload/batch-images` | 批次上傳圖片推論 |
| GET | `/api/media/batch-images/:index` | 取得批次中特定幀 |
| POST | `/api/media/seek` | 影片 seek 跳轉 |
### WebSocket
| Path | 說明 |
|------|------|
| `/ws/devices/events` | 裝置連接 / 斷開事件 |
| `/ws/devices/:id/flash-progress` | 韌體更新進度 |
| `/ws/devices/:id/inference` | 推論結果即時串流 |
| `/ws/server-logs` | server log 即時廣播 |
| `/ws/system` | 系統事件(含 shutdown-imminent |
---
## 6. M8 重構變更紀錄2026-04-14 ~ 2026-04-16
以下是 M8 重構後的所有修復和改動,按時間排序:
### 架構變更R5 決策實作)
| Commit | 變更 |
|--------|------|
| `8cd5751` | **M8 重構 — Wails 控制台 + 瀏覽器 Web UI**:原 Wails 內嵌 Next.js 改為「Wails 控制台管理 server lifecycle + 瀏覽器開 Web UI」。砍 yt-dlpM8-1、砍 Mock 模式M8-2、ffmpeg LGPL vendorM8-3、ServerController v2 state machineM8-4、啟動階段管線 6 stage pipelineM8-4b、Wails 控制台 vanilla JS UIM8-5、Offline OverlayM8-7、CORS middlewareM8-8、shutdown broadcastMAJ-4、Boot-ID + tab 重連M8-9 |
### Bug 修復
| Commit | 問題 | 修法 |
|--------|------|------|
| `d7cddf3` | **預設模型永遠載入 0 個** — server 預設 dataDir 算錯models.json 找不到 | 拆 `builtInDataDir`read-only bundlevs `dataDir`writable user home新增 `resolveBuiltInDataDir` + `findFirstExisting` helper跨 macOS/Windows/Linux AppImage 五路徑自動偵測 |
| `a6cd1c1` | **Wails 控制台一打開就看到 Settings + shutdown-modal** — CSS `.modal-backdrop { display: flex }` 覆蓋 user agent `[hidden] { display: none }` | 全域 `[hidden] { display: none !important; }` |
| `a209470` | **Windows 乾淨環境啟動失敗Stage 2 Python bootstrap > 60s** | StartupPipeline 加 `PauseHardTimeout` / `ResumeHardTimeout` API首次 bootstrap 不算入 hard timeout budget |
| `c649a81` | **Stage 3 waitHealthy 也被 hard timeout 幹掉** | waitHealthy 冷啟動時也 pausehealthCheckTimeout 30s → 180s |
| `35db6c8` | **shutdown-modal「正在停止伺服器」popup 卡死 + Wails app stderr 在 Windows 上看不到** | 前端 15s watchdog + Esc/backdrop 可關 + stopGraceful hardBailout timer + appLog 覆蓋啟動流程關鍵訊息到 wails.log |
| `d946561` | **Stage 順序亂跳Stage 1 等待中但 Stage 2 完成)** | 新增 `GetStartupSnapshot()` binding前端 init 後拉 snapshot 補漏 events + monotonic status rank 避免倒退 |
| `ad9beab` | **Restart / Stop+Start 後 5 階段面板不更新** | `startInternal` 進場偵測 pipeline 已完成/已失敗 → 自動 `rebuildStartupPipeline` 重建,`didRebuild` flag 分流 Stage 5 openBrowser |
| `fbd585a` | **Linux build 找不到 webkit2gtk-4.0** | Makefile `wails-linux` 自動偵測 4.1 → `-tags webkit2_41`bootstrap-linux.sh 也做版本偵測 |
| `485a2e0` | **Linux build 找不到 appimagetool** | bootstrap-linux.sh 新增自動下載安裝 appimagetool |
### 功能改善
| Commit | 變更 |
|--------|------|
| `dd35b56` | regen Wails bindingsM8 漏提的 binding 產物) |
| `9c9e005` | Stage 3 sub-step 細步進度 + 啟動完成後面板可收合 |
| `ff5cab6` | hard timeout 放寬 + 全 stage 細步 detail emit13 個 i18n keys+ Stage 1 seed pause |
| `f5655e3` | hard timeout → 5 分鐘300s+ Stage 6 隱藏到 header 連線指示燈 + 全屏 splash overlay |
| `9793a2e` | models.json 從 15 筆精簡為 7 筆(只保留有實體 .nef 的模型) |
### 開發工具 / Bug A
| Commit | 變更 |
|--------|------|
| `a209470` | `killStaleServerOnPort` 改用 `ps -o args=` 識別 `go run` 產生的 server開發/Reviewer 測試用) |
---
## 7. 資料目錄
| 平台 | 位置 |
|------|------|
| macOS | `~/Library/Application Support/visiona-local/` |
| Windows | `%APPDATA%\visiona-local\` |
| Linux | `~/.config/visiona-local/``$XDG_DATA_HOME/visiona-local/` |
### 目錄結構
```
visiona-local/
├── visiona-local.lock # single-instance 鎖
├── visiona-local.ipc-port # server port供 raise 用)
├── visiona-local.wails-ipc-port # Wails IPC port
├── preferences.json # 使用者偏好autoOpenBrowser / locale
├── models.json # 預設模型 catalog首次啟動從 bundle seed
├── nef/ # 預設 .nef 模型檔(首次啟動從 bundle seed
│ ├── kl520/
│ └── kl720/
├── custom-models/ # 使用者上傳的自訂模型
├── runtime/ # Python runtime首次啟動解壓
│ ├── python/
│ └── venv/
├── logs/
│ ├── server.stdout.log # server subprocess stdout
│ ├── server.stderr.log # server subprocess stderr
│ └── wails.log # Wails app (appLog) 啟動流程日誌
└── .first-ws-connected # WebSocket sentinel file啟動階段用
```
---
## 8. Build 指引
### macOS
```bash
cd local-tool
make vendor-sync # 下載 Python + wheels + 驗證 ffmpeg LGPL
make payload-macos # 準備 payload/darwin/
make dmg # → dist/visiona-local.dmg (~163MB)
```
### Windows需在 Windows 機器上)
```powershell
cd local-tool
.\scripts\bootstrap-windows.ps1 # 安裝 Go / Node / pnpm / Wails / Python / MSYS2
make exe # → dist/visiona-local-*-windows-x64.exe
```
### LinuxUbuntu 22.04+
```bash
cd local-tool
bash scripts/bootstrap-linux.sh # 安裝所有依賴 + 自動 build
# 或手動:
make vendor-python-linux vendor-wheels-linux vendor-ffmpeg-linux
make payload-linux
make appimage # → dist/visiona-local-*-linux-x64.AppImage
```
---
## 9. 除錯指引
### Windows 啟動問題
1. 檢查 `%APPDATA%\visiona-local\logs\wails.log`
- 第一行應有 `fix marker: d946561+`(確認 build 版本)
- Stage 1-5 的細步文案會記錄每個 sub-step
2. 檢查 `server.stdout.log` / `server.stderr.log`
3. 如需更詳細的 Wails 端 log從命令列啟動
```
"C:\Program Files\visiona-local\visiona-local.exe" > %TEMP%\wails-debug.txt 2>&1
```
### 常見問題
| 症狀 | 可能原因 | 解法 |
|------|---------|------|
| 啟動 Stage 3 timeout | Windows Defender 首次掃 .exe | 等待,有 pause 機制不會 fail或加白名單 |
| 第二次啟動閃黑窗消失 | 前一次 crash 的 lock 殘留 | 刪 `visiona-local.lock` |
| 瀏覽器看不到裝置 | USB 權限Linux/ WinUSB driver 沒裝 | Linux: `sudo bash install-udev.sh`Windows: 從 UI 點「安裝 Kneron USB 驅動程式」 |
| 模型庫是空的 | 首次啟動 seed 失敗 | 檢查 `wails.log` 的 seed 訊息;或手動複製 `models.json + nef/` 從 installer 到 user dataDir |