MrSimple07 commited on
Commit
451cdc6
·
1 Parent(s): f9e7c0c

added the load_table_data function

Browse files
Files changed (2) hide show
  1. documents_prep.py +138 -56
  2. table_prep.py +85 -94
documents_prep.py CHANGED
@@ -354,28 +354,43 @@ def load_image_data(repo_id, hf_token, image_data_dir):
354
  df = pd.read_csv(local_path)
355
  log_message(f"Загружено {len(df)} записей изображений из файла {file_path}")
356
 
357
- # Обработка с правильными названиями колонок
358
  for _, row in df.iterrows():
359
  section_value = row.get('Раздел документа', 'Неизвестно')
 
 
 
 
 
360
 
361
- content = f"Изображение: {row.get('№ Изображения', 'Неизвестно')}\n"
362
- content += f"Название: {row.get('Название изображения', 'Неизвестно')}\n"
363
- content += f"Описание: {row.get('Описание изображение', 'Неизвестно')}\n" # Опечатка в названии колонки
364
- content += f"Документ: {row.get('Обозначение документа', 'Неизвестно')}\n"
365
  content += f"Раздел: {section_value}\n"
366
- content += f"Файл: {row.get('Файл изображения', 'Неизвестно')}\n"
 
 
 
 
 
 
 
 
 
 
367
 
368
  doc = Document(
369
  text=content,
370
  metadata={
371
  "type": "image",
372
- "image_number": str(row.get('№ Изображения', 'unknown')),
373
- "image_title": str(row.get('Название изображения', 'unknown')),
374
- "image_description": str(row.get('Описание изображение', 'unknown')),
375
- "document_id": str(row.get('Обозначение документа', 'unknown')),
376
- "file_path": str(row.get('Файл изображения', 'unknown')),
377
- "section": str(section_value),
378
- "section_id": str(section_value)
 
379
  }
380
  )
381
  image_documents.append(doc)
@@ -392,53 +407,120 @@ def load_image_data(repo_id, hf_token, image_data_dir):
392
  return []
393
 
394
  def load_table_data(repo_id, hf_token, table_data_dir):
395
- files = list_repo_files(repo_id=repo_id, repo_type="dataset", token=hf_token)
396
- table_files = [f for f in files if f.startswith(table_data_dir) and f.endswith('.json')]
397
-
398
- table_documents = []
399
 
400
- for file_path in table_files:
401
- try:
402
- local_path = hf_hub_download(
403
- repo_id=repo_id,
404
- filename=file_path,
405
- local_dir='',
406
- repo_type="dataset",
407
- token=hf_token
408
- )
409
-
410
- with open(local_path, 'r', encoding='utf-8') as f:
411
- table_data = json.load(f)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
412
 
413
- if isinstance(table_data, dict):
414
- document_id = (
415
- table_data.get('document_id') or
416
- table_data.get('document') or
417
- table_data.get('Обозначение документа') or
418
- 'unknown'
419
- )
420
-
421
- if 'НП-104-18' in str(document_id):
422
- document_id = 'ГОСТ 59023'
423
 
424
- if 'sheets' in table_data:
425
- for sheet in table_data['sheets']:
426
- sheet['document_id'] = document_id
427
- sheet['document'] = document_id
428
- docs_list = table_to_document(sheet, document_id=document_id)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
429
  table_documents.extend(docs_list)
430
- else:
431
- table_data['document_id'] = document_id
432
- table_data['document'] = document_id
433
- docs_list = table_to_document(table_data, document_id=document_id)
434
- table_documents.extend(docs_list)
435
-
436
- except Exception as e:
437
- log_message(f"Ошибка {file_path}: {str(e)}")
438
- continue
439
-
440
- return table_documents
441
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
442
 
443
  def load_csv_chunks(repo_id, hf_token, chunks_filename, download_dir):
444
  log_message("Загружаю данные чанков из CSV")
 
