教程
如何在 hiapi API 上调用 recraft-v4-styles-pro/text-to-image:curl 与 Python
此端点做什么以及何时使用
recraft-v4-styles-pro/text-to-image 将文本提示词转换为图像,其显著特点是风格感知:你可以通过风格参考来引导结果的视觉语言,而不是仅依赖提示词的措辞。当输出需要在大量生成中保持一致感、而非只在一两次生成中好看时,这是一个实用的选择。
开发者常在以下场景中使用它:
- 品牌一致性素材——主视觉图、社交卡片和广告变体,都需要落在同一套视觉体系内。
- 产品与营销样机——反复调整提示词、固定风格,产出一组符合品牌的变体。
- 流水线步骤——生成作为更大自动化中的一个阶段,由另一个服务消费保存好的图像。
有一个特性决定了下面每个代码示例的写法:图像生成是异步的。请求提交任务后立即返回;图像稍后才会出现。你需要编写提交步骤和轮询步骤,并将它们视为两个独立的关注点。
准备 hiapi 凭据和请求基础
所有调用都经过 hiapi 统一的端点界面,因此在首次请求之前需要准备三样东西:
- 一个 API 密钥,来自你的 hiapi 账户。像对待其他机密一样对待它:从环境变量加载,绝不要硬编码进你可能分享的脚本中。
- 模型标识符,必须与发布时完全一致:
recraft-v4-styles-pro/text-to-image。 - 一个支持 HTTP 的工具——用于探索的
curl,以及用于任何持久化场景的 HTTP 库。
export HIAPI_API_KEY="your-key-here"
值得尽早内化的约定:
- 发送 JSON 请求体时使用
Content-Type: application/json。 - 使用 bearer token 请求头进行认证。
- 将模型 id、提示词和风格参考作为载荷中各自独立的字段,而不是把所有东西塞进一个字符串——这样轮询步骤和日志都会更容易理解。
关于确切的请求头名称、基础 URL 和当前字段定义,请查阅此模型的 hiapi API 参考文档;将本教程视为调用的形态,将参考文档视为名称的权威来源。
一个可用的 curl 请求
以下是提交调用。将其理解为三个层次:传输、认证和请求体。
curl -sS -X POST "$HIAPI_BASE_URL/generate" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "recraft-v4-styles-pro/text-to-image",
"prompt": "minimalist product photo of a ceramic mug on a linen surface, soft daylight",
"style_references": []
}'
逐行解释:
-X POST——提交任务,而非获取。Authorization: Bearer ...——令牌来自环境变量,因此该命令可以安全地粘贴到终端,去掉变量后也可以安全分享。-d '{...}'——JSON 请求体。model是确切的标识符。prompt是描述场景的自由文本。style_references是风格控制的挂载点,接下来会讨论。-sS——静默进度条,但仍然显示错误,因此失败的调用可见。
成功的响应是一个确认,而非图像:你会得到任务的标识符和状态。记录下该标识符——它是轮询所需的唯一句柄。如果你在交互式探索,将响应通过 JSON 格式化器处理,以便任务 id 和状态更加醒目。
将风格参考与提示词一起传递
心智模型很简单:提示词说明什么,风格参考说明应该看起来怎样。在载荷中保持它们分离,你就能保留灵活性——可以用同一提示词对多组风格重新运行以比较结果。
{
"model": "recraft-v4-styles-pro/text-to-image",
"prompt": "ceramic mug on a linen surface, soft daylight",
"style_references": [
"https://your-bucket.example.com/styles/mug-ref-01.jpg",
"https://your-bucket.example.com/styles/mug-ref-02.jpg"
]
}
实用建议:
- 从无参考开始。 先裸跑提示词。然后添加一个参考并观察差异,再加两个。每次只改一处带来的信息量,远大于首次尝试就使用整套风格。
- 保持参考可访问。 将它们托管在服务能可靠获取的地方——公共存储桶或有效期充裕的签名 URL——而不是几分钟后就失效的链接。
- 保持集合协调。 相互一致的参考(相似的光照、调色板、纹理)往往比混杂的一堆产生更稳定的结果,后者需要模型调和矛盾。
- 对参考进行版本化。 将它们存储在稳定的键下。下个月输出出问题时,你需要确切知道当时使用了哪些参考文件。
查阅此模型的 hiapi 参考文档,确认风格参考是以 URL、上传的资源还是命名预设的形式传递,以及对其数量和格式有哪些限制。
Python 中的相同调用
curl 调用可直接转换。将其封装在小函数中,可作为流水线阶段复用。
import os
import requests
HIAPI_BASE_URL = os.environ["HIAPI_BASE_URL"]
HIAPI_API_KEY = os.environ["HIAPI_API_KEY"]
def submit_generation(prompt: str, style_references: list[str] | None = None) -> str:
"""提交一个文本到图像任务并返回任务 id。"""
payload = {
"model": "recraft-v4-styles-pro/text-to-image",
"prompt": prompt,
"style_references": style_references or [],
}
response = requests.post(
f"{HIAPI_BASE_URL}/generate",
headers={
"Authorization": f"Bearer {HIAPI_API_KEY}",
"Content-Type": "application/json",
},
json=payload,
timeout=30,
)
response.raise_for_status()
data = response.json()
return data["job_id"]
设计说明:
- 始终设置超时。 一个无限挂起的提交会像崩溃一样有效地阻塞你的工作进程。
raise_for_status()将非 2xx 响应转换为可捕获和记录日志的异常,而不是带着格式错误的响应体默默继续。- 只返回 id。 任务 id 是提交与轮询之间的契约。将响应的其余部分排除在调用代码之外,下一节会更容易编写。
在 hiapi 参考文档中确认实际响应字段名称,并相应调整 data["job_id"]——字段命名是最可能与本文示例不同的地方。
轮询任务完成状态
生成需要时间。以固定间隔轮询,在终止状态时停止,并最终放弃。
import time
def wait_for_job(job_id: str, timeout: float = 300, interval: float = 3) -> dict:
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
response = requests.get(
f"{HIAPI_BASE_URL}/jobs/{job_id}",
headers={"Authorization": f"Bearer {HIAPI_API_KEY}"},
timeout=30,
)
response.raise_for_status()
job = response.json()
status = job["status"]
if status == "succeeded":
return job
if status == "failed":
raise RuntimeError(f"Job {job_id} failed: {job.get('error')}")
time.sleep(interval)
raise TimeoutError(f"Job {job_id} did not finish within {timeout}s")
不那么明显的部分:
- 三种结果,而非两种。 待处理、成功、失败。将任何未识别的状态视为待处理并记录一行日志,这样新添加的状态就不会让工作进程崩溃。
- 整个等待使用一个截止时间。
time.monotonic()截止时间不受时钟调整影响,而挂钟时间算术则不然。 - 不要频繁请求。 对于图像生成,每次检查之间几秒钟就足够了。如果你必须更快轮询,应在尝试之间退避,而不是缩短间隔。
- 强制执行超时。 永不终止的任务应表现为可告警的错误,而不是一直运行直到容器被杀死的循环。
如果你运行大量任务,请批量提交并并发轮询——使用一个事件循环或线程池并错开间隔——而不是为每个任务在紧密循环中生成一个轮询器。
下载并保存输出
完成的任务会给你一个图像引用,通常是一个 URL。请及时下载,因为这些链接可能有时间限制。
def save_image(job: dict, path: str) -> None:
url = job["output"]["image_url"]
for attempt in range(3):
try:
with requests.get(url, stream=True, timeout=60) as r:
r.raise_for_status()
with open(path, "wb") as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
return
except requests.RequestException:
if attempt == 2:
raise
time.sleep(2 ** attempt)
在生产中值得采用的做法:
- 流式下载。 生成的图像并不小;无理由地将其完全加载到内存中是浪费。
- 写入临时路径,然后重命名。 写入中途崩溃不应在流水线期望有效图像的位置留下截断的文件。
- 重试下载,而非生成。 对不稳定的存储桶获取重试成本低;浪费一次生成则不然。限制重试次数并使用指数退避。
- 将任务 id 与文件一起持久化。 当有人问图像来自哪里时,答案应该只需一次查询,而不是翻遍日志。
对于对象存储,将 open() 替换为你的 SDK 的流式上传,并保持相同的重试外壳。
错误、重试与成本合理性检查
你会最先遇到的失败模式,以及每种的处理方式:
- 401 / 认证错误——密钥缺失、拼写错误或未导出到运行脚本的 shell 中。在触碰载荷之前先检查环境。
- 4xx 验证错误——通常是模型 id 拼写错误、缺少
prompt或格式错误的风格参考。逐字记录响应体;验证消息是这里最快的修复途径。 - 429 / 速率限制——使用抖动退避,而不是立即重试。在提交函数前设置队列胜过重试风暴。
- 任务超时——轮询截止时间已触发。刻意决定是否重新提交;盲目重新提交会使支出翻倍而不提高成功率。
- 瞬时网络错误——对有上限的指数退避重试提交和下载。自由重试下载失败;谨慎重试生成。
成本纪律,从实用角度来说:
- 计费跟随模型实际执行的工作,因此失败的任务和被放弃的批次是隐性成本。记录每次提交及其提示词哈希和任务 id,以便日后核算用量。
- 使用尽可能便宜的提示词进行迭代。 在小规模、快速运行中调整措辞和风格参考,然后再投入大批次。
- 去重。 如果相同的提示词和风格集被请求两次,从你自己的缓存中提供第一次的结果。
- 在工作进程中添加硬性并发上限。 提高限制比解释意外账单更容易。
将提交、轮询和保存作为三个独立、可测试的函数,该端点就能干净地嵌入任何流水线。关于确切的字段名称、状态和当前定价,请在集成前查看 hiapi 上的 recraft-v4-styles-pro/text-to-image 模型页面。