build(photo-ai): CPU/GPU сборка, gfpgan+facexlib без dev-зависимостей, healthcheck

Stage 2: photo-ai/Dockerfile получил ARG TORCH_VARIANT/TORCH_INDEX (один образ,
cu124 — вариант сборки) и явные пины gfpgan==1.3.8 / facexlib==0.3.0 через
--no-deps: tb-nightly и yapf (dev-зависимости gfpgan/basicsr) больше не попадают
в рантайм, matplotlib остаётся как зависимость filterpy (требование facexlib).
Патч basicsr/data/degradations.py сохранён байт-в-байт — без него basicsr падает
на torch >= 2.0.

Пин numpy<2 был невыполним: opencv-python-headless 5.0.0.93 требует numpy >= 2.
Зафиксирована фактическая версия numpy==2.2.6 в общем вызове pip install, а
opencv-python (не-headless) больше не ставится — раньше он приходил через gfpgan
и перезаписывал headless-сборку (активным был cv2 с GUI: QT5). I1 после этого
перепроверен: 5/5 MATCH байт-в-байт против эталона Stage 0.

ENV PHOTO_AI_MODELS_DIR=/models, MODEL_PATH остаётся валидным алиасом.
COPY vendor/ ./vendor/ + vendor/.gitkeep — вендоренный CodeFormer (D5)
подхватится из sys.path без правок Dockerfile.

docker-compose.yml: у photo-ai новые env (DEVICE, TILE, FACE_MODEL, LOAD_ALL,
JPEG_QUALITY, MODELS_DIR) и healthcheck со start_period 300s; MAX_INPUT_PIXELS
заменён на канонический PHOTO_AI_MAX_PIXELS (старое имя читается app.py как алиас).
У app — PHOTO_AI_FACE_MODEL и PHOTO_AI_FACE_TIMEOUT_MS (воркер читает их в Stage 4).
Новый docker-compose.gpu.yml (по образцу minio): TORCH_VARIANT=cu124,
PHOTO_AI_DEVICE=cuda, deploy.resources.reservations.devices для nvidia.

.env.example и таблица переменных README описывают ровно те переменные, которые
теперь подставляет compose; блок про GPU и NVIDIA Container Toolkit — Stage 6 (D6).

Проверено на живом стеке: сборка EXIT=0 (2.63 ГБ), /health отдаёт device=cpu,
face_models=[gfpgan], контейнер healthy, /api/photo-jobs/status отдаёт
service.device, I3 (пустой PHOTO_AI_URL -> 503 + 8 маршрутов 200), I4
(PHOTO_AI_DEVICE=cuda без CUDA -> WARN + CPU), docker compose config валиден для
базы, minio и gpu. GPU-пуск не выполнялся: nvidia-ctk на хосте отсутствует.
This commit is contained in:
dev
2026-09-29 09:35:40 +03:00
parent e8c15cc425
commit 7367d66ac3
7 changed files with 143 additions and 19 deletions
+9 -3
View File
@@ -121,14 +121,20 @@ REDIS_PASSWORD=случайная-длинная-строка
## ИИ-улучшение фото (photo-ai)
Сервис `photo-ai` (Real-ESRGAN) поднимается вместе со стеком и **включён по умолчанию**: `PHOTO_AI_URL`
в `docker-compose.yml` равен `http://photo-ai:8080`, кнопка «🤖 ИИ» активна, а задания обрабатывает
фоновый воркер. Работает на CPU, GPU не требуется.
Сервис `photo-ai` (Real-ESRGAN + GFPGAN) поднимается вместе со стеком и **включён по умолчанию**:
`PHOTO_AI_URL` в `docker-compose.yml` равен `http://photo-ai:8080`, кнопка «🤖 ИИ» активна,
а задания обрабатывает фоновый воркер. Работает на CPU, GPU не требуется.
| Переменная | По умолчанию | Назначение |
|---|---|---|
| `PHOTO_AI_URL` | `http://photo-ai:8080` | Адрес сервиса. **Пустое значение = сервис выключен**: кнопка «🤖 ИИ» скрыта, `POST /api/entries/:id/photo/enhance-ai` отвечает `503`, приложение при этом полностью работоспособно |
| `PHOTO_AI_MAX_PIXELS` | `4000000` | Максимум пикселей входного изображения, вход большего размера уменьшается |
| `PHOTO_AI_DEVICE` | `auto` | Устройство инференса: `auto` (CUDA, если контейнеру выдан GPU, иначе CPU), `cuda`, `cpu`. Явный `cuda` без CUDA не роняет сервис: WARN в лог и работа на CPU |
| `PHOTO_AI_TILE` | `256` | Размер тайла инференса (`0` — без тайлов): меньше тайл — меньше памяти, но медленнее |
| `PHOTO_AI_FACE_MODEL` | `gfpgan` | Модель восстановления лиц: `gfpgan`; `codeformer` доступен только при вендоринге модуля в `photo-ai/vendor` |
| `PHOTO_AI_LOAD_ALL` | `0` | Загружать все модели при старте (`1`) или лениво по требованию (`0`) |
| `PHOTO_AI_JPEG_QUALITY` | `92` | Качество JPEG результата, 70..100 |
| `PHOTO_AI_FACE_TIMEOUT_MS` | `600000` | Таймаут заданий с восстановлением лиц (мс) |
| `PHOTO_AI_SOFT_MAX_RETRIES` | `60` | Сколько раз задание ждёт недоступный сервис, не увеличивая счётчик попыток; после исчерпания — честная ошибка |
| `PHOTO_AI_SOFT_BACKOFF_MS` | `10000` | Первая пауза перед мягким повтором |
| `PHOTO_AI_SOFT_BACKOFF_MAX_MS` | `300000` | Потолок паузы (задержка растёт вдвое) |