354
  df = pd.read_csv(local_path)
355
  log_message(f"Загружено {len(df)} записей изображений из файла {file_path}")
356
 
 
357
  for _, row in df.iterrows():
358
  section_value = row.get('Раздел документа', 'Неизвестно')
359
+ image_num = str(row.get('№ Изображения', 'Неизвестно'))
360
+ image_title = str(row.get('Название изображения', 'Неизвестно'))
361
+ image_desc = str(row.get('Описание изображение', 'Неизвестно'))
362
+ doc_id = str(row.get('Обозначение документа', 'Неизвестно'))
363
+ file_name = str(row.get('Файл изображения', 'Неизвестно'))
364
 
365
+ # FIXED: Create structured, searchable content
366
+ content = f"=== ИЗОБРАЖЕНИЕ ===\n"
367
+ content += f"Документ: {doc_id}\n"
368
+ content += f"Стандарт: {doc_id}\n"
369
  content += f"Раздел: {section_value}\n"
370
+ content += f"Изображение: {image_num}\n"
371
+ content += f"Название: {image_title}\n"
372
+ content += f"Описание: {image_desc}\n"
373
+ content += f"Файл: {file_name}\n"
374
+ content += f"Уникальный ID: {doc_id} | {section_value} | {image_num}\n"
375
+ content += f"===================\n\n"
376
+
377
+ # Add contextual information for better retrieval
378
+ content += f"Это изображение {image_num} из документа {doc_id}, "
379
+ content += f"расположенное в разделе '{section_value}'. "
380
+ content += f"{image_title}. {image_desc}"
381
 
382
  doc = Document(
383
  text=content,
384
  metadata={
385
  "type": "image",
386
+ "image_number": image_num,
387
+ "image_title": image_title,
388
+ "image_description": image_desc,
389
+ "document_id": doc_id,
390
+ "file_path": file_name,
391
+ "section": section_value,
392
+ "section_id": section_value,
393
+ "full_image_id": f"{doc_id} | {section_value} | {image_num}"
394
  }
395
  )
396
  image_documents.append(doc)
 
407
  return []
408
 
409
  def load_table_data(repo_id, hf_token, table_data_dir):
410
+ """Load and process table data with sheet-level document_id extraction"""
411
+ log_message("=" * 60)
412
+ log_message("НАЧАЛО ЗАГРУЗКИ ТАБЛИЧНЫХ ДАННЫХ")
413
+ log_message("=" * 60)
414
 
415
+ try:
416
+ from huggingface_hub import hf_hub_download, list_repo_files
417
+ import json
418
+ from collections import defaultdict
419
+
420
+ files = list_repo_files(repo_id=repo_id, repo_type="dataset", token=hf_token)
421
+ table_files = [f for f in files if f.startswith(table_data_dir) and f.endswith('.json')]
422
+
423
+ log_message(f"Найдено {len(table_files)} JSON файлов с таблицами")
424
+
425
+ table_documents = []
426
+ stats = {
427
+ 'total_tables': 0,
428
+ 'total_size': 0,
429
+ 'by_document': defaultdict(lambda: {'count': 0, 'size': 0})
430
+ }
431
+
432
+ for file_path in table_files:
433
+ try:
434
+ local_path = hf_hub_download(
435
+ repo_id=repo_id,
436
+ filename=file_path,
437
+ local_dir='',
438
+ repo_type="dataset",
439
+ token=hf_token
440
+ )
441
 
442
+ log_message(f"\nОбработка файла: {file_path}")
443
+
444
+ with open(local_path, 'r', encoding='utf-8') as f:
445
+ table_data = json.load(f)
 
 
 
 
 
 
446
 
