Skip to content

TALIE-1651 new interfaces - #564

Open
NastyBoget wants to merge 10 commits into
future_masterfrom
TALIE-1651_new_interfaces
Open

NastyBoget wants to merge 10 commits into
future_masterfrom
TALIE-1651_new_interfaces

Conversation

@NastyBoget

@NastyBoget NastyBoget commented Aug 10, 2026 •

Copy link
Copy Markdown
Collaborator

В рамках ПР:

  • TALIE-1651 - добавлен интерфейс для абстрактного обработчика и основные структуры данных (но не все). В будущем планируется добавить структуры данных для аннотаций (жирность шрифта, размер и т.д.) и для хранения логических типов узлов (например, "глава", "статья" и т.п. для законов - вероятно, типизацию нужно будет делать настраиваемой в зависимости от типа структуры).
  • TALIE-1637 - написаны модули предобработки PDF (Binarizer, OrientationClassification, SkewCorrection), вспомогательные модули для начала обработки (MetadataExtractor, PagesCreator, PopplerRender) и ContentMimeDetector, обработчик DocxProcessor реализован не до конца (оставила для примера)

@NastyBoget NastyBoget self-assigned this Aug 10, 2026
@NastyBoget
NastyBoget force-pushed the TALIE-1651_new_interfaces branch 2 times, most recently from 14be5b0 to 01c0a9a Compare August 10, 2026 13:41
Comment thread requirements.txt Outdated
Comment thread dedoc_future/processors/parsing/office/docx/docx_processor.py
Comment thread dedoc_future/helpers/artifacts/download_models.py
Comment thread dedoc_future/helpers/formats.py
Comment thread dedoc_future/abstract/processor.py Outdated
structure: dict[AbstractNode, Iterable[AbstractNode]]


class AbstractProcessor(Generic[_Node, _Config, _DeployConfig], metaclass=ABCMeta):

@NastyBoget NastyBoget Aug 12, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: возможно, стоит еще подумать в сторону subprocessors для составных обработчиков, которые разбиваются на подзадачи с нестандартным входом/выходом для запуска этих подзадач на CPU/GPU (пример: OCR+постпроцессинг)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Описала в README тип обработчика configurator - составной обработчик

from dedoc_future.datamodel.nodes.page import PageNode, PageNodeWrapper


class PopplerRender(AbstractProcessor[PageNode, PdfBaseConfig, ImmutableBaseModel]):

@NastyBoget NastyBoget Aug 12, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

функционал dedoc.readers.pdf_reader.pdf_base_reader.PdfBaseReader._split_pdf2image (предполагается, что до этого в документ добавлены пустые page ноды с помощью PagesCreator)

впоследствии планируется добавить еще один способ рендеринга, предложенный Олегом

from dedoc_future.datamodel.nodes.file import FileNode


class ContentMimeDetector(AbstractProcessor[FileNode, ImmutableBaseModel, ImmutableBaseModel]):

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

функционал dedoc.utils.utils.get_file_mime_by_content - предполагается запускать этот обработчик тогда, когда основная обработка упала с ошибкой

from dedoc_future.datamodel.nodes.file import FileNode


class MetadataExtractor(AbstractProcessor[FileNode, ImmutableBaseModel, ImmutableBaseModel]):

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

функционал dedoc.metadata_extractors.concrete_metadata_extractors.base_metadata_extractor.BaseMetadataExtractor, предполагается использовать его в начале, чтобы впоследствии определять нужный парсер

@NastyBoget
NastyBoget requested a review from Tenebroso-M August 12, 2026 11:49

@Tenebroso-M Tenebroso-M left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Кажется не хватает примера какого-то обработчика для всего документа. И после примеров для узлов мне начало казаться, что это некоторая вырожденная сущность и все различие состоит в том, работаем мы с узлом-файлом, или узлами-страницами

Comment thread dedoc_future/abstract/processor.py Outdated
"""
Predicate function that returns whether the processor needs to be executed.
"""
return lambda document, node, config: True

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

возможно лучше сразу заявить метод, который принимает документ, узел и конфиг, а не прятать его за полем

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

определила метод can_process, который сразу принимает то, что ему нужно

Comment thread dedoc_future/abstract/processor.py Outdated
return lambda document, node, config: True

@abstractmethod
def process(self, document: TalismanDocument, nodes: Sequence[_Node], config: _Config) -> ProcessorResult[_Node]:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

не очень понимаю, будет ли удобен такой метод сразу для двух видов обработчиков. Вроде у нас принципиально есть те, которые ждут на вход только отдельные узлы (зачем им документ?) и те, которые ждут целый документ (нужно ли для них всегда перечислять все узлы документа, чтобы они могли измениться?)

@NastyBoget NastyBoget Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

согласна, сделала AbstractNodeProcessor и AbstractDocumentProcessor

Comment thread dedoc_future/abstract/processor.py Outdated
:param document: Document to process.
:param nodes: Nodes to process (only these nodes will be changed). The nodes should belong to the given document.
:param config: Processing configuration.
:return: Changed input nodes and new nodes with structure.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

почему не возвращать в качестве результата документ + (если нужно) те узлы которые изменились, удалились и добавились?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

сделала что-то похожее в AbstractNodeProcessor, он не работает с документом, только с узлами

Comment thread dedoc_future/abstract/processor.py Outdated
Process the input document and return an enriched document.

:param document: Document to process.
:param nodes: Nodes to process (only these nodes will be changed). The nodes should belong to the given document.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

а что с добавлением новых узлов, когда из картинки текст получаем, или что-то похожее?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Может быть, я не совсем поняла вопрос, но сейчас мы на вход можем принять ImageNode (например) и записать в результат добавляемую структуру с новыми узлами new_nodes

