# gpt-image-2: генерация и редактирование изображений

QCode.cc предоставляет **полностью OpenAI-совместимое** API `gpt-image-2`, охватывающее две эндпоинты:

- **Text-to-image** `POST /v1/images/generations` — JSON-запрос, генерация изображения из текста
- **Редактирование изображения** `POST /v1/images/edits` — multipart-загрузка 1–8 исходных изображений (опциональная маска), перерисовка / правка / композиция по prompt (запущено в мае 2026)

`gpt-image-2` — это новейшая модель text-to-image от OpenAI (выпущена в апреле 2026 года) с **сильнейшим на сегодня рендерингом текста внутри изображения** среди публичных моделей (стабильно отрисовывает английские и китайские символы внутри картинки).

Что добавляет QCode.cc:

- **Drop-in для OpenAI SDK** — меняется только `base_url`; форматы запроса и ответа на 100% идентичны (включая multipart-эндпоинт edits)
- **Мульти-регион**: HK / Япония / США / Европа / прямое подключение Шэньчжэня — выбирайте ближайший узел
- **Единый API-ключ**: используется ваш существующий ключ QCode.cc (`cr_…`) — общая квота с Claude Code, Codex и Gemini CLI
- **Единый просмотр использования**: вызовы изображений и чата объединены в дашборде клиента + отдельная страница самообслуживания
- **Квоты делятся между эндпоинтами**: `generations` и `edits` используют общий лимит 100 изображений/день/ключ и 2 параллельных запроса

Типичные сценарии: постеры, иллюстрации, изображения товаров, UI-моки, материалы для соцсетей, **редактирование изображений (локальная перерисовка / композиция нескольких изображений / смена фона / высокоточная реставрация)**.

---

## Быстрый старт

### Text-to-image (`generations`)

Три строки Python для первого изображения:

```python
from openai import OpenAI
import base64

client = OpenAI(
    base_url="https://api.qcode.cc/qcode-img/v1",
    api_key="cr_YOUR_QCODE_API_KEY",
    timeout=180.0,  # 30–120 с на изображение, задайте ≥ 180 с
)

result = client.images.generate(
    model="gpt-image-2",
    prompt="A cyberpunk Tokyo street at night, neon reflecting in rain puddles",
    size="1024x1024",
    quality="low",
    n=1,
)

with open("output.png", "wb") as f:
    f.write(base64.b64decode(result.data[0].b64_json))
```

### Редактирование (`edits`)

Загрузите существующее изображение + prompt, опционально маску для локальной перерисовки:

```python
from openai import OpenAI
import base64

client = OpenAI(
    base_url="https://api.qcode.cc/qcode-img/v1",
    api_key="cr_YOUR_QCODE_API_KEY",
    timeout=180.0,
)

result = client.images.edit(
    model="gpt-image-2",
    image=open("cat.png", "rb"),
    mask=open("mask.png", "rb"),          # опционально: PNG alpha, прозрачная зона = область перерисовки
    prompt="put a tiny crown on the cat",
    size="1024x1024",
    quality="high",
)

with open("edited.png", "wb") as f:
    f.write(base64.b64decode(result.data[0].b64_json))
```

