# Stage 2 Results — OCR Pipeline ## Путь проекта ### Исходная точка Единый скрипт `src/cli.py` → разрезание изображений на страницы (Stage 1). Нужен Stage 2 — распознавание текста и структуры документа, генерация LaTeX/HTML/Markdown для последующего анализа LLM. --- ## Опробованные варианты ### 1. PaddleOCR базовый (PP-OCRv5) **Результат:** 66 текстовых блоков, русский текст — ~60% точности. - `i-WHAeKC AOrOBOpa` вместо `і - индекс договора` - `t - номер месяцаB дефолте` — латиница смешана с кириллицей - Нет структуры документа (заголовки, формулы, таблицы слиты в сплошной текст) - **Вывод:** только для английского, для русского требуется структура ### 2. PP-StructureV3 (ансамбль специализированных моделей) **Результат:** 22 структурированных блока с layout-разметкой. - Layout detection: ✅ `[number]`, `[formula]`, `[text]`, `[paragraph_title]` - Display-формулы: ✅ `\mathrm{C Rec}_{\mathrm{it}}=\sum...` - Таблицы: ✅ PP-TableMagic с bbox ячеек - Русский текст: ⚠️ ~85% (eslav_PP-OCRv5_mobile_rec) - **Вывод:** структура отлично, текст — терпимо ### 3. Замена на cyrillic_PP-OCRv5_mobile_rec **Результат:** разница ~1-2%, несущественна. - eslav: `LGD_ехtг;` (кириллица г) - cyrillic: `LGD_ехtr;` (латиница r) — чуть лучше - **Вывод:** обе мобильные модели, серверной русской не существует ### 4. PP-OCRv5_server_rec / PP-OCRv6 **Результат:** ❌ не поддерживают русский. - Server model: только CN/JP/EN - PP-OCRv6: 52 латинских языка - **Вывод:** русский — только mobile-версии ### 5. Локальный LLM-корректор (Qwen2.5-7B GGUF) **Результат:** +25% читаемости текста. ``` До: t - номер месяцаB дефолте, на который прогнозируются возвраты После: т — номер месяца в диапазоне между текущим сроком в дефолте и горизонтом взыскания ``` - ~4 tok/sec на CPU, ~20s/блок - **Вывод:** эффективен для пост-обработки ### 6. VLM-корректор (Qwen3.8 Max через OpenCode API) **Результат:** полное восстановление текста + авто inline-формулы. ``` До: ΣДсе, - дисконтированная сумма возвратов После: $\sum_t DCF_{i,t}$ — дисконтированная сумма возвратов ``` - ~10s/блок, Anthropic API `zen/go/v1/messages` - **Вывод:** лучшее качество, требует API-доступа ### 7. Docling (IBM Research) **Результат:** ❌ не поддерживает PaddleOCR как OCR-backend. - Поддерживает: EasyOCR, Tesseract, RapidOCR, Nemotron - **Вывод:** несовместим с нашим пайплайном ### 8. PaddleOCR-VL (ERNIE-4.5-0.3B) **Результат:** модель загружена (1.79 GB), ~15 мин/стр на CPU. - Одна VLM вместо ансамбля - Теоретически решает проблему русского (LM понимает контекст) - **Вывод:** правильный подход при GPU, нереализуем на CPU ### 9. Surya 2 (Datalab, 650M VLM) ⭐ **Результат:** лучший русский OCR из коробки — но медленно на CPU. - 95%+ точность русского текста без коррекции - Авто inline-формулы: `MRec_{it}` → `$MRec_{it}$` - ~300s/стр после CPU-оптимизаций (vs 140s PaddleOCR) - **Слабость:** таблицы требуют много токенов → таймауты на CPU - **Вывод:** лучший выбор по качеству, медленнее на CPU ### 10. VLM full-page (Qwen3.8 Max) для таблиц **Результат:** 118s на страницу с таблицей, качество отличное. - Таблица → pipe-Markdown: `| col1 | col2 |` - Формулы → `$...$` - Структура заголовков сохранена - **Вывод:** для табличных страниц — лучший вариант --- ## Итоговая архитектура ``` Входное изображение (JPEG/PNG/TIFF) │ ▼ src/image_prepare.py ← Stage 1: разрезание │ --slice / --slice-auto │ --border, --post-crop │ ▼ src/image_ocr.py ← Stage 2: OCR + Markdown │ --ocr-engine paddle|surya │ --llm, --vlm │ --force-ocr, --pause │ --result-one-document (ON по умолчанию) │ ├─ PaddleEngine / SuryaEngine (OCR) ├─ fix_ocr_errors (VaR, V^2) ├─ LlmCorrector (Qwen2.5-7B, local) ├─ VlmCorrector (Qwen3.8 Max, API) │ ▼ .md + .json (per page) + merged.md ``` ### По умолчанию включено | Функция | Статус | |---------|:------:| | `--resume` (пропуск JSON) | ON | | `--result-one-document` | ON | | `--pause 5` | ON | | `--post-crop` (Stage 1) | ON | ### Модули ``` src/ 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 ocr/ paddle_engine.py — PP-StructureV3 + кастом YAML (eslav) surya_engine.py — Surya 2 + CPU-оптимизации + health_check postprocess/ fixups.py — VaR, V^2 corrector.py — Corrector Protocol llm_corrector.py — Qwen2.5-7B локально vlm_corrector.py — Qwen3.8 Max API (Anthropic) markdown/generator.py — Markdown + валидация LaTeX latex/ json_to_latex.py — Единый JSON→LaTeX (Paddle + Surya) surya2html.py — Surya JSON → HTML + MathJax tex2html.py — TeX → HTML ``` --- ## Оптимизации Surya 2 для CPU | Параметр | До | После | Эффект | |----------|:---:|:---:|--------| | 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%** | ### Health-check + retry ``` llama-server не отвечает → logger.warning → перезапуск SuryaEngine → повторный health_check → OK / RuntimeError с инструкцией ``` --- ## Сравнение движков | Параметр | PaddleOCR | Surya 2 | VLM Qwen3.8 | |----------|:---:|:---:|:---:| | Архитектура | Ансамбль 5 моделей | Один VLM (650M) | Cloud VLM | | Русский текст | ~85% | 95%+ | 98%+ | | Формулы | PP-FormulaNet | VLM (отлично) | VLM (отлично) | | Таблицы | PP-TableMagic + bbox | ❌ CPU timeout | ✅ Pipe-Markdown | | Inline-формулы | Нет | `` тэги | `$...$` | | Скорость CPU | ~140s | ~300s | ~120s (API) | | Офлайн | ✅ | ✅ | ❌ | | Размер моделей | ~2.5 GB | ~1.5 GB | 0 (cloud) | --- ## Ключевые цифры (на CPU: 8 ядер, 32 GB RAM) | Этап | PaddleOCR | Surya 2 | VLM | |------|:---:|:---:|:---:| | OCR (одна страница) | 140s | 300s | 120s | | LLM-корректор | +5 min | не нужен | не нужен | | VLM-корректор | +10s/блок | не нужен | — | | JSON + MD сохранение | <1s | <1s | <1s | | Merge в один документ | <1s | <1s | <1s | | **Итого на страницу** | ~5 min | ~5 min | ~2 min | | **12 страниц (batch)** | ~28 min* | ~60 min | ~24 min | \* PaddleOCR с `--pause 5` --- ## Неиспользованные подходы 1. **EasyOCR** — WER 0.12 vs Paddle 0.056 2. **Tesseract** — нет GPU, хуже на русском 3. **RapidOCR** — легче, качество ниже 4. **Fine-tune eslav** — требует GPU + датасет --- ## Выводы 1. **PP-StructureV3** — надёжен для структуры и формул, русский текст требует LLM/VLM коррекции 2. **Surya 2** — лучший русский OCR из коробки, CPU-оптимизации дали -30% времени 3. **VLM Qwen3.8 Max** — решает таблицы там, где Surya падает, при приемлемой скорости 4. **Гибридный подход**: Surya для текста + VLM для таблиц = лучший баланс 5. **LLM/VLM коррекция** эффективна для PaddleOCR, не нужна для Surya 2 6. **CPU-ограничения** — основной фактор, GPU сделал бы Surya/PaddleOCR-VL идеальным выбором