玄枢API

图片生成与编辑示例

用 gpt-image-2 完成文生图、图生图与图片编辑,包含可运行的 Python 与 Node.js 流式示例,以及常见问题排查。

1. 准备 API Key

  1. 还没有账户的先到 /register 注册。
  2. /keys 创建 Key,把示例里的 <YOUR_API_KEY> 换成完整值。
  3. /available-channels 确认 gpt-image-2 对当前 Key 可见。

2. 文生图

只给提示词,不传参考图。响应用 SSE 推送,partial_image 事件表示进度,最终事件里的 b64_json 就是图片。

import base64
import json
import urllib.request
from pathlib import Path

API_URL = "https://www.xuanshuapi.com/v1/images/generations"
API_KEY = "<YOUR_API_KEY>"


def iter_sse(response):
    buffer = ""
    while chunk := response.read(4096):
        buffer += chunk.decode("utf-8", errors="replace")
        frames = buffer.split("\n\n")
        buffer = frames.pop()
        for frame in frames:
            payload = [
                line[5:].strip()
                for line in frame.splitlines()
                if line.startswith("data:")
            ]
            data = "\n".join(payload).strip()
            if data and data != "[DONE]":
                yield data


body = {
    "model": "gpt-image-2",
    "prompt": "一只在太空里漂浮的猫,科技感插画风格",
    "n": 1,
    "size": "1024x1024",
    "stream": True,
    "response_format": "b64_json",
}

request = urllib.request.Request(
    API_URL,
    data=json.dumps(body).encode("utf-8"),
    method="POST",
    headers={
        "Authorization": "Bearer " + API_KEY,
        "Content-Type": "application/json",
        "Accept": "text/event-stream",
    },
)

with urllib.request.urlopen(request, timeout=900) as response:
    for data in iter_sse(response):
        event = json.loads(data)
        if event.get("type") == "image_generation.partial_image":
            print(".", end="", flush=True)
        image = (
            event.get("b64_json")
            or ((event.get("data") or [{}])[0]).get("b64_json")
            or (event.get("item") or {}).get("result")
        )
        if image:
            Path("generated-image.png").write_bytes(base64.b64decode(image))
            print("\n已保存:generated-image.png")
            break

3. 图生图(JSON 传参考图)

参考图用 images[].image_url 传入,支持多张,也接受 data URL。images[].file_id 不受支持,传了会直接报错。

import base64
import json
import urllib.request
from pathlib import Path

API_URL = "https://www.xuanshuapi.com/v1/images/edits"
API_KEY = "<YOUR_API_KEY>"


def iter_sse(response):
    buffer = ""
    while chunk := response.read(4096):
        buffer += chunk.decode("utf-8", errors="replace")
        frames = buffer.split("\n\n")
        buffer = frames.pop()
        for frame in frames:
            payload = [
                line[5:].strip()
                for line in frame.splitlines()
                if line.startswith("data:")
            ]
            data = "\n".join(payload).strip()
            if data and data != "[DONE]":
                yield data


# 参考图用 images[].image_url 传入,支持多张,也可传 data URL。
# 注意:images[].file_id 不受支持。
body = {
    "model": "gpt-image-2",
    "prompt": "参考这张图,生成一张更精致的科技风品牌图。",
    "images": [{"image_url": "https://www.xuanshuapi.com/brand/og-cover.png"}],
    "n": 1,
    "size": "1024x1024",
    "quality": "auto",
    "stream": True,
    "response_format": "b64_json",
}

request = urllib.request.Request(
    API_URL,
    data=json.dumps(body).encode("utf-8"),
    method="POST",
    headers={
        "Authorization": "Bearer " + API_KEY,
        "Content-Type": "application/json",
        "Accept": "text/event-stream",
    },
)

with urllib.request.urlopen(request, timeout=900) as response:
    for data in iter_sse(response):
        event = json.loads(data)
        if event.get("type") == "image_generation.partial_image":
            print(".", end="", flush=True)
        image = (
            event.get("b64_json")
            or ((event.get("data") or [{}])[0]).get("b64_json")
            or (event.get("item") or {}).get("result")
        )
        if image:
            Path("generated-image.png").write_bytes(base64.b64decode(image))
            print("\n已保存:generated-image.png")
            break

4. 图片编辑(multipart 上传)

直接上传图片文件并按提示词修改。这条路径用 multipart/form-data,不要手写 Content-Type,交给 FormData 生成 boundary。

import { writeFile } from "node:fs/promises";

const API_URL = "https://www.xuanshuapi.com/v1/images/edits";
const API_KEY = "<YOUR_API_KEY>";
const SOURCE_URL = "https://www.xuanshuapi.com/brand/og-cover.png";

async function* readSse(response) {
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buffer = "";
  while (true) {
    const { value, done } = await reader.read();
    if (done) break;
    buffer += decoder.decode(value, { stream: true });
    const frames = buffer.split(/\r?\n\r?\n/);
    buffer = frames.pop() || "";
    for (const frame of frames) {
      const data = frame
        .split(/\r?\n/)
        .filter((line) => line.startsWith("data:"))
        .map((line) => line.slice(5).trim())
        .join("\n");
      if (data && data !== "[DONE]") yield data;
    }
  }
}

const source = await fetch(SOURCE_URL);
const sourceType = source.headers.get("content-type") || "image/png";
const sourceFile = new File(
  [await source.arrayBuffer()], "source.png", { type: sourceType });

const form = new FormData();
form.append("image", sourceFile);
form.append("prompt", "把图片整体色调改为蓝色。");
form.append("model", "gpt-image-2");
form.append("n", "1");
form.append("quality", "auto");
form.append("size", "1024x1024");
form.append("stream", "true");
form.append("response_format", "b64_json");

const response = await fetch(API_URL, {
  method: "POST",
  headers: { Authorization: "Bearer " + API_KEY, Accept: "text/event-stream" },
  body: form,
});
if (!response.ok) throw new Error(await response.text());

for await (const data of readSse(response)) {
  const event = JSON.parse(data);
  if (event.type === "image_generation.partial_image") process.stdout.write(".");
  const image = event.b64_json ?? event.data?.[0]?.b64_json ?? event.item?.result;
  if (image) {
    await writeFile("edited-image.png", Buffer.from(image, "base64"));
    console.log("\n已保存:edited-image.png");
    break;
  }
}

5. 成功标准

命令正常退出并在当前目录生成 generated-image.png 或 edited-image.png,图片能正常打开;在 /usage 能看到 gpt-image-2 的成功调用记录,且没有 404、401/403 或 429。

6. 常见问题排查

现象检查处理
404文生图端点是 /v1/images/generations,图生图与编辑是 /v1/images/edits,都带 /v1。修正 URL 后重试。
400 缺少参考图JSON 方式调用 edits 时 images[].image_url 是必填项。补上 images 数组,或改用 multipart 上传图片文件。
file_id 报错images[].file_id 与 mask.file_id 都不受支持。改用 image_url 或 data URL 传图。
模型不可用/available-channels 确认 gpt-image-2 对当前 Key 可见。换用控制台中可见的图片模型。
429/usage 检查余额、Key 限额与并发。降低并发并等待限流窗口恢复。
拿不到图片流式响应的最终图片可能出现在 b64_json、data[0].b64_json 或 item.result 之一。按示例里三个位置都取一遍,取到即写文件并跳出循环。