可靠的四格漫畫整合不只需要一次生成請求。最基本的正式環境流程是:
upload character reference -> create four panels -> poll terminal status -> inspect every panel -> repair only the failed panel
本快速入門會在 TypeScript 中實作這個流程。它會將 API 金鑰保留在伺服器端、提供穩定的角色記錄、為建立請求使用冪等鍵、記錄耗時與失敗情況,並在連續性中斷時只針對單一面板處理。
先從 LlamaGen.AI Comic API 開始,接著使用下方完整範例作為伺服器端整合的基準。
本文已於 2026 年 10 月 10 日,依據線上 Comic API 文件 的實際內容進行合約核對。
| 檢查項目 | 已驗證行為 |
|---|---|
| 驗證 | 每個請求都使用 Bearer token |
| 正式環境基底 URL | https://api.llamagen.ai |
| 上傳 | POST /v1/comics/upload 會回傳可重複使用的 fileUrl |
| 建立 | POST /v1/comics/generations 接受 fixPanelNum: 4 與 comicRoles |
| 狀態 | GET /v1/comics/generations/{generationId} 回傳狀態與面板輸出 |
| 修復 | PATCH /v1/comics/generations/{generationId} 可重新生成單一個以零為起點索引的面板 |
| 用量 | 建立與修復回應都會提供 usage 資料,供你自行記錄 |
我們沒有虛構延遲或成功率基準。這些數值會依帳號、佇列、模型設定與輸入而異。範例會記錄你的實際耗時、API 用量、最終狀態與失敗細節,讓你能在自己的環境中建立可辯護的基準。
提示詞告訴模型發生了什麼事。角色參考圖則告訴模型,故事是發生在誰身上。
對於重複出現的角色,請保持以下欄位穩定:
在這個範例中,角色是一位短深色頭髮、穿黃色雨衣、背紅色郵差包的快遞員。這些細節既足夠精簡,能夠重複使用,也足夠鮮明,便於稽核。

請使用 Node.js 20 或更新版本,以確保 fetch、FormData 與 Blob 可用。將金鑰保存在僅供伺服器使用的環境變數中。
export LLAMAGEN_API_KEY="your_server_side_key"
不要在瀏覽器 bundle、行動應用程式、公開儲存庫或任何用戶端請求中暴露這個金鑰。如果你的產品有前端,請將使用者的簡述傳送到你自己的後端,再由該後端呼叫 LlamaGen.AI。
此工作流程包含四個網路操作:

將以下內容儲存為 comic-quickstart.ts,把角色圖片放在 ./courier-reference.png,並從你的伺服器環境執行它。
import { basename } from "node:path";
import { readFile } from "node:fs/promises";
import { randomUUID } from "node:crypto";
const API_BASE = "https://api.llamagen.ai";
const API_KEY = process.env.LLAMAGEN_API_KEY;
if (!API_KEY) {
throw new Error("Set LLAMAGEN_API_KEY before running this script.");
}
type UploadResponse = {
code?: number;
fileUrl: string;
};
type Usage = {
total_comics?: number;
redraw_panels?: number;
amount?: number;
};
type Generation = {
id: string;
status: "LOADING" | "PROCESSED" | "FAILED" | "CANCELLED" | string;
usage?: Usage;
comics?: Array<{
page?: number;
panels?: Array<{
panel?: number;
image?: string;
assetUrl?: string;
caption?: string;
}>;
}>;
error?: unknown;
};
async function api<T>(path: string, init: RequestInit = {}): Promise<T> {
const response = await fetch(`${API_BASE}${path}`, {
...init,
headers: {
Authorization: `Bearer ${API_KEY}`,
...init.headers,
},
});
const text = await response.text();
const body = text ? JSON.parse(text) : null;
if (!response.ok) {
throw new Error(
`Comic API ${response.status}: ${JSON.stringify(body)}`,
);
}
return body as T;
}
async function uploadReference(filePath: string) {
const bytes = await readFile(filePath);
const form = new FormData();
form.set("file", new Blob([bytes]), basename(filePath));
return api<UploadResponse>("/v1/comics/upload", {
method: "POST",
body: form,
});
}
async function waitForGeneration(
generationId: string,
timeoutMs = 10 * 60_000,
) {
const startedAt = Date.now();
while (Date.now() - startedAt < timeoutMs) {
const job = await api<Generation>(
`/v1/comics/generations/${generationId}`,
);
console.log(
JSON.stringify({
generationId,
status: job.status,
elapsedMs: Date.now() - startedAt,
usage: job.usage,
}),
);
if (job.status === "PROCESSED") return job;
if (job.status === "FAILED" || job.status === "CANCELLED") {
throw new Error(
`Generation ended as ${job.status}: ${JSON.stringify(job.error)}`,
);
}
await new Promise((resolve) => setTimeout(resolve, 4_000));
}
throw new Error(`Generation ${generationId} timed out.`);
}
async function main() {
const startedAt = Date.now();
try {
const reference = await uploadReference("./courier-reference.png");
const created = await api<Generation>("/v1/comics/generations", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Idempotency-Key": randomUUID(),
},
body: JSON.stringify({
prompt: [
"Create one four-panel comic page in a restrained cinematic manga style.",
"Panel 1: Ren enters a rain-soaked station and notices a golden key.",
"Panel 2: Close view as Ren lifts the key and studies it.",
"Panel 3: Ren runs toward an old locked service door.",
"Panel 4: Ren opens the door and warm light spills into the station.",
"Keep the same face, haircut, yellow jacket, and red messenger bag.",
"Leave clean space for later lettering.",
].join("\n"),
preset: "japanese_manga",
size: "1024x1024",
fixPanelNum: 4,
language: "en",
comicRoles: [
{
name: "Ren",
age: 22,
gender: "male",
dress: "yellow rain jacket, black trousers, red messenger bag",
image: reference.fileUrl,
},
],
}),
});
const firstPass = await waitForGeneration(created.id);
console.log("first_pass_complete", {
id: firstPass.id,
elapsedMs: Date.now() - startedAt,
usage: firstPass.usage,
pages: firstPass.comics?.length ?? 0,
});
// Example review result: panel 3 lost the red bag.
const repairQueued = await api<Generation>(
`/v1/comics/generations/${created.id}`,
{
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
page: 0,
panel: 2,
panelPrompt:
"Ren runs toward the service door. Preserve his exact face, short dark hair, yellow rain jacket, and visible red messenger bag.",
images: [reference.fileUrl],
}),
},
);
console.log("repair_queued", {
id: repairQueued.id,
usage: repairQueued.usage,
});
const repaired = await waitForGeneration(created.id);
console.log("workflow_complete", {
id: repaired.id,
totalElapsedMs: Date.now() - startedAt,
finalStatus: repaired.status,
});
} catch (error) {
console.error("comic_workflow_failed", {
elapsedMs: Date.now() - startedAt,
message: error instanceof Error ? error.message : String(error),
});
process.exitCode = 1;
}
}
await main();
執行方式如下:
npx tsx comic-quickstart.ts
這個範例刻意記錄結構化物件。在正式環境中,請將相同欄位送到你的可觀測性系統,並加入你自己的請求或專案識別碼。
不要因為整頁在縮圖尺寸下看起來漂亮就直接通過。請依照角色鎖定條件逐格稽核:
| 檢查項目 | 通過條件 |
|---|---|
| 臉部 | 年齡、特徵與比例一致 |
| 頭髮 | 輪廓、長度與顏色一致 |
| 服裝 | 黃色外套維持黃色,且結構一致 |
| 道具 | 紅色郵差包持續存在且位置正確 |
| 序列 | 鑰匙、門、天氣與移動方向保持連續 |
| 構圖 | 每個面板都有明確且不同的敘事任務 |
| 留字空間 | 臉部與關鍵動作未被遮擋 |
如果你正在建立更大的流程,請把這視為可機器讀取的品質控管。請為每個面板儲存通過/失敗原因,而不只是整頁層級的簡單核可。
最快的修復提示詞會同時指出新的動作,以及哪些元素不得改變。
Panel 3 repair:
Ren runs toward the service door.
Preserve his exact face, short dark hair, yellow rain jacket,
and visible red messenger bag.
Keep the rainy station and left-to-right movement.
面板索引是以零為起點,因此畫面上第三格對應的是 panel: 2。更新端點可以接受 panelPrompt、參考 images,或替換用的 caption。

這在操作層面上很重要。重建全部四格,可能會在修復一個舊問題的同時引入三個新的連續性風險。針對性修復能縮小審查範圍。
在整合正式上線前,請加入以下控制項:
對於更長的序列,請從 fixPanelNum 改用 pagination.totalPages 與 pagination.panelsPerPage。不要在同一個建立請求中同時傳送這兩種模式。
當漫畫是在你自己的產品、批次工作、教育工具、出版流程或客戶工作流程中生成時,請使用 Comic API。
當創作者希望以互動方式探索故事、比較不同方案,或逐頁手動進行美術指導時,請使用視覺化編輯器。許多團隊會兩者並用:API 負責建立並記錄可重複的初稿,而編輯器則處理例外修訂。
如果你的故事結構仍在變動,請先規劃好再製作完成面板。下一篇指南 Storyboard First or Comic Panels First? 會示範如何衡量返工差異。
可以。對單頁四格請求傳送 fixPanelNum: 4 即可。若要生成多頁,請改用 pagination 物件。
上傳乾淨的參考圖,將其回傳的 fileUrl 傳入 comicRoles[].image,保持角色名稱與服裝描述穩定,並在繼續序列前稽核每一個回傳面板。
可以。傳送 PATCH 請求,附上以零為起點的頁面與面板索引,以及新的 panelPrompt、可選的參考圖片或 caption。
請依照 LlamaGen.AI 文件記載的冪等行為處理,避免網路重試意外建立重複工作。只有在你有意產生新的生成結果時,才使用新的鍵。
沒有。它提供的是擷取真實數字所需的監測機制。只有在你於自己的帳號中,在相同條件下重複執行相同輸入並完成記錄後,才應公開延遲、用量與失敗率。
本文由 Jay 撰寫,並由 LlamaGen.AI 內容團隊依據實際端點合約進行技術審閱。產品行為可能變動;以上連結文件才是最終依據。
準備好建立這個工作流程了嗎?開啟 LlamaGen.AI Comic API,建立伺服器端金鑰,並使用你自己的角色參考圖執行這份快速入門。
热门创作工具
从漫画、分镜到照片风格化,用 LlamaGen 更快完成视觉创作。
彙整最新的 LlamaGen 功能發布、產品強化、設計更新與重要錯誤修正。
© 2026 LlamaGen.Ai 版權所有
引領 AI 漫畫生成的未來



