Перейти к содержимому
Зарегистрироваться бесплатно
GPT Image

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

Редактируйте изображения GPT Image через OpenAI-совместимый API BetterToken: multipart/form-data, маски, сохранение, расчёт стоимости и обработка ошибок.

POST /v1/images/edits

Endpoint для редактирования изображений использует тело запроса multipart/form-data. Загрузите одно или несколько референсных изображений и передайте prompt и параметры как поля формы. Приём Model ID или параметра не гарантирует доступность модели, размера или операции редактирования для запроса.

Рекомендуемые значения

Это начальные рекомендации, а не фиксированные требования. Рекомендуется n=1; endpoint принимает целое число от 1 до 10, но может вернуть меньше изображений.

model=gpt-image-2
n=1
response_format=b64_json
output_format=png

Для одного референсного изображения используйте image. Для нескольких референсных изображений используйте повторяющиеся поля image[].

Используйте gpt-image-2, gpt-image-2.5-flare или gpt-image-2.5-sunburst, если модель доступна для запроса. quality принимает auto, low, medium, high для gpt-image-2; две модели 2.5 также принимают xhigh и max. Приём параметра сам по себе не гарантирует доступность модели или операции редактирования. В multipart quality должна быть непустой строкой, а size не может быть пустым.

Одно референсное изображение

Подготовьте reference.png и замените YOUR_API_KEY своим BetterToken API Key. Один ключ подходит для всех доступных моделей. Не задавайте Content-Type вручную: curl -F или Python files должны сформировать boundary.

Поле формыПример
modelgpt-image-2
promptUsing this reference image, create a more polished square product key visual while preserving the subject style.
n1
size1024x1024
response_formatb64_json
output_formatpng
imageВыберите файл reference.png
Окно терминала
curl --max-time 300 'https://bettertoken.ai/v1/images/edits' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-F 'model=gpt-image-2' \
-F 'prompt=Using this reference image, create a more polished square product key visual while preserving the subject style.' \
-F 'n=1' \
-F 'size=1024x1024' \
-F 'response_format=b64_json' \
-F 'output_format=png' \
-F 'image=@reference.png'

Несколько референсных изображений

Отправьте следующие поля:

Поле формыПример
modelgpt-image-2
promptCombine these reference images into a promotional poster with a consistent style.
n1
size1024x1024
response_formatb64_json
output_formatpng
image[]Выберите reference-1.png
image[]Выберите reference-2.jpg
image[]Выберите reference-3.png
Окно терминала
curl --max-time 300 'https://bettertoken.ai/v1/images/edits' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-F 'model=gpt-image-2' \
-F 'prompt=Combine these reference images into a promotional poster with a consistent style.' \
-F 'n=1' \
-F 'size=1024x1024' \
-F 'response_format=b64_json' \
-F 'output_format=png' \
-F 'image[]=@reference-1.png' \
-F 'image[]=@reference-2.jpg' \
-F 'image[]=@reference-3.png'

Локальное редактирование по маске

Добавьте необязательное файловое поле mask, если нужно направить редактирование на выбранную область. Текущий endpoint BetterToken читает один файл mask. Не отправляйте повторяющиеся поля mask[].

  • Исходное изображение и mask должны иметь одинаковый формат и размеры в пикселях. Размер каждого файла должен быть меньше 50 MB. Для максимальной совместимости рекомендуется использовать PNG с Alpha-каналом для исходного изображения и mask.
  • Mask должна содержать Alpha-канал. Полностью прозрачные пиксели (Alpha 0) отмечают область, которую модель может перерисовать. Полностью непрозрачные пиксели (Alpha 255) направляют модель на сохранение области.
  • Обычное чёрно-белое RGB-изображение не является корректной mask, если в файле нет Alpha-канала.
  • Если вы передаёте несколько полей image[], mask применяется к первому входному изображению.
  • Mask служит ориентиром для модели и не гарантирует, что пиксели за пределами прозрачной области останутся абсолютно неизменными.
  • Доступность mask зависит от сочетания модели и размера. Для обычного редактирования по референсному изображению mask не нужна. В тестах GPT Image 2 и Flare заметно менялись и области вне маски; точность локального управления Sunburst не проверялась. Проверяйте результат перед использованием для товаров, логотипов и точной ретуши.
