hubris
Возможности
ВОЗМОЖНОСТИ

Генерация изображений

Генерация и редактирование изображений: гибридные модели через /v1/chat/completions с modalities, премиум-модели через /v1/images/generations с input_references.

Hubris генерирует изображения двумя путями — какой использовать, зависит от модели:

Линейка моделейЭндпоинтВход для редактирования
Google Gemini *-image (Nano Banana), OpenAI GPT-5 ImagePOST /v1/chat/completionsкартинка в messages (как во Vision)
FLUX.2, Recraft, Seedream, Riverflow, Grok ImaginePOST /v1/images/generationsполе input_references

Первый путь — «диалоговый»: модель отвечает и текстом, и картинкой, умеет пошагово дорабатывать результат в переписке. Второй — классический Images API в формате OpenAI: один запрос → готовые изображения, фиксированная цена за штуку. Полный список моделей — фильтр «Output: image» в каталоге; на карточке модели видно, как она тарифицируется: токенами (chat-путь) или за изображение (images-путь).

Генерация через chat completions

Передайте modalities и модель с поддержкой image-output:

curl -s https://api.hubris.pw/v1/chat/completions \
  -H "Authorization: Bearer sk-gw-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/gemini-2.5-flash-image",
    "modalities": ["image", "text"],
    "messages": [{"role": "user", "content": "Закат над горами в стиле Гибли"}]
  }'

Картинка возвращается как base64 data URL в choices[0].message.images[0].image_url.url:

{
  "id": "chatcmpl-...",
  "model": "google/gemini-2.5-flash-image",
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "Готово!",
        "images": [
          {
            "type": "image_url",
            "image_url": { "url": "data:image/png;base64,iVBORw0KGgo..." }
          }
        ]
      }
    }
  ],
  "usage": { "prompt_tokens": 18, "completion_tokens": 1290, "total_tokens": 1308 }
}

modalities: ["image", "text"] — модель отдаёт и текст-комментарий, и картинку. Если передать modalities не-image модели, вернётся ошибка провайдера.

Генерация через /v1/images/generations

FLUX.2, Recraft, Seedream, Riverflow и Grok Imagine через chat completions недоступны (404 model_not_found) — они работают только через выделенный эндпоинт в формате OpenAI Images API:

curl -s https://api.hubris.pw/v1/images/generations \
  -H "Authorization: Bearer sk-gw-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "black-forest-labs/flux.2-pro",
    "prompt": "product photo of a ceramic mug on a linen tablecloth, soft window light"
  }'

Ответ — data[].b64_json (base64 без префикса data:), как у OpenAI. Официальные SDK работают из коробки:

import base64
from openai import OpenAI

client = OpenAI(base_url="https://api.hubris.pw/v1", api_key="sk-gw-...")

resp = client.images.generate(
    model="black-forest-labs/flux.2-pro",
    prompt="product photo of a ceramic mug on a linen tablecloth",
)
open("mug.png", "wb").write(base64.b64decode(resp.data[0].b64_json))

Совет по FLUX: пишите промпт на английском — кириллицу эта линейка норовит отрисовать как текст на самой картинке. Gemini, Seedream и Recraft русский понимают нормально.

Все поля запроса, коды ошибок и биллинг — в референсе POST /v1/images/generations.

Редактирование изображений

Оба пути умеют image-to-image: подаёте исходную картинку + текст, что с ней сделать. Картинка передаётся как data URL с base64 (надёжно у всех провайдеров) или как публичная https-ссылка.

Через chat completions (Gemini, GPT-5 Image)

Исходное изображение кладётся в content-массив сообщения — ровно так же, как во Vision:

