Фото-пайплайн — что уже есть и что нужно добавить

Дата: 15 мая 2026  ·  Простыми словами для команды: как должен работать пайплайн в идеале, что уже сделано, что осталось.
Главная мысль: примерно 65% желаемого уже работает. Большие задачи на этот спринт: подключить автоматический фильтр качества (вместо ручной разметки), добавить ветку апскейла, и ввести промежуточный слой photo.json как единый источник правды для всех выходов (HTML / IPTC / база / WordPress API).
⚠ Важная оговорка: сам визуальный фильтр (14 критериев) пока ещё не до конца протестирован. Скрипт и тесты есть, но прогон на большой выборке (сотни фоток) не делали. Перед включением в продакшен нужен отдельный этап валидации — прогнать на ≥200 фотках, проверить точность каждого критерия и подкрутить пороги.
~65%
уже работает
3
больших блока добавить
1
новый JSON-слой
2
отложены (enhance, R2)

Идеальный пайплайн — как должно работать

Фотки проходят через 7 этапов. На третьем — нейросеть-фильтр решает, что с фоткой делать дальше: одобрить, поднять разрешение, улучшить или выбросить.

1
Массовая загрузка с WordPress-сайтов
Скачиваем фотки из всех статей сайта через его WordPress REST API. Дубли (одна и та же фотка на разных сайтах) убираются автоматически по хэшу.
✓ Уже работает
2
Определение локации — в два уровня
Статья (1 раз): страна + город из заголовка и первого абзаца — дешёвой текстовой моделью, без vision.
Фото (на каждое): POI из подзаголовка над фоткой + meta + абзаца до фотки + самой фотки. Vision только верифицирует и достаёт название конкретной точки, если оно ещё не в подзаголовке.
🔄 Переделать с vision-first на text-first
3
Авто-фильтр по качеству (вместо ручной разметки)
Нейросеть проверяет фотку по 14 критериям (резкость, экспозиция, водяные знаки, лица, погода, обрезка и т.д.) и выдаёт один из 4 вердиктов. Замена ручной странице /label.
+ Подключить + тестировать
4
Развилка: 4 пути по вердикту
См. карточки ниже. Все 4 статуса (включая «брак») сохраняются в БД — даже отбракованные фотки видны в системе с историей решения.
+ Новое
5
Обработка: image-to-image или апскейл
«Чистые» идут через image-to-image модель (fal.ai FLUX.2 Pro) — лёгкая переделка без смены композиции. «Низкое разрешение» идут на апскейл-модель. ~$0.03 за фотку.
✓ Работает (image-to-image), + апскейл новый
6
Генерация photo.json — единый источник правды
Нейросеть пишет SEO-данные (alt, заголовок, подпись, ключевые слова) в JSON-файл с проверкой по схеме. Из этого JSON потом собираются все выходы: HTML-отчёт, IPTC-теги, payload для WordPress API, запись в БД. Один JSON = много применений.
+ Новое
7
19 вариантов фотки + IPTC-метаданные + запись в БД
4 ширины × 3 формата (WebP/AVIF/JPEG) + два 16:9-кропа × 3 формата + og:image. Итого 19 файлов на каждую фотку. Вшиваем авторство и копирайт в IPTC. Сохраняем в Postgres.
✓ Уже работает

Развилка после фильтра — 4 пути

На этапе 4 каждая фотка получает один из четырёх вердиктов. Вердикт хранится только в БД, не в JSON. Все фотки попадают в базу со своим статусом.

✓ Чистая
image-to-image модель (fal.ai) → переделка с минимальными правками → photo.json + 19 файлов → база
↑ Апскейл
Низкое разрешение → апскейл-модель fal.ai (конкретную модель ты подберёшь позже) → photo.json + 19 файлов → база
~ Тусклая
На паузе: сохраняем в базу со статусом PENDING_ENHANCE. Когда выберем модель для тонкой коррекции света/контраста — обработаем пачкой через CLI.
✕ Брак
Сохраняем в базу со статусом REJECTED и причиной. Дальше не обрабатываем. Видно в админке для аудита.
Где фотки <1600 px? Текущий жёсткий порог MIN_SOURCE_WIDTH=1600 опускаем до 400 px. Раньше мы такие фотки сразу выкидывали — теперь они тоже идут на фильтр, и если фильтр скажет «low_quality» — отправляются на апскейл-модель. То есть низкое разрешение больше не означает «не использовать».

Поток данных через photo.json

оригинал.jpg Gemini photo.json HTML / IPTC / БД / WordPress API
Шаг 1: один раз зовём нейросеть, валидируем по схеме, сохраняем JSON
Шаг 2: pure-функции преобразуют JSON в любой формат, без сети и нейросети

Что уже работает

Что нужно добавить в этом спринте

A
Подключить визуальный фильтр к пайплайну
Перенести scripts/visual-screen/ в основной код, сделать BullMQ-джобу. Запускается автоматически после определения локации.
+ Новое
B
Валидация фильтра на ≥200 фотках
Прогнать на большой выборке, проверить точность каждого из 14 критериев, подкрутить пороги. Только после этого включать в продакшен. Делается до этапа A.
+ Тестирование
C
Развилка по 4 вердиктам
Маршрутизация в очередях: чистая → image-to-image, апскейл → апскейл-модель, тусклая → парковка, брак → стоп.
+ Новое
D
Ветка апскейла
Новая джоба, вызывает апскейл-модель на fal.ai. Конкретную модель ты подбираешь позже — сейчас оставляем слот с интерфейсом.
+ Новое
E
JSON-per-photo + JSON Schema + рефакторинг рендеров
Шаг enrichment теперь пишет photo.json (рядом с фоткой), валидирует по схеме. HTML-отчёт и IPTC-эмбеддер становятся pure-функциями над JSON. Это разделение делает систему расширяемой.
+ Новое
F
Команда для массовой регистрации сайтов
site:bulk-add --config sites.json — добавить 10 сайтов одной командой вместо 10 ручных вызовов site:add.
+ Удобство
G
Понизить MIN_SOURCE_WIDTH с 1600 до 400 px
Маленький, но важный change: больше не выкидываем фотки <1600 px на этапе загрузки. Теперь решает фильтр — если качество низкое, отправляем на апскейл.
+ Правка
H
Отключить ручную разметку
Страница /label остаётся в коде, но больше не вызывается автоматически. Можно вернуть как fallback, если фильтр будет ошибаться на пограничных случаях.
⏸ На паузе

Отложено — отдельные этапы после спринта

I
Ветка улучшения (enhance)
Слот под модель тонкой коррекции света/контраста/насыщенности (без перерисовки сцены). Сейчас фотки с этим вердиктом просто паркуются со статусом PENDING_ENHANCE. CLI enhance --all обработает пачкой, когда выберем модель.
⏸ Отложено
J
Миграция хранилища на Cloudflare R2
Сейчас фотки лежат локально в storage/. В продакшене надо в R2 (S3-совместимое объектное хранилище от Cloudflare). Делаем абстракцию STORAGE_DRIVER=fs|r2: dev на диске, прод в R2. Отдельный этап — после того как пайплайн заработает.
⏸ После спринта
K
Векторный поиск (Qdrant)
В дополнение к Postgres — векторный индекс фоток в Qdrant. По тексту статьи находит подходящие фотки из общего пула. Контейнер Qdrant уже стоит в docker-compose, но не используется. Phase 4 в roadmap.
⏸ Phase 4