Окно терминала
curl --max-time 300 'https://bettertoken.ai/v1/images/edits' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-F 'model=gpt-image-2' \
-F 'prompt=Replace only the masked area with a blue circle. Preserve everything else.' \
-F 'n=1' \
-F 'size=1024x1024' \
-F 'response_format=b64_json' \
-F 'output_format=png' \
-F 'image=@original.png' \
-F 'mask=@mask.png'

Редактирование по маске на Python

Откройте оба файла в одном операторе with, чтобы Python закрыл их после запроса:

import requests
url = "https://bettertoken.ai/v1/images/edits"
headers = {"Authorization": "Bearer YOUR_API_KEY"}
data = {
"model": "gpt-image-2",
"prompt": "Replace only the masked area with a blue circle. Preserve everything else.",
"n": "1",
"size": "1024x1024",
"response_format": "b64_json",
"output_format": "png",
}
with open("original.png", "rb") as image_file, open("mask.png", "rb") as mask_file:
files = {
"image": ("original.png", image_file, "image/png"),
"mask": ("mask.png", mask_file, "image/png"),
}
response = requests.post(url, headers=headers, data=data, files=files, timeout=300)
response.raise_for_status()
result = response.json()

Проверка файлов перед загрузкой

Этот минимальный пример с Pillow проверяет обязательные требования к формату, размерам и Alpha-каналу. Для обычной локальной mask он также выводит предупреждение, если Alpha-канал не содержит одновременно полностью прозрачные и полностью непрозрачные области:

from pathlib import Path
from PIL import Image
image_path = Path("original.png")
mask_path = Path("mask.png")
if image_path.stat().st_size >= 50 * 1024 * 1024 or mask_path.stat().st_size >= 50 * 1024 * 1024:
raise ValueError("Each file must be smaller than 50 MB")
with Image.open(image_path) as image, Image.open(mask_path) as mask:
if image.format != mask.format:
raise ValueError("The image and mask formats must match")
if image.size != mask.size:
raise ValueError("The image and mask dimensions must match")
if "A" not in mask.getbands():
raise ValueError("The mask must contain an Alpha channel")
alpha_min, alpha_max = mask.getchannel("A").getextrema()
if alpha_min > 0 or alpha_max < 255:
print("Warning: for a typical local mask, include fully transparent and fully opaque areas")

Пример на Python

import base64
from pathlib import Path
import requests
url = "https://bettertoken.ai/v1/images/edits"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
}
data = {
"model": "gpt-image-2",
"prompt": "Using this reference image, create a more polished square product key visual while preserving the subject style.",
"n": "1",
"size": "1024x1024",
"response_format": "b64_json",
"output_format": "png",
}
with open("reference.png", "rb") as image_file:
files = {
"image": ("reference.png", image_file, "image/png"),
}
response = requests.post(url, headers=headers, data=data, files=files, timeout=300)
response.raise_for_status()
result = response.json()
for index, item in enumerate(result["data"], start=1):
encoded = item["b64_json"]
if "," in encoded and "base64" in encoded.split(",", 1)[0]:
encoded = encoded.split(",", 1)[1]
image_bytes = base64.b64decode(encoded)
if image_bytes.startswith(b"\x89PNG\r\n\x1a\n"):
extension = "png"
elif image_bytes.startswith(b"\xff\xd8\xff"):
extension = "jpg"
elif image_bytes.startswith(b"RIFF") and image_bytes[8:12] == b"WEBP":
extension = "webp"
else:
raise ValueError("Unsupported image signature")
Path(f"output-{index}.{extension}").write_bytes(image_bytes)

Рекомендуемые размеры

sizeСоотношениеСценарий
autoAutoАвтоматический выбор размера
1024x10241:1Квадратные изображения, аватары, обложки, assets
1536x10243:2Landscape-постеры, баннеры, сцены
1024x15362:3Portrait-обложки для мобильных и постеры
1536x11524:3Стандартные landscape-изображения, product images, content graphics
1152x15363:4Стандартные portrait-изображения, mobile covers, vertical posters
2048x20481:1High-resolution квадратные изображения
2048x115216:9High-resolution landscape-изображения
3840x216016:94K landscape-изображения
2160x38409:164K portrait-изображения