@NastyBoget
NastyBoget force-pushed the TALIE-1651_new_interfaces branch 3 times, most recently from 06b841e to 4a2dd77 Compare September 17, 2026 11:00
Comment thread dedoc_future/processors/parsing/pdf/preprocessing/orientation_classification.py Outdated
Comment thread dedoc_future/datamodel/markup/pdf_page.py
Comment thread dedoc_future/datamodel/metadata/page_object.py
@OligerMan

OligerMan commented Sep 18, 2026 •

Copy link
Copy Markdown
Collaborator

По поводу хранения картинок и рендеров страниц - нужно архитектурно предусмотреть 2 крайне важных вещи - отгрузку на диск и/или освобождение картинок когда не нужно, а также возможность передачи данных через shared memory. Возможно для этого нужно добавить хранение по ссылкам для штук типа PdfPageMarkup._orig_image, если мы хотим сделать передачу чисто примитивов типа ndarray(я в своём варианте именно так и делал, и рекомендую), либо передачу целых объектов со страницами.

По моим замерам получалось что если хранить все страницы с их рендерами в памяти, в том числе те, которые не нужны, то получится потребление памяти на 300 страничном документе 16+ гб вместо 6.5гб(в которые входят всякие библиотеки загруженные в память каждого процесса, типа numpy/torch), так что отсутствие выгрузки из памяти ненужных страниц быстро убъет обработчики по памяти

Shared memory необходим так как дефолтный метод для больших массивов данных, потому что дефолтная передача между процессами крайне неоптимальна, обычный путь это "pickle.dumps в байты, запись из пользовательской памяти в ядро, чтение из ядра в перекрывающийся буфер, оттуда в BytesIO, оттуда в bytes через getvalue, и наконец pickle.loads в новый массив", то есть 6 копирований. Если передавать через shared memory питоновские объекты, нужно их пиклить, это 4 копирования. Если передаём чисто ndarray и подобные объекты, а всё остальное оформлено как обёртка со ссылкой, и передается по обычному пути, то на основной кусок памяти в виде условного ndarray получаем 2 копирования.

Если вспомнить что для 300 страничного документа получается 10+гб данных, то получается что это копирование 60гб против 20гб, с добавками на выделение буферов на это всё - у меня на замерах разница в десятки секунд только на этом моменте(напоминаю что в итоге я дожал общее время исполнения примерно до минуты)

Comment thread dedoc_future/processors/parsing/pdf/render/poppler_render.py Outdated
Base automatically changed from develop to master September 22, 2026 10:14
@NastyBoget
NastyBoget force-pushed the TALIE-1651_new_interfaces branch from 3c64efb to 46b8b6b Compare September 22, 2026 12:30
@NastyBoget
NastyBoget changed the base branch from master to future_master September 22, 2026 12:31
@NastyBoget

NastyBoget commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator Author

По поводу хранения картинок и рендеров страниц - нужно архитектурно предусмотреть 2 крайне важных вещи - отгрузку на диск и/или освобождение картинок когда не нужно, а также возможность передачи данных через shared memory. Возможно для этого нужно добавить хранение по ссылкам для штук типа PdfPageMarkup._orig_image, если мы хотим сделать передачу чисто примитивов типа ndarray(я в своём варианте именно так и делал, и рекомендую), либо передачу целых объектов со страницами.

По моим замерам получалось что если хранить все страницы с их рендерами в памяти, в том числе те, которые не нужны, то получится потребление памяти на 300 страничном документе 16+ гб вместо 6.5гб(в которые входят всякие библиотеки загруженные в память каждого процесса, типа numpy/torch), так что отсутствие выгрузки из памяти ненужных страниц быстро убъет обработчики по памяти

Shared memory необходим так как дефолтный метод для больших массивов данных, потому что дефолтная передача между процессами крайне неоптимальна, обычный путь это "pickle.dumps в байты, запись из пользовательской памяти в ядро, чтение из ядра в перекрывающийся буфер, оттуда в BytesIO, оттуда в bytes через getvalue, и наконец pickle.loads в новый массив", то есть 6 копирований. Если передавать через shared memory питоновские объекты, нужно их пиклить, это 4 копирования. Если передаём чисто ndarray и подобные объекты, а всё остальное оформлено как обёртка со ссылкой, и передается по обычному пути, то на основной кусок памяти в виде условного ndarray получаем 2 копирования.

Если вспомнить что для 300 страничного документа получается 10+гб данных, то получается что это копирование 60гб против 20гб, с добавками на выделение буферов на это всё - у меня на замерах разница в десятки секунд только на этом моменте(напоминаю что в итоге я дожал общее время исполнения примерно до минуты)

Согласна с тем, что об этом нужно подумать заранее, но думаю, что стоит обсудить. Я бы предложила сделать некоторую обертку (хотя бы для node) в ссылку на shared memory и обратно в np.array. Непосредственно на обработчики это не должно никак повлиять, структуры данных затронет, но может быть сделать это отдельной задачей?

Upd: добавила комментарии в код и создала на это отдельную задачу.

Comment thread dedoc_future/README.md

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Конфигурирование обработчиков еще не продумано до конца (буду делать это в отдельной задаче https://jira.intra.ispras.ru/browse/TALIE-1707)

Основные моменты:

  • как (в последовательном случае) обработчики будут отрабатывать и передавать друг другу данные
  • на любом уровне вложенности обработки может встретиться составной обработчик (configurator), но такую функциональность не надо использовать без необходимости

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants