|
|
|
|
|
|
|
|
1
|
+# Наработанные навыки
|
|
|
|
2
|
+
|
|
|
|
3
|
+## OCR / PaddleOCR
|
|
|
|
4
|
+
|
|
|
|
5
|
+- **PP-StructureV3**: конфигурация через YAML-файл, замена моделей распознавания (`eslav_PP-OCRv5_mobile_rec` для русского, `PP-OCRv6_medium_rec` для английского), смена детектора `PP-OCRv5_server_det` → `PP-OCRv6_medium_det` без апгрейда `paddlepaddle`
|
|
|
|
6
|
+- **Архитектура детекторов**: DB (Differentiable Binarization) vs DB++ (RepLKFPN, ASF, DCN), PPLCNetV4, EncoderWithLightSVTR
|
|
|
|
7
|
+- **Модельный зоопарк**: `eslav` vs `cyrillic` (обе mobile, разница ~1%), `PP-OCRv6_medium_rec` (46 латинских + CN/JP/EN, без кириллицы), PP-FormulaNet для формул, SLANeXt для таблиц
|
|
|
|
8
|
+- **Параметры детектора**: `thresh` (порог карты вероятности), `box_thresh` (фильтр bbox), `unclip_ratio` (расширение контура), `max_side_limit` (обрезает upscale)
|
|
|
|
9
|
+- **Источники моделей**: PaddlePaddle CDN, HuggingFace Hub, modelscope — fallback-цепочка в `paddlex`
|
|
|
|
10
|
+
|
|
|
|
11
|
+## Surya 2 / llama.cpp
|
|
|
|
12
|
+
|
|
|
|
13
|
+- **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)
|
|
|
|
14
|
+- **Health-check + retry**: проверка `http://host:port/health`, пересоздание engine при падении llama-server, `lru_cache.cache_clear()` для сброса
|
|
|
|
15
|
+
|
|
|
|
16
|
+## OpenCV
|
|
|
|
17
|
+
|
|
|
|
18
|
+- **Unwarping**: Canny → findContours → approxPolyDP → _order_points → getPerspectiveTransform → warpPerspective с порогом `min_area ≥ 30%` (чтобы не детектить внутренние таблицы как страницу)
|
|
|
|
19
|
+- **Denoising**: `fastNlMeansDenoisingColored` — Non-Local Means. Полезен для шумных сканов, NOP для чистых. НЕ вреден для нейросетевого OCR
|
|
|
|
20
|
+- **Бинаризация**: `adaptiveThreshold` (Gaussian, окно 31) вредна для нейросетевого OCR — жёсткие границы рвут буквы, создают ложные контуры. Нейросети обучены на естественных изображениях, не на бинарных
|
|
|
|
21
|
+- **Upscale**: `cv2.resize(INTER_CUBIC)` бесполезен, если OCR-движок обрезает `max_side_limit`
|
|
|
|
22
|
+
|
|
|
|
23
|
+## Архитектура Python / SOLID
|
|
|
|
24
|
+
|
|
|
|
25
|
+- **Вынос общих моделей**: `ParsedBlock`, `OcrPageResult` → отдельный `models.py` — 7 модулей отвязаны от `paddle_engine`
|
|
|
|
26
|
+- **Protocol → Callable**: если Protocol никем не реализован — YAGNI. `Callable[[ParsedBlock], None]` проще
|
|
|
|
27
|
+- **lru_cache вместо глобальных синглтонов**: `@functools.lru_cache(maxsize=N)` вместо `_engine: X | None = None` + `global _engine`
|
|
|
|
28
|
+- **idempotent env loader**: `load_env()` с внутренним guard'ом — не нужны внешние `_ENV_LOADED` флаги
|
|
|
|
29
|
+- **Shared API client**: `call_qwen_vlm()` + `image_to_base64()` в `qwen_client.py` — общий для OCR-движка и корректора
|
|
|
|
30
|
+
|
|
|
|
31
|
+## CLI / Typer
|
|
|
|
32
|
+
|
|
|
|
33
|
+- **Annotated-параметры**: `Annotated[Path, typer.Option("--input", "-i")]` — минимум бойлерплейта
|
|
|
|
34
|
+- **Параметры по умолчанию**: обязательные без default, опциональные с `= None`, булевы через `--flag / --no-flag`
|
|
|
|
35
|
+- **Collapsible --help в README**: `<details><summary>--help</summary>...</details>`
|
|
|
|
36
|
+
|
|
|
|
37
|
+## pip / Управление зависимостями
|
|
|
|
38
|
+
|
|
|
|
39
|
+- **opencv конфликт**: `opencv-contrib-python` и `opencv-python-headless` делят `cv2/` — удаление одного ломает другой. Выбор: headless легче (-18 MB), без X11
|
|
|
|
40
|
+- **version pinning**: `paddlepaddle==3.2.2` (баг ONEDNN/PIR в 3.3.1), `numpy<2.4` (paddlex ограничение), `opencv-python-headless<5.0` (surya-ocr требует 4.11)
|
|
|
|
41
|
+- **pip freeze → ручной requirements.txt**: 118 пакетов → 14 (только прямые зависимости)
|
|
|
|
42
|
+
|
|
|
|
43
|
+## Многоформатный вывод
|
|
|
|
44
|
+
|
|
|
|
45
|
+- **JSON → LaTeX**: 3 формата (Paddle `parsing_res_list`, Surya `blocks[].html`, Qwen `blocks[].content`), автоопределение по структуре
|
|
|
|
46
|
+- **JSON → HTML + MathJax**: единый шаблон `HTML_TEMPLATE`, CDN MathJax 3, `$$...$$` для display-формул
|
|
|
|
47
|
+- **Таблицы**: HTML `<table>` → LaTeX `tabular`, Markdown `|...|` → HTML `<table>`
|
|
|
|
48
|
+
|
|
|
|
49
|
+## Документирование
|
|
|
|
50
|
+
|
|
|
|
51
|
+- **Аудит SOLID/DRY/KISS/YAGNI**: дважды за проект, фиксация нарушений с severity и планом исправления
|
|
|
|
52
|
+- **История экспериментов**: `stage2_results.md` — 16 вариантов, маркировка ✅/❌/⚠️, причина решения
|
|
|
|
53
|
+- **Модельный инвентарь**: какие модели установлены, размер, назначение, какие можно удалить
|
|
|
|
54
|
+
|
|
|
|
55
|
+## Удалённое за ненадобностью
|
|
|
|
56
|
+
|
|
|
|
57
|
+| Что | Причина |
|
|
|
|
58
|
+|---|---|
|
|
|
|
59
|
+| LLM-корректор (Qwen2.5-7B, 4.4 GB) | Галлюцинации, слепой, большой |
|
|
|
|
60
|
+| Binarization (adaptive threshold) | Вредна для нейросетевого OCR |
|
|
|
|
61
|
+| Upscale ×2 | max_side_limit=4000 съедает |
|
|
|
|
62
|
+| surya2html.py, tex2html.py | Дубликаты json_to_latex.py |
|
|
|
|
63
|
+| 100+ пакетов в requirements.txt | Транзитивные зависимости pip freeze |
|
|
|
|
64
|
+| 2.2 GB мёртвых моделей | Неиспользуемые v5 и cyrillic |
|