Таблица содержит примеры, а не закрытый список. Явные ширина и высота должны быть положительными кратными 16, каждая не больше 3840; соотношение сторон не должно превышать 3:1, а число пикселей должно быть от 655360 до 8294400. Например, 2080x2080 допустим. Фактический размер может отличаться от запрошенного, поэтому проверяйте размеры изображения и не обрезайте его принудительно.

Сохранение изображения

Успешный ответ следует OpenAI-совместимой форме image response. Суммы ниже показывают формат квитанции и не являются фиксированными ценами:

{
"created": 1710000000,
"data": [
{
"b64_json": "iVBORw0KGgoAAAANSUhEUgAA...(truncated)",
"revised_prompt": "Optional revised prompt"
}
],
"bettertoken_image_billing": {
"currency": "CNY",
"settled_amount": "0.15",
"outputs": [
{
"index": 0,
"width": 1254,
"height": 1254,
"billing_resolution": "2K",
"currency": "CNY",
"amount": "0.15"
}
]
}
}

Прочитайте все data[].b64_json и разрешайте дополнительные поля, например revised_prompt. BetterToken возвращает расчёт в корневом bettertoken_image_billing: суммы settled_amount и amount являются decimal strings, а outputs[].index начинается с 0. output_format — запрос формата, не гарантия кодирования; определяйте фактический формат по байтам и используйте соответствующее расширение. На странице Text to image приведены примеры сохранения PNG, JPEG и WebP без дополнительных зависимостей.

Фактическая стоимость

bettertoken_image_billing возвращается в том же ответе; отдельный запрос стоимости не нужен.

ПолеЗначение
currencyВалюта расчёта; это не обязательно USD или CNY.
settled_amountИтоговая сумма запроса в виде десятичной строки.
requested_resolutionУровень разрешения, определённый по запросу.
outputs[].indexИндекс с нуля, соответствующий изображению в data[].
outputs[].width, heightФактические размеры изображения в пикселях.
outputs[].billing_resolutionИтоговый тарифный уровень изображения.
outputs[].currency, amountВалюта и сумма расчёта за изображение.

Размер запроса и тарифный уровень могут различаться: запрос 1024x1024 возвращал 1254x1254 с тарификацией 2K. Используйте сумму из квитанции; текущие цены указаны на модельной площадке. Для отображения сохраняйте суммы строками, для вычислений используйте десятичную арифметику. Отсутствующая квитанция не означает нулевую стоимость.

from decimal import Decimal
billing = result.get("bettertoken_image_billing")
if billing is None:
print("Billing receipt unavailable; check your usage records.")
else:
total = Decimal(billing["settled_amount"])
print(f"Total: {billing['currency']} {total}")
for output in billing.get("outputs", []):
print(
f"Image {output['index'] + 1}: "
f"{output['width']}x{output['height']}, "
f"{output['billing_resolution']}, "
f"{output['currency']} {output['amount']}"
)

Поток ответа

Endpoint синхронный. После отправки POST /images/edits держите HTTP-запрос открытым до ответа сервера. При успехе каждое изображение возвращается в data[].b64_json со сведениями о доставке и расчёте.

Endpoint не возвращает task_id; отдельного status query или endpoint для скачивания результата нет.

Тайм-ауты, повторные запросы и списания

Задайте timeout HTTP-клиента в несколько минут. Timeout, disconnect или неоднозначный 5xx не показывают, было ли редактирование выполнено и списана ли оплата; соединение может прерваться при записи результата после расчёта, поэтому возможны повторные списания. Не повторяйте автоматически POST редактирования. Сначала проверьте записи потребления или логи запросов; сохраните возвращённый request ID и, если получены, заголовки X-BetterToken-Image-Receipt и X-BetterToken-Billing-State. Собственный request ID клиента не обеспечивает идемпотентность сервера; повторная отправка может создать новый запрос и списание. Отдельного endpoint проверки статуса нет.

Исправьте отклонённые данные, аутентификацию или проблему квоты перед повторной отправкой. Повторяйте 429 с backoff только после подтверждения отказа запроса. Перед обработкой BetterToken может предварительно удержать максимум, равный наибольшей применимой цене за единицу, умноженной на n. Поэтому баланса, достаточного для фактически доставленного изображения 1K, может не хватить на удержание; такой отказ возвращается как 403 с error.code=insufficient_user_quota. Итоговая сумма рассчитывается по фактически доставленным изображениям. Корневой bettertoken_image_billing содержит сумму, валюту и сведения по каждому результату.

Чек-лист подключения

  • Base URL: https://bettertoken.ai/v1.
  • Заголовок содержит Authorization: Bearer sk-....
  • Запрос использует multipart/form-data.
  • Выберите доступный для запроса Model ID: gpt-image-2, gpt-image-2.5-flare или gpt-image-2.5-sunburst.
  • Для одного референса используйте image, для нескольких повторяйте image[].
  • Для маски передайте один mask того же формата и размера, что и оригинал, с Alpha-каналом.
  • Используйте response_format=b64_json. output_format — запрошенное значение; при сохранении определяйте формат по байтам.
  • n принимает целые числа от 1 до 10. Рекомендуется 1; изображений может быть меньше.
  • size можно пропустить, задать auto или допустимые размеры.
  • HTTP-клиент допускает ожидание генерации в течение нескольких минут.
  • Логи и скриншоты ошибок не раскрывают API Key или полное содержимое изображения в base64.

Смежные документы

POST/v1/images/edits

Авторизации

Authorizationstringheaderобязательно

Используйте API Key BetterToken как bearer token. Не публикуйте API keys во frontend-коде, скриншотах, логах, тикетах или Git-репозиториях.

Тело multipart/form-data

modelenum<string>по умолчанию: gpt-image-2обязательно

Model ID GPT Image. Один BetterToken API Key работает со всеми доступными моделями.

Доступные опции: gpt-image-2, gpt-image-2.5-flare, gpt-image-2.5-sunburst

Пример:"gpt-image-2"
promptstringобязательно

Инструкция для редактирования изображения или генерации по референсному изображению.

Пример:"На основе этого изображения создай более аккуратное квадратное главное изображение продукта, сохранив общий стиль основного объекта."
imagestring<binary>

Поле для одного референсного изображения. В этом случае используйте image.

image[]string[]

Поле для нескольких референсных изображений. Повторяйте image[] для каждого файла.

maskstring<binary>

Необязательный одиночный файл mask. Сервер читает только один файл mask. Формат и размеры mask должны совпадать с исходным изображением, размер каждого файла должен быть меньше 50 MB, а mask должна содержать Alpha-канал. Для максимальной совместимости рекомендуется использовать PNG с Alpha-каналом для обоих файлов. При нескольких image[] mask применяется к первому входному изображению. Доступность зависит от сочетания модели и размера. Для обычного редактирования по референсному изображению mask не нужна. Mask направляет генерацию, но не гарантирует сохранение пикселей за целевой областью; проверяйте результат.

ninteger | stringпо умолчанию: 1

Допустимо 1–10; начните с 1. Может быть передано меньше изображений, чем запрошено. Перебирайте data[] и используйте расчет по фактическому результату.

Пример:"1"
sizestringпо умолчанию: 1024x1024

Опустите поле или передайте auto для автоматического размера. Для WxH обе стороны должны быть положительными и кратными 16, не более 3840 каждая; соотношение сторон не более 3:1, площадь 655360–8294400 пикселей. Примеры не являются закрытым списком: 2080x2080 тоже соответствует правилам. Проверяйте фактические размеры. Допустимые параметры не гарантируют доступный сервис.

Пример:"1024x1024"
Пример: ["auto","1024x1024","2048x2048","2080x2080","3840x2160"]
response_formatenum<string>по умолчанию: b64_json

Рекомендуется фиксировать b64_json.

Доступные опции: b64_json

Пример:"b64_json"
output_formatstringпо умолчанию: png

Запрошенный формат; рекомендуется png, но перекодирование ответа в PNG не гарантируется. Определяйте PNG, JPEG или WebP по реальным байтам перед выбором расширения. Если нужен конкретный формат, преобразуйте файл самостоятельно.

Пример:"png"
qualityenum<string>по умолчанию: auto

gpt-image-2 принимает auto, low, medium, high. Обе модели 2.5 также принимают xhigh и max. Если поле опущено, используется значение модели по умолчанию; JSON null считается отсутствующим, а multipart требует непустую строку. Допустимое значение не гарантирует доступный сервис для любого сочетания модели, размера и редактирования или улучшение изображения при повышении уровня.

Доступные опции: auto, low, medium, high, xhigh, max

Пример:"auto"

Ответ

200Расширение тарификации BetterToken. Сумма определяется фактическими пикселями и тарифным уровнем результата, который может отличаться от запрошенного. Денежные суммы — десятичные строки; используйте значения из ответа.

OpenAI-совместимый ответ с изображениями. Перебирайте data[] и читайте b64_json каждого изображения, допуская дополнительные поля, например revised_prompt. Фактическое число изображений может быть меньше запрошенного.

createdinteger
Пример:1710000000
dataobject[]
Show child attributes

Содержимое изображения в кодировке Base64.

Пример:"iVBORw0KGgoAAAANSUhEUgAA...(truncated)"

Необязательный переписанный prompt.

Расширение тарификации BetterToken. Сумма определяется фактическими пикселями и тарифным уровнем результата, который может отличаться от запрошенного. Денежные суммы — десятичные строки; используйте значения из ответа.

Show child attributes

Номера переданных изображений, фактические размеры, тарифные уровни и стоимость каждого изображения. index начинается с 0 и соответствует изображению в data[].

Требуемый диапазон: x >= 0

Требуемый диапазон: x >= 1

Требуемый диапазон: x >= 1

Доступные опции: 1K, 2K, 4K

Уровень разрешения, определённый по запросу; он может отличаться от фактического тарифа.

Пример
{
  "created": 1710000000,
  "data": [
    {
      "b64_json": "iVBORw0KGgoAAAANSUhEUgAA...(truncated)",
      "revised_prompt": "<string>"
    }
  ],
  "bettertoken_image_billing": {
    "currency": "<string>",
    "settled_amount": "<string>",
    "outputs": [
      {
        "index": 0,
        "width": 1,
        "height": 1,
        "billing_resolution": "1K",
        "currency": "<string>",
        "amount": "<string>"
      }
    ],
    "partial": false,
    "requested_resolution": "<string>"
  }
}
400Неверный формат запроса, отсутствующие параметры, ошибка разбора JSON или multipart, либо неверный формат размера.
errorobject
Show child attributes
Пример:"invalid request"
Пример:"invalid_request_error"
Пример:"invalid_request"
messagestring
Пример:"insufficient quota"
Пример
{
  "error": {
    "message": "invalid request",
    "type": "invalid_request_error",
    "code": "invalid_request"
  },
  "message": "insufficient quota"
}
401API Key отсутствует или недействителен.
errorobject
Show child attributes
Пример:"invalid request"
Пример:"invalid_request_error"
Пример:"invalid_request"
messagestring
Пример:"insufficient quota"
Пример
{
  "error": {
    "message": "invalid request",
    "type": "invalid_request_error",
    "code": "invalid_request"
  },
  "message": "insufficient quota"
}
402Недостаточно квоты или баланса.
errorobject
Show child attributes
Пример:"invalid request"
Пример:"invalid_request_error"
Пример:"invalid_request"
messagestring
Пример:"insufficient quota"
Пример
{
  "error": {
    "message": "invalid request",
    "type": "invalid_request_error",
    "code": "invalid_request"
  },
  "message": "insufficient quota"
}
403Недостаточно баланса или квоты ключа: error.code равен insufficient_user_quota. Средств также должно хватать на резерв по максимальной цене уровня, умноженной на верхний предел числа изображений; затем выполняется расчет по результату. Проверяйте error.code, а не считайте любой 403 ошибкой доступа.
errorobject
Show child attributes
Пример
{
  "error": {
    "code": "insufficient_user_quota",
    "message": "Insufficient balance or token quota."
  }
}
429Сработал rate limit, лимит параллельных запросов или upstream временно перегружен.
errorobject
Show child attributes
Пример:"invalid request"
Пример:"invalid_request_error"
Пример:"invalid_request"
messagestring
Пример:"insufficient quota"
Пример
{
  "error": {
    "message": "invalid request",
    "type": "invalid_request_error",
    "code": "invalid_request"
  },
  "message": "insufficient quota"
}
500Ошибка gateway или upstream-сервиса.
errorobject
Show child attributes
Пример:"invalid request"
Пример:"invalid_request_error"
Пример:"invalid_request"
messagestring
Пример:"insufficient quota"
Пример
{
  "error": {
    "message": "invalid request",
    "type": "invalid_request_error",
    "code": "invalid_request"
  },
  "message": "insufficient quota"
}