> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ruapi.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Генерация изображений: Gemini Image и GPT Image

> Генерация и редактирование изображений через RuAPI: Nano Banana (Gemini 2.5/3 Image) через чат-эндпоинт и GPT Image через /v1/images/generations — примеры на curl и Python

RuAPI даёт доступ к двум семействам моделей генерации изображений: **Gemini Image** (в народе — Nano Banana) и **GPT Image**. Они вызываются **по-разному**, и это главное, что нужно понять перед началом. Оплата в USDT, без зарубежной карты.

<Warning>
  **Модели Gemini Image не работают через `/v1/images/generations`.** Они вызываются через обычный чат-эндпоинт `/v1/chat/completions`, а готовое изображение приходит внутри текста ответа. Подробности — в разделе «Способ 1».
</Warning>

## Доступные модели

| ID модели                        | Эндпоинт                 | Тарификация | Когда брать                                            |
| -------------------------------- | ------------------------ | ----------- | ------------------------------------------------------ |
| `gemini-2.5-flash-image`         | chat                     | за вызов    | Самый дешёвый. Отлично редактирует готовые изображения |
| `gemini-3.1-flash-image-preview` | chat                     | за вызов    | Быстрый, качество выше, чем у 2.5                      |
| `gemini-3-pro-image-preview`     | chat                     | за вызов    | Максимальное качество (Nano Banana Pro)                |
| `gpt-image-2`                    | `/v1/images/generations` | по токенам  | Совместимость с экосистемой OpenAI                     |

