visionA/docs/autoflow/02-prd/features/feature-converter-integration.md
jim800121chen fb7da5d180 chore(autoflow): migrate .autoflow/ 共享層文件至 docs/autoflow/
依 autoflow-agent workspace v2 設計把 PRD / 設計 / 架構 / 交付類
共享文件從個人層 .autoflow/(ignored)搬到 docs/autoflow/(進 git),
讓團隊可共享產品與架構文件,個人層只留 progress / review / testing 等
per-branch 筆記。

- 02-prd/        21 個檔(PRD、features、market-analysis 等)
- 03-design/     18 個檔(design-spec、wireframes、flows 等)
- 04-architecture/ 31 個檔(TDD、design-doc、ADR×14、API 規格等)
- 07-delivery/   3 個檔(project-summary、phase-0.6-handover、stage-deployment-setup)

合計 73 檔。原檔已從 .autoflow/ 移除(migration 工具執行 git mv,
但因 .autoflow/ 在 .gitignore 中、git 將此操作視為新增、無 rename history)。
2026-05-04 16:55:55 +08:00

247 lines
15 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.

# Feature轉檔功能整合P0 — Phase 0.8 MVP
> 父文件:[PRD.md](../PRD.md) | 對應 User StoriesUS-24、US-TODO-05
>
> **狀態變更2026-05-02**Phase 0 規劃為「P2、只定 API 契約」Phase 0.8 提升為 P0 MVP 並落地實作。
> 本檔保留 Phase 0 的設計決策脈絡API 契約、ConverterClient 介面),新增 Phase 0.8 的 MVP 範圍與整合決策。
---
## 1. 概要
Kneron 的 `.nef` 是 Kneron 晶片專用格式,使用者手上常是 ONNX / TFLite需要轉檔才能在 KL520 / KL720 / KL630 / KL730 上跑。`kneron_model_converter` 已有完整轉檔 servicePhase 1 已完成 `POST /api/v1/jobs` 提交、`GET` 查狀態、`POST /promote` 把結果搬上 File Access Agent
Phase 0.8 的目標是在 visionA Cloud **接入 converter**,讓使用者**不離開 visionA**就能完成「上傳原始模型 → 轉檔 → 進模型庫推論」的完整流程,把原本斷裂的兩個網站合併成一條動線。
跟「模型管理P0」的關係轉檔產生的 `.nef` 是模型庫的一個**新來源**(與「使用者直接上傳 nef」並列。轉檔成功後使用者**自己決定**是否要把 NEF 加進模型庫;加進去後走的是模型管理既有的 `/api/models/init+finalize` 流程,並標記 `Source="converted"` + `SourceJobID=<converter job_id>`
---
## 2. User StoriesPhase 0.8 MVP 範圍)
| ID | Story | 優先級 |
|----|-------|--------|
| US-24a | 作為 AI 應用開發者,**我有一個 ONNX 模型**,想轉成 NEF 放到我的 KL720 device 上跑,希望全程在 visionA Cloud 完成 | P0 |
| US-24b | 作為使用者,**轉檔完成後**我想決定是「加到模型庫直接推論」還是「下載 NEF 回去自己用」,或者兩個都做 | P0 |
| US-24c | 作為使用者,**轉檔失敗時**我想看到清楚的錯誤原因(不是只有 `failed`),知道是檔案格式不支援、量化失敗、還是其他問題 | P0 |
> Phase 0 規劃中 US-24 的「自動把 NEF 推進模型庫」(端到端全自動)改為 Phase 0.8 的**半自動**設計user 顯式選擇)。理由:避免「使用者試了個轉檔但其實只想下載結果」也被自動塞進模型庫。
---
## 3. 功能需求Phase 0.8 MVP
### F1「轉檔」進入點
- 左側 sidebar 新增「轉檔」tab與既有的 Devices / Models / Inference 並列
- 進入後顯示**轉檔頁面**:上傳區 + 設定區 + 開始按鈕
- 不在 `/models` 頁面內混合(避免「上傳模型」按鈕同時要處理 nef / onnx / tflite 兩種流程UX 變複雜)
### F2上傳與設定
- **支援檔案格式**`.onnx``.tflite`Phase 0.8 不支援 `.pt` / `.h5`,由 converter 能力決定)
- **必填欄位**
- 來源檔案(拖拽或選擇)
- 目標 chipKL520 / KL630 / KL720 / KL730單選
- **可選欄位**
- Reference images多張給 converter 做精度校準用)
- 任務名稱(顯示用,預設用檔名)
- **檔案大小限制**
- 模型檔:≤ 500 MBconverter 端的限制;應透過 config 對齊,建議 `CONVERTER_MAX_MODEL_SIZE_MB`
- Reference images每張 ≤ 10 MB、總數 ≤ 100 張
- **上傳行為**upload 走 **visionA backend streaming proxy**(見 §6 整合決策 D1browser → backend → converter使用者看到的是「上傳到 visionA」的單一進度條XHR upload event
### F3轉檔執行與進度
- 上傳完成後自動切到「轉檔進度頁」(同一個 tab不開新分頁
- 進度顯示用 **polling**(前端每 510 秒打一次 `GET /api/conversion/{job_id}`
- status 機械化的四個狀態:`queued` / `running` / `succeeded` / `failed`
- `running` 時若 converter 提供 progress 比例則顯示百分比,無提供則顯示「轉檔中⋯」+ 跑馬燈
- **同 user 同時只能跑一個 active job**converter 端會回 409 `user_has_active_job`;前端拿到 409 時 UI 提示「你已有一個轉檔任務正在進行,請等待完成或重新整理」並禁用「開始轉檔」
### F4完成後的半自動結果處理
轉檔狀態變為 `succeeded` 後,頁面顯示:
- 任務摘要(來源檔名、目標 chip、輸出 NEF 大小、checksum
- **兩個並列按鈕**
- **「加到模型庫」**:走 F6 流程
- **「下載」**:走 F7 流程
- 兩個按鈕**互不互斥**(使用者可以兩個都按),按鈕點擊後不消失,可重複觸發
- 提醒「7 天後 converter 會自動清除這個任務請在期限內完成處理」converter Phase 1 已有 7 天 GC 機制)
### F5失敗錯誤訊息
- 狀態變為 `failed` 時顯示**翻譯後**的 user-friendly 錯誤訊息
- 對照表visionA backend 維護,避免暴露 converter 內部訊息):
| converter error code | 顯示給使用者的訊息 |
|---|---|
| `UNSUPPORTED_FORMAT` | 此模型格式目前不支援,請改用 ONNX / TFLite |
| `INVALID_CHECKSUM` | 檔案傳輸過程毀損,請重新上傳 |
| `QUANTIZATION_FAILED` | 模型內含不支援的運算子,無法量化到目標晶片 |
| `MODEL_TOO_LARGE` | 模型超過 500 MB 上限 |
| `QUOTA_EXCEEDED` | 系統暫時繁忙,請稍後再試 |
| 其他 / unknown | 轉檔失敗,請稍後重試。若持續發生請聯絡支援團隊(顯示 job_id 供回報) |
- 失敗任務也顯示 job_id縮短前 8 碼)供使用者報修參考
### F6「加到模型庫」流程
- 前端 → visionA backend `POST /api/conversion/{job_id}/promote-to-models`
- visionA backend
1. 確認 job 屬於該 user 且狀態為 `succeeded`
2. 從 converter 取得 `target_object_key`promote 階段已上 FAA
3. **server-to-server** 從 FAA pull NEF`files:download.read` scope不走 delegated token
4. 走既有 `/api/models/init` + `/api/models/finalize` 三段式流程進模型庫
5.`model.Source = "converted"``model.SourceJobID = <converter job_id>``internal/model.Model` 已預埋此兩欄位,無需擴 schema
- 完成後前端 toast「已加入模型庫」+ 提供連結跳到 `/models/{model_id}`
- 若同一 job 已被加入過模型庫,回 409 並顯示「此任務已加入過,請至模型庫查看」
### F7「下載」流程
- 前端 → visionA backend `GET /api/conversion/{job_id}/download`server-side 302 redirect → FAA
- visionA backend
1. 確認 job 屬於該 user 且狀態為 `succeeded`
2. 跟 Member Center 換 **delegated download token**scope `files:download.delegate`TTL 5 分鐘)
3. 直接回 HTTP 302 Redirect`Location: <FAA-URL>/files/{key}?access_token=<token>`token 不暴露給 frontend JS
- 前端觸發方式:
- 用 anchor tag`<a href="/api/conversion/{job_id}/download" download>`)或 `window.location.href = '/api/conversion/{job_id}/download'`
- Browser 跟著 302 redirect 到 FAA瀏覽器內建下載管理器接手
- 觸發後 browser 內建下載管理器接手(無自訂進度條 — 但因為大檔下載 browser 自己有 UI是合理 trade-off
- **不需要 FAA 加 CORS**server-side 302 redirect + browser navigation 完全不適用 CORSFAA owner 2026-05-02 確認 + FAA TestSite `DownloadFileDirect` 範例驗證)
- Browser **直連 FAA**(透過 302 跳轉),不經 visionA backend 中轉檔案內容,避免 N 次跨 internet 流量
---
## 4. 非功能需求
| 類別 | 需求 |
|---|---|
| 大小上限 | 模型 ≤ 500 MBref image 每張 ≤ 10 MB、總計 ≤ 100 張 |
| 上傳體驗 | 上傳進度條XHR `upload.progress` 事件);上傳期間禁止離開頁面(`beforeunload` warning |
| 並行限制 | 同 user 同時最多 1 個 active jobconverter enforce 409 `user_has_active_job` |
| 任務保留 | 7 天後 converter 自動 GCUI 在結果頁顯示倒數提醒 |
| 安全 | 所有 visionA → converter 的呼叫帶 service account JWT使用者不直接接觸 converter 認證 |
| 可觀測性 | visionA backend log 每個 job 的 lifecyclesubmit、poll status change、import、download token issued |
---
## 5. Non-GoalsPhase 0.8 不做)
| # | 不做的事 | 原因 / 後續 |
|---|---------|-----------|
| N1 | 轉檔歷史清單(`/converter/jobs`| Phase 0.8 只支援「眼前這個 job」不做 listconverter Phase 1 GC 7 天,做歷史也只能看 7 天的CP 值低 |
| N2 | 取消正在跑的 job | converter 已支援 `POST /jobs/{id}/cancel`,但 UX flow 與錯誤狀態複雜,留待 Phase 1 |
| N3 | 多 chip 同時轉檔(一次轉成多個目標)| converter 端尚不支援user 可重複跑 |
| N4 | SSE / WebSocket 進度推送 | polling 已足夠前端複雜度低Phase 1 量大時再評估 |
| N5 | 進階轉檔參數FP16、自訂量化| 預設 INT8足以涵蓋 80% case |
| N6 | 模型版本管理(同來源轉多版)/ A/B 比較 | 與「模型管理 Phase 2」共同規劃 |
| N7 | 轉檔配額計費 | Phase 2 Billing 一併處理 |
| N8 | Webhook push 模式converter → visionA| Phase 0.8 純 pollingwebhook 在 converter Phase 1 已實作但 visionA 暫不接,避免在 stage 環境管理 webhook URL / 簽章 |
---
## 6. 整合決策Phase 0.8 確認)
| # | 議題 | 決策 | 理由 |
|---|------|------|------|
| D1 | Upload 流量路徑 | Browser → visionA backend → converterstreaming proxy| 一次性上傳;不需 converter 改 endpoint保持「user 只認 visionA」單一信任邊界 |
| D2 | Download 流量路徑 | Browser 直連 FAA用 delegated token| 同一 NEF 可能被多 user / 多次下載到 device經 backend 中轉會 N 次跨 internet 燒流量 |
| D3 | 結果處理 | 半自動user 顯式選擇 import / download / 都做)| 避免「user 只是試試」的 NEF 被自動推進模型庫 |
| D4 | 進度更新 | Polling 510 秒一次 | 簡單可靠;轉檔本身耗時 110 分鐘polling 開銷可忽略 |
| D5 | 通訊協定 | converter API 採既有 REST `/api/v1/jobs`,不新增 endpoint | converter 完全不用動 |
| D6 | 進入點 | Sidebar 獨立 tab不混進 `/models` | UX 流程線性、避免「上傳模型」按鈕承載過多分支 |
---
## 7. 整合 Dependency 一覽
| 系統 | Phase 0.8 是否需要動? | 細節 |
|---|---|---|
| **kneron_model_converter** | ❌ 完全不用動 | `POST /api/v1/jobs``GET /api/v1/jobs/{id}``POST /api/v1/jobs/{id}/promote` 全部已實作Phase 1 完成) |
| **File Access Agent (FAA)** | ❌ 完全不用動 | server-side 302 redirect 模式不需要 CORSFAA owner 2026-05-02 確認 + TestSite 範例驗證);既有 `PUT /files/{key}``GET /files/{key}?access_token=`、delegated download token validation 都已實作 |
| **Member Center (MC)** | ⚠️ 確認 visionA service client 4 個 scope 已授權 | `converter:job.write``converter:job.read``files:download.read``files:download.delegate` |
| **visionA-backend** | ✅ 新增 `/api/conversion/*` 路由群 + ConverterClient HTTP 實作 | `internal/model.Model` 已預埋 `Source``SourceJobID`,無需 schema migration |
| **visionA-frontend** | ✅ 新增「轉檔」tab + upload / progress / result 三個畫面 | UI 設計依現有設計系統 |
> 跨團隊 P0/P1 工作項目詳見 `kneron_model_converter/docs/TODO-visionA-integration.md`。
---
## 8. 成功指標KPI
| 指標 | 目標Phase 0.8 | 量測方式 |
|---|---|---|
| 第一個內部使用者轉檔成功率 | > 80% | converter job status 統計succeeded / total |
| 從上傳到拿到 NEF 的 P95 時間 | < 10 分鐘含上傳 + 轉檔 + promote| visionA backend import / download 觸發點 log timestamp |
| 加到模型庫按鈕點擊率 | > 50%(驗證半自動設計合理)| 前端事件埋點 / backend `/promote-to-models` 呼叫次數 |
| 轉檔失敗錯誤訊息可理解率 | 100% 失敗 case 都對應到 §F5 表內訊息 | 失敗 log review |
| Stage 環境每週至少 5 次成功 e2e | — | converter job log 統計 |
---
## 9. 驗收條件Phase 0.8
### 功能驗收
- [ ] 左側 sidebar 顯示「轉檔」tab
- [ ] 可上傳 `.onnx` 模型 + 選 KL720 chip + 0 張 ref image跑通 e2e
- [ ] 可上傳 `.onnx` + KL720 + 5 張 ref imagese2e 成功
- [ ] 上傳進度條正確顯示0% → 100%
- [ ] 轉檔中頁面 polling 正確顯示 `queued` / `running` / `succeeded` 狀態變化
- [ ] 完成頁顯示「加到模型庫」與「下載」兩個按鈕
- [ ] 點「加到模型庫」後 `/models` 頁可看到新模型,標記為「轉檔來源」
- [ ] 點「下載」後 browser 開始下載 NEF檔名合理
- [ ] 同一個 job 可重複按「加到模型庫」(第二次顯示 409 已加入過)
- [ ] 同一個 job 可重複按「下載」拿到新 token
- [ ] 同 user 已有 active job 時submit 第二個 job 顯示 409 提示
- [ ] 上傳 600 MB 檔案被拒(前端先擋 + 後端兜底)
- [ ] 上傳 `.pb`(不支援格式)顯示明確錯誤
- [ ] 轉檔失敗時顯示翻譯後的錯誤訊息 + job_id
### 整合驗收
- [ ] visionA service client 在 MC 已有 4 個 scope人工確認
- [ ] 端到端browser → visionA backend → converter → FAA → browserstage 環境跑通
- [ ] `model.Source="converted"` + `SourceJobID=<job_id>` 正確寫入 DB
- [ ] FAA delegated token TTL 5 分鐘正確;過期後再次點下載拿到新 token
---
## 10. 後續 Phase 規劃Non-Goals 升級路線)
| Phase | 項目 | 說明 |
|---|---|---|
| Phase 1 | 轉檔歷史清單 | 列出該 user 過去 7 天的 jobs配合 converter 提供 `GET /api/v1/jobs?user_id=` |
| Phase 1 | 取消 job | UI 加「取消」按鈕,呼叫 `POST /jobs/{id}/cancel` |
| Phase 1 | 自訂下載進度條 / 暫停恢復 | 改成 visionA backend stream proxy 模式(多一跳但有完整 UI 控制);只在使用者要求時做,目前 browser 內建下載管理器足夠 |
| Phase 1 | Webhook push 進度 | converter → visionA backend webhook用於精確進度與避免 polling 浪費 |
| Phase 2 | 進階參數FP16 / 自訂量化)| converter 暴露更多 knob 後接入 |
| Phase 2 | 多 chip 同時轉 | 一次提交產出多個 NEF |
| Phase 2 | 模型版本管理 | 同來源 ONNX 不同 chip 的多版 NEF 視為同一邏輯模型的 variant |
| Phase 2 | 轉檔配額 / Billing | 與 Billing feature 一併處理 |
---
## 11. 給 Architect / Design 的注意事項
- **Architect**
- visionA backend 需新增 `internal/converter/` 套件實作 `HTTPConverterClient`(取代 Phase 0 的 Stub
- 上傳要走 streaming proxy`io.Copy` + `multipart.Reader`**不可 buffer 全 RAM、不可寫 disk**
- polling 端點 `/api/conversion/{job_id}` 要做 user-scoped 授權檢查
- promote-to-models 流程要 idempotent同 job 重複呼叫不重複建模型)
- **Design**
- 轉檔 tab 的 wireframeupload → progress → result需獨立設計
- 失敗狀態的視覺處理(顏色 / icon參考既有錯誤模式
- 「加到模型庫」與「下載」兩個按鈕的視覺平衡(不要讓使用者覺得有預設答案)
- 進度條設計要區分「上傳階段」0100% 精確)與「轉檔階段」(不確定百分比)
---
## 12. 連結
- 回:[PRD 索引](../PRD.md)
- 相關:[模型管理](feature-model-management.md)、[介面契約](../interface-contracts.md)
- 跨專案:`kneron_model_converter/docs/TODO-visionA-integration.md``kneron_model_converter/apps/task-scheduler/docs/openapi.yaml`