IMG=$(base64 -w0 photo.jpg)
curl -s https://api.hubris.pw/v1/chat/completions \
  -H "Authorization: Bearer sk-gw-..." \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "model": "google/gemini-2.5-flash-image",
  "modalities": ["image", "text"],
  "messages": [{
    "role": "user",
    "content": [
      { "type": "text", "text": "Убери фон, оставь предмет на чистом белом" },
      { "type": "image_url", "image_url": { "url": "data:image/jpeg;base64,$IMG" } }
    ]
  }]
}
EOF

Python (в официальном SDK поле modalities не объявлено — передаётся через extra_body, а images ответа читается из model_extra):

import base64
from openai import OpenAI

client = OpenAI(base_url="https://api.hubris.pw/v1", api_key="sk-gw-...")

b64 = base64.b64encode(open("photo.jpg", "rb").read()).decode()

resp = client.chat.completions.create(
    model="google/gemini-2.5-flash-image",
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": "Сделай из фото акварельную иллюстрацию"},
            {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{b64}"}},
        ],
    }],
    extra_body={"modalities": ["image", "text"]},
)

data_url = resp.choices[0].message.model_extra["images"][0]["image_url"]["url"]
header, b64_out = data_url.split(",", 1)
open("result.png", "wb").write(base64.b64decode(b64_out))

TypeScript:

import fs from 'node:fs';
import OpenAI from 'openai';

const client = new OpenAI({ baseURL: 'https://api.hubris.pw/v1', apiKey: 'sk-gw-...' });

const b64 = fs.readFileSync('photo.jpg').toString('base64');

const resp = await client.chat.completions.create({
  model: 'google/gemini-2.5-flash-image',
  messages: [{
    role: 'user',
    content: [
      { type: 'text', text: 'Замени фон на вечерний город, предмет не трогай' },
      { type: 'image_url', image_url: { url: `data:image/jpeg;base64,${b64}` } },
    ],
  }],
  modalities: ['image', 'text'],
} as any);

const dataUrl = (resp.choices[0].message as any).images[0].image_url.url as string;
fs.writeFileSync('result.png', Buffer.from(dataUrl.split(',')[1]!, 'base64'));

Главное преимущество chat-пути — пошаговая доработка в диалоге. Получили картинку → не понравилась деталь → кладёте её в следующее user-сообщение как image_url и пишете, что поправить («сделай небо темнее, остальное не трогай»). Модель редактирует именно ваш результат, а не генерирует заново.

Через /v1/images/generations (FLUX, Recraft, Seedream, Riverflow, Grok)

Референсные изображения передаются полем input_references — массив в том же формате image_url:

IMG=$(base64 -w0 product.jpg)
curl -s https://api.hubris.pw/v1/images/generations \
  -H "Authorization: Bearer sk-gw-..." \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "model": "bytedance-seed/seedream-4.5",
  "prompt": "Перенеси предмет с фото в интерьер лофта, мягкий дневной свет",
  "input_references": [
    { "type": "image_url", "image_url": { "url": "data:image/jpeg;base64,$IMG" } }
  ]
}
EOF

То же через официальный SDK — extra_body:

resp = client.images.generate(
    model="bytedance-seed/seedream-4.5",
    prompt="Перенеси предмет с фото в интерьер лофта, мягкий дневной свет",
    extra_body={"input_references": [
        {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{b64}"}}
    ]},
)

Сколько референсов принимает модель (по нашим замерам; проверка на стороне провайдера — лишние он отклонит своей ошибкой):

МодельРеференсов
Seedream 4.5до 14
FLUX.2 (pro/max/flex/klein)до 8
Grok Imagineдо 3
Recraft (v3–v4.1)1

Лимит Riverflow мы не замеряли — начните с 1–2 референсов. У Recraft дополнительно работает strength (0..1, по умолчанию 0.2) — насколько далеко уходить от оригинала; у Riverflow — super_resolution_references для image-to-image-апскейла (до 4, только при image-to-image). Провайдер-специфичные поля передаются в теле запроса как есть.

Параметры генерации

Chat-путь (Gemini): объект image_config в теле запроса:

  • aspect_ratio"1:1" (default), "16:9", "9:16", "4:3", "3:4", "21:9"; у gemini-3.1-flash-image-preview дополнительно "1:4", "4:1", "1:8", "8:1".
  • image_size"1K" (default), "2K", "4K"; "0.5K" — только у gemini-3.1-flash-image-preview.
curl -s https://api.hubris.pw/v1/chat/completions \
  -H "Authorization: Bearer sk-gw-..." \
  -d '{
    "model": "google/gemini-3-pro-image-preview",
    "modalities": ["image", "text"],
    "messages": [{"role": "user", "content": "Морской пейзаж"}],
    "image_config": { "aspect_ratio": "16:9", "image_size": "2K" }
  }'

