Перейти к содержанию
VALERAWEBDEV07
AI7 ноября 2026 г.3 мин чтения

AI OPS изнутри: как за 20 секунд заменить фон и не сломать товар

Разбираю архитектуру AI OPS: асинхронный пайплайн, Supabase, fal.ai, лимиты, polling и деплой на Caddy + systemd.

ПоделитьсяTelegram
Назад в блог
Содержание

Почему это сложнее, чем «просто заменить фон»

На первый взгляд задача звучит просто: берём фото товара, убираем фон, генерируем новый. На практике обычные генераторы ломают логотипы, швы, текстуры и мелкий текст. Для интернет-магазина это не «некрасивая картинка», а возврат, потерянный клиент и деньги.

В AI OPS я строил не генератор картинок, а пайплайн, в котором продукт остаётся нетронутым, а меняется только окружение. Ниже — как это устроено и какие решения оказались важными.

Что делает сервис

Пользователь загружает фото товара, выбирает или описывает сцену и получает готовый фон. Демо бесплатное, с лимитами, работает на трёх языках. Генерация занимает примерно 20 секунд, а стоимость одной генерации — около $0.02.

Под капотом — Next.js 16, Supabase, fal.ai и Telegram для уведомлений о лидах.

Архитектура

Browser → Next.js API → Supabase → fal.ai → Telegram
  • Браузер отправляет фото и описание сцены.
  • Next.js сохраняет заявку и запуск пайплайна в Supabase.
  • fal.ai генерирует новый фон.
  • Результат сохраняется в pipeline_runs.result_url.
  • Telegram получает уведомление о новом лиде.

Ключевая идея: API не ждёт генерацию. Он отвечает сразу, а работа продолжается в фоне.

Решение 1. Очередь без отдельной инфраструктуры

Для MVP не хотелось поднимать Redis, воркеры и отдельный сервис очередей. В Next.js есть after() — функция, которая выполняется после отправки ответа:

after(async () => {
  await processPipelineRun(runId);
});

Пользователь сразу получает runId, а пайплайн продолжает работать. Если генерация упала, статус в базе становится error, и лимит не расходуется.

Решение 2. Polling, который переживает перезагрузку

Клиент опрашивает /api/relight/[id] каждые две секунды. runId хранится в localStorage, поэтому даже после перезагрузки страницы можно продолжить ждать результат.

При сетевой ошибке клиент не показывает «всё сломалось», а переподключается. Это мелочь, которая сильно влияет на ощущение надёжности.

Решение 3. Лимиты, которые не сбрасываются ошибкой

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

Лимиты считаются атомарно, через keyed-мьютекс. Это защищает от гонок, когда несколько запросов приходят одновременно.

Решение 4. Три языка и продакшен

Интерфейс и юридические страницы переведены на en, ru и uk. Язык определяется по браузеру, ручной выбор сохраняется.

Прод живёт на этом же сервере: Caddy принимает HTTPS, systemd держит Next.js, health-check проверяет приложение, а деплой идёт через атомарную замену .next с откатом при ошибке.

Что бы я улучшил дальше

  • Вынести пайплайн в отдельный воркер, если нагрузка вырастет.
  • Добавить очередь с ретраями и дедлайнами.
  • Показывать прогресс генерации, а не только spinner.
  • Добавить сравнение «до/после» прямо в результате.

Итог

AI OPS — пример того, как AI-продукт держится не на одной модели, а на инженерии вокруг неё: лимитах, восстановлении после сбоев, хранении результата, локализации и деплое. Модель можно заменить. Надёжный пайплайн — сложнее.

ПоделитьсяTelegram
Назад в блог

Валера · webdev07

Senior Fullstack + AI. Строю системы, которые работают.

@webdevs07

Нужна такая автоматизация?

Напиши в Telegram — обсудим задачу и формат работы.

Обсудить проект