feat(sf): OCR pipeline izjatie EKB Tesseract rus land_reservation 1062 #1153

Merged
lekss361 merged 1 commit from feat/izyatie-ocr-pipeline into main 2026-06-07 15:21:20 +00:00
Collaborator

Summary

  • Dockerfile: tesseract-ocr + tesseract-ocr-rus in runner apt layer
  • pymupdf>=1.24 (PDF rasterization without poppler) + pytesseract>=0.3.13
  • izyatie_client.py: list_izyatie_documents() + fetch_pdf() from ekaterinburg.rf (verify=False)
  • izyatie_ocr.py: ocr_pdf_text() (PyMuPDF + PIL + Tesseract rus, dpi=300) + extract_izyatie_records() with OCR noise normalization (spaces in cad-num, O->0, b->6)
  • izyatie_ocr_ingest.py: Celery task ingest_izyatie_ocr -> land_reservation UPSERT (SAVEPOINT per-row, CAST psycopg v3)
  • beat_schedule.py: izyatie-ocr-ingest-weekly (Friday 07:00 MSK)
  • 33 tests, 33 passed, 0 failed

Test plan

  • docker compose build backend worker (check tesseract-ocr-rus installed)
  • celery call tasks.izyatie_ocr_ingest.ingest_izyatie_ocr
  • SELECT count(*), source FROM land_reservation WHERE source='izyatie_ekb_ocr' GROUP BY source
