dokumentace
API

Images

Markdown

Generování a úpravy obrázků ve formátu OpenAI Images.

Úplný průvodce
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": "Akvarelová kresba: maják na skále, úsvit",
    "size": "1024x1024"
  }' 
200 OK
{
  "created": 1790812800,
  "data": [
    { "url": "https://…/content" }
  ],
  "usage": { "input_tokens": 18, "output_tokens": 1056 }
}

Autorizace

  • Authorizationheaderpovinný

    Klíč ve tvaru Bearer sk-…. Lze použít také hlavičky x-api-key nebo x-goog-api-key.

Tělo požadavku

  • modelstringpovinný

    Model pro obrázky: 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 a ještě 4.

  • promptstringpovinný

    Popis obrázku.

  • nintegernepovinný

    Kolik obrázků vygenerovat. Účtuje se za každý hotový obrázek.

  • sizestringnepovinný

    Velikost, například 1024x1024. Povolené velikosti závisejí na modelu.

  • qualitystringnepovinný

    Kvalita, pokud ji model podporuje (například low, medium, high).

  • response_formatstringnepovinný

    url nebo b64_json – pokud model podporuje tuto volbu.

Úpravy

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

Požadavek multipart/form-data: pole image (jeden nebo více obrázků), prompt, model, v případě potřeby mask.

Odpověď

  • data[]array

    Hotové obrázky: odkaz url nebo data b64_json, podle modelu.

Úpravy · 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 a Anthropic obvykle automaticky opakují požadavky při síťových chybách a chybách 5xx. U generování tuto funkci vypněte (max_retries=0) a kontrolujte X-Should-Retry před novým pokusem. Ztracená odpověď neznamená, že požadavek nebyl proveden.

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")
Máte další dotazy? Pošlete Request ID a popis – pomůžeme situaci objasnit.Napsat podpoře