Spaces:
Sleeping
Sleeping
File size: 5,954 Bytes
a85d6bf 5884230 a85d6bf 5884230 0067c9d bf93cc0 0067c9d 5884230 a85d6bf 0067c9d 5884230 0067c9d 5884230 a85d6bf 0067c9d 5884230 0067c9d 5884230 90e6b4c a85d6bf 90e6b4c aa38fcf a85d6bf aa38fcf a85d6bf aa38fcf a85d6bf aa38fcf a85d6bf 90e6b4c a85d6bf 90e6b4c a85d6bf aa38fcf a85d6bf 90e6b4c a85d6bf 90e6b4c 822ef8c 90e6b4c a85d6bf 90e6b4c 822ef8c 90e6b4c f85ad1c a85d6bf 5884230 a85d6bf c81fd8c bf93cc0 822ef8c c81fd8c bf93cc0 822ef8c a85d6bf 822ef8c 90e6b4c a85d6bf 90e6b4c a85d6bf 90e6b4c a85d6bf 822ef8c a85d6bf | 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 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | from llama_index.core.text_splitter import SentenceSplitter
from llama_index.core import Document
from config import CHUNK_SIZE, CHUNK_OVERLAP
from my_logging import log_message
def create_table_content(table_data):
"""Create formatted content from table data"""
doc_id = table_data.get('document_id', table_data.get('document', 'Неизвестно'))
table_num = table_data.get('table_number', 'Неизвестно')
table_title = table_data.get('table_title', 'Неизвестно')
section = table_data.get('section', 'Неизвестно')
# Header section
content = f"Таблица: {table_num}\n"
content += f"Название: {table_title}\n"
content += f"Документ: {doc_id}\n"
content += f"Раздел: {section}\n"
headers = table_data.get('headers', [])
if headers:
content += f"\nЗаголовки: {' | '.join(headers)}\n"
# Data section
if 'data' in table_data and isinstance(table_data['data'], list):
content += "\nДанные таблицы:\n"
for row_idx, row in enumerate(table_data['data'], start=1):
if isinstance(row, dict):
row_text = " | ".join([f"{k}: {v}" for k, v in row.items() if v])
content += f"Строка {row_idx}: {row_text}\n"
return content
def chunk_table_document(doc, chunk_size=None, chunk_overlap=None):
"""
Smart table chunking:
- Small tables: keep whole
- Large tables: split by row-blocks, preserve headers in each chunk
"""
if chunk_size is None:
chunk_size = CHUNK_SIZE
if chunk_overlap is None:
chunk_overlap = CHUNK_OVERLAP
table_num = doc.metadata.get('table_number', 'unknown')
doc_id = doc.metadata.get('document_id', 'unknown')
# Parse table structure
lines = doc.text.strip().split('\n')
table_header_lines = []
data_rows = []
in_data = False
for line in lines:
if line.startswith('Данные таблицы:'):
in_data = True
table_header_lines.append(line)
elif in_data and line.startswith('Строка'):
data_rows.append(line)
elif not in_data:
table_header_lines.append(line)
table_header = '\n'.join(table_header_lines) + '\n'
# If no data rows or small table, use standard splitting
if not data_rows or len(doc.text) < chunk_size * 1.5:
log_message(f" 📊 Таблица {table_num}: малая, без разбиения")
return [doc]
# Row-block chunking for large tables
log_message(f" 📋 Таблица {table_num}: {len(data_rows)} строк → row-block chunking")
header_size = len(table_header)
available_size = chunk_size - header_size - 100 # Reserve space
text_chunks = []
current_chunk_rows = []
current_size = 0
for row in data_rows:
row_size = len(row) + 1
# Check if adding this row exceeds limit
if current_size + row_size > available_size and current_chunk_rows:
# Create chunk with header + rows
chunk_text = table_header + '\n'.join(current_chunk_rows)
text_chunks.append(chunk_text)
# Overlap: keep last 2 rows for context continuity
overlap_count = min(2, len(current_chunk_rows))
current_chunk_rows = current_chunk_rows[-overlap_count:]
current_size = sum(len(r) + 1 for r in current_chunk_rows)
current_chunk_rows.append(row)
current_size += row_size
# Final chunk
if current_chunk_rows:
chunk_text = table_header + '\n'.join(current_chunk_rows)
text_chunks.append(chunk_text)
log_message(f" ✂️ Таблица {table_num} → {len(text_chunks)} чанков")
# Create Document objects
chunked_docs = []
for i, chunk_text in enumerate(text_chunks):
chunk_metadata = doc.metadata.copy()
chunk_metadata.update({
"chunk_id": i,
"total_chunks": len(text_chunks),
"chunk_size": len(chunk_text),
"is_chunked": True
})
chunked_doc = Document(
text=chunk_text,
metadata=chunk_metadata
)
chunked_docs.append(chunked_doc)
return chunked_docs
def table_to_document(table_data, document_id=None):
"""Convert table data to Document, with smart chunking if needed"""
if not isinstance(table_data, dict):
return []
doc_id = document_id or table_data.get('document_id') or table_data.get('document', 'Неизвестно')
table_num = table_data.get('table_number', 'Неизвестно')
table_title = table_data.get('table_title', 'Неизвестно')
section = table_data.get('section', 'Неизвестно')
table_rows = table_data.get('data', [])
if not table_rows:
log_message(f"⚠️ Таблица {table_num} пропущена: нет данных")
return []
content = create_table_content(table_data)
content_size = len(content)
base_doc = Document(
text=content,
metadata={
"type": "table",
"table_number": table_num,
"table_title": table_title,
"document_id": doc_id,
"section": section,
"section_id": section,
"total_rows": len(table_rows),
"content_size": content_size
}
)
# Apply smart chunking if too large
if content_size > CHUNK_SIZE:
log_message(f"📊 CHUNKING: Таблица {table_num} | {content_size} > {CHUNK_SIZE}")
return chunk_table_document(base_doc)
else:
log_message(f"✓ Таблица {table_num} добавлена целиком ({content_size} символов)")
return [base_doc] |