447
+ if isinstance(table_data, dict):
448
+ # Extract file-level document_id
449
+ file_level_doc_id = (
450
+ table_data.get('document_id') or
451
+ table_data.get('document') or
452
+ table_data.get('Обозначение документа') or
453
+ 'unknown'
454
+ )
455
+
456
+ # Handle multiple sheets
457
+ if 'sheets' in table_data:
458
+ sorted_sheets = sorted(
459
+ table_data['sheets'],
460
+ key=lambda sheet: sheet.get('table_number', '')
461
+ )
462
+
463
+ for sheet in sorted_sheets:
464
+ # CRITICAL FIX: Use sheet-level document_id if available
465
+ sheet_doc_id = (
466
+ sheet.get('document_id') or
467
+ sheet.get('document') or
468
+ sheet.get('Обозначение документа') or
469
+ file_level_doc_id
470
+ )
471
+
472
+ log_message(f" Sheet doc_id: {sheet_doc_id} (file: {file_level_doc_id})")
473
+
474
+ # Pass sheet's own document_id
475
+ docs_list = table_to_document(sheet, document_id=sheet_doc_id)
476
+ table_documents.extend(docs_list)
477
+
478
+ for doc in docs_list:
479
+ stats['total_tables'] += 1
480
+ size = doc.metadata.get('content_size', 0)
481
+ stats['total_size'] += size
482
+ stats['by_document'][sheet_doc_id]['count'] += 1
483
+ stats['by_document'][sheet_doc_id]['size'] += size
484
+ else:
485
+ # Single table
486
+ docs_list = table_to_document(table_data, document_id=file_level_doc_id)
487
  table_documents.extend(docs_list)
488
+
489
+ for doc in docs_list:
490
+ stats['total_tables'] += 1
491
+ size = doc.metadata.get('content_size', 0)
492
+ stats['total_size'] += size
493
+ stats['by_document'][file_level_doc_id]['count'] += 1
494
+ stats['by_document'][file_level_doc_id]['size'] += size
495
+
496
+ except Exception as e:
497
+ log_message(f"❌ ОШИБКА файла {file_path}: {str(e)}")
498
+ import traceback
499
+ log_message(f"Traceback: {traceback.format_exc()}")
500
+ continue
501
+
502
+ # Log summary
503
+ log_message("\n" + "=" * 60)
504
+ log_message("СТАТИСТИКА ПО ТАБЛИЦАМ")
505
+ log_message("=" * 60)
506
+ log_message(f"Всего таблиц: {stats['total_tables']}")
507
+ log_message(f"Общий размер: {stats['total_size']:,} символов")
508
+ if stats['total_tables'] > 0:
509
+ log_message(f"Средний размер: {stats['total_size'] // stats['total_tables']:,} символов")
510
+
511
+ log_message("\nПо документам:")
512
+ for doc_id, doc_stats in sorted(stats['by_document'].items()):
513
+ log_message(f" • {doc_id}: {doc_stats['count']} таблиц, {doc_stats['size']:,} символов")
514
+
515
+ log_message("=" * 60)
516
+
517
+ return table_documents
518
+
519
+ except Exception as e:
520
+ log_message(f"❌ КРИТИЧЕСКАЯ ОШИБКА: {str(e)}")
521
+ import traceback
522
+ log_message(f"Traceback: {traceback.format_exc()}")
523
+ return []
524
 
525
  def load_csv_chunks(repo_id, hf_token, chunks_filename, download_dir):
526
  log_message("Загружаю данные чанков из CSV")
table_prep.py CHANGED
@@ -3,7 +3,23 @@ from llama_index.core import Document
3
  from config import CHUNK_SIZE, CHUNK_OVERLAP
4
  from my_logging import log_message
5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  def create_table_content(table_data):
 
7
  doc_id = (
8
  table_data.get('document_id') or
9
  table_data.get('document') or
@@ -18,80 +34,46 @@ def create_table_content(table_data):
18
  'Неизвестно'
19
  )
20
 
21
- content = f"ГОСТ {doc_id} Стандарт {doc_id}\n"
 
 
 
 
22
  content += f"Документ: {doc_id}\n"
