dokumentasi
API

Images

Markdown

Penjanaan dan penyuntingan imej dalam format OpenAI Images.

Panduan lengkap
POSThttps://api.ailoot.ai/v1/images/generations
Images
curl https://api.ailoot.ai/v1/images/generations \
  -H "Authorization: Bearer $AILOOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2.5",
    "prompt": "Lukisan cat air: rumah api di atas tebing, waktu fajar",
    "size": "1024x1024"
  }' 
200 OK
{
  "created": 1790812800,
  "data": [
    { "url": "https://…/content" }
  ],
  "usage": { "input_tokens": 18, "output_tokens": 1056 }
}

Pengesahan

  • Authorizationheaderwajib

    Kunci dalam bentuk Bearer sk-…. Pengepala berikut juga boleh digunakan x-api-key atau x-goog-api-key.

Badan permintaan

  • modelstringwajib

    Model imej: gpt-image-2.5-sunburst, gemini-3.1-flash-image, grok-imagine-image-2.0, qwen-image-3.0-pro, image-01, gpt-image-2, gemini-3.1-flash-lite-image, grok-imagine-image, wan2.7-image, gpt-image-2.5-sunburst-2026-09-08, gemini-3-pro-image, grok-imagine-image-quality dan lagi 4.

  • promptstringwajib

    Penerangan imej.

  • nintegerpilihan

    Bilangan imej yang hendak dijana. Setiap imej yang siap dicaj.

  • sizestringpilihan

    Saiz, contohnya 1024x1024. Saiz yang dibenarkan bergantung pada model.

  • qualitystringpilihan

    Kualiti, jika disokong oleh model (contohnya, low, medium, high).

  • response_formatstringpilihan

    url atau b64_json — jika model menyokong pemilihan format.

Penyuntingan

POSThttps://api.ailoot.ai/v1/images/edits

Permintaan multipart/form-data: medan image (satu atau beberapa imej), prompt, model, jika perlu mask.

Respons

  • data[]array

    Imej yang siap: pautan url atau data b64_json, bergantung pada model.

Penyuntingan · multipart/form-data

: "${AILOOT_IMAGE_EDIT_MODEL:?Select a model whose actual card or GET /v1/models method supports /v1/images/edits}"
curl --fail-with-body --max-time 300 \
  -D image-edit-headers.txt -o image-edit.json \
  https://api.ailoot.ai/v1/images/edits \
  -H "Authorization: Bearer $AILOOT_API_KEY" \
  -F "model=$AILOOT_IMAGE_EDIT_MODEL" \
  -F 'prompt=Keep the subject and replace the background with a sunset' \
  -F 'image=@input.png'

input.png → image-edit.json → data[] → url | b64_json

import base64
import json
import mimetypes
import os
from pathlib import Path
import time
from urllib.parse import urljoin, urlsplit
from urllib.request import Request, urlopen

origin = "https://api.ailoot.ai"
out = Path("image-edit-results")
out.mkdir(exist_ok=True)

def save_all(data):
    rows = data.get("data", [])
    if not rows:
        raise RuntimeError("No completed image data; keep the original response")
    for index, row in enumerate(rows, 1):
        if row.get("b64_json"):
            content = base64.b64decode(row["b64_json"], validate=True)
            suffix = ".png" if content.startswith(b"\x89PNG") else ".bin"
        elif row.get("url"):
            url = row["url"]
            if urlsplit(url).scheme != "https":
                raise ValueError("Expected the exact returned HTTPS image URL")
            # Signed result URLs are downloaded without sending the API key to another host.
            with urlopen(url, timeout=300) as response:
                content = response.read()
                suffix = mimetypes.guess_extension(response.headers.get_content_type()) or ".bin"
        else:
            raise RuntimeError("Image has neither url nor b64_json")
        (out / ("image-%03d" % index + suffix)).write_bytes(content)


with open("image-edit.json", encoding="utf-8") as response:
    save_all(json.load(response))

Images · async

SDK OpenAI dan Anthropic biasanya mengulangi permintaan secara automatik apabila berlaku ralat rangkaian dan 5xx. Untuk penjanaan, nyahaktifkan ciri ini (max_retries=0) dan semak X-Should-Retry sebelum percubaan baharu. Respons yang hilang tidak bermaksud permintaan tidak dilaksanakan.

import base64
import json
import mimetypes
import os
from pathlib import Path
import time
from urllib.parse import urljoin, urlsplit
from urllib.request import Request, urlopen

origin = "https://api.ailoot.ai"
key = os.environ["AILOOT_API_KEY"]
out = Path("image-results")
out.mkdir(exist_ok=True)

def api(url, payload=None):
    url = urljoin(origin, url)
    if urlsplit(url).scheme != "https" or urlsplit(url).netloc != "api.ailoot.ai":
        raise ValueError("Unexpected API origin")
    request = Request(url, data=None if payload is None else json.dumps(payload).encode(),
                      headers={"Authorization": "Bearer " + key, "Content-Type": "application/json"})
    with urlopen(request, timeout=300) as response:
        headers = dict(response.headers)
        data = json.load(response)
    (out / "response-headers.json").write_text(json.dumps(headers, indent=2))
    return data, headers

def save_all(data):
    rows = data.get("data", [])
    if not rows:
        raise RuntimeError("No completed image data; keep the original response")
    for index, row in enumerate(rows, 1):
        if row.get("b64_json"):
            content = base64.b64decode(row["b64_json"], validate=True)
            suffix = ".png" if content.startswith(b"\x89PNG") else ".bin"
        elif row.get("url"):
            url = row["url"]
            if urlsplit(url).scheme != "https":
                raise ValueError("Expected the exact returned HTTPS image URL")
            # Signed result URLs are downloaded without sending the API key to another host.
            with urlopen(url, timeout=300) as response:
                content = response.read()
                suffix = mimetypes.guess_extension(response.headers.get_content_type()) or ".bin"
        else:
            raise RuntimeError("Image has neither url nor b64_json")
        (out / ("image-%03d" % index + suffix)).write_bytes(content)

# One POST. If its result is unknown, preserve it and check history; do not rerun creation.
task, headers = api("/v1/images/generations/async", {
    "model": "gpt-image-2.5", "prompt": "Watercolor lighthouse at dawn", "size": "1024x1024"})
(out / "created-task.json").write_text(json.dumps(task, indent=2))
task_id = task.get("task_id") or task.get("id")
poll_url = task.get("poll_url") or headers.get("Location") or headers.get("location")
if not task_id or not poll_url:
    raise RuntimeError("Keep the create response and Request ID; do not submit again")

for poll in range(60):
    task, headers = api(poll_url)  # Read the original task with the same key.
    (out / "task-status.json").write_text(json.dumps(task, indent=2))
    if task.get("status") == "completed":
        result = task["result"]
        (out / "image-response.json").write_text(json.dumps(result, indent=2))
        save_all(result)
        break
    if task.get("status") == "failed":
        raise RuntimeError(json.dumps(task.get("error")))
    if task.get("status") != "processing" or task.get("result_pending_check"):
        raise RuntimeError("Keep the original task ID and check it later; no new POST")
    time.sleep(min(60, max(1, int(headers.get("Retry-After", headers.get("retry-after", "3"))))))
else:
    raise TimeoutError("Polling stopped; resume GET reads using created-task.json, never repeat POST")
Masih ada soalan? Hantar Request ID dan penerangannya — kami akan membantu menyiasatnya.Hubungi sokongan