HiAPI
博客

教程

如何在 HiAPI API 上调用 muse-image-1.0/image-to-image:curl、Python 与一次可用的请求示例

2026年10月31日
奶油色底上的多层薄纸叠层插画,一块陶红色纸层作点缀,构图克制均衡,为教程文章封面图。

图像到图像(image-to-image)请求究竟发送什么

在写第一行代码之前,先弄清楚一次图像到图像调用期望什么,会很有帮助。与纯文本到图像请求中提示词是唯一创意输入不同,muse-image-1.0/image-to-image 需要一张源图像,再加上如何转换它的指令。

最低限度,你的请求负载包括:

  • model:标识符 muse-image-1.0/image-to-image。
  • image:你想编辑的源图像。这通常以 base64 编码字符串或可公开访问的 URL 发送,具体取决于端点接受的形式。请查阅模型的输入 schema,确认确切的字段名和格式。
  • prompt:你想要进行的编辑的文本描述。要具体说明要改什么、要保留什么。
  • 诸如 strength 或 guidance 之类的可选参数(如果模型暴露了它们)可以让你控制输出与源图像的偏离程度。确切参数集因模型而异,因此务必根据 API 参考确认,而不是想当然。

关键的心态转变是:你不是从零生成,而是提供一个起点和一个方向。像 "make it better" 这样含糊的提示词会产生不可预测的结果,因为模型有太多自由。而像 "replace the sky with a sunset and keep the buildings unchanged" 这样的提示词就给模型一个明确的约束。

此外,要事先确认图像约束——支持的格式、最大尺寸和文件大小。如果你的源图像是 12 MB 的 PNG,可能需要先降采样或转换为 JPEG,请求才会被接受。在发送之前正确处理图像,可以省去一次往返和一条令人困惑的错误信息。

一旦你有了源图像和清晰的编辑提示词,就可以进行第一次调用了。

用 curl 发出第一个请求

验证集成最快的方法是从终端直接发送请求。确切的端点路径和负载 schema 在模型的 API 参考中定义;下面的示例展示了一般形态,以便你根据当前规范进行调整。

curl -X POST https://api.hiapi.ai/v1/images/edits \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "muse-image-1.0/image-to-image",
    "image": "https://your-bucket.example.com/source.jpg",
    "prompt": "replace the sky with a warm sunset, keep the buildings unchanged",
    "strength": 0.6
  }'

请用环境变量替换 $HIAPI_API_KEY,而不是把密钥直接粘贴进去。如果你的工具支持,在 shell 会话中导出密钥,这样它就不会留在命令历史中。

返回的响应会包含一个作业标识符。由于图像编辑计算密集,API 通常不会在同一次响应中返回完成的图像。相反,你会收到一个作业 ID 和状态。保存该 ID——下一步你将用它轮询结果。

如果调用失败,请仔细阅读错误响应体。400 通常表示负载格式错误或图像格式不受支持。401 表示密钥缺失或错误。429 表示你发送请求太快。在终端阶段修复这些问题,比在完整应用程序中调试要容易得多。

同样的请求用 Python 实现

curl 调用成功后,把它转换成一个小型 Python 函数。使用 requests 可以让示例依赖少且易于移植。

import os
import requests

HIAPI_API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = "https://api.hiapi.ai/v1/images/edits"

def submit_edit(image_url: str, prompt: str, strength: float = 0.6) -> str:
    payload = {
        "model": "muse-image-1.0/image-to-image",
        "image": image_url,
        "prompt": prompt,
        "strength": strength,
    }
    headers = {
        "Authorization": f"Bearer {HIAPI_API_KEY}",
        "Content-Type": "application/json",
    }
    response = requests.post(BASE_URL, json=payload, headers=headers, timeout=30)
    response.raise_for_status()
    data = response.json()
    return data["id"]

关于这个函数,有几点说明:

  • timeout 参数可以防止网络停滞时脚本无限挂起。对于提交调用,30 秒很宽裕,但可按需调整。
  • raise_for_status() 将 HTTP 错误转换为异常,这样你可以在一个地方捕获它们。
  • 只返回作业 ID 让函数保持专注。轮询逻辑应放在单独的函数中。

如果你希望以字节而不是 URL 发送源图像,请读取文件、进行 base64 编码,并将结果放入 image 字段。在切换之前,请确认文档中期望的格式,因为这两种编码并不总是可以互换。

这个函数有意保持最小化。在实际服务中,你会添加日志、重试处理和类型校验,但核心请求模式正是你在这里看到的。

处理异步作业并轮询结果

