教程
如何使用 FLUX.1 Fill Pro API:用 curl 和 Python 进行 Mask Inpainting
flux-1-fill-pro 是 hiapi 的基于遮罩的 inpainting 模型:你发送一张源图、一张黑白遮罩和一条提示词,只有白色区域会被重绘。本指南给出可用的 curl 和 Python 请求、异步流程,以及一次真实运行在遮罩边界和输出尺寸方面所显示的结果。你需要从 dashboard 获取 API key。
请求结构
该模型运行在统一任务 API 上。用 POST https://api.hiapi.ai/v1/tasks 创建任务,轮询 GET /v1/tasks/<taskId>,然后读取 data.output[0].url。以下输入来自 模型页面和 API 文档:
| 字段 | 类型 | 说明 |
|---|---|---|
input.image |
URL,必填 | 源图像。JPEG、PNG、GIF 或 WebP。 |
input.mask |
URL,必填 | 黑色保留源图,白色被重绘。必须与源图尺寸一致。 |
input.prompt |
string,必填 | 描述白色区域内的新内容。最多 4,000 个字符。 |
input.steps |
int,15–50 | 默认 50。 |
input.guidance |
number,1.5–100 | 默认 60。 |
input.seed |
int | 相同输入下固定 seed 会得到一致的结果。 |
input.output_format |
jpg | png |
默认 jpg。 |
input.prompt_upsampling |
bool | 默认 false。保持关闭可保留你的确切措辞。 |
image 和 mask 都是 URL,不是 base64 或文件上传。请将它们托管在 API 可通过 http(s) 获取的位置。
最小 curl 请求
curl -s https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer $HIAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "flux-1-fill-pro",
"input": {
"image": "https://dev-static.hiapi.ai/model-onboarding/flux-1-fill-pro/2026/10/19/2026/10/19/1792418738578-4e5072a121d7018f-source.jpg",
"mask": "https://dev-static.hiapi.ai/model-onboarding/flux-1-fill-pro/2026/10/19/2026/10/19/1792418739459-82bb18075f29c864-mask.png",
"prompt": "一幅晨雾中朦胧山湖的油画风景大画作,配细黑画框,平整地挂在墙上;保持沙发、地板和光照不变。",
"steps": 30,
"guidance": 60,
"seed": 42,
"output_format": "png"
}
}'
响应是 {"code":200,"data":{"taskId":"tk-hiapi-..."},"message":"success"}。轮询该 ID,直到 data.status 为 success 或 fail。
Python:创建、轮询、下载
import os, time, requests
API = "https://api.hiapi.ai"
HEADERS = {"Authorization": f"Bearer {os.environ['HIAPI_KEY']}"}
def inpaint(image_url, mask_url, prompt, **opts):
body = {"model": "flux-1-fill-pro",
"input": {"image": image_url, "mask": mask_url, "prompt": prompt, **opts}}
r = requests.post(f"{API}/v1/tasks", headers=HEADERS, json=body, timeout=30)
r.raise_for_status()
task_id = r.json()["data"]["taskId"]
while True:
try:
d = requests.get(f"{API}/v1/tasks/{task_id}", headers=HEADERS, timeout=20).json()["data"]
except requests.RequestException:
time.sleep(5) # transient network error: poll the same taskId again
continue
if d["status"] == "success":
return d["output"][0]["url"]
if d["status"] == "fail":
raise RuntimeError(d.get("error", d))
time.sleep(5)
url = inpaint(
"https://example.com/room.jpg",
"https://example.com/room-mask.png",
"一幅带框的风景画,细黑画框;保持房间不变。",
steps=30, seed=42, output_format="png",
)
open("out.png", "wb").write(requests.get(url, timeout=60).content)
立即下载结果。输出 URL 带有 expireAt,且文件为临时存储,因此不要将该链接作为永久地址保存。
生产环境注意事项
- 轮询或回调。对于批量任务,在任务 body 中添加
"callback": {"url": "https://your-domain.com/hiapi/callback", "when": "final"},并使用任务 ID 对通知去重。保留轮询作为后备方案。 - 重试轮询,而不是创建。新的
POST会创建并计费一个新任务。如果某个轮询请求出错,请再次轮询同一个taskId。 - 遮罩与源图保持一致。遮罩必须与源图尺寸完全一致,因此请从同一文件生成(多边形工具、分割输出),而不是缩放截图。
- 调参时固定 seed。使用同一个 seed,只更改
steps或guidance,这样每个差异都来自该参数。
每张图的费用见定价页面,在运行大量素材前请先确认。
一次真实运行所显示的结果
我对该页面自带的示例房间照片(1600×900)及其矩形遮罩(白色框位于 x 840–1240、y 160–580)运行了上面的 curl 请求一次。设置为 steps: 30、guidance: 60、seed: 42、output_format: png。
- 耗时。任务处于
handling约 25 秒,然后archiving,端到端约 38 秒达到success。 - 输出尺寸与源图不同。返回的 PNG 为 1440×810,而不是 1600×900。宽高比一致,但像素尺寸不同。如果你要将结果合成回原始图,请先调整其中一张的尺寸,不要假设为 1:1。
- 遮罩之外保持不变。将源图缩放到 1440×810 并与输出做差分后,白色框内 81% 的像素变化超过 8 级(0–255),而框外只有 0.03% 的像素如此。距遮罩边缘超过 12 px 处,最大差异为 11 级。沙发、靠垫、植物、地板和窗户光均未被重绘。
- 提示词范围。提示词只描述了画作及需要保留的内容,结果是一幅填满白色框的带框山湖场景。
- 错误的 URL 在轮询时失败,而不是在创建时。另一个将
image和mask设为非 URL 字符串的请求返回了200和一个taskId,随后任务在约 3 秒后以status: fail和error.code: TASK_FAILED结束。你的POST成功并不意味着输入有效,因此务必检查最终状态。
未测试:遮罩与源图尺寸不匹配、带灰色(软边缘)值的遮罩、alpha 通道遮罩,以及 guidance 或 steps 的极端值。文档说明遮罩必须与源图尺寸匹配,而我只测试了硬二值矩形。我没有运行多个 seed,因此无法说明填充在多次运行间的变化程度。
何时选择 Fill Pro
当编辑必须停在由你控制的硬边界时使用它,例如产品标签、墙线或衣物接缝。对于用文字描述、无需遮罩的编辑,请使用纯提示词模型。图像 inpainting 与对象移除指南对它们进行了比较。若要从遮罩中擦除某些内容而不写提示词,请参阅 Bria Eraser 指南。
相关
常见问题
image 和 mask 都是必填的吗?
是的。当前文档将 image、mask 和 prompt 列为必填。
模型重绘哪种颜色?
白色。黑色像素保留源图。
遮罩需要与源图尺寸相同吗?
文档是这样说的。我在运行中使用了匹配的一对,没有测试不匹配的情况。
输出的尺寸是什么样的?
在我的运行中,1600×900 的源图返回了 1440×810 的 PNG,宽高比相同。