23
- content += f"Таблица {table_num}\n"
24
- content += f"Название: {table_title}\n"
25
  content += f"Раздел: {section}\n"
26
-
27
- if 'Приложени' in section:
28
- content += f"Приложение таблица {table_num}\n"
 
29
 
30
  headers = table_data.get('headers', [])
31
  if headers:
32
- content += f"\nКолонки: {' | '.join(str(h) for h in headers)}\n"
33
 
 
34
  if 'data' in table_data and isinstance(table_data['data'], list):
35
- content += "\nДанные:\n"
36
  for row_idx, row in enumerate(table_data['data'], start=1):
37
  if isinstance(row, dict):
38
- for k, v in row.items():
39
- if v and str(v).strip():
40
- content += f"{k} {v} "
41
- content += "\n"
 
 
 
 
 
 
 
42
  elif isinstance(row, list):
43
- content += " ".join([str(v) for v in row if v]) + "\n"
 
44
 
45
- return content
46
 
47
 
48
- def table_to_document(table_data, document_id=None):
49
- if not isinstance(table_data, dict):
50
- return []
51
-
52
- doc_id = (
53
- document_id or
54
- table_data.get('document_id') or
55
- table_data.get('document') or
56
- table_data.get('Обозначение документа') or
57
- 'Неизвестно'
58
- )
59
-
60
- if 'НП-104-18' in str(table_data.get('document', '')):
61
- doc_id = 'ГОСТ 59023'
62
-
63
- table_num = table_data.get('table_number', 'Неизвестно')
64
- table_title = table_data.get('table_title', 'Неизвестно')
65
- section = (
66
- table_data.get('section') or
67
- table_data.get('Раздел документа') or
68
- 'Неизвестно'
69
- )
70
-
71
- table_rows = table_data.get('data', [])
72
- if not table_rows:
73
- return []
74
-
75
- content = create_table_content(table_data)
76
-
77
- base_doc = Document(
78
- text=content,
79
- metadata={
80
- "type": "table",
81
- "table_number": str(table_num),
82
- "table_title": str(table_title),
83
- "document_id": str(doc_id),
84
- "section": str(section),
85
- "total_rows": len(table_rows),
86
- "content_size": len(content)
87
- }
88
- )
89
-
90
- if len(content) > CHUNK_SIZE:
91
- return chunk_table_document(base_doc)
92
- else:
93
- return [base_doc]
94
-
95
  def chunk_table_document(doc, chunk_size=None, chunk_overlap=None):
96
  if chunk_size is None:
97
  chunk_size = CHUNK_SIZE
@@ -100,16 +82,21 @@ def chunk_table_document(doc, chunk_size=None, chunk_overlap=None):
100
 
101
  table_num = doc.metadata.get('table_number', 'unknown')
102
  doc_id = doc.metadata.get('document_id', 'unknown')
 
 
 
 
 
103
 
104
- # Parse table structure
105
  lines = doc.text.strip().split('\n')
106
 
 
107
  table_header_lines = []
108
  data_rows = []
109
  in_data = False
110
 
111
  for line in lines:
112
- if line.startswith('Данные таблицы:'):
113
  in_data = True
114
  table_header_lines.append(line)
115
  elif in_data and line.startswith('Строка'):
@@ -119,16 +106,14 @@ def chunk_table_document(doc, chunk_size=None, chunk_overlap=None):
119
 
120
  table_header = '\n'.join(table_header_lines) + '\n'
121
 
122
- # If no data rows or small table, use standard splitting
123
  if not data_rows or len(doc.text) < chunk_size * 1.5:
124
- log_message(f" 📊 Таблица {table_num}: малая, без разбиения")
125
  return [doc]
126
 
127
- # Row-block chunking for large tables
128
- log_message(f" 📋 Таблица {table_num}: {len(data_rows)} строк → row-block chunking")
129
 
