Skip to content

Starsoup Image Platform (SIP) — 主文件

版本: 0.2 日期: 2026-03-24 狀態: 遷移進行中


目錄

  1. 產品定義
  2. 現有技術棧(遷移後)
  3. 當前問題清單
  4. 後端遷移計劃
  5. 前端修復計劃
  6. 目標架構
  7. 核心數據結構(SIP 特有)
  8. 開發 Phase 計劃
  9. 待確認事項

一、產品定義

項目名稱

Starsoup Image Platform(代號:sip

定位

一個自托管的 AI 輔助圖片自動化平台,核心由三層組成:

【Layer 0】AI 素材生成(SIP 內建,從 Jaaz 遷移)
  └─→ 連接 OpenAI / Anthropic / Ollama / ComfyUI 等供應商
  └─→ 在畫布上生成水晶背景圖、商品去背圖等素材

【Layer 1】Template Studio(SIP 新增功能)
  └─→ 在生成的背景圖上,視覺化定義 zones(文字插槽 / 圖片插槽)
  └─→ 設定每個 zone 的字體、顏色、尺寸、位置
  └─→ 即時預覽效果,存入 Supabase

【Layer 2】Render API(SIP 新增服務)
  └─→ 接收 { templateId, data }
  └─→ 合成背景圖 + zones → 輸出 PNG
  └─→ 返回圖片 URL,供 @crystal/erp、@crystal/ec 等項目直調

與現有 SaaS 的差異

功能Bannerbear / PlacidSIP
AI 素材生成✅ 內建(多供應商)
視覺化模版編輯✅ 雲端✅ 自建
程式化渲染 API✅ 自建
自托管
費用$49/月起 + 渲染費Vercel + R2 成本

二、現有技術棧(遷移後)

前端(已遷移自 Jaaz)

類別技術
框架Vue 3(Composition API + <script setup>
構建Vite 8
語言TypeScript 5.9
路由Vue Router 4
狀態管理Pinia 3
樣式Tailwind CSS 4
畫布Fabric.js 7
即時通訊Socket.IO Client 4
國際化vue-i18n 10

後端(目前問題所在)

現狀目標
Jaaz 的 FastAPI(Python)jaaz/server/獨立 Python FastAPI,不依賴 Jaaz repo
硬綁定 http://localhost:57988可配置,支持 Vercel / Docker 部署
認證耦合 jaaz.app 雲端設備流程改為本地 API Key 配置,去除 Jaaz 帳戶依賴

新增技術(Layer 1 & 2,待開發)

技術用途授權
vue-konva / Konva.jsTemplate Studio zone 編輯器MIT
HonoRender API serverMIT
Satori(Vercel)HTML/CSS → SVG 渲染引擎Apache 2.0
@resvg/resvg-jsSVG → PNG 轉換Apache 2.0
Supabase JS模版資料庫MIT
Cloudflare R2圖片儲存商業服務
Google Fonts / Noto TC中文字體(OFL,可商用)OFL 1.1

三、當前問題清單

從 README 和你描述的情況,整理出以下問題,按優先級排序:

P0:服務完全無法啟動

#問題根因
P0-1所有 API 呼叫返回 502前端指向 localhost:57988,但後端(Jaaz Python server)未在本機運行
P0-2WebSocket 連線失敗Socket.IO 無法連上 localhost:57988

P1:功能缺失

#問題根因
P1-1新建模型無法選擇模型名稱模型列表 API(/api/models)返回失敗或空值
P1-2測試連接無法成功供應商配置 API 依賴後端轉發,後端未啟動
P1-3畫布資產無法讀取媒體資源 API(/api/assets)無回應
P1-4畫布操作失敗畫布 CRUD(/api/canvas)無回應

P2:架構依賴問題

#問題影響
P2-1認證流程依賴 jaaz.app 雲端離線或 Jaaz 服務中斷即失效
P2-2後端仍在 Jaaz repo,非獨立服務無法獨立部署,版本升級有衝突風險
P2-3VITE_JAAZ_CLOUD_URL 硬編碼 jaaz.app無法完全去除 Jaaz 品牌依賴

四、後端遷移計劃(核心任務)

這是解決所有 P0/P1 問題的根本。目標是把 Jaaz 的 FastAPI 後端剝離出來,變成 SIP 自己的後端服務。

Step 1:在本機先讓現有後端跑通(臨時方案)

在找到 Jaaz repo 的情況下,先讓服務跑起來,確認前端哪些端點能通、哪些不通:

bash
# 在 jaaz/server/ 目錄
pip install -r requirements.txt
python main.py --port 57988

確認以下端點是否正常回應:

  • GET /api/models → 模型列表
  • GET /api/tools → 工具列表
  • POST /api/config → 供應商配置
  • GET /api/canvas → 畫布列表
  • POST /api/canvas → 新建畫布
  • GET /api/assets → 資產列表
  • POST /api/upload → 圖片上傳
  • POST /api/chat → 聊天發送
  • WS /socket.io/ → WebSocket

Step 2:建立 SIP 獨立後端

建立新的後端項目,不依賴 Jaaz repo:

sip-server/                  ← 新建,SIP 自己的後端
  main.py
  routers/
    canvas.py
    chat.py
    config.py
    models.py
    assets.py
    upload.py
  services/
    llm_service.py           ← 多供應商 LLM 呼叫(從 Jaaz 移植)
    image_service.py         ← 圖片生成(從 Jaaz 移植)
    socket_service.py        ← WebSocket(從 Jaaz 移植)
  models/
    schemas.py
  storage/
    local.py                 ← 本地檔案儲存(開發用)
    r2.py                    ← Cloudflare R2(生產用)
  requirements.txt
  .env.example

從 Jaaz 移植的核心邏輯:

Jaaz 原始文件SIP 對應位置移植難度
server/services/llm_service.pysip-server/services/llm_service.py低(直接複製,去除 Jaaz 帳戶 token 邏輯)
server/routers/chat_router.pysip-server/routers/chat.py
server/routers/config_router.pysip-server/routers/config.py
server/routers/canvas_router.pysip-server/routers/canvas.py中(儲存層需替換)
server/socket_manager.pysip-server/services/socket_service.py
server/routers/upload_router.pysip-server/routers/upload.py中(改為 R2)

Step 3:認證去耦

現有的設備授權流程完全依賴 jaaz.app,對 SIP 來說是不必要的外部依賴。

目標方案:移除設備授權流程,改為純 API Key 配置模式:

用戶在 Settings 中配置各供應商 API Key
  → 存入 localStorage(前端)/ .env(後端)
  → 無需任何帳戶登錄

前端需修改:

  • src/api/auth.ts — 移除設備授權流程
  • src/components/auth/ — 移除登錄對話框,或改為「輸入 API Key」的簡化介面
  • src/composables/useAuth.ts — 簡化為「是否已配置至少一個供應商」的狀態
  • src/stores/configs.ts — 移除 Jaaz token 相關欄位

Step 4:供應商列表修復(解決 P1-1 模型名稱無法選擇)

這個問題最常見的原因是:前端呼叫 /api/models 取得模型列表時,後端需要先知道你配置了哪個供應商,才能返回對應的模型名稱。

後端 GET /api/models?provider=openai 應返回:

json
{
  "models": [
    { "id": "gpt-4.1", "name": "GPT-4.1", "type": "text" },
    { "id": "gpt-4o-mini", "name": "GPT-4o Mini", "type": "text" },
    { "id": "dall-e-3", "name": "DALL-E 3", "type": "image" }
  ]
}

如果後端無法動態查詢,可先改為前端靜態模型列表,在 src/constants/ 中硬編碼各供應商的已知模型名稱,待後端穩定後再改回動態查詢。


五、前端修復計劃

後端跑通後,前端需要做以下修復:

5.1 環境變數整理

新增 .env.example

env
# 後端 API 地址
VITE_API_BASE_URL=http://localhost:57988

# 去除 Jaaz 雲端依賴(Step 3 完成後可留空)
VITE_JAAZ_CLOUD_URL=

# Supabase(Layer 1 Template Studio 啟用後填入)
VITE_SUPABASE_URL=
VITE_SUPABASE_ANON_KEY=

# Cloudflare R2(Layer 2 Render API 啟用後填入)
VITE_R2_PUBLIC_URL=

5.2 API 層統一錯誤處理

目前 src/api/ 各文件的錯誤處理分散,建議在 src/lib/http.ts 建立統一的 fetch wrapper:

typescript
// src/lib/http.ts
const BASE = import.meta.env.VITE_API_BASE_URL

export async function apiFetch<T>(
  path: string,
  options?: RequestInit
): Promise<T> {
  const res = await fetch(`${BASE}${path}`, {
    headers: { 'Content-Type': 'application/json' },
    ...options,
  })
  if (!res.ok) {
    const error = await res.text()
    throw new Error(`[${res.status}] ${path}: ${error}`)
  }
  return res.json()
}

5.3 路由新增(Layer 1 Template Studio)

在現有路由基礎上新增:

typescript
// src/router/index.ts 新增
{
  path: '/templates',
  name: 'TemplateList',
  component: () => import('../views/TemplateListView.vue'),
},
{
  path: '/templates/:id/edit',
  name: 'TemplateEditor',
  component: () => import('../views/TemplateEditorView.vue'),
},

5.4 導航欄新增入口

src/components/common/ 的頂部導航欄中新增「Templates」入口,與現有的 Assets、Knowledge 同層級。


六、目標架構

遷移完成後,SIP 的完整架構如下:

starsoup-image-platform/
  ├── src/                         ← Vue 前端(現有,已遷移自 Jaaz)
  │   ├── views/
  │   │   ├── HomeView.vue
  │   │   ├── CanvasView.vue       ← AI 生圖(Layer 0)
  │   │   ├── TemplateListView.vue ← 新增(Layer 1)
  │   │   ├── TemplateEditorView.vue ← 新增(Layer 1,vue-konva)
  │   │   ├── AgentStudioView.vue
  │   │   ├── AssetsView.vue
  │   │   └── KnowledgeView.vue
  │   └── ...

  ├── sip-server/                  ← Python FastAPI 後端(從 Jaaz 剝離)
  │   ├── main.py
  │   ├── routers/
  │   ├── services/
  │   └── requirements.txt

  ├── render-api/                  ← Hono + Satori 渲染 API(新增,Layer 2)
  │   ├── src/
  │   │   ├── renderer/
  │   │   │   ├── satori.ts
  │   │   │   └── compositor.ts
  │   │   └── index.ts             ← Hono app
  │   └── package.json

  └── supabase/                    ← DB schema migrations
      └── migrations/

部署拓撲

Cloudflare R2
  ├── templates/backgrounds/       ← 背景底圖(AI 生成後上傳)
  └── generated/                   ← Render API 輸出

Vercel(前端)
  └── starsoup-image-platform      ← Vue 前端

Vercel / Railway(後端)
  ├── sip-server(Python FastAPI) ← 現有功能的後端
  └── render-api(Hono)           ← Layer 2 渲染服務

Supabase
  └── templates table              ← 模版 JSON 定義

七、核心數據結構(SIP 特有)

以下是 Layer 1 & 2 的新增數據結構,與現有 Jaaz 功能互不干涉。

Template JSON Schema

typescript
interface Template {
  id: string
  name: string
  width: number           // 例如 1080
  height: number          // 例如 1080
  background_url: string  // R2 URL
  zones: Zone[]
  project_id?: string     // 多項目隔離(未來用)
  created_at: string
  updated_at: string
}

interface Zone {
  id: string              // 對應 Render API 的 data key
  type: 'text' | 'image'
  x: number
  y: number
  width: number
  height: number
  // text zone
  font_family?: string    // 例如 "Noto Serif TC"
  font_size?: number
  font_weight?: string    // "400" | "700"
  color?: string          // hex,例如 "#2D1B4E"
  align?: 'left' | 'center' | 'right'
  line_height?: number
  max_lines?: number
  prefix?: string         // 例如 "¥"
  // image zone
  border_radius?: number
  object_fit?: 'cover' | 'contain' | 'fill'
}

Supabase Tables

sql
CREATE TABLE templates (
  id            TEXT PRIMARY KEY,
  name          TEXT NOT NULL,
  width         INT NOT NULL,
  height        INT NOT NULL,
  background_url TEXT NOT NULL,
  zones         JSONB NOT NULL DEFAULT '[]',
  project_id    TEXT,
  created_at    TIMESTAMPTZ DEFAULT NOW(),
  updated_at    TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE render_logs (
  id            UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  template_id   TEXT REFERENCES templates(id),
  caller        TEXT,         -- 例如 "crystal-erp"
  image_url     TEXT,
  rendered_at   TIMESTAMPTZ DEFAULT NOW()
);

Render API Contract

POST /v1/render
Authorization: Bearer <sip-internal-key>

Request Body:
{
  "template_id": "crystal-detail-1x1",
  "data": {
    "product_image": "https://r2.../amethyst.jpg",
    "crystal_name": "天然紫水晶原石",
    "price": "3,800",
    "description": "來自烏拉圭深礦..."
  }
}

Success Response (200):
{
  "image_url": "https://r2.../generated/uuid.png",
  "template_id": "crystal-detail-1x1",
  "rendered_at": "2026-03-24T10:00:00Z"
}

八、開發 Phase 計劃

Phase 0:現有功能跑通(當前優先)

目標:解決所有 P0/P1 問題,讓從 Jaaz 遷移過來的功能完全正常運作。

  • [ ] 建立 sip-server/,從 Jaaz 剝離後端代碼
  • [ ] 修復 502:確保 sip-serverlocalhost:57988 正常啟動
  • [ ] 修復模型名稱無法選擇:GET /api/models 正確返回模型列表
  • [ ] 修復測試連接:POST /api/config/test 正確轉發供應商 API
  • [ ] 修復 WebSocket:Socket.IO 連線穩定
  • [ ] 修復畫布 CRUD:新建、讀取、保存畫布正常
  • [ ] 修復資產管理:圖片上傳、瀏覽正常
  • [ ] 去除 jaaz.app 設備認證依賴(改為純 API Key 配置)
  • [ ] 更新 .env.example,整理環境變數

Phase 1:Layer 1 Template Studio

目標:在 SIP 內建立視覺化模版編輯器。

  • [ ] 安裝 vue-konva、Supabase JS
  • [ ] 建立 TemplateListView.vue(模版列表 + 新建入口)
  • [ ] 建立 TemplateEditorView.vue(主編輯器)
    • [ ] 從 R2 載入背景圖至 Konva canvas
    • [ ] 拖拽新增 text zone / image zone
    • [ ] Zone 樣式面板(字體、顏色、字號、對齊)
    • [ ] 即時預覽(canvas 直接顯示樣式)
    • [ ] 存入 Supabase
  • [ ] 導航欄新增 Templates 入口

Phase 2:Layer 2 Render API

目標:建立程式化圖片生成服務,供 ERP/EC 直調。

  • [ ] 建立 render-api/(Hono + TypeScript)
  • [ ] 整合 Satori + @resvg/resvg-js
  • [ ] 嵌入 Noto Serif TC / Noto Sans TC 字體
  • [ ] 實現 POST /v1/render 端點
    • [ ] 從 Supabase 取 template JSON
    • [ ] 從 R2 取背景圖(base64)
    • [ ] Satori 渲染合成
    • [ ] PNG 上傳 R2,返回永久 URL
  • [ ] 部署至 Vercel(獨立 project)
  • [ ] @crystal/erp 整合呼叫測試

Phase 3:Starsoup 化(未來)

  • [ ] 多項目隔離(project_id
  • [ ] API Key 管理
  • [ ] 渲染統計後台
  • [ ] 懶人包長圖支援

九、待確認事項

Q1sip-server 你有 Jaaz 的完整 repo 可以參照移植嗎?還是需要從頭重寫後端?

Q2:Template Studio(/templates)是獨立頁面,還是要整合進現有的 CanvasView 工作流?(例如:在畫布上完成 AI 生圖後,直接有「存為模版」按鈕)

Q3:Phase 0 的後端,先在本機跑(Python),還是直接目標部署到 Railway / Vercel?

Q4:Supabase 使用現有 ERP 的 Supabase project,還是為 SIP 建立獨立的 project?


本文件合併自 SIP 產品定義文件(v0.1)與遷移技術分析,Phase 0 完成後升版至 v0.3。