> ⚠️ **Обязательно задайте timeout ≥ 180 с явно**: дефолтный timeout OpenAI SDK слишком короткий. Время инференса `gpt-image-2` значительно больше, чем у классических text-to-image моделей (см. [Время генерации и timeout](#время-генерации-и-настройка-timeout) ниже).

---

## Точки входа

Сервис `gpt-image-2` (`generations` + `edits` общие) доступен на всех доменах QCode.cc — просто добавьте `/qcode-img/v1` к базе:

| Местоположение | Рекомендуемый base_url | Протокол | Примечания |
|---|---|---|---|
| Китай (требуется HTTPS) | `https://api.qcode.cc/qcode-img/v1` | HTTPS | Через глобальный CDN; `medium` / `high` может упереться в 524 (см. [100-секундный лимит CDN](#100-секундный-лимит-cdn-ошибки-524)) |
| HK / ЮВА | `https://asia.qcode.cc/qcode-img/v1` | HTTPS | Гонконгский PoP |
| Европа | `https://eu.qcode.cc/qcode-img/v1` | HTTPS | PoP во Франкфурте |
| Северная Америка | `https://us.qcode.cc/qcode-img/v1` | HTTPS | PoP в Лос-Анджелесе |

Все точки входа маршрутизируются в одну систему биллинга — использование и квоты унифицированы. Полное описание эндпоинтов: [Эндпоинты и API-пути](/ru/docs/getting-started/endpoints-and-api-paths).

> `qcode-img` — это префикс пути, выделенный для генерации и редактирования изображений; параллелен `/api` (Anthropic), `/openai/v1` (OpenAI chat) и `/gemini` (Gemini).

---

## API-справочник

### Общие заголовки запроса

| Header | Обязателен | Значение |
|---|---|---|
| `Authorization` | ✓ | `Bearer cr_xxxxxxxxxxxxxxxx` (ваш API-ключ QCode.cc) |
| `Content-Type` | ✓ | `application/json` (generations)<br/>`multipart/form-data` (edits) |

### Эндпоинт generations `/v1/images/generations`

**Эндпоинт**: `POST {base_url}/images/generations`
**Content-Type**: `application/json`

Тело запроса:

```json
{
  "model": "gpt-image-2",
  "prompt": "A small ceramic vase with sunflower, photorealistic",
  "size": "1024x1024",
  "quality": "low",
  "n": 1
}
```

Поля:

| Поле | Тип | Обяз. | По умолчанию | Значения |
|---|---|---|---|---|
| `model` | string | ✓ | — | Только `gpt-image-2` |
| `prompt` | string | ✓ | — | Описание изображения, **многоязычно** (включая английский и китайский) |
| `size` | string | ✗ | `1024x1024` | `1024x1024` (квадрат) / `1024x1536` (портрет) / `1536x1024` (альбом) |
| `quality` | string | ✗ | `medium` | `low` / `medium` / `high` |
| `n` | integer | ✗ | 1 | Изображений за вызов (1 – 4); **при > 4 возвращается 400** (без тихого усечения) |

### Эндпоинт edits `/v1/images/edits`

**Эндпоинт**: `POST {base_url}/images/edits`
**Content-Type**: `multipart/form-data` (загрузка файлов требует form-data, JSON не подходит)

Поля:

| Поле | Тип | Обяз. | По умолчанию | Значения / примечания |
|---|---|---|---|---|
| `model` | string | ✓ | — | Только `gpt-image-2` |
| `image` | file (× N) | ✓ | — | Исходное изображение (PNG / JPEG / WebP); **поддерживается 1 – 8 изображений** для композиции (повторяйте имя поля: `-F image=@a.png -F image=@b.png`) |
| `mask` | file | ✗ | — | PNG alpha-маска; **прозрачная зона = область перерисовки**; разрешение mask должно совпадать с `image` (масштабируется автоматически); применимо к одному изображению |
| `prompt` | string | ✓ | — | Инструкция редактирования (многоязычно) |
| `size` | string | ✗ | `auto` | `auto` / `1024x1024` / `1024x1536` / `1536x1024` / `2048x2048`. **Выходное разрешение модель выбирает адаптивно (по текущим замерам — примерно 1254×1254); `size` служит подсказкой о намерении.** Недопустимые значения возвращают 422 |
| `quality` | string | ✗ | `auto` | `auto` / `low` / `medium` / `high` |
| `n` | integer | ✗ | 1 | Изображений за вызов (1 – 4); **при > 4 возвращается 400** (без тихого усечения) |
| `background` | string | ✗ | `auto` | `auto` / `opaque`. **`transparent` не поддерживается gpt-image-2** (модель не может генерировать alpha-канал; при передаче возвращается 400) |
| `output_format` | string | ✗ | `png` | `png` / `jpeg` / `webp` |
| `output_compression` | integer | ✗ | — | `0 – 100`, действует для JPEG / WebP (игнорируется для PNG); **значения вне диапазона возвращают 400** |
| `input_fidelity` | string | ✗ | — | **Устарел**: gpt-image-2 всегда обрабатывает входные изображения с высокой верностью; переданное значение игнорируется и больше не пересылается в upstream |
| `response_format` | string | ✗ | `b64_json` | Принимается только `b64_json` (передача `url` возвращает 400) |
| `user` | string | ✗ | — | ID конечного пользователя для прозрачной передачи (используется для детекции abuse выше) |

**Лимиты загрузки**: один файл ≤ 25 МБ; суммарно ≤ 200 МБ (превышение даёт `413 image_too_large`).

### Ответ (одинаков для обоих эндпоинтов)

```json
{
  "created": 1777135432,
  "data": [
    {
      "b64_json": "iVBORw0KGgo...(base64 PNG/JPEG/WebP, 1-3 МБ)",
      "revised_prompt": "A small ceramic vase with sunflower..."
    }
  ]
}
```

- `b64_json`: base64-закодированные данные изображения, во фронте можно использовать напрямую: `<img src="data:image/<format>;base64,...">`
- `revised_prompt`: улучшенная моделью версия вашего prompt (опционально показать пользователю)

### Ответы об ошибках

Ошибки следуют стандартной схеме OpenAI:

```json
{
  "error": {
    "type": "rate_limit_error",
    "code": "image_daily_limit",
    "message": "Daily image generation count limit reached..."
  }
}
```

| HTTP | code | Значение |
|---|---|---|
| 401 | `invalid_api_key` | API-ключ недействителен или заблокирован |
| 401 | `key_expired` | API-ключ просрочен |
| 413 | `image_too_large` | Один файл > 25 МБ, или суммарно > 200 МБ |
| 422 | `unsupported_size` | size не поддерживается (допустимые значения — в таблице параметров каждого эндпоинта) |
| 429 | `crs_daily_exhausted` | Дневной бюджет аккаунта исчерпан |
| 429 | `crs_total_exhausted` | Накопленный бюджет аккаунта исчерпан |
| 429 | `image_daily_limit` | Лимит 100 изображений/день на ключ достигнут (общий для `generations` и `edits`; повышается по запросу) |
| 429 | `concurrency_exhausted` | Лимит 2 параллельных запросов на ключ достигнут (повышается по запросу) |
| 503 | `service_overloaded` | Общая нагрузка сервиса высокая — повторите позже |
| 503 | `image_provider_unavailable` | Upstream временно недоступен — повторите позже |

---

## Примеры кода

### Python (OpenAI SDK, рекомендуется)

**Text-to-image:**

```python
from openai import OpenAI
import base64

client = OpenAI(
    base_url="https://api.qcode.cc/qcode-img/v1",
    api_key="cr_YOUR_QCODE_API_KEY",
    timeout=180.0,
)

result = client.images.generate(
    model="gpt-image-2",
    prompt="A cyberpunk Tokyo street at night, neon reflecting in rain puddles",
    size="1024x1024",
    quality="low",
    n=1,
)

img_bytes = base64.b64decode(result.data[0].b64_json)
with open("output.png", "wb") as f:
    f.write(img_bytes)
print("Сохранено output.png")
```

**Редактирование (одно изображение + mask, локальная перерисовка):**

```python
from openai import OpenAI
import base64

client = OpenAI(
    base_url="https://api.qcode.cc/qcode-img/v1",
    api_key="cr_YOUR_QCODE_API_KEY",
    timeout=180.0,
)

result = client.images.edit(
    model="gpt-image-2",
    image=open("cat.png", "rb"),
    mask=open("mask.png", "rb"),
    prompt="put a tiny crown on the cat",
    size="1024x1024",
    quality="high",
    extra_body={"output_format": "png"},
)

img = base64.b64decode(result.data[0].b64_json)
with open("edited.png", "wb") as f:
    f.write(img)
```

**Редактирование (композиция нескольких изображений, 2 – 8):**

```python
result = client.images.edit(
    model="gpt-image-2",
    image=[
        open("scene.png", "rb"),       # 1-е изображение: сцена-фон
        open("product.png", "rb"),     # 2-е изображение: товар для размещения
    ],
    prompt="Place the product naturally into the scene, match the lighting and shadows.",
    size="1536x1024",
    quality="high",
)
```

### curl

**Text-to-image:**

```bash
curl https://api.qcode.cc/qcode-img/v1/images/generations \
  -H "Authorization: Bearer cr_YOUR_QCODE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2",
    "prompt": "A cyberpunk Tokyo street at night",
    "size": "1024x1024",
    "quality": "low",
    "n": 1
  }' \
  | jq -r ".data[0].b64_json" | base64 -d > output.png
```

**Редактирование:**

```bash
curl https://api.qcode.cc/qcode-img/v1/images/edits \
  -H "Authorization: Bearer cr_YOUR_QCODE_API_KEY" \
  -F "model=gpt-image-2" \
  -F "image=@cat.png" \
  -F "mask=@mask.png" \
  -F "prompt=put a tiny crown on the cat" \
  -F "size=1024x1024" \
  -F "quality=high" \
  -F "output_format=png" \
  | jq -r ".data[0].b64_json" | base64 -d > edited.png
```

**Композиция нескольких изображений (просто повторите `-F image=@`):**

```bash
curl https://api.qcode.cc/qcode-img/v1/images/edits \
  -H "Authorization: Bearer cr_YOUR_QCODE_API_KEY" \
  -F "model=gpt-image-2" \
  -F "image=@scene.png" \
  -F "image=@product.png" \
  -F "prompt=Place the product naturally into the scene" \
  -F "size=1536x1024" \
  -F "quality=high"
```

### JavaScript / Node.js / браузер

**Text-to-image:**

```javascript
const r = await fetch("https://api.qcode.cc/qcode-img/v1/images/generations", {
  method: "POST",
  headers: {
    "Authorization": "Bearer cr_YOUR_QCODE_API_KEY",
    "Content-Type":  "application/json",
  },
  body: JSON.stringify({
    model: "gpt-image-2",
    prompt: "A cyberpunk Tokyo street at night",
    size: "1024x1024",
    quality: "low",
    n: 1,
  }),
});
const json = await r.json();
const dataUrl = "data:image/png;base64," + json.data[0].b64_json;
document.querySelector("img").src = dataUrl;
```

**Редактирование (браузерный FormData):**

```javascript
const fd = new FormData();
fd.append("model", "gpt-image-2");
fd.append("image", imageFile);              // объект File из <input type="file">
fd.append("mask", maskFile);                // опционально
fd.append("prompt", "put a tiny crown on the cat");
fd.append("size", "1024x1024");
fd.append("quality", "high");
fd.append("output_format", "png");

const r = await fetch("https://api.qcode.cc/qcode-img/v1/images/edits", {
  method: "POST",
  headers: { "Authorization": "Bearer cr_YOUR_QCODE_API_KEY" },
  // Не задавайте Content-Type вручную — FormData выставит multipart/form-data с boundary автоматически
  body: fd,
});
const json = await r.json();
const dataUrl = "data:image/png;base64," + json.data[0].b64_json;
document.querySelector("img").src = dataUrl;
```

---

## Квоты

### Лимиты по умолчанию

| Параметр | Значение | Примечания |
|---|---|---|
| **Изображений в день** | 100 / день / ключ | Сброс в 00:00 по Пекинскому времени; **общий для `generations` и `edits`** |
| **Параллелизм** | 2 одновременно | Превышение — 429 `concurrency_exhausted`; общий для обоих эндпоинтов |
| **Размер загрузки** (только edits) | один файл 25 МБ / суммарно 200 МБ | Превышение — 413 `image_too_large` |
| **Бюджет аккаунта** | Общий с QCode.cc `dailyCostLimit` / `totalCostLimit` | Превышение — 429 `crs_daily_exhausted` |

Дефолтных квот хватает большинству пользователей. Для повышения — свяжитесь со службой поддержки.

### Просмотр использования

- **Дашборд клиента**: показывает чат и изображения вместе (последняя активность, сегодняшняя стоимость, накопленная стоимость, распределение по моделям)
- **Страница самообслуживания**: [https://api.qcode.cc/qcode-img/usage](https://api.qcode.cc/qcode-img/usage) — введите API-ключ, чтобы посмотреть статистику за последние 30 дней, детальный список вызовов и тренды на ECharts (ключ хранится только локально в браузере, не загружается)

---

## Биллинг

### Базовая цена (за изображение)

`generations` и `edits` используют одну ценовую таблицу:

| size | low | medium | high |
|---|---|---|---|
| **1024×1024** | $0.08 (floor) | $0.08 (floor) | $0.211 |
| **1024×1536** | $0.08 (floor) | $0.08 (floor) | $0.165 |
| **1536×1024** | $0.08 (floor) | $0.08 (floor) | $0.165 |
| **2048×2048** | $0.08 (floor) | $0.08 (floor) | $0.285 |

### Минимум $0.08 за вызов

- Когда фактическая стоимость < $0.08, тариф **$0.08** (`low` / `medium` обычно упираются в этот floor)
- Когда фактическая стоимость ≥ $0.08, оплачивается реальная сумма (без накрутки)
- **Эндпоинт edits тарифицируется по реальному расходу токенов, который возвращает upstream**; всё, что ниже $0.08, оплачивается как $0.08

### Множественные выходы и multi-input edits

- `n > 1` линейно масштабирует по **выходному** количеству. Пример: `n=2` + `1024×1024` high = 2 × $0.211 = $0.422
- Для multi-input в `edits` (`image=[…N]`) биллинг **по выходам** (`n`), а **не по входам**
- `mask` не влияет на оплату

### Сбои не тарифицируются

Любой 4xx / 5xx — **не оплачивается**; разрыв соединения клиентом тоже не оплачивается.

### Валюта

Стоимости в USD, расчёт по валютной политике основного аккаунта QCode.cc (RMB / USD).

---

## Время генерации и настройка timeout

`gpt-image-2` — модель на основе инференса, **значительно медленнее классических text-to-image** (DALL·E 3 / SDXL):

| quality | Типично | Сложные prompt, экстрим |
|---|---|---|
| `low` | 20 – 35 с | ~50 с |
| `medium` | 50 – 90 с | ~120 с |
| `high` | 70 – 120 с | ~150 с |

Замеры edits (успешные запросы редактирования): **p50 ≈ 43 с, p95 ≈ 91 с, около 3% запросов превышают 100 с.** Длинные запросы через CDN (жёсткий лимит 100 с) с небольшой вероятностью получают 524 — для редактирования рекомендуем `quality=low` / `medium`.

**Практические рекомендации**:

- Дефолтный timeout в OpenAI Python SDK слишком короткий — **всегда задавайте `timeout=180.0` или больше явно**
- В браузере у `fetch` нет дефолтного timeout, но при использовании `AbortController` задайте минимум 180 с
- При использовании `medium` / `high` из материкового Китая рекомендуется `asia.qcode.cc` (прямое подключение, без CDN 100 с лимита)

---

## 100-секундный лимит CDN (ошибки 524)

HTTPS-запросы к `api.qcode.cc / asia.qcode.cc / eu.qcode.cc / us.qcode.cc` проходят через глобальный CDN (CloudFlare). **CDN принудительно возвращает `524` для любого запроса, ждущего ответ origin более 100 секунд.**

| quality | Безопасно за CDN 100 с? |
|---|---|
| `low` | ✅ Безопасно (< 35 с) |
| `medium` | ⚠️ Иногда у потолка (близко к 100 с) |
| `high` | ❌ Регулярные 524 |

**Меры (рекомендуется для `medium` / `high`)**:

1. **Используйте `qcode-img` прямой вход**: `https://api.qcode.cc/qcode-img/v1` (без CDN, без 100-секундного лимита)
2. Или принимайте редкие 524 + клиентский ретрай

---

## Советы по prompt

### Text-to-image (`generations`)

- **Многоязычно**: китайский, английский, смешанные prompts работают
- **Чем больше деталей, тем лучше**: окружение, композиция, освещение, стиль, дистанция объектива / фокусное расстояние / ракурс
- **Избегайте брендов и знаменитостей**: модель может отказать или выдать размытый результат (политика контента OpenAI)
- **Рендеринг текста внутри изображения**: `gpt-image-2` исключителен в рендеринге английских / китайских символов внутри изображений (заголовки постеров, слоганы, вывески) — просто запишите текст в prompt, специальный синтаксис не нужен

Пример:

```
A vintage poster in Bauhaus style, bold black text "MORNING COFFEE" centered,
warm orange and cream color palette, geometric shapes, slightly textured paper background
```

### Редактирование (`edits`)

- **Маска говорит "где", а не "что"**: прозрачная зона = область перерисовки, непрозрачная сохраняется. Prompt описывает, что нарисовать. Разрешение mask должно совпадать с `image` (система масштабирует).
- **Для multi-input в prompt укажите роль каждого изображения** — например "First image is the scene, second image is the product to place into it" — `gpt-image-2` читает входы по порядку.
- **Передавать `input_fidelity` не нужно**: gpt-image-2 всегда обрабатывает входные изображения с высокой верностью, автоматически сохраняя лица / логотипы / текст / детали товара (параметр устарел; при передаче игнорируется).
- **Без mask** перерисовывается всё изображение по prompt (семантика сохраняется, но любая зона может измениться).

Пример:

```
# Локальная перерисовка: добавить корону, остальное без изменений
prompt = "Put a tiny golden crown on the cat's head. Keep everything else unchanged."
mask = (alpha PNG только с прозрачной зоной головы)
```

---

## Отличия от официального OpenAI API

| Параметр | OpenAI официально | QCode.cc |
|---|---|---|
| Совместимость SDK | — | ✅ 100% совместимо, меняется только `base_url` |
| Биллинг | Потокенно | По таблице выше, минимум $0.08 / изображение |
| `/v1/images/generations` (text-to-image) | ✅ | ✅ |
| `/v1/images/edits` (редактирование) | ✅ | ✅ **В работе** (впервые запущено в мае 2026; восстановлено и обновлено 2026-07-29: биллинг по реальному usage upstream): композиция 1–8 изображений, mask-инпейнтинг |
| `stream + partial_images` (инкрементальная отдача) | ✅ | ⏳ Пока не поддерживается; **передача `stream` / `partial_images` возвращает 400** |
| `/v1/images/variations` (чистые вариации) | ✅ (legacy DALL·E эндпоинт) | ⏳ Пока не поддерживается (как обходной путь — `edits` + пустой prompt) |

---

## Онлайн Playground

[https://api.qcode.cc/qcode-img/](https://api.qcode.cc/qcode-img/) — попробуйте в браузере:

- **Text-to-image и Image-edit** оба режима — визуальные (загрузка, рисование mask, выбор background / output_format и т. д.)
- Введите API-ключ + prompt и сразу генерируйте
- Переключение языка интерфейса (английский / китайский)
- По умолчанию `low` (избегает CDN 524)
- Включает полную API-документацию inline (вкладки curl / Python / JavaScript + таблица параметров + коды ошибок)
- Скачивание в один клик как PNG / JPEG / WebP

---

## Связанные документы

- [Эндпоинты и API-пути](/ru/docs/getting-started/endpoints-and-api-paths) — все домены QCode.cc, пути протоколов, curl-проверка
- [Биллинг](/ru/docs/reference/billing) — тарифы, квоты, правила тарификации