130
  header_size = len(table_header)
131
- available_size = chunk_size - header_size - 100 # Reserve space
132
 
133
  text_chunks = []
134
  current_chunk_rows = []
@@ -137,28 +122,25 @@ def chunk_table_document(doc, chunk_size=None, chunk_overlap=None):
137
  for row in data_rows:
138
  row_size = len(row) + 1
139
 
140
- # Check if adding this row exceeds limit
141
  if current_size + row_size > available_size and current_chunk_rows:
142
- # Create chunk with header + rows
143
  chunk_text = table_header + '\n'.join(current_chunk_rows)
144
  text_chunks.append(chunk_text)
145
 
146
- # Overlap: keep last 2 rows for context continuity
147
- overlap_count = min(2, len(current_chunk_rows))
148
  current_chunk_rows = current_chunk_rows[-overlap_count:]
149
  current_size = sum(len(r) + 1 for r in current_chunk_rows)
150
 
151
  current_chunk_rows.append(row)
152
  current_size += row_size
153
 
154
- # Final chunk
155
  if current_chunk_rows:
156
  chunk_text = table_header + '\n'.join(current_chunk_rows)
157
  text_chunks.append(chunk_text)
158
 
159
- log_message(f" ✂️ Таблица {table_num} → {len(text_chunks)} чанков")
160
 
161
- # Create Document objects
162
  chunked_docs = []
163
  for i, chunk_text in enumerate(text_chunks):
164
  chunk_metadata = doc.metadata.copy()
@@ -166,7 +148,12 @@ def chunk_table_document(doc, chunk_size=None, chunk_overlap=None):
166
  "chunk_id": i,
167
  "total_chunks": len(text_chunks),
168
  "chunk_size": len(chunk_text),
169
- "is_chunked": True
 
 
 
 
 
170
  })
171
 