图像编辑需要时间——通常从几秒到几十秒不等,取决于提示词和分辨率。API 的处理方式是接受你的请求、返回作业 ID,并在后台处理工作。你的任务是反复检查,直到状态达到终态。

轮询听起来简单,但一个每 100 毫秒触发一次的幼稚循环会浪费配额,还可能触发速率限制。使用合理的间隔和重试上限:

import time
import requests

def poll_job(job_id: str, interval: float = 2.0, max_attempts: int = 30) -> dict:
    url = f"https://api.hiapi.ai/v1/jobs/{job_id}"
    headers = {"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"}
    for attempt in range(max_attempts):
        response = requests.get(url, headers=headers, timeout=15)
        response.raise_for_status()
        data = response.json()
        status = data["status"]
        if status == "succeeded":
            return data
        if status == "failed":
            raise RuntimeError(data.get("error", "job failed"))
        time.sleep(interval)
    raise TimeoutError(f"job {job_id} did not finish after {max_attempts} attempts")

两秒的间隔是合理的起点。如果你的作业通常五秒内完成,可以在开始更频繁地轮询,然后逐渐退避。如果它们通常需要更长时间,就降低轮询频率,避免不必要的调用。

重试上限是你的安全网。没有它,卡住的作业可能会无限循环。达到上限时,抛出明确的错误,让调用方知道操作超时,而不是静默挂起。

在生产环境中,考虑将轮询移到后台 worker 或队列中,这样你的请求处理线程就不会被阻塞等待图像渲染完成。

下载并存储输出图像

当作业达到 succeeded 状态时,响应包含一张或多张输出图像,通常以 URL 形式提供。你的下一步是下载图像并持久存储。

def download_image(result: dict, dest_path: str) -> None:
    image_url = result["output"][0]["url"]
    response = requests.get(image_url, timeout=30)
    response.raise_for_status()
    with open(dest_path, "wb") as f:
        f.write(response.content)

几个实际考虑:

  • 输出 URL 可能是临时的。把它们当作短生命周期资源,及时下载,而不是把 URL 作为唯一引用存储。
  • 以二进制模式写入文件。图像响应不是文本;用 "w" 打开会损坏数据。
  • 在宣告成功之前,验证文件非空。零字节下载通常意味着 URL 已过期或请求被阻止。

对于本地脚本之外的任何场景,请将下载直接流式传输到你的存储提供商,而不是先保存到磁盘。大多数对象存储 SDK 接受类文件对象或字节流,因此你可以将 response.raw 或 response.content 管道传入上传调用,无需中间文件。

最后,将作业 ID 与存储的对象一起记录。如果输出后来损坏,或者你需要重现特定编辑,作业 ID 加上原始输入可以让你追溯发送的内容。

常见故障点及其修复方法

大多数集成问题属于少数几类。以下是诊断每种问题的方法。

请求在创建作业前被拒绝

提交时的 400 错误通常表示负载错误。检查 model 是否确切为 muse-image-1.0/image-to-image,image 是否可访问或 base64 编码正确,以及 prompt 是否为非空字符串。如果图像是 URL,确认其可公开访问——私有 bucket 或已过期的签名 URL 将无法通过验证。

作业在处理过程中失败

如果轮询返回 failed 状态,请阅读响应体中的错误消息。常见原因包括图像过大、提示词违反内容政策,或参数值超出允许范围。缩小图像尺寸并简化提示词,以隔离原因。

轮询超时

如果你达到重试上限而没有终态,作业可能确实需要更多时间,或者可能卡住了。首先,增加 max_attempts,并根据 API 参考确认典型处理时间。如果作业持续超时,检查源图像是否异常大。不要简单地移除重试上限——有界重试可以防止静默的无限循环。

速率限制

429 响应意味着你发送请求太快。请退避、遵守任何 retry-after 头,并错开并发提交。如果你正在处理一批图像,请顺序处理或使用较小的并发限制,而不是一次性全部发出。

输出缺失或被截断

如果作业成功但下载的文件为空,输出 URL 可能在轮询和下载之间过期了。成功之后立即下载。如果图像损坏,确认你以二进制模式写入,并且没有对流应用任何文本编码。

当你记录请求负载、作业 ID 和状态转换时,调试会更容易。有了这三条信息,几乎任何失败都可以追溯到源头。

有了请求形态、curl 和 Python 模式、轮询逻辑以及下载步骤,你就拥有了在 HiAPI API 上使用 muse-image-1.0/image-to-image 的可工作流水线。从终端示例开始,将其移入脚本,待正常路径稳定后再添加重试和日志。

立即开始构建持久 AI 产物

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

阅读 API 文档