Spaces:
Sleeping
Sleeping
File size: 4,142 Bytes
86c402d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
"""
Базовый класс для всех стратегий чанкинга.
"""
from abc import ABC, abstractmethod
from ntr_fileparser import ParsedDocument
from ..models import Chunk, DocumentAsEntity, LinkerEntity
class ChunkingStrategy(ABC):
"""
Базовый абстрактный класс для всех стратегий чанкинга.
"""
@abstractmethod
def chunk(self, document: ParsedDocument, doc_entity: DocumentAsEntity | None = None) -> list[LinkerEntity]:
"""
Разбивает документ на чанки в соответствии со стратегией.
Args:
document: ParsedDocument для извлечения текста
doc_entity: Опциональная сущность документа для привязки чанков.
Если не указана, будет создана новая.
Returns:
list[LinkerEntity]: Список сущностей (документ, чанки, связи)
"""
raise NotImplementedError("Стратегия чанкинга должна реализовать метод chunk")
def dechunk(self, chunks: list[LinkerEntity], repository: 'EntityRepository' = None) -> str:
"""
Собирает документ из чанков и связей.
Базовая реализация сортирует чанки по chunk_index и объединяет их тексты,
сохраняя структуру параграфов и избегая дублирования текста.
Args:
chunks: Список отфильтрованных чанков в случайном порядке
repository: Репозиторий сущностей для получения дополнительной информации (может быть None)
Returns:
Восстановленный текст документа
"""
import re
# Проверяем, есть ли чанки для сборки
if not chunks:
return ""
# Отбираем только чанки
valid_chunks = [c for c in chunks if isinstance(c, Chunk)]
# Сортируем чанки по chunk_index
sorted_chunks = sorted(valid_chunks, key=lambda c: c.chunk_index or 0)
# Собираем текст документа с учетом структуры параграфов
result_text = ""
for chunk in sorted_chunks:
# Получаем текст чанка (предпочитаем text, а не in_search_text для избежания дублирования)
chunk_text = chunk.text if hasattr(chunk, 'text') and chunk.text else ""
# Добавляем текст чанка с сохранением структуры параграфов
if result_text and result_text[-1] != "\n" and chunk_text and chunk_text[0] != "\n":
result_text += " "
result_text += chunk_text
# Пост-обработка результата
# Заменяем множественные переносы строк на одиночные
result_text = re.sub(r'\n+', '\n', result_text)
# Заменяем множественные пробелы на одиночные
result_text = re.sub(r' +', ' ', result_text)
# Убираем пробелы перед переносами строк
result_text = re.sub(r' +\n', '\n', result_text)
# Убираем пробелы после переносов строк
result_text = re.sub(r'\n +', '\n', result_text)
# Убираем лишние переносы строк в начале и конце текста
result_text = result_text.strip()
return result_text |