## Summary - Dockerfile: tesseract-ocr + tesseract-ocr-rus in runner apt layer - pymupdf>=1.24 (PDF rasterization without poppler) + pytesseract>=0.3.13 - izyatie_client.py: list_izyatie_documents() + fetch_pdf() from ekaterinburg.rf (verify=False) - izyatie_ocr.py: ocr_pdf_text() (PyMuPDF + PIL + Tesseract rus, dpi=300) + extract_izyatie_records() with OCR noise normalization (spaces in cad-num, O->0, b->6) - izyatie_ocr_ingest.py: Celery task ingest_izyatie_ocr -> land_reservation UPSERT (SAVEPOINT per-row, CAST psycopg v3) - beat_schedule.py: izyatie-ocr-ingest-weekly (Friday 07:00 MSK) - 33 tests, 33 passed, 0 failed ## Test plan - [ ] docker compose build backend worker (check tesseract-ocr-rus installed) - [ ] celery call tasks.izyatie_ocr_ingest.ingest_izyatie_ocr - [ ] SELECT count(*), source FROM land_reservation WHERE source='izyatie_ekb_ocr' GROUP BY source
bot-backend added 1 commit 2026-06-07 15:07:54 +00:00
feat(sf): OCR-пайплайн изъятия ЕКБ (Tesseract rus) → land_reservation (#1062)
All checks were successful
CI / frontend-tests (push) Has been skipped
CI / changes (pull_request) Successful in 6s
CI / changes (push) Successful in 6s
CI / frontend-tests (pull_request) Has been skipped
CI / backend-tests (push) Successful in 6m22s
CI / backend-tests (pull_request) Successful in 6m19s
5da4271235
- Dockerfile: добавлены tesseract-ocr tesseract-ocr-rus в runner apt-слой
- pyproject.toml: pymupdf>=1.24 (рендер PDF без poppler) + pytesseract>=0.3.13
- izyatie_client.py: list_izyatie_documents() + fetch_pdf() с екатеринбург.рф
- izyatie_ocr.py: ocr_pdf_text() (PyMuPDF→PIL→Tesseract rus) + extract_izyatie_records()
  с нормализацией OCR-шума (пробелы в кад-номерах, кирилл. О→0, б→6)
- izyatie_ocr_ingest.py: Celery task → land_reservation UPSERT (SAVEPOINT per-row)
- beat_schedule.py: izyatie-ocr-ingest-weekly (пятница 07:00 МСК)
- 33 теста, все зелёные; без реального Tesseract/сети в CI
lekss361 added the
GG-форсайт
scope/backend
scrapers
site-finder
ИРД
labels 2026-06-07 15:08:53 +00:00
Owner

⚠️ Для reviewer/deploy: этот PR меняет backend/Dockerfile (apt: tesseract-ocr + tesseract-ocr-rus) → деплой пересоберёт образ (дольше обычного, +tesseract ~50MB). После merge+deploy:

  1. docker exec gendesign-worker-1 tesseract --version (проверить установку + rus в --list-langs).
  2. Прогон ingest_izyatie_ocr через /app/.venv/bin/python (или celery call).
  3. SELECT count(*), reservation_kind FROM land_reservation WHERE source='izyatie_ekb_ocr' GROUP BY 2 + sample cad_nums — сверить с реальными сообщениями (Татищева/Базовый, кад 66:41:...).

Я прогоню эту верификацию после деплоя (OCR на живых сканах — финальная проверка recall кад-номеров).

⚠️ **Для reviewer/deploy:** этот PR меняет `backend/Dockerfile` (apt: tesseract-ocr + tesseract-ocr-rus) → деплой **пересоберёт образ** (дольше обычного, +tesseract ~50MB). После merge+deploy: 1. `docker exec gendesign-worker-1 tesseract --version` (проверить установку + rus в `--list-langs`). 2. Прогон `ingest_izyatie_ocr` через `/app/.venv/bin/python` (или celery call). 3. `SELECT count(*), reservation_kind FROM land_reservation WHERE source='izyatie_ekb_ocr' GROUP BY 2` + sample cad_nums — сверить с реальными сообщениями (Татищева/Базовый, кад 66:41:...). Я прогоню эту верификацию после деплоя (OCR на живых сканах — финальная проверка recall кад-номеров).
bot-reviewer requested changes 2026-06-07 15:11:30 +00:00
bot-reviewer left a comment
Collaborator

🔴 HOLD — нужно решение человека по лицензии (не мерджу авто).

Технически PR в порядке (uv.lock синхронизирован с pyproject ✓, Dockerfile добавляет tesseract-ocr+rus в runtime-слой ✓, 33 теста). Единственный, но серьёзный блокер — лицензия новой зависимости:

⚠️ PyMuPDF = AGPL-3.0

pymupdf>=1.24.0 — двойная лицензия AGPL-3.0 / commercial. GenDesign — коммерческий SaaS (gendsgn.ru); AGPL §13 (network-copyleft) срабатывает на «взаимодействии по сети» → обязывает предоставлять исходники пользователям сервиса. С учётом compliance-контекста проекта (реестр ПО / 152-ФЗ) это юридическое решение, которое бот не вправе принимать сам.

Есть non-AGPL альтернатива (уже в зависимостях!)

pypdfium2 (BSD-3 + Apache-2 + PDFium BSD) уже транзитивно подтянут через pdfplumber (#1118) и умеет растеризовать PDF→image (PdfDocument(...).render(...)→PIL). Замена pymupdfpypdfium2 в izyatie_ocr.ocr_pdf_text убирает AGPL без новых зависимостей и без poppler.

Варианты (выбор за человеком)

  1. Свапнуть на pypdfium2 (рекоменд.) — растеризация эквивалентна, лицензия чистая. → тогда убрать pymupdf из pyproject/lock, переписать rasterize-часть izyatie_ocr.py, обновить моки в тестах.
  2. Оставить PyMuPDF — только если осознанно принимаем AGPL-обязательства / есть коммерческая лицензия PyMuPDF. Решение владельца продукта.

Полное ревью OCR-логики (izyatie_ocr.py extract/normalize, ingest SAVEPOINT/CAST) сделаю после фиксации rasterize-библиотеки — она может затронуть код.

Ставлю needs-human + blocked: нужно решение по лицензии до мерджа. tesseract (apt) лицензионно чист (Apache-2) — вопрос только к PyMuPDF.

<!-- gendesign-review-bot: sha=5da4271 verdict=changes --> 🔴 **HOLD — нужно решение человека по лицензии (не мерджу авто).** Технически PR в порядке (uv.lock синхронизирован с pyproject ✓, Dockerfile добавляет tesseract-ocr+rus в **runtime**-слой ✓, 33 теста). Единственный, но серьёзный блокер — **лицензия новой зависимости**: ## ⚠️ PyMuPDF = AGPL-3.0 `pymupdf>=1.24.0` — двойная лицензия **AGPL-3.0 / commercial**. GenDesign — коммерческий SaaS (gendsgn.ru); **AGPL §13 (network-copyleft)** срабатывает на «взаимодействии по сети» → обязывает предоставлять исходники пользователям сервиса. С учётом compliance-контекста проекта (реестр ПО / 152-ФЗ) это **юридическое решение, которое бот не вправе принимать сам**. ## Есть non-AGPL альтернатива (уже в зависимостях!) `pypdfium2` (BSD-3 + Apache-2 + PDFium BSD) **уже транзитивно подтянут** через pdfplumber (#1118) и **умеет растеризовать** PDF→image (`PdfDocument(...).render(...)→PIL`). Замена `pymupdf` → `pypdfium2` в `izyatie_ocr.ocr_pdf_text` убирает AGPL без новых зависимостей и без poppler. ## Варианты (выбор за человеком) 1. **Свапнуть на pypdfium2** (рекоменд.) — растеризация эквивалентна, лицензия чистая. → тогда убрать `pymupdf` из pyproject/lock, переписать rasterize-часть `izyatie_ocr.py`, обновить моки в тестах. 2. **Оставить PyMuPDF** — только если осознанно принимаем AGPL-обязательства / есть коммерческая лицензия PyMuPDF. Решение владельца продукта. Полное ревью OCR-логики (`izyatie_ocr.py` extract/normalize, ingest SAVEPOINT/CAST) сделаю после фиксации rasterize-библиотеки — она может затронуть код. Ставлю `needs-human` + `blocked`: нужно решение по лицензии до мерджа. tesseract (apt) лицензионно чист (Apache-2) — вопрос только к PyMuPDF.
bot-reviewer added the
needs-human
status/blocked
labels 2026-06-07 15:11:39 +00:00
lekss361 merged commit 08acc25c43 into main 2026-06-07 15:21:20 +00:00
lekss361 deleted branch feat/izyatie-ocr-pipeline 2026-06-07 15:21:21 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#1153
No description provided.