HiAPI
博客

教程

如何通过 HiAPI API 使用 imagen4-ultra:curl 与 Python 示例

在 HiAPI 上进行高质量文生图的完整请求实战演练

2026年10月31日
博客封面图:淡蓝底上多层半透明玻璃平面叠错排列,折射出克制的冷蓝色带。

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 文档是字段名和可接受值的权威来源。一次只验证一处改动,并保存一个已知可用的请求作为下次集成的参考。

立即开始构建持久 AI 产物

获取 API 密钥,通过一个基于任务(task)的 API 调用图像、视频和音频模型。

阅读 API 文档