Актуальные цены — на **[странице цен](https://www.ruapi.ai/pricing)**. Модели Gemini тарифицируются **за вызов** (одна фиксированная цена за картинку), `gpt-image-2` — **по токенам** (чем больше и качественнее картинка, тем дороже).

## Адрес API и авторизация

* **Base URL**: `https://www.ruapi.ai/v1`
* **Авторизация**: заголовок `Authorization: Bearer sk-ВАШ_КЛЮЧ` (создаётся в панели, раздел «Токены»)

***

## Способ 1. Gemini Image — через чат

Модели Gemini Image живут на **чат-эндпоинте**. Вы отправляете обычный запрос как к текстовой модели, а в ответ получаете изображение.

<Warning>
  **Изображение приходит как Markdown-ссылка с data URI прямо внутри `choices[0].message.content`** — отдельного поля для картинки нет. Ответ выглядит так:

  ```
  Вот рыжий кот в скафандре на фоне Сатурна!
  ![image](data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...)
  ```

  Base64 нужно вытащить из текста самостоятельно. Ниже готовый код.
</Warning>

### Текст → изображение

<CodeGroup>
  ```bash curl theme={null}
  curl https://www.ruapi.ai/v1/chat/completions \
    -H "Authorization: Bearer sk-ВАШ_КЛЮЧ" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "gemini-2.5-flash-image",
      "messages": [
        { "role": "user", "content": "Нарисуй рыжего кота в скафандре на фоне Сатурна" }
      ]
    }'
  ```

  ```python Python (requests) theme={null}
  import base64
  import re

  import requests

  resp = requests.post(
      "https://www.ruapi.ai/v1/chat/completions",
      headers={"Authorization": "Bearer sk-ВАШ_КЛЮЧ"},
      json={
          "model": "gemini-2.5-flash-image",
          "messages": [
              {"role": "user", "content": "Нарисуй рыжего кота в скафандре на фоне Сатурна"}
          ],
      },
  )
  content = resp.json()["choices"][0]["message"]["content"]

  # Вытаскиваем все изображения из Markdown data URI
  images = re.findall(r"!\[image\]\(data:(image/[^;]+);base64,([^)]+)\)", content)
  for i, (mime, b64) in enumerate(images):
      ext = mime.split("/")[-1]
      with open(f"image_{i}.{ext}", "wb") as f:
          f.write(base64.b64decode(b64))

  # Текст, который модель написала рядом с картинкой
  caption = re.sub(r"!\[image\]\([^)]*\)", "", content).strip()
  print(caption, f"— сохранено изображений: {len(images)}")
  ```
</CodeGroup>

<Tip>
  Изображений в ответе может быть **несколько** — поэтому в примере `findall`, а не `search`. Модель также почти всегда добавляет короткую текстовую подпись рядом с картинкой.
</Tip>

### Изображение → изображение (редактирование)

Чтобы отредактировать существующее изображение, передайте его в том же формате, что и для vision-моделей: массив `content` с частями `text` и `image_url`. В `url` можно подставить как обычную ссылку, так и data URI.

<CodeGroup>
  ```bash curl theme={null}
  curl https://www.ruapi.ai/v1/chat/completions \
    -H "Authorization: Bearer sk-ВАШ_КЛЮЧ" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "gemini-2.5-flash-image",
      "messages": [
        {
          "role": "user",
          "content": [
            { "type": "text", "text": "Сделай это изображение чёрно-белым. Больше ничего не меняй." },
            { "type": "image_url", "image_url": { "url": "https://example.com/photo.jpg" } }
          ]
        }
      ]
    }'
  ```

  ```python Python (requests) theme={null}
  import base64
  import re
  from pathlib import Path

  import requests

  # Вариант А — ссылка на изображение
  source = {"url": "https://example.com/photo.jpg"}

  # Вариант Б — локальный файл через data URI
  # raw = Path("photo.jpg").read_bytes()
  # source = {"url": "data:image/jpeg;base64," + base64.b64encode(raw).decode()}

  resp = requests.post(
      "https://www.ruapi.ai/v1/chat/completions",
      headers={"Authorization": "Bearer sk-ВАШ_КЛЮЧ"},
      json={
          "model": "gemini-2.5-flash-image",
          "messages": [
              {
                  "role": "user",
                  "content": [
                      {"type": "text", "text": "Сделай это изображение чёрно-белым. Больше ничего не меняй."},
                      {"type": "image_url", "image_url": source},
                  ],
              }
          ],
      },
  )
  content = resp.json()["choices"][0]["message"]["content"]
  mime, b64 = re.findall(r"!\[image\]\(data:(image/[^;]+);base64,([^)]+)\)", content)[0]
  Path("edited.png").write_bytes(base64.b64decode(b64))
  ```
</CodeGroup>

<Note>
  Соотношение сторон исходного изображения сохраняется — результат не обрезается до квадрата.
</Note>

### Многошаговое редактирование

Ответ модели можно **вернуть обратно** в `messages` как сообщение `assistant` — Markdown data URI будет распознан и изображение уйдёт на вход следующего шага. Так строится диалог «сделай чёрно-белым» → «а теперь добавь рамку».

```python theme={null}
messages = [{"role": "user", "content": "Нарисуй рыжего кота"}]

for instruction in ["Сделай изображение чёрно-белым", "Добавь белую рамку"]:
    resp = requests.post(URL, headers=HEADERS, json={"model": MODEL, "messages": messages}).json()
    reply = resp["choices"][0]["message"]["content"]
    messages.append({"role": "assistant", "content": reply})   # картинка остаётся в контексте
    messages.append({"role": "user", "content": instruction})
```

<Warning>
  Каждый шаг — это **отдельный платный вызов**. Кроме того, история с base64-изображениями быстро раздувает запрос: не тащите в контекст больше двух-трёх последних кадров.
</Warning>

### Поддерживаемые форматы входных изображений

`image/png`, `image/jpeg`, `image/webp`, `image/heic`, `image/heif`. Всё остальное будет отклонено с ошибкой `mime type is not supported by Gemini`.

### Нативный эндпоинт Gemini

Если вы уже пишете под Google GenAI SDK, тот же ключ работает и с нативным форматом:

```bash theme={null}
curl "https://www.ruapi.ai/v1beta/models/gemini-2.5-flash-image:generateContent" \
  -H "Authorization: Bearer sk-ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{ "contents": [{ "parts": [{ "text": "Нарисуй рыжего кота в скафандре" }] }] }'
```

Здесь изображение приходит **структурно** — в `candidates[0].content.parts[].inlineData.data` (base64), без Markdown. Если вам не нужна совместимость с OpenAI SDK, этот вариант удобнее.

***

## Способ 2. GPT Image — через `/v1/images/generations`

`gpt-image-2` — это классический эндпоинт генерации изображений OpenAI. Никаких `messages`, только `prompt`.

<CodeGroup>
  ```bash curl theme={null}
  curl https://www.ruapi.ai/v1/images/generations \
    -H "Authorization: Bearer sk-ВАШ_КЛЮЧ" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "gpt-image-2",
      "prompt": "Рыжий кот в скафандре на фоне Сатурна",
      "size": "1024x1024",
      "quality": "low",
      "n": 1
    }'
  ```

  ```python Python (openai SDK) theme={null}
  import base64

  from openai import OpenAI

  client = OpenAI(api_key="sk-ВАШ_КЛЮЧ", base_url="https://www.ruapi.ai/v1")

  result = client.images.generate(
      model="gpt-image-2",
      prompt="Рыжий кот в скафандре на фоне Сатурна",
      size="1024x1024",
      quality="low",
      n=1,
  )

  with open("image.png", "wb") as f:
      f.write(base64.b64decode(result.data[0].b64_json))
  ```
</CodeGroup>

### Параметры

| Параметр  | Значения                                 | Комментарий                                                    |
| --------- | ---------------------------------------- | -------------------------------------------------------------- |
| `size`    | `1024x1024`, `1536x1024`, `1024x1536`, … | Обе стороны должны быть **кратны 16**                          |
| `quality` | `low`, `medium`, `high`                  | Влияет на число выходных токенов, то есть **напрямую на цену** |
| `n`       | 1 и больше                               | Каждое изображение тарифицируется отдельно                     |

### Ответ

```json theme={null}
{
  "data": [
    {
      "b64_json": "iVBORw0KGgoAAAANSUhEUg...",
      "url": "https://.../image.png",
      "revised_prompt": "Рыжий кот в скафандре на фоне Сатурна"
    }
  ],
  "usage": { "input_tokens": 17, "output_tokens": 425, "total_tokens": 442 }
}
```

<Warning>
  **Используйте `b64_json`, а не `url`.** Поле `url` указывает на внешнее хранилище: срок жизни ссылки не гарантируется, и она может перестать открываться в любой момент. `b64_json` — это сама картинка, она у вас навсегда.
</Warning>

<Tip>
  `usage.output_tokens` — это токены изображения, по ним и считается стоимость. Понижение `quality` до `low` уменьшает их в разы: удобно для черновиков и тестов.
</Tip>

***

## Частые вопросы

<AccordionGroup>
  <Accordion title="Почему gemini-2.5-flash-image не работает через /v1/images/generations?">
    Потому что это не модель генерации изображений в терминах OpenAI, а мультимодальная чат-модель, которая умеет отдавать картинки. Вызывайте её через `/v1/chat/completions` — см. «Способ 1».
  </Accordion>

  <Accordion title="Что за огромная строка base64 в поле content?">
    Это и есть изображение. При отдаче через OpenAI-совместимый чат-эндпоинт картинка вставляется в текст ответа как `![image](data:image/png;base64,...)`. Вытащите её регуляркой (пример выше) или используйте нативный эндпоинт Gemini, где изображение приходит отдельным полем.
  </Accordion>

  <Accordion title="Какую модель выбрать для редактирования фотографий?">
    `gemini-2.5-flash-image` — лучшее соотношение цены и качества для правок. Если нужен максимум детализации, берите `gemini-3-pro-image-preview`. `gpt-image-2` тоже умеет редактировать, но через отдельный эндпоинт `/v1/images/edits`.
  </Accordion>

  <Accordion title="Сколько хранятся результаты?">
    Модели Gemini не хранят ничего: base64 приходит прямо в ответе. У `gpt-image-2` в ответе есть поле `url`, но полагаться на него не стоит — сохраняйте `b64_json`.
  </Accordion>

  <Accordion title="В ответе Gemini есть usage с токенами — за них списывают?">
    Нет. Модели Gemini Image тарифицируются **за вызов**: одна фиксированная цена за картинку. Поле `usage` приходит справочно и на списание не влияет. По токенам считается только `gpt-image-2`.
  </Accordion>
</AccordionGroup>
