Зачем
Поток PDF неоднороден. Часть документов электронные, и текст лежит в слое. Часть — сканы. Часть — картинки с текстом поверх. Часть — экспорт из OCR-программ, где слой выглядит электронным, но доверять ему нельзя. Распознавание стоит времени GPU, а чтение слоя почти бесплатно. Поэтому первым шагом идёт классификация страницы, и распознавание вызывается только там, где слоя нет или он ненадёжен.
Главное требование — не пропустить страницу с плохим слоем как электронную. Лишний раз отправить страницу в OCR дешевле, чем молча выдать неверный текст.
Как устроено
Классификатор — детерминированные правила, а не обученная модель. Никаких Surya, Qwen и Docling на этом шаге.
- Признаки. PyMuPDF достаёт из PDF текст, шрифты, координаты, размещения картинок, векторы и метаданные. NumPy считает «чернила» по рендеру страницы в 96 DPI.
- Тип страницы. Правила проверяются по порядку, срабатывает первое: пустая страница → нет текста → растровая подложка → повреждённый текст → гибрид → невидимый текст → электронная.
- Маршрут. Тип плюс признаки OCR-программы в метаданных дают один из маршрутов: «только слой», «слой со сверкой», «распознавание», «пропустить». Каждое решение сопровождается списком причин.
Ключевые признаки
| Признак | Что ловит | Порог |
|---|---|---|
| Доля сломанных символов (U+FFFD, служебные категории) | слой с битой кодировкой | > 1.5 % → слою не верить |
| Доля дублей (тот же текст в тех же координатах) | двойной слой, «печать поверх» | > 15 % |
| Доля текста за краем страницы | спрятанный текст | > 10 % |
| Доля символов мельче 3 pt | служебный мусор в слое | > 30 % |
| Доля невидимого текста (режим 3, прозрачность) | слой OCR-программы под картинкой | > 70 % → распознавание |
| Изменение рендера без текстового слоя | текст есть в слое, но его не видно | < 1.5 % чернил |
| Покрытие страницы картинками | скан как подложка | ≥ 70 % |
| Чернила в картинках вне текстового слоя | вставки, текст которых есть только в растре | > 8 % → гибрид |
| Доля «ж» и «й» среди кириллицы | мусорная раскладка вместо русского текста | грубая проверка |
Самый полезный признак — контрафактивный рендер. Страница рисуется второй раз без текстового слоя, и считается, сколько чернил исчезло. Если почти ничего, слой невидим: он белый, скрыт или перекрыт картинкой. Так ловятся сканы с подложенным невидимым слоем от OCR-программы, где сам текст может быть любым.
Проверка
| Набор | Страниц | Электронных | В распознавание | Ложных «электронных» |
|---|---|---|---|---|
| Синтетика (20 PDF) | 24 | 12 | 12 | 0 |
| Отложенные публичные PDF (10 файлов) | 14 | 1 | 13 | 0 |
Отложенные PDF — сканы писем и договоров, скриншоты интерфейсов, расписания, страницы с ценами внутри картинок. Маршрут для каждой страницы независимо проверен глазами и Qwen. На этом наборе строгая политика осторожничает: 4 страницы, которые можно было читать из слоя, она отправила в распознавание. Ни одной ошибки в опасную сторону нет.
На контрольном корпусе из 42 страниц 22 обошлись без распознавания. Классификация всего корпуса занимает 1.4 с на CPU.
Нагрузочный прогон
Полный прогон строгой политики на 432 реальных PDF (2160 страниц): 428 страниц признаны электронными, 1727 отправлены в распознавание, 5 пустых пропущены, 9 файлов не открылись. Это проверка на падения и распределение маршрутов, а не точности: разметки у этих файлов нет.
Извлечение из слоя
Для электронных страниц из слоя собираются абзацы, порядок чтения (XY-cut), таблицы (поиск PyMuPDF плюс признак сетки без линий) и роли блоков. В распознавание уходят только области, которых нет в слое: крупные картинки и вставки с чернилами вне текста. Перед отправкой картинка уменьшается до 2048 px по ширине.
На маршруте сверки числа сравниваются точно, слова — по покрытию. Расхождение попадает в замечания к странице. На выходе — JSON, markdown и HTML, где у каждого блока указан источник: слой, распознавание страницы или распознавание области.
Насколько итоговый текст лучше, чем распознавание всей страницы, показано в статье про сверку с Surya и LLM-судьёй: 0.29 % ошибок в символах против 5.77 %.
Ограничения
- Метаданные «создано в Excel» — только вспомогательный сигнал, а не разрешение читать слой.
- Порядок чтения и разметка страницы оцениваются отдельно от выбора маршрута.
- Пороги подобраны на контрольном корпусе, отложенная проверка пока маленькая.