教程
如何通过 HiAPI API 使用 imagen4-ultra:curl 与 Python 示例
在 HiAPI 上进行高质量文生图的完整请求实战演练
HiAPI 上的 imagen4-ultra 能为你提供什么
imagen4-ultra 是 HiAPI 的高质量文生图模型:你发送一段提示词,就能收到一张生成的图片。它对开发者真正实用的地方在于,它和平台上其他所有模型一样,运行在统一的 HiAPI 接口背后,因此你在这里学到的鉴权方式、请求结构和任务处理模式,都能直接沿用到其他端点。
本教程是一份可运行的实战演练,而不是参数罗列。读完之后,你将拥有:
- 一个可直接复制粘贴的
curl请求,用于提交文生图任务, - 同一个请求改写而成的小型 Python 客户端,
- 对宽高比及其他选项如何影响输出的清晰认识,
- 以及一个轮询循环,用于等待任务完成并将图片保存到磁盘。
先做个预期说明:图片生成不是即时的。imagen4-ultra 以异步方式运行——你提交任务,拿到一个任务标识符,然后轮询直到渲染完成。如果你用过 HiAPI 的其他异步端点,这套流程会很熟悉;如果没用过,轮询章节会覆盖完整的生命周期。
我们会始终停留在 HiAPI 自己的 API 范围内:不使用特定厂商的 SDK,也不涉及第三方控制台。一个基础 URL、一个密钥、一种请求格式。
在发送第一个请求之前
在第一个调用成功之前,你需要准备三样东西。
1. 一个 API 密钥
从你的 HiAPI 账户控制台生成密钥。把它当作密码对待:存进环境变量,而不是直接粘贴到源文件里。
export HIAPI_API_KEY="your-key-here"
2. 基础 URL
所有 HiAPI 请求都发往平台文档中记录的同一个 API 主机。在代码里把它集中放在一处,这样你就不会在多个位置硬编码:
export HIAPI_BASE_URL="https://api.hiapi.ai"
如果你的账户或区域走的是其他主机,请使用控制台中显示的值——下面的请求路径保持不变。
3. 鉴权信息的传递方式
HiAPI 使用 Authorization 请求头中的 bearer 令牌。每个请求——无论是提交还是轮询——都携带同样的两个请求头:
Authorization: Bearer $HIAPI_API_KEY
Content-Type: application/json
鉴权就这么多。没有请求签名步骤,也没有逐次调用的令牌交换。只要你能设置请求头,就能调用这个 API。
继续之前先做个基本检查:确认你的密钥已在你将要运行 curl 的同一个 shell 会话中导出。相当大比例的“401 Unauthorized”报告,最终都归结为密钥在一个终端标签页里导出、却在另一个标签页里使用。
下文我们将始终假定模型标识符为 imagen4-ultra。如果你想确认自己账户暴露的确切字符串,请查看文档中的模型列表。
可运行的 curl 请求
下面是一个完整的提交请求。它发送提示词、设置输出宽高比,并要求生成单张图片。
curl -sS -X POST "$HIAPI_BASE_URL/v1/images/generations" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "imagen4-ultra",
"prompt": "A lone lighthouse on a rocky coast at dusk, long exposure, dramatic clouds, cinematic lighting",
"aspect_ratio": "16:9",
"n": 1
}'
逐字段讲解请求体:
model—— 你正在调用的模型标识符。它决定请求的路由;没有它,API 无法知道要运行哪个模型。prompt—— 对图片的自然语言描述。这是影响输出质量的主要杠杆。对主体、光照、风格和构图要具体;模糊的提示词只会产生模糊的图片。aspect_ratio—— 输出画布的形状,以宽度:高度表示。后文会详细说明。n—— 本次提交要生成多少张图片。测试期间保持为1,这样每次运行的成本都容易推算。
取决于端点配置,响应要么包含已完成的图片,要么——对于这类模型更常见——包含一个带有标识符和状态字段的任务对象。请捕获该标识符;轮询章节依赖它。
# 提交响应的典型结构
{
"id": "job_abc123",
"status": "queued"
}
把响应通过 JSON 格式化工具处理一下(如果有就 | jq .),这样你就能对照自己账户的响应读懂字段名,而不用眯着眼看一整行。
用 Python 写同样的请求
Python 版本是逐行对应的翻译——相同的 URL、相同的请求头、相同的请求体。使用 requests 能让映射关系一目了然:
import os
import requests
API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = os.environ.get("HIAPI_BASE_URL", "https://api.hiapi.ai")
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
payload = {
"model": "imagen4-ultra",
"prompt": "A lone lighthouse on a rocky coast at dusk, long exposure, dramatic clouds, cinematic lighting",
"aspect_ratio": "16:9",
"n": 1,
}
response = requests.post(
f"{BASE_URL}/v1/images/generations",
headers=headers,
json=payload,
timeout=30,
)
response.raise_for_status()
job = response.json()
print(job["id"], job["status"])
把这段代码搬进真实服务时,有几处值得保留:
- 从环境变量读取密钥,绝不要从文件里的字面量读取。
os.environ[...]这种写法在变量缺失时会明确报错,这正是你想要的。 - 为提交调用设置显式超时。任务本身是异步运行的,所以 HTTP 请求应该很快返回;30 秒的上限能捕获网络问题,而不是让程序挂起。
- 在触碰 JSON 之前先调用
raise_for_status()。4xx 响应的响应体并不是你期望的结构,提前失败比三行后抛出KeyError能给出更清晰的回溯信息。 - 复用
requests.Session,如果你要提交大量任务——连接池的作用比看起来更重要。
如果你更偏好 httpx 或 aiohttp,转换是机械性的:相同的 headers 字典、相同的 JSON 请求体、相同的路径。请求本身与 HTTP 库无关。
宽高比与请求选项
宽高比是你最常调整的选项,因为它同时改变构图和下游布局可用的输出尺寸。
宽高比在请求体中以 "width:height" 字符串形式传入——"1:1"、"16:9"、"9:16"、"4:3"、"3:2" 等等。选择与图片最终使用场景相匹配的比例:
1:1—— 头像、商品图块、会裁剪成正方形的社交帖子。16:9/9:16—— 主视觉横幅、视频缩略图、竖版故事格式的投放位置。4:3/3:2—— 经典摄影构图、画廊布局。
要有意识地设置比例,而不是先生成正方形再裁剪。裁剪会丢弃你已经付费生成的像素,还可能把主体裁出画面。如果你知道最终投放位置,就把它编码进请求里。
除了宽高比之外,日常使用中重要的选项还有:
prompt—— 仍然是影响力最大的输入。在其他任何地方迭代之前,先在这里迭代。n—— 每次提交生成的图片数量。当你想要多个变体来挑选时很有用;在探索提示词阶段保持较低值。model—— 模型变体的确切标识符。如果你的账户暴露了多个图片模型,这就是它们之间的切换开关。
坚持使用该端点文档中记录的参数,不要猜测名称。未知字段是导致 400 响应的常见原因,而拼错的选项在大型请求体中很容易被忽略。拿不准时,先发送最小请求体——model、prompt、aspect_ratio——确认它可用,然后一次添加一个选项。
轮询异步任务并下载结果
图片生成需要时间,所以提交调用返回的是任务,而不是图片。生命周期是:提交 → 轮询状态 → 下载输出。
第 1 步:提交并捕获任务 ID
复用前面的请求,从响应中取出 id:
job = response.json()
job_id = job["id"]
第 2 步:轮询直到任务进入终态
用相同的鉴权请求头轮询状态端点,每次尝试之间休眠。逐步退避,避免对 API 造成过大压力:
import time
def wait_for_job(job_id, headers, base_url, timeout=300):
deadline = time.time() + timeout
delay = 2
while time.time() < deadline:
r = requests.get(
f"{base_url}/v1/images/generations/{job_id}",
headers=headers,
timeout=30,
)
r.raise_for_status()
data = r.json()
status = data["status"]
if status == "succeeded":
return data
if status == "failed":
raise RuntimeError(f"job failed: {data}")
time.sleep(delay)
delay = min(delay * 2, 15)
raise TimeoutError(f"job {job_id} not finished within {timeout}s")
关键细节:一个硬性截止时间、对退避间隔设置上限,以及为失败状态设置显式分支,这样出问题的任务会以异常形式暴露,而不是一直挂起。
第 3 步:下载图片
完成后的任务响应包含输出位置——一个 URL 或等价的产物引用。获取它并把字节写入磁盘:
result = wait_for_job(job_id, headers, BASE_URL)
image_url = result["output"][0]["url"]
img = requests.get(image_url, timeout=60)
img.raise_for_status()
with open("lighthouse.png", "wb") as f:
f.write(img.content)
两个能避免大多数生产环境意外的习惯:始终以字节模式写入("wb"),绝不用文本模式;并把下载 URL 视为临时性的——立即把文件保存到你自己的存储中,而不是指望链接无限期有效。
常见错误及修复方法
大多数失败都可归入几类。下面是每一类的表现和解决方法。
401 Unauthorized
密钥缺失、格式错误,或对发起请求的进程不可见。
- 检查请求头是否恰好是
Authorization: Bearer <key>——Bearer这个词、一个空格、然后是密钥。 - 确认环境变量在同一个 shell 或进程中已设置。在容器和 CI 中,你本地 shell 导出的变量不会随代码一起过去。
- 如果你最近轮换了密钥,请确保旧密钥没有仍被缓存在某处。
400 Bad Request
通常是请求体问题。
- 未知或拼错的字段名——坚持使用文档中记录的参数。
- 端点不接受的
aspect_ratio值——使用文档中的width:height形式。 n超出允许范围。- JSON 格式错误——比如多余的逗号,或提示词字符串内未转义的引号。如果怀疑是这个问题,发送前先把请求体格式化输出检查一下。
状态查询或下载步骤返回 404
任务 ID 有误,或者你轮询的路径与你提交时使用的端点不匹配。首次集成时完整记录提交响应,并逐字符比对 ID。
轮询超时
如果 wait_for_job 到达了截止时间:
- 确认你检查的是正确的状态值;一个你无法识别的终态会看起来像挂起。
- 对于大型、复杂的渲染,应增加整体超时时间,而不是缩短轮询间隔。
- 集成期间记录每一次状态响应,这样你能看出在你的提示词组合下任务实际需要多久。
任务状态返回 failed
阅读 API 返回的错误响应体——它存在是有原因的。失败的任务通常出在提示词或参数一侧,修复点在请求里,而不是轮询代码里。
当有不清楚的地方,该模型的 HiAPI 文档是字段名和可接受值的权威来源。一次只验证一处改动,并保存一个已知可用的请求作为下次集成的参考。