Как добавить adult-фильтры для фото в своё приложение
Добавить adult-фильтр для фото в продукт выглядит как задача про изображения, а оказывается задачей про обвязку. Работу модели вы покупаете одним вызовом. Спринт съедает всё остальное: загрузки, которые отваливаются по таймауту; задачи, которые завершились, пока никто не слушал; ретраи, которые тихо списывают деньги дважды; и очередь в поддержку с вопросом, куда делся результат. Ниже — интеграция от начала до конца и места, где время теряется стабильно.
Из чего на самом деле состоит интеграция
API обработки фото асинхронно по своей природе. Генерация идёт достаточно долго, чтобы держать под неё открытое HTTP-соединение было плохой идеей: мобильные сети рвутся, балансировщики режут простаивающие соединения, а собственные таймауты начинают работать против вас. Поэтому схема всегда одна: вы ставите задачу, получаете идентификатор и забираете результат позже.
- Отправить фото и нужный пресет, получить идентификатор задачи.
- Следить за задачей — опросом статуса или подпиской на события.
- Забрать готовое изображение, когда задача сообщит об успехе.
- Обработать ошибки и ретраи — здесь и лежит основная работа.
Шаг первый: постановка задачи
Отправка — это multipart-запрос с изображением, идентификатором пресета и подтверждением, что у вас есть права и согласие на обработку фото. Приложите к нему ключ идемпотентности. Один этот заголовок отделяет чистую интеграцию от проблемы в поддержке, а стоит он ровно ничего.
curl -X POST https://api.example/api/v1/jobs \ -H "X-API-Key: $API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -F image=@photo.jpg \ -F feature=bikini \ -F consent=confirmed
В ответе приходит идентификатор задачи и её начальный статус. Сохраните этот идентификатор рядом с записью пользователя или сессии сразу же, до всего остального. Если через секунду процесс упадёт, эта строка — единственное, что позволит снова найти работу.
Шаг второй: отслеживание прогресса
Следить за задачей можно двумя способами, и зрелые интеграции используют оба. WebSocket-соединение даёт живые смены статуса и прогресс — именно то, чем стоит питать прогресс-бар в интерфейсе. Опрос эндпоинта задачи — это запасной путь, который делает систему корректной, а не просто приятной: сокеты рвутся, телефоны засыпают, а опрос раз в несколько секунд почти ничего не стоит.
Считайте WebSocket оптимизацией, а опрос — источником правды. Команды, которые делают наоборот, получают задачи, идеально завершившиеся на сервере и навечно зависшие в клиенте, потому что единственное важное событие пришло, пока сокет переподключался.
Шаг третий: получение результата
Когда задача сообщает об успехе, она несёт список результатов. Каждый результат забирается тем же API-ключом, который создал задачу, — то есть результаты никогда не доступны публично и не угадываются по URL. Если продукту нужно показывать изображение позже, скачивайте его в собственное хранилище сразу при получении: image API — это сервис обработки, а не фотоархив, и результаты не хранятся бесконечно.
Шаг четвёртый: ошибки, ретраи и ловушка двойного списания
Интересна не та ошибка, когда API вернул код ошибки. Интересна неопределённость: запрос ушёл, сеть отвалилась, и вы не знаете, создалась задача или нет. Наивный ретрай — и вы заплатили дважды и сделали два результата на одно действие пользователя.
Это и решает ключ идемпотентности. Повторите запрос с тем же ключом — и получите исходную задачу, а не новую, сколько бы раз ретрай ни сработал. Генерируйте ключ в момент действия пользователя, храните его вместе с записью задачи и переиспользуйте при каждом ретрае того же действия — а не создавайте новый на каждую попытку, это убивает весь механизм.
Где интеграции обычно застревают
- Валидация загрузки только на клиенте. Проверяйте файл на сервере по содержимому, а не по расширению, до того как тратить на него вызов API.
- Весь поток сделан синхронно — и потом выясняется, что мобильные клиенты рвут соединение задолго до конца генерации.
- WebSocket как единственный канал прогресса, без фолбэка на опрос.
- Локально не хранится ничего, и рестарт теряет связь между вашими пользователями и задачами в работе.
- Забыли, что результаты временные, и ждут от API роли постоянного хранилища.
Разумный порядок работ
Прогоните одно фото по всему пути через curl до того, как напишете хоть строку кода приложения: отправка, опрос, скачивание. Потом свяжите те же четыре вызова со своим бэкендом и сохранением состояния. WebSocket добавляйте последним — чисто как улучшение прогресс-бара поверх системы, которая и без него работает. В таком порядке интеграция занимает день; в обратном — две недели отладки.
Частые вопросы
Сколько выполняется запрос?
Генерация асинхронна и завершается в фоне. Стройте интерфейс вокруг состояния прогресса, а не вокруг блокирующего вызова — и точная длительность перестанет влиять на вашу архитектуру.
Нужен ли WebSocket, чтобы работать с API?
Нет. Всё работает по одному REST. WebSocket нужен, чтобы прогресс выглядел живым; опрос эндпоинта задачи даёт ту же информацию.
Что будет, если отправить один и тот же запрос дважды?
С тем же ключом идемпотентности вы получите исходную задачу, вторая генерация не выполняется и не тарифицируется.
Разрабатывайте на uncloth.app
Один REST-эндпоинт, одиннадцать пресетов, результат приходит на ваш бэкенд. Расскажите, что вы делаете, и мы вышлем доступы.
Запросить доступ