visionA/docs/autoflow/04-architecture/api/api-converter-contract.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

7.4 KiB
Raw Blame History

Converter Integration Contract

本文件定義 visionA-backend 呼叫 kneron_model_converter 的 API 契約。 目的:提前把介面定義清楚,讓 converter 團隊知道要實作什麼;同時讓 visionA-backend 雛形可先用 stub 開發。


1. 通訊方向

visionA-backend/api-server            kneron_model_converter
       │                                      │
       │ 1. POST /v1/jobs提交轉檔         │
       │ ────────────────────────────────────►│
       │                                      │
       │ ◄────── 202 + {job_id} ──────────────│
       │                                      │
       │ 2. GET /v1/jobs/{id}(輪詢 / 或等 webhook
       │ ────────────────────────────────────►│
       │ ◄────── 200 + {status, result_url}──│
       │                                      │
       │ 3. 下載產物GET result_url          │
       │ ────────────────────────────────────►│

Converter 可選:

  • Pull 模式visionA 輪詢 /v1/jobs/{id}
  • Push 模式visionA 提供 webhook URLconverter 完成後回呼

雛形先用 Pull 模式Phase 1 評估 webhook。


2. 認證

visionA → converter

  • 服務對服務,使用 API Key 或 mTLS
  • HeaderAuthorization: Bearer <VISIONA_CONVERTER_API_KEY>

API Key 由 converter 團隊簽發,放 VISIONA_CONVERTER_API_KEY env。


3. 端點

3.1 POST /v1/jobs — 提交轉檔

Request

POST /v1/jobs
Authorization: Bearer ...
Content-Type: application/json

{
  "source": {
    "type": "url",
    "url": "https://storage.visiona.cloud/converter/source/demo-user/job-xxx.onnx?signature=...",
    "checksum_sha256": "abc123...",
    "format": "onnx"
  },
  "target": {
    "chip": "kl520",
    "quantization": "int8",
    "input_shape": [1, 3, 224, 224]
  },
  "callback": {
    "webhook_url": null,     // 雛形先 null
    "idempotency_key": "<uuid>"
  },
  "client_job_id": "<visionA 這邊的 job id對應 converter_jobs.id>"
}

欄位說明

欄位 必要 說明
source.type "url" | "upload"(雛形只支援 url
source.url Presigned GET URLconverter 自己下載
source.checksum_sha256 visionA 計算好的 sha256converter 下載後驗證
source.format "onnx" | "keras" | "tflite" | ...
target.chip "kl520" | "kl720"
target.quantization "int8" | "fp16",預設依 chip
target.input_shape 若 source 不含 shape由此補
callback.webhook_url 未來 push 模式
callback.idempotency_key 重試時避免重複執行
client_job_id visionA 內部 job idconverter 回傳時要帶上

Response 202

{
  "success": true,
  "data": {
    "job_id": "cvt-abc-123",     // converter 側的 id
    "status": "queued",
    "accepted_at": "2026-04-21T12:00:00Z",
    "estimated_duration_seconds": 120
  }
}

Response 錯誤

{
  "success": false,
  "error": {
    "code": "UNSUPPORTED_FORMAT" | "INVALID_CHECKSUM" | "SOURCE_UNREACHABLE" | "QUOTA_EXCEEDED",
    "message": "..."
  }
}

3.2 GET /v1/jobs/{job_id} — 查詢狀態

Response 200

{
  "success": true,
  "data": {
    "job_id": "cvt-abc-123",
    "client_job_id": "<visionA 的>",
    "status": "queued" | "running" | "succeeded" | "failed",
    "progress": 0.65,           // 0.0 - 1.0
    "stage": "quantizing",      // 可選
    "accepted_at": "...",
    "started_at": "...",
    "completed_at": "...",

    "result": {                 // status == succeeded 時才有
      "url": "https://converter.cloud/result/....nef?signature=...",
      "url_expires_at": "...",
      "checksum_sha256": "...",
      "size_bytes": 12345678,
      "target_chip": "kl520"
    },

    "error": {                  // status == failed 時才有
      "code": "QUANTIZATION_FAILED",
      "message": "Layer ... not supported",
      "details": {}
    }
  }
}

3.3 POST /v1/jobs/{job_id}/cancel — 取消

Response

{ "success": true, "data": { "job_id": "...", "status": "cancelled" } }

若已 completed → 400 ALREADY_COMPLETED;若 already cancelled → 200 idempotent。


3.4 Webhook未來

Converter push 到 visionA 的 webhook URL

Requestconverter → visionA

POST https://api.visiona.cloud/webhooks/converter
X-Converter-Signature: sha256=<hmac of body using shared secret>
Content-Type: application/json

{
  "event": "job.completed" | "job.failed",
  "job_id": "cvt-abc-123",
  "client_job_id": "<visionA 的>",
  "status": "succeeded" | "failed",
  "result": { ... },
  "error": { ... },
  "timestamp": "..."
}

visionA 驗證 signature 後

  • 更新 converter_jobs
  • 若 succeeded下載產物存到 storage/converter/result/
  • 建立對應的 models recordsource=converted, source_job_id=<client_job_id>
  • 回 200

retry 約定

  • Webhook 失敗 converter 最多重試 5 次,指數退避
  • visionA 必須 idempotent 處理(用 event + job_id 當 key

4. 雛形階段visionA 端 stub

// internal/converter/stub.go
type StubClient struct {
    jobs map[string]*Job
    mu   sync.Mutex
}

func (s *StubClient) SubmitConvert(ctx, req) (string, error) {
    s.mu.Lock()
    defer s.mu.Unlock()
    jobID := "stub-job-" + uuid.NewString()
    s.jobs[jobID] = &Job{
        ID: jobID, Status: "queued", CreatedAt: time.Now(),
        TargetChip: req.TargetChip,
    }
    // 雛形15 秒後「完成」,指向假 result URL
    time.AfterFunc(15*time.Second, func() {
        s.mu.Lock()
        defer s.mu.Unlock()
        if j, ok := s.jobs[jobID]; ok {
            j.Status = "succeeded"
            j.ResultKey = "stub-result-key"
            j.CompletedAt = ptrTime(time.Now())
        }
    })
    return jobID, nil
}

雛形期前端可以用這個 stub 走完整 UX但不會真的產生 .nef


5. Error 對應表

Converter 回傳 visionA 前端顯示
UNSUPPORTED_FORMAT 「目前不支援此格式」
INVALID_CHECKSUM 「檔案下載驗證失敗,請重新上傳」
QUOTA_EXCEEDED 「本月轉檔配額已滿」
QUANTIZATION_FAILED 「模型轉檔失敗:[detail]」
其他 「轉檔失敗,請聯絡支援」

6. 相容性 / 版本

  • URL 含 /v1/ 前綴,日後升級 /v2/ 可並存
  • 欄位採「新增只是 optional」原則不破壞舊版
  • visionA 用 env VISIONA_CONVERTER_API_VERSION 切換(預設 v1

7. 給 Converter 團隊的確認清單

  • 同意採用此 API spec
  • 確認 source.type "url" 的 presigned URL 長度 / TTL 要求
  • 確認支援的 source format 清單
  • 確認 webhook push 模式的實作意願 / 時程
  • 確認 rate limit / quota 政策
  • 確認產物儲存位置converter 自己的 bucket還是回 visionA bucket
  • 提供測試 API key

雛形實作internal/converter/stub.go + 前端走 stub 驗流程。 Phase 1internal/converter/http.go 實作上述 API + webhook endpoint。