переименование фото украшений + комплекты по чёрным разделителям

SILVER-RenamerBlack

Развитие SILVER-Renamer: добавлены чёрные кадры-разделители между сериями и поддержка комплектов через vision-классификатор.

Сервис: https://renamerblack.6sl.ru (Selectel, РФ-хост — обход блокировки upload через ТСПУ для зарубежных IP).

Чем отличается от SILVER-Renamer

SILVER-Renamer SILVER-RenamerBlack
Базовое переименование (бирка → артикул → серия) да да
Чёрные кадры как границы групп да
Vision-классификация типа украшения OpenAI gpt-4o-mini / Anthropic claude-sonnet-4-6
Комплекты: копия общего фото для всех артикулов группы да
CLI / .exe-сборка да — (только web — vision требует сети)
Хостинг Hetzner (EU) + зеркало Selectel (RU) Selectel (RU)

Как пользоваться

  1. Фотограф снимает партию. Между сериями каждого артикула (или комплекта) делает кадр глухого чёрного — закрытая крышка объектива. Этот кадр — разделитель.
  2. Внутри партии одного комплекта может быть несколько артикулов (бирки на каждый из них) и общие фото комплекта целиком (все украшения вместе на одной поверхности).
  3. Менеджер открывает https://renamerblack.6sl.ru и загружает папку с фото + Excel (колонка A=УИН, B=Артикул). - Имена файлов могут быть YYYYMMDD_HHMMSS.jpg (Samsung) или file_1.jpg, file_2.jpg, ... — главное, чтобы порядок «по возрастанию» соответствовал хронологии съёмки.
  4. Сервис обрабатывает партию (этапы — см. ниже) и возвращает HTML-отчёт + ZIP с переименованными файлами и CSV-логом.

Что делает сервис (пошагово)

  1. Сортировка. Все .jpg сортируются natsort'ом (естественный порядок: file_1 < file_2 < file_10).
  2. Разбиение на группы. Каждый файл проверяется на «глухой чёрный» (mean < 10 И std < 10 по grayscale). Чёрные кадры режут поток на группы. Сами разделители в результат не попадают.
  3. Внутри группы — базовое переименование (как в SILVER-Renamer): - Бирка декодируется zxing-cpp (Data Matrix / QR). UIN → артикул из Excel → новая под-серия. - Кадр с биркой → output/{артикул}_001.jpg (технический, для проверки). - Следующие фото без бирки → ракурсы артикула output/{артикул}_01.jpg, _02.jpg, … - До первой бирки или UIN не из Excel → _unknown/.
  4. Vision-классификация каждого переименованного фото (KIND_RENAMED). Метки: ring | earrings | pendant | bracelet | chain | necklace | set | tag | unknown. Параллельно через ThreadPoolExecutor (10 воркеров) — 600 фото ≈ 90 секунд.
  5. Размножение set-фото. Для каждой группы, где есть ≥ 2 разных артикула: - Находим фото с меткой set. - Каждое такое фото копируется под каждый артикул группы кроме того, к которому оно уже отнесено. Имя копии — {артикул}_{max_NN_для_артикула + 1}.jpg.
  6. CSV-лог. rename_log.csv фиксирует все операции (tag | renamed | tag-uin-not-in-excel | no-tag-yet | black-divider | set-copy) с указанием group_idx.

Архитектура

src/
├── silver_renamer.py    # ядро: чёрные кадры, группы, бирки → артикулы → серии
├── sets.py              # vision-классификация + копии set-фото в группе
├── vision.py            # OpenAI / Anthropic классификаторы + SOCKS5
└── web.py               # FastAPI: /process, /report/<job>, /docs, /thumb, /file
templates/{base,index,report,docs}.html
static/style.css
deploy/
├── silver-renamerblack.service   # systemd unit (port 8770, requires tg-tunnel)
├── Caddyfile.snippet             # reverse_proxy renamerblack.6sl.ru → :8770
└── install.sh                    # идемпотентный sudo-установщик на Selectel
requirements.txt
initial-delmepls/with_razdeliteli_test/   # smoke-test: 18 фото + 3 чёрных разделителя

Поток данных

upload (folder + .xlsx)
        ↓
   web.py:/process  — сохраняет в /tmp/silver-renamer-jobs/<id>/input/
        ↓
silver_renamer.process()    — основное переименование, output/ + _unknown/ + rename_log.csv
        ↓
   sets.expand_sets()       — vision-классификация (через SOCKS5) + set-копии
        ↓
   pickle(result, expansion) → /report/<id>  — HTML-отчёт
   zip(output/ + _unknown/ + rename_log.csv) → /download/<id>/result.zip

Vision и сеть

Стек

Python 3.12, FastAPI + uvicorn + Jinja2, Caddy reverse proxy. zxing-cpp (Data Matrix/QR), openpyxl, opencv-python-headless, natsort, Pillow, markdown. Vision: openai, anthropic, httpx[socks], python-dotenv.

Запуск (dev, Hetzner)

python3.12 -m venv .venv
.venv/bin/pip install -r requirements.txt

# Один раз — секреты в ~/.config/silver-renamerblack/.env (mode 600):
#   OPENAI_API_KEY=sk-proj-...
#   ANTHROPIC_API_KEY=sk-ant-...   # опционально
#   VISION_PROVIDER=openai
#   # SOCKS_PROXY=socks5://127.0.0.1:1080  # только на Selectel

PYTHONPATH=src .venv/bin/uvicorn web:app --host 127.0.0.1 --port 8770

Деплой (Selectel)

# на Hetzner
rsync -av --delete \
  --exclude='.venv' --exclude='.git' --exclude='__pycache__' \
  --exclude='initial-delmepls' --exclude='*.pyc' \
  ./ 135.106.137.112:/home/vadim/PROJECTS/SILVER-RenamerBlack/

# на Selectel: создать venv (если ещё нет) и поставить deps
ssh 135.106.137.112 'cd PROJECTS/SILVER-RenamerBlack && \
  python3.12 -m venv .venv && \
  .venv/bin/pip install -r requirements.txt'

# секреты — на Selectel ~/.config/silver-renamerblack/.env mode 600
# (с SOCKS_PROXY=socks5://127.0.0.1:1080 — vision идёт через tg-tunnel)

# первый раз — sudo-установщик копирует env в /etc, systemd unit, Caddy block:
ssh 135.106.137.112 'cd PROJECTS/SILVER-RenamerBlack && sudo bash deploy/install.sh'

# обновления кода — rsync + рестарт:
ssh 135.106.137.112 'sudo systemctl restart silver-renamerblack'

Тестовая партия

initial-delmepls/with_razdeliteli_test/ — 18 фото + 3 чёрных разделителя + Vega2005.xlsx. Ожидаемый результат: 3 группы (по 2 артикула каждая, с парой кольцо + серьги), 15 переименованных + 3 set-копии (по одной на группу). Эталон от менеджера: yandex-disk.

Статус

Развёрнут на https://renamerblack.6sl.ru. Smoke-тест на 18 фото — пройден end-to-end (3 группы, 3 set-копии, корректное переименование, ZIP без оригиналов). Следующий шаг — реальная партия (≈600 фото) от менеджера.