172
  chunked_doc = Document(
@@ -177,49 +164,53 @@ def chunk_table_document(doc, chunk_size=None, chunk_overlap=None):
177
 
178
  return chunked_docs
179
 
 
180
  def table_to_document(table_data, document_id=None):
 
181
  if not isinstance(table_data, dict):
182
  return []
183
 
184
- doc_id = (
185
- document_id or
186
  table_data.get('document_id') or
187
  table_data.get('document') or
188
- table_data.get('Обозначение документа') or
189
- 'Неизвестно'
190
  )
191
 
192
- if 'НП-104-18' in str(table_data.get('document', '')):
193
- doc_id = 'ГОСТ 59023'
194
 
195
  table_num = table_data.get('table_number', 'Неизвестн��')
196
  table_title = table_data.get('table_title', 'Неизвестно')
197
- section = (
198
- table_data.get('section') or
199
- table_data.get('Раздел документа') or
200
- 'Неизвестно'
201
- )
202
 
203
  table_rows = table_data.get('data', [])
204
  if not table_rows:
 
205
  return []
206
 
207
- content = create_table_content(table_data)
 
208
 
209
  base_doc = Document(
210
  text=content,
211
  metadata={
212
  "type": "table",
213
- "table_number": str(table_num),
214
- "table_title": str(table_title),
215
- "document_id": str(doc_id),
216
- "section": str(section),
 
 
217
  "total_rows": len(table_rows),
218
- "content_size": len(content)
 
219
  }
220
  )
221
 
222
- if len(content) > CHUNK_SIZE:
 
223
  return chunk_table_document(base_doc)
224
  else:
 
225
  return [base_doc]
 
3
  from config import CHUNK_SIZE, CHUNK_OVERLAP
4
  from my_logging import log_message
5
 
6
+ def normalize_table_number(table_num, section):
7
+ """Normalize table numbers for consistent retrieval"""
8
+ if not table_num or table_num == 'Неизвестно':
9
+ return 'Неизвестно'
10
+
11
+ # Clean up common prefixes
12
+ tn = str(table_num).replace('Таблица', '').replace('№', '').strip()
13
+
14
+ # Add section context for appendix tables
15
+ if section and ('Приложение' in str(section) or 'приложение' in str(section).lower()):
16
+ return f"№{tn} ({section})"
17
+
18
+ return f"№{tn}"
19
+
20
+
21
  def create_table_content(table_data):
22
+ """Create formatted content with strong contextual anchors"""
23
  doc_id = (
24
  table_data.get('document_id') or
25
  table_data.get('document') or
 
34
  'Неизвестно'
35
  )
36
 
37
+ # Normalize table number
38
+ normalized_num = normalize_table_number(table_num, section)
39
+
40
+ # STRONG ANCHOR: Unique identification for semantic search
41
+ content = f"=== ИСТОЧНИК ДАННЫХ ===\n"
42
  content += f"Документ: {doc_id}\n"
43
+ content += f"Стандарт: {doc_id}\n"
 
44
  content += f"Раздел: {section}\n"
45
+ content += f"Таблица: {normalized_num}\n"
46
+ content += f"Полное название: {table_title}\n"
47
+ content += f"Уникальный ID: {doc_id} | {section} | {normalized_num}\n"
48
+ content += f"======================\n\n"
49
 
50
  headers = table_data.get('headers', [])
51
  if headers:
52
+ content += f"Заголовки колонок: {' | '.join(str(h) for h in headers)}\n\n"
53
 
54
+ # Structured row data with JSON-like clarity
55
  if 'data' in table_data and isinstance(table_data['data'], list):
56
+ content += "Содержимое таблицы:\n"
57
  for row_idx, row in enumerate(table_data['data'], start=1):
58
  if isinstance(row, dict):
59
+ # Add row identifier if available
60
+ row_id = row.get('Условное обозначение сварного соединения',
61
+ row.get('Обозначение', ''))
62
+ if row_id:
63
+ content += f"Строка {row_idx} ({row_id}): "
64
+ else:
65
+ content += f"Строка {row_idx}: "
66
+
67
+ # Structured key-value pairs for better semantic understanding
68
+ row_parts = [f"{k}={v}" for k, v in row.items() if v and str(v).strip()]
69
+ content += " | ".join(row_parts) + "\n"
70
  elif isinstance(row, list):
71
+ content += f"Строка {row_idx}: "
72
+ content += " | ".join([str(v) for v in row if v and str(v).strip()]) + "\n"
73
 
74
+ return content, normalized_num
75
 
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  def chunk_table_document(doc, chunk_size=None, chunk_overlap=None):
78
  if chunk_size is None:
79
  chunk_size = CHUNK_SIZE
 
82
 
83
  table_num = doc.metadata.get('table_number', 'unknown')
84
  doc_id = doc.metadata.get('document_id', 'unknown')
85
+ section = doc.metadata.get('section', 'Неизвестно')
86
+ table_title = doc.metadata.get('table_title', 'Неизвестно')
87
+
88
+ # Create unique anchor for this table
89
+ full_table_id = f"{doc_id} | {section} | {table_num}"
90
 
 
91
  lines = doc.text.strip().split('\n')
92
 
93
+ # Extract header (everything before data rows)
94
  table_header_lines = []
95
  data_rows = []
96
  in_data = False
97
 
98
  for line in lines:
99
+ if line.startswith('Содержимое таблицы:'):
100
  in_data = True
101
  table_header_lines.append(line)
102
  elif in_data and line.startswith('Строка'):
 
106
 
107
  table_header = '\n'.join(table_header_lines) + '\n'
108
 
 
109
  if not data_rows or len(doc.text) < chunk_size * 1.5:
110
+ log_message(f" 📊 {full_table_id}: малая таблица, без разбиения")
111
  return [doc]
112
 
113
+ log_message(f" 📋 {full_table_id}: {len(data_rows)} строк chunking")
 
114
 
115
  header_size = len(table_header)
116
+ available_size = chunk_size - header_size - 200 # More reserve for anchor
117
 
118
  text_chunks = []
119
  current_chunk_rows = []
 
122
  for row in data_rows:
123
  row_size = len(row) + 1
124
 
 
125
  if current_size + row_size > available_size and current_chunk_rows:
 
126
  chunk_text = table_header + '\n'.join(current_chunk_rows)
127
  text_chunks.append(chunk_text)
128
 
129
+ # Overlap: keep last 3 rows for better context
130
+ overlap_count = min(3, len(current_chunk_rows))
131
  current_chunk_rows = current_chunk_rows[-overlap_count:]
132
  current_size = sum(len(r) + 1 for r in current_chunk_rows)
133
 
134
  current_chunk_rows.append(row)
135
  current_size += row_size
136
 
 
137
  if current_chunk_rows:
138
  chunk_text = table_header + '\n'.join(current_chunk_rows)
139
  text_chunks.append(chunk_text)
140
 
141
+ log_message(f" ✂️ {full_table_id} → {len(text_chunks)} чанков")
142
 
143
+ # Create chunks with strong anchors
144
  chunked_docs = []
145
  for i, chunk_text in enumerate(text_chunks):
146
  chunk_metadata = doc.metadata.copy()
 
148
  "chunk_id": i,
149
  "total_chunks": len(text_chunks),
150
  "chunk_size": len(chunk_text),
151
+ "is_chunked": True,
152
+ # CRITICAL: Add unique identifiers
153
+ "full_table_id": full_table_id,
154
+ "chunk_anchor": f"{full_table_id} | chunk_{i+1}/{len(text_chunks)}",
155
+ "document_section": section,
156
+ "table_number_normalized": table_num
157
  })
