搭一个 AI 漫画制作网站:Agent 自动分镜排版,中途接 4sapi 跑通文生图
输入一个故事,输出一整页排好版的漫画。这篇讲我怎么用 Agent 把"编剧—分镜—画图—排版"这条链路自动化,以及中途怎么接入 4sapi 中转 API 把文生图跑通。
写在前面
上一篇我写了 AI 漫剧(动态漫短剧)网站,这篇是它的姊妹篇——静态漫画制作网站。
两者链路像,但难点不同:漫剧难在"让画面动起来 + 配音剪辑",漫画难在**"分镜排版" + "角色一致性"**——同一个角色在几十个格子里得长得像同一个人,而且每一页的格子布局还得讲究阅读节奏。
这篇我同样用"Agent 编排 + 中转 API 统一接入"的思路来搭,重点讲漫画特有的那几个坎怎么过,以及中途接入 4sapi.com 这个中转网关把文生图环节跑通的具体步骤。
一、先理清楚:一页漫画是怎么"生产"出来的
和漫剧类似,漫画生产也是一条流水线,但环节不太一样:
① 剧情脚本 故事梗概 → 分章节/分页的剧情文本
↓
② 分镜脚本 剧情 → 每页几个格子,每格画什么、谁说什么
↓
③ 角色设定 生成统一的角色参考图(保证一致性的基准)
↓
④ 文生图 每个格子的画面描述 → 漫画分格图
↓
⑤ 排版合成 把分格图 + 对话气泡,按布局拼成成品页
其中①②靠大语言模型,③④靠文生图模型,⑤靠图像合成(代码排版 + 加气泡)。
和漫剧一样的老问题:这些模型分散在不同厂商。挨个对接官方 API 太累,所以我们中途引入一个中转网关,用一个 Key、一套格式把它们全接进来。
二、架构:四个 Agent + 一个排版引擎 + 统一网关
┌────────────────────────┐
用户输入故事 ─→ │ Orchestrator 总调度 │
└──────────┬─────────────┘
┌──────────┬────────┼────────┬──────────┐
↓ ↓ ↓ ↓ ↓
[脚本Agent] [分镜Agent] [角色Agent] [画图Agent] │
└──────────┴────────┼────────┴──────────┘
↓
┌────────────────┐ ┌──────────────┐
│ 统一网关(4sapi) │ │ 排版引擎 │
└────────────────┘ │ (分格+气泡) │
└──────────────┘
设计要点和漫剧那套一脉相承:所有模型调用统一走 4sapi 中转网关,业务层只跟一个 OpenAI 兼容接口打交道。区别是漫画多了一个纯代码实现的排版引擎(不调模型,用 Pillow/Canvas 拼图加气泡)。
我选 4sapi.com 当网关的理由不变:兼容 OpenAI 格式、文本和图像模型都能调、一个 Key 管到底、计费集中好对账。
三、中途接入 4sapi:把文生图网关接通
漫画这套系统最吃接口的是文生图环节,所以网关接通是第一优先级。还是三步走。
第一步:拿 Key、记 BaseURL
在 4sapi.com 后台创建令牌,记下 Key 和接口地址,放进环境变量,别硬编码:
bash
# .env
FOURSAPI_BASE_URL=https://4sapi.com/v1
FOURSAPI_KEY=sk-你的令牌
第二步:封装统一客户端
4sapi 兼容 OpenAI 格式,直接用 openai SDK 把 base_url 指过去:
python
# gateway.py
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["FOURSAPI_KEY"],
base_url=os.environ["FOURSAPI_BASE_URL"], # 指向中转网关
)
def gen_image(model, prompt, size="1024x1024", **extra):
"""文生图统一入口,所有画图都走这里"""
resp = client.images.generate(
model=model, prompt=prompt, size=size, extra_body=extra
)
return resp.data[0].url
第三步:发一张测试图验证连通
python
if __name__ == "__main__":
url = gen_image("flux-dev", "a cute cat, comic style")
print("生成成功:", url) # 能打印出图片 URL 即网关接通
能拿到图片 URL,网关就通了。接入的全部工作量,就是「换个 base_url + 配个 Key」——一次配好,文本和图像都能调。
四、逐环节实现:漫画特有的难点怎么破
4.1 脚本 Agent —— 故事变分页剧情
python
def script_agent(story):
prompt = f"""你是漫画编剧。把下面的故事改写成漫画剧情,按页划分,
每页标注关键情节和情绪节奏。故事:{story}"""
return chat(model="gpt-4o",
messages=[{"role": "user", "content": prompt}],
temperature=0.8)
4.2 分镜 Agent —— 决定每页"几个格子、怎么排"
这是漫画区别于漫剧的核心。漫画的分镜不光要描述画面,还要规划格子的布局(panel layout)和阅读顺序——大格子给高潮,小格子推进节奏。我让模型直接输出结构化布局:
python
def panel_agent(page_script):
prompt = f"""把这一页剧情拆成漫画分镜,输出 JSON。
字段:page_layout(布局,如 "2x2"/"1大2小"),
panels[]: 每格含 visual_prompt(画面英文描述),
dialogue(对白), bubble_pos(气泡位置:top/bottom/left/right)。
剧情:{page_script}"""
raw = chat(model="gpt-4o",
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"})
return json.loads(raw)
4.3 角色 Agent —— 先定一张"角色基准图"
漫画的角色一致性比漫剧更难,因为格子更多。我的解法是先生成一张角色参考图,后面所有格子都基于它做图生图,而不是每次重新文生图:
python
def role_agent(role_desc):
# 先生成一张高质量的角色立绘当"基准"
ref_url = gen_image(
model="flux-dev",
prompt=f"{role_desc}, full body, character reference sheet, comic style, white background",
size="768x1024",
)
return ref_url # 这张图后面反复复用
4.4 画图 Agent —— 基于基准图画每一格
关键在于用**图生图(image-to-image)**而非纯文生图,把角色基准图作为参考传进去,角色长相就能稳住:
python
def panel_image_agent(panel, role_ref_url, style="japanese manga"):
full_prompt = f"{panel['visual_prompt']}, {style}, consistent character"
# 走网关的图生图接口,传入角色参考图
resp = client.images.edit(
model="flux-dev",
image=role_ref_url, # 角色基准图,锁住一致性
prompt=full_prompt,
extra_body={"strength": 0.6}, # 控制对参考图的保留程度
)
return resp.data[0].url
一致性三板斧:① 统一角色基准图;② 图生图而非文生图;③ 固定画风描述词。三个一起上,角色基本不会跑偏。
五、排版引擎:把分格图拼成一页漫画
这一步不调任何模型,纯靠代码。用 Pillow 按分镜给的布局把格子拼起来,再贴上对话气泡:
python
from PIL import Image, ImageDraw, ImageFont
def compose_page(panels_with_img, layout):
page = Image.new("RGB", (1240, 1754), "white") # A4 比例画布
boxes = layout_to_boxes(layout, page.size) # 布局→每格坐标
for panel, box in zip(panels_with_img, boxes):
img = load(panel["img_url"]).resize(box.size)
page.paste(img, box.pos) # 贴分格图
draw_bubble(page, panel["dialogue"], # 画对话气泡
pos=panel["bubble_pos"], box=box)
return page
def draw_bubble(page, text, pos, box):
"""在指定格子的指定位置画一个对话气泡 + 文字"""
draw = ImageDraw.Draw(page)
# 简化:画个圆角白底气泡,写上对白
bubble_box = calc_bubble_box(box, pos, text)
draw.rounded_rectangle(bubble_box, radius=20, fill="white", outline="black")
draw.text(bubble_box.text_pos, text, fill="black", font=load_font())
排版引擎是漫画系统里最"工程"的一块——没有 AI 的魔法,但决定了成品看起来专不专业。布局映射、气泡避让、文字换行,这些细节抠到位,出来的页面才像正经漫画而不是图片拼贴。
六、串起来:从一个故事到一整本漫画
python
def make_comic(story):
pages_script = script_agent(story) # ① 分页剧情
role_ref = role_agent("少年, 黑发, 校服") # ③ 先定角色基准图
comic_pages = []
for page_script in pages_script:
layout = panel_agent(page_script) # ② 本页分镜布局
panels = []
for panel in layout["panels"]:
# ④ 基于角色基准图画每一格
img = panel_image_agent(panel, role_ref)
panels.append({**panel, "img_url": img})
# ⑤ 排版合成本页
page_img = compose_page(panels, layout["page_layout"])
comic_pages.append(page_img)
return export_pdf(comic_pages) # 导出整本 PDF
同样地,所有模型调用——脚本、分镜、角色、画图——全部走 4sapi 一个网关、一个 Key。排版那步是纯代码,不烧接口。
七、前端:上传故事,预览成品
jsx
function ComicMaker() {
const [story, setStory] = useState("");
const [pages, setPages] = useState([]);
async function generate() {
const res = await fetch("/api/comic", {
method: "POST",
body: JSON.stringify({ story }),
});
const data = await res.json();
setPages(data.pages); // 渲染预览
}
return (
<div>
<textarea value={story} onChange={e => setStory(e.target.value)}
placeholder="贴入你的故事,AI 帮你画成漫画" />
<button onClick={generate}>生成漫画</button>
<div className="preview">
{pages.map((p, i) => <img key={i} src={p} alt={`第${i+1}页`} />)}
</div>
</div>
);
}
同样的安全提醒:/api/comic 背后每次都在烧文生图算力,上线前务必加鉴权 + 频率限制,并给单用户设每日生成上限,防止被恶意刷爆。
八、几条实战经验
- 角色基准图是一致性的地基,一定要先把它生成好、让用户确认满意了,再批量画格子。基准图歪了,后面全废。
- 分镜的布局字段越结构化越好。
"2x2"、"1大2小" 这种枚举值,比让模型自由描述布局好解析得多。
- 气泡排版别交给 AI,用代码精确控制。我试过让模型连气泡一起画进图里,结果文字经常糊、位置乱。分离开——AI 画画面,代码加气泡。
- 画图批量并发,但要限流。一页好几格、一本几十页,串行太慢;并发又容易触发网关限流。我的做法是控制在并发 3-5,配合重试。
- 画风描述词做成预设。给用户几个预设画风(日漫/美漫/水彩/Q版),背后对应固定的 style prompt,比让用户自己描述靠谱得多。
写在最后
漫画系统和漫剧系统是一对姊妹——骨架都是"Agent 编排 + 中转网关统一接入",区别只在各自的难点:漫剧难在动效配音,漫画难在分镜排版和角色一致性。
把模型能力收敛到一个网关后面,把工程难点(排版、一致性)留在自己代码里——这套分工,是我做这类 AI 内容生产工具最核心的心得。
中途接入 4sapi 这一步,依然是整套方案里最"四两拨千斤"的地方:一个 base_url、一个 Key,就把文本和图像两类模型一次性接齐了,剩下的精力全可以花在真正的难点上。
两篇姊妹篇到这就齐了。如果你打算动手,建议先跑通漫画(静态、链路短、好调试),再上漫剧(多了视频和配音环节)。
本文代码为说明思路的简化示意,模型名称与接口字段请以 4sapi.com 官方文档为准。涉及付费接口,务必做好用量控制与接口鉴权。