Images-путь: параметры — плоские поля тела запроса, набор у каждой линейки свой (image_config здесь не используется):

  • n — сколько изображений за запрос (Seedream до 10, Recraft до 6; FLUX и Grok — по одному).
  • aspect_ratio, resolution — понимает Grok Imagine ("1K"/"2K"); FLUX, Recraft и Seedream размер задают сами — эти поля им слать не нужно (в лучшем случае игнор, в худшем 400).
  • Recraft: style (стилевые пресеты — список на карточке модели), text_layout (текст на картинке, только V3), rgb_colors, background_rgb_color, strength.
  • Riverflow: font_inputs — массив { font_url, text } для фирменных шрифтов, до 2.

Какую модель когда выбирать

  • Отредактировать фото по инструкции → Gemini *-image (Nano Banana): диалоговое редактирование, понимает русский.
  • Текст на изображении (баннер, постер) → Recraft (text_layout у V3).
  • Фирменные шрифты → Riverflow (font_inputs).
  • Максимальное качество / фотореализм → FLUX.2 Pro / Max, Gemini 3 Pro Image.
  • Быстро и дёшево → Gemini 2.5 Flash Image, FLUX.2 Klein 4B.
  • Скомбинировать несколько референсов в одну сцену → Seedream 4.5 (до 14 входных картинок).

Стриминг

На chat-пути работает stream: true — картинка приходит в delta.images[] одним или несколькими чанками, финальный чанк содержит usage (как в обычном стриме). На /v1/images/generations стриминга нет: один POST → готовый ответ.

curl -N https://api.hubris.pw/v1/chat/completions \
  -H "Authorization: Bearer sk-gw-..." \
  -d '{
    "model": "google/gemini-2.5-flash-image",
    "modalities": ["image", "text"],
    "messages": [{"role": "user", "content": "Космический корабль"}],
    "stream": true
  }'

Биллинг

  • Images-путь — фиксированная цена за изображение: в каталоге у каждой модели видна цена в рублях за штуку, спишется n × цена. Списание — после успешного ответа; за отказ провайдера или пустой ответ не списывается ничего.
  • Chat-путь — по токенам модели: сгенерированное изображение засчитывается провайдером как пакет completion-токенов. Итоговая сумма в рублях по каждому запросу — в журнале и разделе «Расходы».

Все списания атомарны: баланс, запись в журнале и движение по балансу пишутся одной транзакцией.

Лимиты

  • Баланс — на /v1/images/generations запрос блокируется с 402 insufficient_balance, если баланса не хватает на ожидаемую стоимость заказа (n × цена за изображение); на chat-пути действует общий минимальный порог (см. Лимиты и баланс).
  • Дневной лимит ключа — действует на оба пути. Превышение — 429 daily_limit_exceeded.
  • Размер тела запроса на chat-пути — 36 МБ: этого хватает на несколько base64-картинок; при больших исходниках сжимайте JPEG перед отправкой.

Чего пока нет

  • Edits по маске (inpainting в формате OpenAI images.edit с полем mask).
  • Variations (images.createVariation).
  • response_format: "url" — ответ всегда b64_json.

Если что-то из этого критично — напишите в support@hubris.pw, расскажите use case.

Обновлено: