Руководство
Удаление фона изображения через API: редактирование по текстовому запросу
Как заменить или удалить фон изображения с помощью моделей image-to-image на hiapi — минимум кода, пакетный режим и детали schema, которые обеспечивают безошибочную композицию продуктовых фотографий.
Традиционные инструменты удаления фона предлагают только одно действие: вырезать объект, оставив прозрачную область (или сплошную заливку). А удаление фона по текстовому запросу с помощью моделей image-to-image позволяет за один вызов получить одновременно и результат вырезания, и заменённый фон — бесшовный белый студийный фон, сцену из жизни, сплошной брендовый цвет — потому что модель попиксельно перегенерирует фон вокруг сохранённого объекта, а не просто вычисляет альфа-маску.
Это руководство покажет, как именно это сделать на hiapi: какие модели image-to-image действительно хорошо справляются с удалением фона, структуру запроса/ответа, под которую нужно писать код, и производственные паттерны (колбэки, повторные попытки, обработка ошибок), которые не позволят пакетным задачам незаметно испортить ваш продуктовый каталог.
Предварительные требования:
- Получите ключ hiapi API из вашей панели управления
- Python 3.9+ с установленным
requests(pip install requests) - Ваши исходные изображения размещены на публичном URL — task API hiapi получает изображения по URL, а не через загрузку файлов, поэтому локальные пути к файлам не подходят. Подойдёт любое объектное хранилище или CDN.
Как удаление фона работает как задача image-to-image
Каждая генерация на hiapi — изображение, видео или аудио — проходит один и тот же асинхронный жизненный цикл задачи: вы отправляете задачу, получаете taskId, а затем либо опрашиваете результат, либо получаете его через callback URL. Полный контракт описан в справочнике по асинхронному API задач; для удаления фона важны следующие части:
POST /v1/tasksсmodel+input(ваш промпт, URL исходного изображения и форма вывода) возвращает{"code":200,"data":{"taskId":"tk-hiapi-..."}}. Поляstatusна этом этапе ещё нет.GET /v1/tasks/{taskId}возвращаетdata.statusсо значением одно изqueued,handling,archiving,success,fail. Толькоsuccessиfailявляются терминальными.- Когда статус
success,data.output— это массив объектов{"url","type","expireAt"}.url— это подписанная ссылка с коротким сроком действия (expireAt— это Unix-временная метка) — скачайте её немедленно, не сохраняйте эту горячую ссылку.
Что касается модели, используйте эндпоинт image-to-image и описывайте в промпте заменённый фон, а не говорите изолированно «удалить фон» — эти модели гораздо лучше реагируют на конкретную цель, чем на отрицательные инструкции:
Remove the background completely and replace it with a seamless, pure white
studio background. Keep the subject's shape, edges, lighting, and colors
exactly unchanged. Do not add shadows, reflections, or any other objects
that were not in the original image.
Минимальный пример: одно изображение на входе, замена фона
seedream-5.0-lite/image-to-image — самый дешёвый и достаточный вариант для этой цели — он принимает prompt, image_urls, aspect_ratio и resolution (поддерживается только 2K или 4K; у этого эндпоинта нет уровня 1K, а неизвестные поля вроде n или seed отклоняются с кодом 400).
import os
import time
import requests
API = "https://api.hiapi.ai/v1"
HEADERS = {
"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}",
"Content-Type": "application/json",
}
BACKGROUND_PROMPT = (
"Remove the background completely and replace it with a seamless, pure "
"white studio background. Keep the subject's shape, edges, lighting, and "
"colors exactly unchanged. Do not add shadows, reflections, or any other "
"objects that were not in the original image."
)
def create_task(model: str, task_input: dict) -> str:
resp = requests.post(f"{API}/tasks", headers=HEADERS,
json={"model": model, "input": task_input}, timeout=60)
resp.raise_for_status()
return resp.json()["data"]["taskId"]
def wait_task(task_id: str, timeout_s: int = 180, poll_s: int = 3) -> dict:
deadline = time.time() + timeout_s
while time.time() < deadline:
resp = requests.get(f"{API}/tasks/{task_id}", headers=HEADERS, timeout=30)
resp.raise_for_status()
task = resp.json()["data"]
if task["status"] == "success":
return task
if task["status"] == "fail":
err = task.get("error") or {}
raise RuntimeError(f"task {task_id} failed: {err.get('code')} {err.get('message')}")
time.sleep(poll_s)
raise TimeoutError(f"task {task_id} still {task['status']} after {timeout_s}s")
task_id = create_task("seedream-5.0-lite/image-to-image", {
"prompt": BACKGROUND_PROMPT,
"image_urls": ["https://your-cdn.example.com/product-photo.jpg"],
"aspect_ratio": "1:1",
"resolution": "2K",
})
task = wait_task(task_id)
image_bytes = requests.get(task["output"][0]["url"], timeout=60).content
with open("product-no-bg.png", "wb") as f:
f.write(image_bytes)
Это весь цикл: отправить, опросить, скачать. Если перед подключением к конвейеру вы хотите быстро проверить без кода, AI 产品照片实验室 выполняет тот же тип замены фона прямо в браузере.
Пакетная обработка продуктового каталога
Реальные продуктовые каталоги содержат десятки или сотни изображений, а у task API нет нативного пакетного эндпоинта — вам нужно самостоятельно развернуть отправку отдельных задач и опрашивать их параллельно:
from concurrent.futures import ThreadPoolExecutor, as_completed
def remove_background(image_url: str, aspect_ratio: str = "1:1") -> str:
task_id = create_task("seedream-5.0-lite/image-to-image", {
"prompt": BACKGROUND_PROMPT,
"image_urls": [image_url],
"aspect_ratio": aspect_ratio,
"resolution": "2K",
})
task = wait_task(task_id)
return task["output"][0]["url"]
source_urls = [
"https://your-cdn.example.com/sku-1001.jpg",
"https://your-cdn.example.com/sku-1002.jpg",
# ...
]
results = {}
with ThreadPoolExecutor(max_workers=5) as pool:
futures = {pool.submit(remove_background, url): url for url in source_urls}
for future in as_completed(futures):
url = futures[future]
try:
results[url] = future.result()
except Exception as exc:
results[url] = None
print(f"failed: {url}: {exc}")
Держите max_workers умеренным — слишком частый опрос на множестве параллельных задач лишь расходует вашу квоту запросов и не ускоряет генерацию, поскольку время выполнения каждой задачи в основном определяется выводом модели, а не частотой вашего опроса.
Подготовка к продакшену: точная композиция, колбэки, идемпотентность, ошибки
Сохраняйте точную композицию продукта. Для работы с каталогом вы обычно не можете допустить, чтобы модель изменила композицию или слегка обрезала объект — центрированный ботинок на входе должен оставаться центрированным на выходе. seedream-5.0-pro/image-to-image поддерживает значение aspect_ratio, которого нет у уровня lite: match_input_image, которое фиксирует выходной холст под собственные размеры входного изображения, а не принудительно задаёт фиксированный соотношение. Он также принимает до 10 image_urls за вызов и ограничивает resolution значениями 1K/2K (отличный от lite набор разрешений — не предполагайте, что schema всех эндпоинтов seedream одинаковы, у каждого эндпоинта свои перечисления). Для задач чистого удаления и замены фона, где композиция должна точно совпадать, это тот уровень, который следует выбирать, хотя стоимость за изображение выше — актуальные тарифы см. в прайс-листе.
Если вам нужно ссылаться на несколько исходных ракурсов за раз (например, вид спереди и вид сбоку одного продукта), а не обрабатывать одно изображение за вызов, nano-banana-2 — разумная альтернатива — он принимает референсные изображения через image_input (а не image_urls), а resolution может быть 1K/2K/4K.
Используйте колбэки вместо опроса. Для любой пакетной задачи реального масштаба webhook предпочтительнее опроса: добавьте объект callback на том же уровне, что и input — не вкладывайте его внутрь, POST /v1/tasks отклонит такую структуру:
task_input = {
"prompt": BACKGROUND_PROMPT,
"image_urls": [image_url],
"aspect_ratio": "1:1",
"resolution": "2K",
}
resp = requests.post(f"{API}/tasks", headers=HEADERS, json={
"model": "seedream-5.0-lite/image-to-image",
"input": task_input,
"callback": {"url": "https://your-service.example.com/hooks/hiapi", "when": "final"},
}, timeout=60)
После достижения задачей терминального состояния hiapi отправит POST на ваш callback URL с тем же объектом data, который вернул бы GET /v1/tasks/{taskId}. Если вы хотите проверять подлинность колбэка на сервере, обратитесь к опциональному HMAC-заголовку X-HiAPI-Signature в справочнике по асинхронным задачам.
Идемпотентность. У POST /v1/tasks нет документированного поля idempotency_key — реализуйте идемпотентность на уровне приложения. Используйте небольшое хранилище (строка в БД, ключ Redis или даже локальный файл для одноразового скрипта) с ключом по хешу (image_url, prompt, model) и перед отправкой новой задачи проверяйте, есть ли для этого ключа сохранённый taskId или URL вывода. Если ваша пакетная задача упадёт на полпути и перезапустится, вы сможете пропустить повторную оплату за уже обработанные изображения, а не незаметно увеличить расходы.
Обработка ошибок — три разные формы, не относитесь к ним одинаково:
- Валидация запроса (ошибочные входные данные при создании) — HTTP 400, плоская структура:
{"code":400,"error_code":"INVALID_REQUEST","message":"...","data":null}. Это означает, что ваш словарьinputне соответствует schema модели — проверьте опечатки в именах полей или неверные значения перечислений. - Ошибка аутентификации — HTTP 401, вложенность другая:
{"error":{"code":"permission_denied","message":"...","request_id":"...","type":"hiapi_error"}}. Ключ API отсутствует/просрочен, а не ошибка запроса — не повторяйте попытку, исправьте ключ. - Ошибка уровня задачи (запрос действителен, но сама генерация не удалась) — проявляется при опросе:
data.status == "fail",data.errorописывает причину. Это можно повторить; временные ошибки вышестоящего сервиса могут завершиться успешно при повторной отправке.
if task["status"] == "fail":
err = task.get("error") or {}
# log err["code"] / err["message"], then decide: retry, skip, or alert
Не объединяйте все три в один except Exception — повторная попытка при 401 в цикле лишь израсходует ваш лимит запросов и никогда не завершится успешно, а задача уровня fail действительно может успешно завершиться со второй попытки.
Следующие шаги
- Справочник по асинхронному API задач — полный жизненный цикл, подписи колбэков, все значения статусов
- Страницы моделей seedream-5.0-lite/image-to-image и seedream-5.0-pro/image-to-image — актуальная schema и примеры
- Построение конвейера асинхронных задач — если удаление фона — это лишь один этап более крупного конвейера генерации
- Решение проблемы, когда колбэк задачи hiapi не срабатывает — если ваш webhook молчит, это чек-лист для отладки
- Промпты image-to-image для Flux 2 Klein 9B — паттерны промптов другой модели i2i для сравнения
- AI 产品照片实验室 — версия того же рабочего процесса без кода
Часто задаваемые вопросы
Это действительно удаляет фон или просто перекрывает его? Функционально и то и другое — модель перегенерирует весь холст вокруг сохранённого объекта, поэтому не остаются остаточные маски или рваные края, как у инструментов вырезания на основе обнаружения краёв. Цена этого — необходимость явно указывать в промпте «сохранить всё остальное без изменений», иначе модель с радостью перестилизует и сам объект.
Могу ли я получить прозрачный PNG вместо сплошного фона? Укажите это прямо в промпте (например, «заменить фон на прозрачный» или «изолировать объект на прозрачном фоне») и запросите вывод в PNG там, где модель поддерживает поле output_format — поддержка зависит от модели, поэтому перед предположением о доступности проверьте страницу конкретной модели.
Почему моё изображение возвращается с другой композицией, а не совпадает с исходным? Скорее всего, вы используете уровень, в перечислении aspect_ratio которого нет match_input_image — на уровнях lite/4.5 вы выбираете фиксированное соотношение, которое может обрезать или добавить чёрные полосы относительно исходника. Переключитесь на seedream-5.0-pro/image-to-image и установите aspect_ratio в match_input_image.
Сколько стоит одно изображение? Цены зависят от модели и уровня разрешения и меняются со временем — смотрите прайс-лист, а не хардкодьте цифры в своём коде или документации.
Что делать, если URL моих изображений ещё не публичны? Task API получает изображения по URL на стороне сервера, поэтому они должны быть доступны без аутентификации. Сначала загрузите их в любой публичный бакет или путь CDN — подписанные/приватные URL или пути localhost приведут к ошибке при создании задачи или (что хуже) молчаливому сбою в процессе обработки.
Похожие статьи
Все статьи →-
Руководство
Как вызвать hailuo-2.3-fast/image-to-video через HiAPI API: практика с curl и Python
Первый рабочий запрос к быстрому и недорогому уровню генерации видео по изображению — от ID модели до загрузки MP4
-
Руководство
Как вызывать hailuo-2.3/text-to-video через API HiAPI: curl, Python и рабочие примеры запросов
-
Руководство
Использование Kandinsky 6.0 Pro для преобразования текста в видео на HiAPI: руководство по curl и Python
Практическая демонстрация с упором на запросы: построение вызова от промпта до видеоклипа, отправка запроса, опрос статуса завершения и скачивание результата