# 使用現有模板生成 — API 教學 > 本文件只涵蓋「套用既有模板生成圖片」這個流程:查詢模板 → 上傳 1 張人物/參考圖 → 取得輸出圖。 > 若要建立/編輯/刪除模板,或使用不套模板的直接生成,請參考 [api-guide.md](api-guide.md)。 --- ## 基本資訊 | 項目 | 內容 | |------|------| | Base URL | `http://localhost:8067` | | 協定 | HTTP/1.1 | | 認證 | 無(內部服務,建議部署在內網) | | 圖片上傳格式 | `multipart/form-data`,支援 `image/jpeg`、`image/png`、`image/webp` | | 回應格式 | `application/json`,編碼 UTF-8 | | 生圖等待時間 | 約 **10 ~ 30 秒** | 模板的概念:每個模板已經固定好「目標模板/畫布」圖片 + 提示詞(+選填的負面提示詞/固定 seed)。 呼叫端只需要提供 `template_id` 和 1 張「人物/參考」圖片,其餘全部由模板決定,不需要也不能傳入 `prompt`、`negative_prompt` 等欄位。 --- ## 完整流程 ``` 1. 查詢模板列表,取得 template_id ↓ 2. 上傳使用者的人物/參考圖片,呼叫套用模板 API(同一個請求完成生成) ↓ 3. 解析回應,取得輸出圖片網址 ↓ 4. 下載圖片(GET 該網址) ``` --- ## 1. 查詢模板列表 ``` GET /api/templates ``` 取得目前所有可用模板,包含每個模板的固定參考圖。 **回應範例:** ```json [ { "id": 3, "name": "ESG-女", "prompt": "使用圖2作為人物身份參考,使用圖1作為目標模板。將圖2中人物融合到圖1中...", "negative_prompt": "", "fixed_seed": 937239937275129, "created_at": "2026-07-13T07:18:31.254965+00:00", "inputs": [ { "id": 3, "filename": "ff29804b-a8d6-494b-aec6-8a1d3afd8be4.png", "original_name": "圖片 1-女.png", "display_order": 0, "url": "/uploads/inputs/ff29804b-a8d6-494b-aec6-8a1d3afd8be4.png", "thumb_url": "/uploads/thumbs_in/ff29804b-a8d6-494b-aec6-8a1d3afd8be4.jpg" } ] } ] ``` **欄位說明:** | 欄位 | 型別 | 說明 | |------|------|------| | `id` | int | 模板 ID,套用生成時需要用到 | | `name` | string | 模板名稱 | | `prompt` | string | 模板內建的提示詞(自動帶入,不需另外傳) | | `fixed_seed` | int \| null | 若不為 `null`,代表每次套用都固定用這個 seed;為 `null` 則每次隨機 | | `inputs[0].url` | string | 模板固定圖片的完整路徑(接在 Base URL 後即可存取) | | `inputs[0].thumb_url` | string | 縮圖路徑(400×400 JPEG,適合列表預覽用) | 若只是想確認單一模板的內容,也可以直接查: ``` GET /api/templates/{template_id} ``` --- ## 2. 套用模板生成 ⭐ 核心端點 ``` POST /api/templates/{template_id}/generate Content-Type: multipart/form-data ``` **請求參數:** | 欄位 | 類型 | 必填 | 說明 | |------|------|------|------| | `image` | File | ✅ | 使用者的人物/參考圖片,支援 JPG / PNG / WEBP | | `seed` | int | 選填 | `0` ~ `9223372036854775807`;若模板有設定 `fixed_seed`,一律以模板的為準,此欄位會被忽略 | > ⚠️ **注意**:`prompt`、`negative_prompt` 等欄位全部由模板內部決定,呼叫端不需要也不能傳入。 **成功回應(HTTP 200):** ```json { "id": 15, "prompt": "使用圖2作為人物身份參考,使用圖1作為目標模板...", "size": "auto", "n": 1, "status": "completed", "error_message": null, "request_id": "bc04273d-41be-404f-8980-d87412d53253", "duration_ms": 10860, "model": "flux2-klein-edit", "negative_prompt": "", "seed": 937239937275129, "created_at": "2026-07-13T06:53:06.572813+00:00", "inputs": [ { "id": 3, "filename": "64d....jpg", "original_name": "user_photo.jpg", "url": "/uploads/inputs/64d....jpg", "thumb_url": "/uploads/thumbs_in/64d....jpg" }, { "id": 4, "filename": "f2f....jpg", "original_name": "canvas.jpg", "url": "/uploads/inputs/f2f....jpg", "thumb_url": "/uploads/thumbs_in/f2f....jpg" } ], "outputs": [ { "id": 2, "filename": "a9dd869d-4ea6-4c0f-94a9-2307b3bc8a38.png", "url": "/uploads/outputs/a9dd869d-4ea6-4c0f-94a9-2307b3bc8a38.png", "thumb_url": "/uploads/thumbs/a9dd869d-4ea6-4c0f-94a9-2307b3bc8a38.jpg" } ] } ``` **輸出圖片取得方式:** ``` outputs[0].url = "/uploads/outputs/a9dd869d-....png" 完整下載網址 = http://localhost:8067/uploads/outputs/a9dd869d-....png ``` **錯誤回應:** | HTTP 狀態碼 | 情況 | |-------------|------| | `400` | 未上傳圖片、圖片格式不支援、或 `seed` 超出範圍 | | `404` | 指定的 `template_id` 不存在 | | `502` | ComfyUI 回應錯誤,或生成結果解析失敗 | | `504` | ComfyUI 執行逾時(預設輪詢上限 180 秒) | 錯誤回應格式: ```json { "detail": "錯誤原因說明" } ``` --- ## 程式碼範例 ### Python(requests) ```python import requests BASE_URL = "http://localhost:8067" # Step 1:查詢模板列表,取得 template_id templates = requests.get(f"{BASE_URL}/api/templates").json() template_id = templates[0]["id"] # 選擇第一個模板 print(f"使用模板:{templates[0]['name']} (ID: {template_id})") # Step 2:上傳人物/參考圖片並生成 with open("user_photo.jpg", "rb") as f: response = requests.post( f"{BASE_URL}/api/templates/{template_id}/generate", files={"image": ("user_photo.jpg", f, "image/jpeg")}, timeout=120, # 生圖最長等 120 秒 ) response.raise_for_status() data = response.json() # Step 3:取得輸出圖片並下載 if data["status"] == "completed" and data["outputs"]: output_url = BASE_URL + data["outputs"][0]["url"] print(f"生圖成功,耗時:{data['duration_ms']}ms,seed={data['seed']}") img_data = requests.get(output_url).content with open("result.png", "wb") as f: f.write(img_data) print("圖片已儲存為 result.png") else: print(f"生圖失敗:{data.get('error_message')}") ``` ### JavaScript(fetch / 瀏覽器) ```javascript const BASE_URL = 'http://localhost:8067'; async function generateFromTemplate(templateId, imageFile) { const formData = new FormData(); formData.append('image', imageFile); // imageFile 為 File 或 Blob 物件 const response = await fetch( `${BASE_URL}/api/templates/${templateId}/generate`, { method: 'POST', body: formData } ); if (!response.ok) { const err = await response.json(); throw new Error(err.detail || `HTTP ${response.status}`); } const data = await response.json(); const outputUrl = BASE_URL + data.outputs[0].url; console.log(`生圖成功,耗時 ${data.duration_ms}ms`); return outputUrl; } // 使用範例(瀏覽器環境) const fileInput = document.getElementById('file-input'); fileInput.addEventListener('change', async () => { const templateId = 1; const url = await generateFromTemplate(templateId, fileInput.files[0]); document.getElementById('result-img').src = url; }); ``` ### cURL ```bash # 查詢模板列表 curl http://localhost:8067/api/templates # 套用模板生圖(指定 template_id=1,上傳 user_photo.jpg) curl -X POST http://localhost:8067/api/templates/1/generate \ -F "image=@user_photo.jpg" \ --max-time 120 ``` --- ## 重要注意事項 1. **請求逾時設定**:生圖通常 10~30 秒,建議 HTTP 客戶端 timeout 設為至少 **120 秒**。 2. **圖片格式限制**:僅支援 `image/jpeg`、`image/png`、`image/webp`,建議單張不超過 10MB。 3. **輸出尺寸**:由模板固定的圖片決定,無法另外指定。 4. **固定 seed**:若模板設定了 `fixed_seed`,每次套用都會產生相同構圖/風格的結果;若要每次都隨機,建立模板時不要填 `fixed_seed`。 5. **輸出圖片保存**:回應中的 `outputs[].url` 為相對路徑,需自行拼接 Base URL 才能下載。圖片實際存放在伺服器上,可直接 GET 下載。 6. **生圖失敗處理**:若 `status` 為 `failed`,錯誤原因在 `error_message` 欄位。 7. **Swagger 互動文件**:`http://localhost:8067/docs` 可直接在瀏覽器測試這支 API。