Единый скрипт src/cli.py → разрезание изображений на страницы (Stage 1). Нужен Stage 2 — распознавание текста и структуры документа, генерация LaTeX/HTML/Markdown для последующего анализа LLM.
Результат: 66 текстовых блоков, русский текст — ~60% точности.
i-WHAeKC AOrOBOpa вместо і - индекс договораt - номер месяцаB дефолте — латиница смешана с кириллицейРезультат: 22 структурированных блока с layout-разметкой.
[number], [formula], [text], [paragraph_title]\mathrm{C Rec}_{\mathrm{it}}=\sum...Результат: разница ~1-2%, несущественна.
LGD_ехtг; (кириллица г)LGD_ехtr; (латиница r) — чуть лучшеРезультат: ❌ не поддерживают русский.
Результат: +4.6% detection accuracy vs v5, на 7% быстрее (97.8s vs 104.7s).
--main-lang выбор распознавалки ✅ оставленРезультат: переключение rec-модели по основному языку страницы.
--main-lang=ru → eslav_PP-OCRv5_mobile_rec (русский, 85-90%)--main-lang=en → PP-OCRv6_medium_rec (английский + греческие в формулах, 75-80%)Результат: 50/50 — исправляет и тут же галлюцинирует.
До: сypporat WoE для гpynnы i
После: коррелят weight of evidence (галлюцинация вместо «суррогат»)
fixups.py уже правит VaR/V^2 без моделиРезультат: полное восстановление текста + авто inline-формулы.
До: ΣДсе, - дисконтированная сумма возвратов
После: $\sum_t DCF_{i,t}$ — дисконтированная сумма возвратов
zen/go/v1/messagesРезультат: ❌ не поддерживает PaddleOCR как OCR-backend.
Результат: модель загружена (1.79 GB), ~15 мин/стр на CPU.
Результат: лучший русский OCR из коробки — но медленно на CPU.
<math>MRec_{it}</math> → $MRec_{it}$Результат: 118s на страницу с таблицей, качество отличное.
| col1 | col2 |$...$Результат: 17 блоков vs 12 без (+42%), исправил «6»→«G», «Пр»→«р».
--denoiseРезультат: жёсткие границы порвали буквы, ложные контуры.
$b_i$ → $b_{-}i-\\sec a$ (мусор)$\alpha\times\alpha\times\alpha...$ — артефакты бинаризацииРезультат: бесполезен — PaddleOCR режет max_side_limit=4000.
max_side_limit жёстко ограничивает входное разрешениеmax_side_limit в YAML для пользыРезультат: работает для фото под углом, NOP для плоского сканера.
min_area ≥ 30% от изображения--unwarp для фото, для сканера — YAGNI| Действие | Результат |
|---|---|
ParsedBlock/OcrPageResult → src/models.py |
7 модулей отвязаны от paddle_engine |
Corrector(Protocol) → Callable |
Удалён неиспользуемый Protocol |
validate_output_dir() удалён |
Мёртвый код из slicer.py |
_ensure_env() → load_env() напрямую |
Убраны дублирующие guard’ы |
calc_scale_dims() в image_utils.py |
Общий pre-scale для Surya + external VLM |
functools.lru_cache для engine-синглтонов |
Убран boilerplate _engine: X \| None |
surya2html.py, tex2html.py удалены |
Дубликаты логики из json_to_latex.py |
binarize_image(), upscale_image() удалены |
Мёртвые функции из slicer.py |
requirements.txt: 118 → 14 пакетов |
Только прямые зависимости |
llm_corrector.py + Qwen2.5-7B (4.4GB) удалены |
Галлюцинации, YAGNI |
Входное изображение (JPEG/PNG/TIFF)
│
▼
src/image_prepare.py ← Stage 1: подготовка
│ --slice / --slice-auto
│ --pre-rotate, --border
│ --unwarp, --denoise
│ --post-crop
│
▼
src/image_ocr.py ← Stage 2: OCR + Markdown
│ --ocr-engine paddle|surya|external-qwen3
│ --main-lang ru|en
│ --fix-by-external-qwen3
│ --pause, --no-result-one-document
│
├─ PaddleEngine / SuryaEngine (OCR)
├─ fix_ocr_errors (VaR, V^2)
├─ VlmCorrector (Qwen3.8 Max, API)
│
▼
.md + .json (per page) + merged.md
│
▼
src/latex/json_to_latex.py ← Stage 3: JSON → LaTeX + HTML
│ Paddle / Surya / Qwen
│ Автоопределение формата
│
▼
.tex + .html (с MathJax для таблиц и формул)
| Функция | Статус |
|---|---|
--main-lang ru |
ON |
| Resume (пропуск JSON) | ON |
--result-one-document |
ON |
--pause 5 |
ON |
--post-crop (Stage 1) |
ON |
src/
models.py — ParsedBlock, OcrPageResult
image_utils.py — calc_scale_dims
image_prepare.py — CLI Stage 1
image_ocr.py — CLI Stage 2
cli_utils.py — run_main()
env.py — загрузка .env
split/slicer.py — разрезание, post-crop, border, unwarp, denoise
ocr/
paddle_engine.py — PP-StructureV3 + v6-det + ru/en rec
surya_engine.py — Surya 2 + CPU-оптимизации + health_check
external_vlm_engine.py — Qwen3.8 Max full-page OCR
postprocess/
fixups.py — VaR, V^2
corrector.py — apply_corrector
vlm_corrector.py — Qwen3.8 Max per-block API
qwen_client.py — общий Qwen API-клиент
markdown/generator.py — Markdown + валидация LaTeX
latex/
json_to_latex.py — JSON→LaTeX+HTML (Paddle + Surya + Qwen)
| Параметр | До | После | Эффект |
|---|---|---|---|
| KEEP_ALIVE | off | on | -23s повторный старт |
| CTX per slot | 12288 | 8192 | -30% RAM |
| Parallel slots | 8 | 1 | -80% слотов |
| Pre-scale | 2552px | 1056px | -60% пикселей |
| Threads | default | -t 8 |
стабильно |
| Итого | 430s | 300s | -30% |
| Параметр | PaddleOCR | Surya 2 | VLM Qwen3.8 |
|---|---|---|---|
| Архитектура | Ансамбль 5 моделей | Один VLM (650M) | Cloud VLM |
| Русский текст | ~85% (eslav rec) | 95%+ | 98%+ |
| Английский текст | ~80% (v6 rec) | 95%+ | 98%+ |
| Формулы | PP-FormulaNet | VLM (отлично) | VLM (отлично) |
| Таблицы | PP-TableMagic + bbox | ❌ CPU timeout | ✅ Pipe-Markdown |
| Inline-формулы | Нет | <math> тэги |
$...$ |
| Скорость CPU | ~100-160s | ~300s | ~120s (API) |
| Офлайн | ✅ | ✅ | ❌ |
| Размер моделей | ~2.5 GB | ~1.5 GB | 0 (cloud) |
| Этап | PaddleOCR | Surya 2 | VLM |
|---|---|---|---|
| OCR (одна страница) | 100-160s | 300s | 120s |
| Denoise (Stage 1) | +35s | — | — |
| VLM-корректор | +10s/блок | не нужен | — |
| JSON + MD сохранение | <1s | <1s | <1s |
| Merge в один документ | <1s | <1s | <1s |
| Итого на страницу | ~3-4 min | ~5 min | ~2 min |
| 12 страниц (batch) | ~15-20 min* | ~60 min | ~24 min |
* PaddleOCR с --pause 5 и --denoise
--main-lang=en — +20% на английских страницах