158
 
159
  chunked_doc = Document(
 
164
 
165
  return chunked_docs
166
 
167
+
168
  def table_to_document(table_data, document_id=None):
169
+ """Convert table data to Document with proper metadata"""
170
  if not isinstance(table_data, dict):
171
  return []
172
 
173
+ # FIXED: Extract sheet-level document_id first
174
+ sheet_doc_id = (
175
  table_data.get('document_id') or
176
  table_data.get('document') or
177
+ table_data.get('Обозначение документа')
 
178
  )
179
 
180
+ # Use sheet doc_id if available, otherwise use passed document_id
181
+ doc_id = sheet_doc_id or document_id or 'Неизвестно'
182
 
183
  table_num = table_data.get('table_number', 'Неизвестн��')
184
  table_title = table_data.get('table_title', 'Неизвестно')
185
+ section = table_data.get('section', table_data.get('Раздел документа', 'Неизвестно'))
 
 
 
 
186
 
187
  table_rows = table_data.get('data', [])
188
  if not table_rows:
189
+ log_message(f"⚠️ Таблица {table_num} ({doc_id}) пропущена: нет данных")
190
  return []
191
 
192
+ content, normalized_num = create_table_content(table_data)
193
+ content_size = len(content)
194
 
195
  base_doc = Document(
196
  text=content,
197
  metadata={
198
  "type": "table",
199
+ "table_number": table_num,
200
+ "table_number_normalized": normalized_num,
201
+ "table_title": table_title,
202
+ "document_id": doc_id,
203
+ "section": section,
204
+ "section_id": section,
205
  "total_rows": len(table_rows),
206
+ "content_size": content_size,
207
+ "full_table_id": f"{doc_id} | {section} | {normalized_num}"
208
  }
209
  )
210
 
211
+ if content_size > CHUNK_SIZE:
212
+ log_message(f"📊 CHUNKING: {doc_id} | {normalized_num} | {content_size} > {CHUNK_SIZE}")
213
  return chunk_table_document(base_doc)
214
  else:
215
+ log_message(f"✓ {doc_id} | {normalized_num} ({content_size} символов)")
216
  return [base_doc]