# Feature:模型管理(P0) > 父文件:[PRD.md](../PRD.md) | 對應 User Stories:US-08、US-09、US-23 --- ## 概述 使用者能瀏覽系統預設的 7 個 Kneron `.nef` 模型,上傳自己的模型,管理模型庫。 對比 local-tool: - local-tool 的模型存在使用者電腦 `~/Library/Application Support/visiona-local/custom-models/` - visionA Cloud 的模型**存在雲端**(Phase 0 用 local filesystem 實作 ObjectStorage 介面,Phase 1 換 S3/MinIO) --- ## 使用者行為 ### 模型庫頁(`/models`) UI 沿用 local-tool,但資料來源改為 visionA-backend。 **三個區塊**: 1. **預設模型**(系統共用,所有使用者都能用) - 7 個預置模型(KL520 × 4 + KL720 × 3) - Phase 0:seed 到 backend 的 local fs - Phase 1:seed 到 S3 的 `public/` prefix 2. **我的模型**(使用者上傳的) - 空狀態顯示 CTA「上傳模型」 - 每個模型顯示:名稱、大小、上傳時間、支援硬體、上傳者 3. **組織模型**(Phase 2,留介面) - 如果使用者在團隊 workspace,能看到團隊共享模型 **篩選**:按任務類型(classification / object_detection)、硬體(KL520 / KL720)、關鍵字。 ### 上傳模型 1. 點「上傳模型」→ 拖拽 or 選檔 2. 檔案類型:`.nef` 3. 檔案大小限制:**Phase 0 上限 100MB;Phase 1 上限 500MB(後續依付費方案調整)** - 此限制必須落在 config(env var 或 config file),**不可硬編碼**,方便跨 Phase 調整 - 建議 config key:`MODEL_UPLOAD_MAX_SIZE_MB`(預設 100) - 前端與後端都要同步使用這個值(前端顯示錯誤提示、後端做實際拒絕) 4. 上傳進度 bar 5. 後端儲存到 ObjectStorage 介面實作 6. 上傳完成後解析 metadata(檔案 header) 7. Phase 0:metadata 存 in-memory map;Phase 1:存 DB ### 模型詳細頁(`/models/[id]`) - 基本資訊:名稱、ID、大小、MD5 - 支援硬體(KL520 / KL720) - Metadata(輸入尺寸、任務類型) - 效能數據(推論 FPS、延遲)— Phase 0 預設模型有,自上傳的沒有 - 下載按鈕(重新下載到本機) - 刪除按鈕(只對自上傳模型) --- ## 技術細節(給 Architect 參考) ### ObjectStorage 介面(重點) Phase 0 要定義清楚介面,讓 Phase 1 可直接換 S3/MinIO 不動業務邏輯。 ```go // internal/storage/storage.go type ObjectStorage interface { Upload(ctx context.Context, key string, reader io.Reader, size int64) error Download(ctx context.Context, key string) (io.ReadCloser, error) Delete(ctx context.Context, key string) error List(ctx context.Context, prefix string) ([]ObjectInfo, error) // Phase 1:presigned URL GetDownloadURL(ctx context.Context, key string, expiresIn time.Duration) (string, error) GetUploadURL(ctx context.Context, key string, expiresIn time.Duration) (string, error) } type ObjectInfo struct { Key string Size int64 LastModified time.Time ETag string } ``` **Phase 0 實作:`LocalFSStorage`** - 存在 `./data/models/{user_id}/{model_id}.nef` - `GetDownloadURL` 回傳 `/api/models/{id}/download`(走 api-server 串流) **Phase 1 實作:`S3Storage`** - 用 AWS SDK 或 minio-go - `GetDownloadURL` / `GetUploadURL` 回傳真的 presigned URL ### 上傳大檔案策略 - Phase 0:Multipart form upload 直接進 api-server,api-server 再寫進 local fs - 限制:100MB 以下 - api-server 的記憶體與磁碟 I/O 壓力 - Phase 1:前端直接用 presigned URL 上傳到 S3,不過 api-server - 需要 CORS 設定 - 上傳完成後通知 api-server 更新 metadata ### 預設模型 seed Phase 0:backend 啟動時,檢查 `data/models/system/` 是否有預設模型,沒有就從 bundled resources 複製過去。 Phase 1:預設模型在 `s3://visiona-models/system/` 共享給所有 user。 --- ## 驗收條件(Phase 0) - [ ] `/models` 頁面顯示 7 個預設模型 - [ ] 不同使用者看到自己的「我的模型」,互相隔離 - [ ] 上傳 `.nef` 檔成功,出現在列表 - [ ] 上傳進度 bar 顯示正確 - [ ] 上傳 > 100MB 被拒絕,回傳明確錯誤(Phase 0 限制值) - [ ] 上傳大小限制從 config(`MODEL_UPLOAD_MAX_SIZE_MB`,預設 100)讀取,非硬編碼 - [ ] 前端顯示的大小限制與後端實際拒絕的值一致 - [ ] 上傳非 `.nef` 檔被拒絕 - [ ] 能下載已上傳的模型 - [ ] 能刪除自上傳的模型,不能刪預設模型 - [ ] ObjectStorage 介面定義完整(有 interface + LocalFSStorage 實作) - [ ] 介面層面預留 S3 實作的 hook,切換時不動業務邏輯 --- ## Phase 0 的 TODO - **TODO 1**:presigned URL 上傳(Phase 1) - **TODO 2**:模型版本管理(Phase 2) - **TODO 3**:模型標籤 / 搜尋增強(Phase 2) - **TODO 4**:團隊共享模型(Phase 2) - **TODO 5**:模型來源追蹤(是轉檔來的還是使用者上傳的,Phase 2) - **TODO 6**:效能數據收集(推論時自動紀錄 FPS / 延遲,Phase 1) --- ## 連結 - 回:[PRD 索引](../PRD.md) - 相關:[介面契約 — ObjectStorage](../interface-contracts.md)、[轉檔整合](feature-converter-integration.md)