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>
166 lines
5.5 KiB
Markdown
166 lines
5.5 KiB
Markdown
# Plan B:預置模型線上下載(R9 Contingency)
|
||
|
||
> 這份文件是 **R9 .nef re-distribution 授權** 的 contingency 方案。
|
||
> 使用時機:發佈前 PM 與 Kneron 確認結果為「不允許將 .nef 內嵌於另一產品 re-distribution」。
|
||
> **目前不啟用**,只在 R9 被否決時才觸發;本文件不影響 M1–M6 開發計畫。
|
||
|
||
---
|
||
|
||
## 1. 觸發條件
|
||
|
||
以下任一條件成立即觸發 Plan B:
|
||
|
||
- M6(首次公開 release 前)PM 或使用者從 Kneron 官方 / OEM 窗口收到「不允許 re-distribute 預置 .nef」的書面回覆
|
||
- 發佈流程中任何時點發現授權問題
|
||
- Innovedus 法務自行判斷風險過高要求下架內嵌模型
|
||
|
||
**不觸發的情況**:任何「尚未確認」的狀態(與現行第四輪 R4-1 決策一致,維持內嵌不主動詢問)。
|
||
|
||
## 2. 目標
|
||
|
||
用最小改動把預置 .nef 從「內嵌打包」改為「首次啟動線上下載」,**保留原本所有功能與使用體驗,僅犧牲「完全離線」承諾**。
|
||
|
||
**不重做**:
|
||
- 使用者自訂上傳的 .nef(`data/custom-models/`)繼續走既有上傳流程
|
||
- Python runtime / KneronPLUS SDK / ffmpeg / yt-dlp 繼續內嵌(授權可重發布)
|
||
|
||
**改動範圍**:只有預置 .nef(`server/data/nef/`,~73MB)
|
||
|
||
## 3. 架構修改
|
||
|
||
### 3.1 移除 payload 中的 .nef
|
||
|
||
```diff
|
||
visiona-local/payload/
|
||
├── bin/
|
||
├── python/
|
||
├── scripts/
|
||
- └── data/
|
||
- ├── models.json
|
||
- └── nef/
|
||
- ├── kl520/*.nef
|
||
- └── kl720/*.nef
|
||
+ └── data/
|
||
+ └── models.json ← 保留 metadata,nef 目錄留空
|
||
```
|
||
|
||
安裝檔大小降為 ~225MB(macOS)/ ~235MB(Windows)/ ~240MB(Linux)。
|
||
|
||
### 3.2 新增下載邏輯
|
||
|
||
**位置**:`visiona-local/model_download.go`(新寫)
|
||
|
||
**觸發點**:`.installed` 寫入後、首次 `launchServer()` 之前,插入一個「模型下載」精靈步驟。
|
||
|
||
```go
|
||
// 流程
|
||
func (inst *Installer) stepDownloadPresetModels(config InstallConfig) error {
|
||
// 1. 讀 models.json → 取得清單
|
||
manifest := loadBundledManifest()
|
||
|
||
// 2. 檢查本地 data/nef/ 下哪些已存在
|
||
missing := diffMissing(manifest, config.InstallDir)
|
||
|
||
// 3. 全數存在 → 跳過
|
||
if len(missing) == 0 {
|
||
return nil
|
||
}
|
||
|
||
// 4. 顯示下載進度 UI(Wails app 內建)
|
||
inst.showProgress("下載預置模型...", len(missing))
|
||
|
||
// 5. 逐檔下載 + 驗證 sha256
|
||
for _, m := range missing {
|
||
if err := downloadWithResume(m.URL, m.LocalPath, m.SHA256); err != nil {
|
||
return fmt.Errorf("模型下載失敗:%w", err)
|
||
}
|
||
inst.incrementProgress()
|
||
}
|
||
|
||
return nil
|
||
}
|
||
```
|
||
|
||
### 3.3 manifest 格式
|
||
|
||
`payload/data/models.json`(擴充原有格式):
|
||
|
||
```json
|
||
{
|
||
"version": "1.0.0",
|
||
"base_url": "https://releases.innovedus.com/visiona-local/models/v1.0.0/",
|
||
"models": [
|
||
{
|
||
"id": "kl520-classification-mobilenetv2",
|
||
"device": "kl520",
|
||
"task": "classification",
|
||
"file": "kl520/classification_mobilenetv2.nef",
|
||
"size_bytes": 6234521,
|
||
"sha256": "abc123...",
|
||
"url_path": "kl520/classification_mobilenetv2.nef"
|
||
},
|
||
...
|
||
]
|
||
}
|
||
```
|
||
|
||
**sha256 欄位必填**:防止下載中間被竄改或損毀。
|
||
|
||
### 3.4 下載來源
|
||
|
||
三選一(M6 前決定):
|
||
|
||
| 選項 | 優點 | 缺點 |
|
||
|------|------|------|
|
||
| A. Innovedus 內部 Gitea Releases | 管理簡單、已有通路(若 R11 通過) | 對外需要 VPN |
|
||
| B. AWS S3 + CloudFront | 速度快、全球 CDN | 需管 IAM / Bucket |
|
||
| C. GitHub Releases(若 repo 公開) | 免費 + 自帶 CDN | 需公開 repo |
|
||
|
||
**預設建議 B(S3 + CloudFront)**,與 R11 發佈通路解耦(安裝檔仍可放 Gitea,模型走 S3)。
|
||
|
||
### 3.5 斷線處理
|
||
|
||
- **下載中斷** → `downloadWithResume` 支援 HTTP Range,下次啟動繼續
|
||
- **全部下載失敗** → 不擋安裝完成,但主 UI 顯示 warning:「預置模型未下載,部分示範功能無法使用」;使用者可在 Settings > 模型 手動點「重新下載預置模型」
|
||
- **完全離線環境** → 提供離線包下載頁(使用者自己 scp .nef 到 `data/nef/`),首次啟動偵測到檔案存在則跳過下載
|
||
|
||
## 4. 安全與驗證
|
||
|
||
- sha256 驗證每個下載檔
|
||
- HTTPS only(不接受 HTTP)
|
||
- 下載失敗自動 retry 3 次,指數退避(2s / 5s / 10s)
|
||
- 下載時顯示進度條(總大小 ~73MB,10Mbps 連線約 60 秒)
|
||
|
||
## 5. 使用者體驗影響
|
||
|
||
| 項目 | 原方案(內嵌) | Plan B(線上下載) |
|
||
|------|--------------|------------------|
|
||
| 完全離線 | ✅ | ❌(首次需要網路) |
|
||
| 首次安裝時間 | 3–5 分鐘 | 3–5 分鐘 + 下載時間(約 60–180 秒) |
|
||
| 後續啟動 | 同 | 同(一次下載後本地使用) |
|
||
| 使用者須知 | 無 | 首次啟動需要網路、之後離線可用 |
|
||
|
||
## 6. 估工
|
||
|
||
| 任務 | 規模 |
|
||
|------|------|
|
||
| model_download.go 新寫 | M(~300 行) |
|
||
| 安裝精靈新增「下載模型」步驟 | S |
|
||
| manifest 格式與 CDN 結構 | S |
|
||
| 離線包下載頁與文件 | S |
|
||
| 測試三平台 + 斷線恢復 | M |
|
||
| 總計 | **~1 週工程師時間** |
|
||
|
||
## 7. 觸發後的行動清單
|
||
|
||
- [ ] 確認 Kneron 回覆書面紀錄
|
||
- [ ] 決定下載來源(A/B/C)並建置
|
||
- [ ] 實作 `model_download.go`
|
||
- [ ] 修改安裝精靈 UI
|
||
- [ ] 修改 payload 打包腳本移除 nef
|
||
- [ ] 建立離線包下載頁
|
||
- [ ] 更新 PRD NFR「完全離線」章節加上註記
|
||
- [ ] 更新 packaging 文件與安裝檔大小估算
|
||
- [ ] 三平台測試
|
||
- [ ] 法務複核 About 頁模型授權聲明
|