HiAPI
博客

教程

如何在 hiapi API 上调用 recraft-v4-styles-pro/text-to-image:curl 与 Python

2026年10月31日
hiapi 博客封面:近黑底色上有序排列的薄荷绿数据点阵由疏到密渐变,呈半调网点质感,另有点缀深青色,画面无文字。

此端点做什么以及何时使用

recraft-v4-styles-pro/text-to-image 将文本提示词转换为图像,其显著特点是风格感知:你可以通过风格参考来引导结果的视觉语言,而不是仅依赖提示词的措辞。当输出需要在大量生成中保持一致感、而非只在一两次生成中好看时,这是一个实用的选择。

开发者常在以下场景中使用它:

  • 品牌一致性素材——主视觉图、社交卡片和广告变体,都需要落在同一套视觉体系内。
  • 产品与营销样机——反复调整提示词、固定风格,产出一组符合品牌的变体。
  • 流水线步骤——生成作为更大自动化中的一个阶段,由另一个服务消费保存好的图像。

有一个特性决定了下面每个代码示例的写法:图像生成是异步的。请求提交任务后立即返回;图像稍后才会出现。你需要编写提交步骤和轮询步骤,并将它们视为两个独立的关注点。

准备 hiapi 凭据和请求基础

所有调用都经过 hiapi 统一的端点界面,因此在首次请求之前需要准备三样东西:

  1. 一个 API 密钥,来自你的 hiapi 账户。像对待其他机密一样对待它:从环境变量加载,绝不要硬编码进你可能分享的脚本中。
  2. 模型标识符,必须与发布时完全一致:recraft-v4-styles-pro/text-to-image。
  3. 一个支持 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 模型页面。

立即开始构建持久 AI 产物

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

阅读 API 文档