# Наработанные навыки ## OCR / PaddleOCR - **PP-StructureV3**: конфигурация через YAML-файл, замена моделей распознавания (`eslav_PP-OCRv5_mobile_rec` для русского, `PP-OCRv6_medium_rec` для английского), смена детектора `PP-OCRv5_server_det` → `PP-OCRv6_medium_det` без апгрейда `paddlepaddle` - **Архитектура детекторов**: DB (Differentiable Binarization) vs DB++ (RepLKFPN, ASF, DCN), PPLCNetV4, EncoderWithLightSVTR - **Модельный зоопарк**: `eslav` vs `cyrillic` (обе mobile, разница ~1%), `PP-OCRv6_medium_rec` (46 латинских + CN/JP/EN, без кириллицы), PP-FormulaNet для формул, SLANeXt для таблиц - **Параметры детектора**: `thresh` (порог карты вероятности), `box_thresh` (фильтр bbox), `unclip_ratio` (расширение контура), `max_side_limit` (обрезает upscale) - **Источники моделей**: PaddlePaddle CDN, HuggingFace Hub, modelscope — fallback-цепочка в `paddlex` ## Surya 2 / llama.cpp - **CPU-оптимизации**: `SURYA_INFERENCE_KEEP_ALIVE=true` (-23s повторный старт), `CTX_PER_SLOT=8192` (-30% RAM), `PARALLEL=1` (-80% слотов), `pre-scale=1056px` (~96 DPI), `-t 8 --threads-batch 8` (стабильная загрузка CPU) - **Health-check + retry**: проверка `http://host:port/health`, пересоздание engine при падении llama-server, `lru_cache.cache_clear()` для сброса ## OpenCV - **Unwarping**: Canny → findContours → approxPolyDP → _order_points → getPerspectiveTransform → warpPerspective с порогом `min_area ≥ 30%` (чтобы не детектить внутренние таблицы как страницу) - **Denoising**: `fastNlMeansDenoisingColored` — Non-Local Means. Полезен для шумных сканов, NOP для чистых. НЕ вреден для нейросетевого OCR - **Бинаризация**: `adaptiveThreshold` (Gaussian, окно 31) вредна для нейросетевого OCR — жёсткие границы рвут буквы, создают ложные контуры. Нейросети обучены на естественных изображениях, не на бинарных - **Upscale**: `cv2.resize(INTER_CUBIC)` бесполезен, если OCR-движок обрезает `max_side_limit` ## Архитектура Python / SOLID - **Вынос общих моделей**: `ParsedBlock`, `OcrPageResult` → отдельный `models.py` — 7 модулей отвязаны от `paddle_engine` - **Protocol → Callable**: если Protocol никем не реализован — YAGNI. `Callable[[ParsedBlock], None]` проще - **lru_cache вместо глобальных синглтонов**: `@functools.lru_cache(maxsize=N)` вместо `_engine: X | None = None` + `global _engine` - **idempotent env loader**: `load_env()` с внутренним guard'ом — не нужны внешние `_ENV_LOADED` флаги - **Shared API client**: `call_qwen_vlm()` + `image_to_base64()` в `qwen_client.py` — общий для OCR-движка и корректора ## CLI / Typer - **Annotated-параметры**: `Annotated[Path, typer.Option("--input", "-i")]` — минимум бойлерплейта - **Параметры по умолчанию**: обязательные без default, опциональные с `= None`, булевы через `--flag / --no-flag` - **Collapsible --help в README**: `
--help...
` ## pip / Управление зависимостями - **opencv конфликт**: `opencv-contrib-python` и `opencv-python-headless` делят `cv2/` — удаление одного ломает другой. Выбор: headless легче (-18 MB), без X11 - **version pinning**: `paddlepaddle==3.2.2` (баг ONEDNN/PIR в 3.3.1), `numpy<2.4` (paddlex ограничение), `opencv-python-headless<5.0` (surya-ocr требует 4.11) - **pip freeze → ручной requirements.txt**: 118 пакетов → 14 (только прямые зависимости) ## Многоформатный вывод - **JSON → LaTeX**: 3 формата (Paddle `parsing_res_list`, Surya `blocks[].html`, Qwen `blocks[].content`), автоопределение по структуре - **JSON → HTML + MathJax**: единый шаблон `HTML_TEMPLATE`, CDN MathJax 3, `$$...$$` для display-формул - **Таблицы**: HTML `` → LaTeX `tabular`, Markdown `|...|` → HTML `
` ## Документирование - **Аудит SOLID/DRY/KISS/YAGNI**: дважды за проект, фиксация нарушений с severity и планом исправления - **История экспериментов**: `stage2_results.md` — 16 вариантов, маркировка ✅/❌/⚠️, причина решения - **Модельный инвентарь**: какие модели установлены, размер, назначение, какие можно удалить ## Удалённое за ненадобностью | Что | Причина | |---|---| | LLM-корректор (Qwen2.5-7B, 4.4 GB) | Галлюцинации, слепой, большой | | Binarization (adaptive threshold) | Вредна для нейросетевого OCR | | Upscale ×2 | max_side_limit=4000 съедает | | surya2html.py, tex2html.py | Дубликаты json_to_latex.py | | 100+ пакетов в requirements.txt | Транзитивные зависимости pip freeze | | 2.2 GB мёртвых моделей | Неиспользуемые v5 и cyrillic |