MrSimple07 commited on
Commit
db48355
·
1 Parent(s): af31260

new info about uploaded files + new main_utils + ui buttons

Browse files
Files changed (4) hide show
  1. app.py +117 -117
  2. converters/converter.py +103 -14
  3. documents_prep.py +23 -2
  4. utils.py → main_utils.py +0 -0
app.py CHANGED
@@ -2,7 +2,7 @@ import gradio as gr
2
  import os
3
  from llama_index.core import Settings
4
  from documents_prep import load_json_documents, load_table_documents, load_image_documents
5
- from utils import get_llm_model, get_embedding_model, get_reranker_model, answer_question
6
  from my_logging import log_message
7
  from index_retriever import create_vector_index, create_query_engine
8
  import sys
@@ -10,116 +10,37 @@ from config import (
10
  HF_REPO_ID, HF_TOKEN, DOWNLOAD_DIR, CHUNKS_FILENAME,
11
  JSON_FILES_DIR, TABLE_DATA_DIR, IMAGE_DATA_DIR, DEFAULT_MODEL, AVAILABLE_MODELS
12
  )
13
- from converters.converter import convert_single_excel_to_json, convert_single_excel_to_csv
 
14
 
15
-
16
- def merge_table_chunks(chunk_info):
17
- merged = {}
18
 
19
- for chunk in chunk_info:
20
- doc_type = chunk.get('type', 'text')
21
- doc_id = chunk.get('document_id', 'unknown')
22
 
23
- if doc_type == 'table' or doc_type == 'table_row':
24
- table_num = chunk.get('table_number', '')
25
- key = f"{doc_id}_{table_num}"
26
-
27
- if key not in merged:
28
- merged[key] = {
29
- 'document_id': doc_id,
30
- 'type': 'table',
31
- 'table_number': table_num,
32
- 'section_id': chunk.get('section_id', 'unknown'),
33
- 'chunk_text': chunk.get('chunk_text', '')
34
- }
35
- else:
36
- merged[key]['chunk_text'] += '\n' + chunk.get('chunk_text', '')
37
- else:
38
- unique_key = f"{doc_id}_{chunk.get('section_id', '')}_{chunk.get('chunk_id', 0)}"
39
- merged[unique_key] = chunk
40
-
41
- return list(merged.values())
42
-
43
- def create_chunks_display_html(chunk_info):
44
- if not chunk_info:
45
- return "<div style='padding: 20px; text-align: center; color: black;'>Нет данных о чанках</div>"
46
-
47
- merged_chunks = merge_table_chunks(chunk_info)
48
-
49
- html = "<div style='max-height: 500px; overflow-y: auto; padding: 10px; color: black;'>"
50
- html += f"<h4 style='color: black;'>Найдено релевантных чанков: {len(merged_chunks)}</h4>"
51
-
52
- for i, chunk in enumerate(merged_chunks):
53
- bg_color = "#f8f9fa" if i % 2 == 0 else "#e9ecef"
54
- section_display = get_section_display(chunk)
55
- formatted_content = get_formatted_content(chunk)
56
 
57
- html += f"""
58
- <div style='background-color: {bg_color}; padding: 10px; margin: 5px 0; border-radius: 5px; border-left: 4px solid #007bff; color: black;'>
59
- <strong style='color: black;'>Документ:</strong> <span style='color: black;'>{chunk['document_id']}</span><br>
60
- <strong style='color: black;'>Раздел:</strong> <span style='color: black;'>{section_display}</span><br>
61
- <strong style='color: black;'>Содержание:</strong><br>
62
- <div style='background-color: white; padding: 8px; margin-top: 5px; border-radius: 3px; font-family: monospace; font-size: 12px; color: black; max-height: 200px; overflow-y: auto;'>
63
- {formatted_content}
64
- </div>
65
- </div>
66
- """
67
-
68
- html += "</div>"
69
- return html
70
-
71
- def get_section_display(chunk):
72
- section_path = chunk.get('section_path', '')
73
- section_id = chunk.get('section_id', 'unknown')
74
- doc_type = chunk.get('type', 'text')
75
-
76
- if doc_type == 'table' and chunk.get('table_number'):
77
- table_num = chunk.get('table_number')
78
- if not str(table_num).startswith('№'):
79
- table_num = f"№{table_num}"
80
- return f"таблица {table_num}"
81
-
82
- if doc_type == 'image' and chunk.get('image_number'):
83
- image_num = chunk.get('image_number')
84
- if not str(image_num).startswith('№'):
85
- image_num = f"№{image_num}"
86
- return f"рисунок {image_num}"
87
-
88
- if section_path:
89
- return section_path
90
- elif section_id and section_id != 'unknown':
91
- return section_id
92
-
93
- return section_id
94
-
95
- def get_formatted_content(chunk):
96
- document_id = chunk.get('document_id', 'unknown')
97
- section_path = chunk.get('section_path', '')
98
- section_id = chunk.get('section_id', 'unknown')
99
- section_text = chunk.get('section_text', '')
100
- parent_section = chunk.get('parent_section', '')
101
- parent_title = chunk.get('parent_title', '')
102
- level = chunk.get('level', '')
103
- chunk_text = chunk.get('chunk_text', '')
104
- doc_type = chunk.get('type', 'text')
105
-
106
- # For text documents
107
- if level in ['subsection', 'sub_subsection', 'sub_sub_subsection'] and parent_section:
108
- current_section = section_path if section_path else section_id
109
- parent_info = f"{parent_section} ({parent_title})" if parent_title else parent_section
110
- return f"В разделе {parent_info} в документе {document_id}, пункт {current_section}: {chunk_text}"
111
- else:
112
- current_section = section_path if section_path else section_id
113
- clean_text = chunk_text
114
- if section_text and chunk_text.startswith(section_text):
115
- section_title = section_text
116
- elif chunk_text.startswith(f"{current_section} "):
117
- clean_text = chunk_text[len(f"{current_section} "):].strip()
118
- section_title = section_text if section_text else f"{current_section} {clean_text.split('.')[0] if '.' in clean_text else clean_text[:50]}"
119
  else:
120
- section_title = section_text if section_text else current_section
121
 
122
- return f"В разделе {current_section} в документе {document_id}, пункт {section_title}: {clean_text}"
 
 
 
 
123
 
124
  def initialize_system(repo_id, hf_token, download_dir, chunks_filename=None,
125
  json_files_dir=None, table_data_dir=None, image_data_dir=None,
@@ -190,7 +111,7 @@ def initialize_system(repo_id, hf_token, download_dir, chunks_filename=None,
190
  'table_number': doc.metadata.get('table_number', ''),
191
  'image_number': doc.metadata.get('image_number', ''),
192
  'section': doc.metadata.get('section', ''),
193
- 'connection_type': doc.metadata.get('connection_type', '') # ADD THIS
194
  })
195
 
196
  log_message(f"Система успешно инициализирована")
@@ -225,15 +146,15 @@ def switch_model(model_name, vector_index):
225
  return None, f"❌ {error_msg}"
226
 
227
  retrieval_params = {
228
- 'vector_top_k': 50,
229
- 'bm25_top_k': 50,
230
- 'similarity_cutoff': 0.55,
231
- 'hybrid_top_k': 100,
232
  'rerank_top_k': 20
233
  }
234
 
235
- def create_query_engine(vector_index, vector_top_k=50, bm25_top_k=50,
236
- similarity_cutoff=0.55, hybrid_top_k=100):
237
  try:
238
  from config import CUSTOM_PROMPT
239
  from index_retriever import create_query_engine as create_index_query_engine
@@ -424,7 +345,7 @@ def create_demo_interface(answer_question_func, switch_model_func, current_model
424
  vector_top_k = gr.Slider(
425
  minimum=10,
426
  maximum=200,
427
- value=50,
428
  step=10,
429
  label="Vector Top K",
430
  info="Количество результатов из векторного поиска"
@@ -434,7 +355,7 @@ def create_demo_interface(answer_question_func, switch_model_func, current_model
434
  bm25_top_k = gr.Slider(
435
  minimum=10,
436
  maximum=200,
437
- value=50,
438
  step=10,
439
  label="BM25 Top K",
440
  info="Количество результатов из BM25 поиска"
@@ -445,7 +366,7 @@ def create_demo_interface(answer_question_func, switch_model_func, current_model
445
  similarity_cutoff = gr.Slider(
446
  minimum=0.0,
447
  maximum=1.0,
448
- value=0.55,
449
  step=0.05,
450
  label="Similarity Cutoff",
451
  info="Минимальный порог схожести для векторного поиска"
@@ -455,7 +376,7 @@ def create_demo_interface(answer_question_func, switch_model_func, current_model
455
  hybrid_top_k = gr.Slider(
456
  minimum=10,
457
  maximum=300,
458
- value=100,
459
  step=10,
460
  label="Hybrid Top K",
461
  info="Количество результатов из гибридного поиска"
@@ -497,7 +418,7 @@ def create_demo_interface(answer_question_func, switch_model_func, current_model
497
 
498
  gr.Markdown("### Текущие параметры:")
499
  current_params_display = gr.Textbox(
500
- value="Vector: 50 | BM25: 50 | Cutoff: 0.55 | Hybrid: 100 | Rerank: 20",
501
  label="",
502
  interactive=False,
503
  lines=2
@@ -520,6 +441,85 @@ Rerank Top K: {retrieval_params['rerank_top_k']}"""
520
  outputs=[current_params_display]
521
  )
522
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
523
  switch_btn.click(
524
  fn=switch_model_func,
525
  inputs=[model_dropdown],
 
2
  import os
3
  from llama_index.core import Settings
4
  from documents_prep import load_json_documents, load_table_documents, load_image_documents
5
+ from main_utils import get_llm_model, get_embedding_model, get_reranker_model, answer_question
6
  from my_logging import log_message
7
  from index_retriever import create_vector_index, create_query_engine
8
  import sys
 
10
  HF_REPO_ID, HF_TOKEN, DOWNLOAD_DIR, CHUNKS_FILENAME,
11
  JSON_FILES_DIR, TABLE_DATA_DIR, IMAGE_DATA_DIR, DEFAULT_MODEL, AVAILABLE_MODELS
12
  )
13
+ from converters.converter import process_uploaded_file, convert_single_excel_to_json, convert_single_excel_to_csv
14
+ from main_utils import *
15
 
16
+ def restart_system():
17
+ """Перезапуск системы для применения новых документов"""
18
+ global query_engine, chunks_df, reranker, vector_index, current_model
19
 
20
+ try:
21
+ log_message("Начало перезапуска системы...")
 
22
 
23
+ query_engine, chunks_df, reranker, vector_index, chunk_info = initialize_system(
24
+ repo_id=HF_REPO_ID,
25
+ hf_token=HF_TOKEN,
26
+ download_dir=DOWNLOAD_DIR,
27
+ json_files_dir=JSON_FILES_DIR,
28
+ table_data_dir=TABLE_DATA_DIR,
29
+ image_data_dir=IMAGE_DATA_DIR,
30
+ use_json_instead_csv=True,
31
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
+ if query_engine:
34
+ log_message("Система успешно перезапущена")
35
+ return "✅ Система успешно перезапущена! Новые документы загружены."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  else:
37
+ return "❌ Ошибка при перезапуске системы"
38
 
39
+ except Exception as e:
40
+ error_msg = f"Ошибка перезапуска: {str(e)}"
41
+ log_message(error_msg)
42
+ return f"❌ {error_msg}"
43
+
44
 
45
  def initialize_system(repo_id, hf_token, download_dir, chunks_filename=None,
46
  json_files_dir=None, table_data_dir=None, image_data_dir=None,
 
111
  'table_number': doc.metadata.get('table_number', ''),
112
  'image_number': doc.metadata.get('image_number', ''),
113
  'section': doc.metadata.get('section', ''),
114
+ 'connection_type': doc.metadata.get('connection_type', '')
115
  })
116
 
117
  log_message(f"Система успешно инициализирована")
 
146
  return None, f"❌ {error_msg}"
147
 
148
  retrieval_params = {
149
+ 'vector_top_k': 70,
150
+ 'bm25_top_k': 70,
151
+ 'similarity_cutoff': 0.45,
152
+ 'hybrid_top_k': 140,
153
  'rerank_top_k': 20
154
  }
155
 
156
+ def create_query_engine(vector_index, vector_top_k=70, bm25_top_k=70,
157
+ similarity_cutoff=0.45, hybrid_top_k=140):
158
  try:
159
  from config import CUSTOM_PROMPT
160
  from index_retriever import create_query_engine as create_index_query_engine
 
345
  vector_top_k = gr.Slider(
346
  minimum=10,
347
  maximum=200,
348
+ value=70,
349
  step=10,
350
  label="Vector Top K",
351
  info="Количество результатов из векторного поиска"
 
355
  bm25_top_k = gr.Slider(
356
  minimum=10,
357
  maximum=200,
358
+ value=70,
359
  step=10,
360
  label="BM25 Top K",
361
  info="Количество результатов из BM25 поиска"
 
366
  similarity_cutoff = gr.Slider(
367
  minimum=0.0,
368
  maximum=1.0,
369
+ value=0.45,
370
  step=0.05,
371
  label="Similarity Cutoff",
372
  info="Минимальный порог схожести для векторного поиска"
 
376
  hybrid_top_k = gr.Slider(
377
  minimum=10,
378
  maximum=300,
379
+ value=140,
380
  step=10,
381
  label="Hybrid Top K",
382
  info="Количество результатов из гибридного поиска"
 
418
 
419
  gr.Markdown("### Текущие параметры:")
420
  current_params_display = gr.Textbox(
421
+ value="Vector: 70 | BM25: 70 | Cutoff: 0.45 | Hybrid: 140 | Rerank: 20",
422
  label="",
423
  interactive=False,
424
  lines=2
 
441
  outputs=[current_params_display]
442
  )
443
 
444
+
445
+ with gr.Tab("📤 Загрузка документов"):
446
+ gr.Markdown("""
447
+ ### Загрузка новых документов в систему
448
+
449
+ Выберите тип документа и загрузите файл. Система автоматически обработает и добавит его в базу знаний.
450
+ """)
451
+
452
+ with gr.Row():
453
+ with gr.Column(scale=2):
454
+ file_type_radio = gr.Radio(
455
+ choices=["Таблица", "Изображение (метаданные)", "JSON документ"],
456
+ value="Таблица",
457
+ label="Тип документа",
458
+ info="Выберите тип загружаемого документа"
459
+ )
460
+
461
+ file_upload = gr.File(
462
+ label="Выберите файл",
463
+ file_types=[".xlsx", ".xls", ".csv", ".json"],
464
+ type="filepath"
465
+ )
466
+
467
+ with gr.Row():
468
+ upload_btn = gr.Button("📤 Загрузить и обработать", variant="primary", size="lg")
469
+ restart_btn = gr.Button("🔄 Перезапустить систему", variant="secondary", size="lg")
470
+
471
+ upload_status = gr.Textbox(
472
+ label="Статус загрузки",
473
+ value="Ожидание загрузки файла...",
474
+ interactive=False,
475
+ lines=8
476
+ )
477
+
478
+ restart_status = gr.Textbox(
479
+ label="Статус перезапуска",
480
+ value="Система готова к работе",
481
+ interactive=False,
482
+ lines=2
483
+ )
484
+
485
+ with gr.Column(scale=1):
486
+ gr.Markdown("""
487
+ ### Требования к файлам:
488
+
489
+ **Таблицы (Excel → JSON):**
490
+ - Формат: .xlsx или .xls
491
+ - Обязательные колонки:
492
+ - Номер таблицы
493
+ - Обозначение документа
494
+ - Раздел документа
495
+ - Название таблицы
496
+
497
+ **Изображения (Excel → CSV):**
498
+ - Формат: .xlsx, .xls или .csv
499
+ - Метаданные изображений
500
+
501
+ **JSON документы:**
502
+ - Формат: .json
503
+ - Структурированные данные
504
+
505
+ ### Процесс загрузки:
506
+ 1. Выберите тип документа
507
+ 2. Загрузите файл
508
+ 3. Дождитесь обработки
509
+ 4. Нажмите "Перезапустить систему"
510
+ """)
511
+
512
+ upload_btn.click(
513
+ fn=process_uploaded_file,
514
+ inputs=[file_upload, file_type_radio],
515
+ outputs=[upload_status]
516
+ )
517
+
518
+ restart_btn.click(
519
+ fn=restart_system,
520
+ inputs=[],
521
+ outputs=[restart_status]
522
+ )
523
  switch_btn.click(
524
  fn=switch_model_func,
525
  inputs=[model_dropdown],
converters/converter.py CHANGED
@@ -1,5 +1,5 @@
1
  from config import *
2
- from utils import log_message
3
  import json
4
  import pandas as pd
5
  import os
@@ -13,35 +13,99 @@ def process_uploaded_file(file, file_type):
13
  from huggingface_hub import HfApi
14
  import tempfile
15
  import shutil
16
-
17
- # Создаем временную директорию
18
  with tempfile.TemporaryDirectory() as temp_dir:
19
- # Сохраняем загруженный файл
20
- file_path = os.path.join(temp_dir, file.name)
21
- shutil.copy(file.name, file_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
- # Определяем целевую директорию на HuggingFace
24
  if file_type == "Таблица":
25
  target_dir = TABLE_DATA_DIR
26
- # Конвертируем Excel в JSON
27
- if file.name.endswith(('.xlsx', '.xls')):
28
  json_path = convert_single_excel_to_json(file_path, temp_dir)
29
  upload_file = json_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  else:
31
  upload_file = file_path
 
 
32
  elif file_type == "Изображение (метаданные)":
33
  target_dir = IMAGE_DATA_DIR
34
- # Конвертируем Excel в CSV
35
- if file.name.endswith(('.xlsx', '.xls')):
36
  csv_path = convert_single_excel_to_csv(file_path, temp_dir)
37
  upload_file = csv_path
 
 
 
 
 
 
 
 
 
 
38
  else:
39
  upload_file = file_path
 
 
 
 
 
 
 
 
40
  else: # JSON документ
41
  target_dir = JSON_FILES_DIR
42
  upload_file = file_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
  # Загружаем на HuggingFace
 
45
  api = HfApi()
46
  api.upload_file(
47
  path_or_fileobj=upload_file,
@@ -51,8 +115,13 @@ def process_uploaded_file(file, file_type):
51
  repo_type="dataset"
52
  )
53
 
54
- log_message(f"Файл {file.name} успешно загружен в {target_dir}")
55
- return f"✅ Файл успешно загружен и обработан: {os.path.basename(upload_file)}\n⚠️ Перезапустите систему для применения изменений"
 
 
 
 
 
56
 
57
  except Exception as e:
58
  error_msg = f"Ошибка обработки файла: {str(e)}"
@@ -69,12 +138,18 @@ def convert_single_excel_to_json(excel_path, output_dir):
69
  "sheets": []
70
  }
71
 
 
 
 
 
72
  for sheet_name, df in df_dict.items():
73
  if df.empty or "Номер таблицы" not in df.columns:
 
74
  continue
75
 
76
  df = df.dropna(how='all').fillna("")
77
  grouped = df.groupby("Номер таблицы")
 
78
 
79
  for table_number, group in grouped:
80
  group = group.reset_index(drop=True)
@@ -98,6 +173,10 @@ def convert_single_excel_to_json(excel_path, output_dir):
98
  sheet_data["data"].append(row_dict)
99
 
100
  result["sheets"].append(sheet_data)
 
 
 
 
101
 
102
  json_filename = os.path.basename(excel_path).replace('.xlsx', '.json').replace('.xls', '.json')
103
  json_path = os.path.join(output_dir, json_filename)
@@ -105,12 +184,22 @@ def convert_single_excel_to_json(excel_path, output_dir):
105
  with open(json_path, 'w', encoding='utf-8') as f:
106
  json.dump(result, f, ensure_ascii=False, indent=2)
107
 
 
 
 
108
  return json_path
109
 
110
  def convert_single_excel_to_csv(excel_path, output_dir):
111
  """Конвертация одного Excel файла в CSV для изображений"""
 
 
112
  df = pd.read_excel(excel_path)
113
  csv_filename = os.path.basename(excel_path).replace('.xlsx', '.csv').replace('.xls', '.csv')
114
  csv_path = os.path.join(output_dir, csv_filename)
115
  df.to_csv(csv_path, index=False, encoding='utf-8')
116
- return csv_path
 
 
 
 
 
 
1
  from config import *
2
+ from my_logging import log_message
3
  import json
4
  import pandas as pd
5
  import os
 
13
  from huggingface_hub import HfApi
14
  import tempfile
15
  import shutil
16
+
 
17
  with tempfile.TemporaryDirectory() as temp_dir:
18
+ source_path = file if isinstance(file, str) else file.name
19
+ filename = os.path.basename(source_path)
20
+ file_path = os.path.join(temp_dir, filename)
21
+
22
+ log_message(f"Начало обработки файла: {filename}")
23
+ log_message(f"Тип документа: {file_type}")
24
+
25
+ if os.path.abspath(source_path) != os.path.abspath(file_path):
26
+ shutil.copy(source_path, file_path)
27
+ else:
28
+ file_path = source_path
29
+
30
+ # Get original file size
31
+ original_size_bytes = os.path.getsize(file_path)
32
+ original_size_mb = original_size_bytes / (1024 * 1024)
33
+
34
+ status_info = []
35
+ status_info.append(f"📁 Исходный файл: {filename}")
36
+ status_info.append(f"📦 Размер файла: {original_size_mb:.2f} МБ ({original_size_bytes:,} байт)")
37
 
 
38
  if file_type == "Таблица":
39
  target_dir = TABLE_DATA_DIR
40
+ if filename.endswith(('.xlsx', '.xls')):
 
41
  json_path = convert_single_excel_to_json(file_path, temp_dir)
42
  upload_file = json_path
43
+
44
+ # Get processed file size
45
+ processed_size_bytes = os.path.getsize(json_path)
46
+ processed_size_mb = processed_size_bytes / (1024 * 1024)
47
+
48
+ with open(json_path, 'r', encoding='utf-8') as f:
49
+ data = json.load(f)
50
+
51
+ total_rows = sum(len(sheet['data']) for sheet in data['sheets'])
52
+
53
+ status_info.append(f"📊 Всего таблиц: {len(data['sheets'])}")
54
+ status_info.append(f"📄 Листов в документе: {data['total_sheets']}")
55
+ status_info.append(f"📝 Всего строк данных: {total_rows:,}")
56
+ status_info.append(f"💾 Размер после обработки: {processed_size_mb:.2f} МБ")
57
+ status_info.append(f"📤 Загружен как: {os.path.basename(json_path)}")
58
  else:
59
  upload_file = file_path
60
+ status_info.append(f"📤 Загружен как: {filename}")
61
+
62
  elif file_type == "Изображение (метаданные)":
63
  target_dir = IMAGE_DATA_DIR
64
+ if filename.endswith(('.xlsx', '.xls')):
 
65
  csv_path = convert_single_excel_to_csv(file_path, temp_dir)
66
  upload_file = csv_path
67
+
68
+ # Get processed file size
69
+ processed_size_bytes = os.path.getsize(csv_path)
70
+ processed_size_mb = processed_size_bytes / (1024 * 1024)
71
+
72
+ df = pd.read_csv(csv_path)
73
+ status_info.append(f"🖼️ Записей изображений: {len(df):,}")
74
+ status_info.append(f"📋 Колонок метаданных: {len(df.columns)}")
75
+ status_info.append(f"💾 Размер после обработки: {processed_size_mb:.2f} МБ")
76
+ status_info.append(f"📤 Загружен как: {os.path.basename(csv_path)}")
77
  else:
78
  upload_file = file_path
79
+ try:
80
+ df = pd.read_csv(upload_file)
81
+ status_info.append(f"🖼️ Записей изображений: {len(df):,}")
82
+ status_info.append(f"📋 Колонок метаданных: {len(df.columns)}")
83
+ except:
84
+ pass
85
+ status_info.append(f"📤 Загружен как: {filename}")
86
+
87
  else: # JSON документ
88
  target_dir = JSON_FILES_DIR
89
  upload_file = file_path
90
+
91
+ try:
92
+ with open(upload_file, 'r', encoding='utf-8') as f:
93
+ json_data = json.load(f)
94
+
95
+ if isinstance(json_data, list):
96
+ status_info.append(f"📝 Документов в JSON: {len(json_data):,}")
97
+ elif isinstance(json_data, dict):
98
+ status_info.append(f"📝 JSON объект (словарь)")
99
+ # Count keys if it's structured data
100
+ if 'sheets' in json_data:
101
+ status_info.append(f"📊 Таблиц в документе: {len(json_data.get('sheets', []))}")
102
+ status_info.append(f"🔑 Ключей верхнего уровня: {len(json_data.keys())}")
103
+ except:
104
+ pass
105
+ status_info.append(f"📤 Загружен как: {filename}")
106
 
107
  # Загружаем на HuggingFace
108
+ log_message(f"Загрузка на HuggingFace: {target_dir}/{os.path.basename(upload_file)}")
109
  api = HfApi()
110
  api.upload_file(
111
  path_or_fileobj=upload_file,
 
115
  repo_type="dataset"
116
  )
117
 
118
+ log_message(f"Файл {filename} успешно загружен в {target_dir}")
119
+
120
+ result_message = f"✅ Файл успешно загружен и обработан\n\n"
121
+ result_message += "\n".join(status_info)
122
+ result_message += "\n\n⚠️ Нажмите кнопку 'Перезапустить систему' для применения изменений"
123
+
124
+ return result_message
125
 
126
  except Exception as e:
127
  error_msg = f"Ошибка обработки файла: {str(e)}"
 
138
  "sheets": []
139
  }
140
 
141
+ log_message(f"Обработка файла: {os.path.basename(excel_path)}")
142
+ log_message(f"Найдено листов: {len(df_dict)}")
143
+
144
+ total_tables = 0
145
  for sheet_name, df in df_dict.items():
146
  if df.empty or "Номер таблицы" not in df.columns:
147
+ log_message(f" Лист '{sheet_name}': пропущен (пустой или отсутствует колонка 'Номер таблицы')")
148
  continue
149
 
150
  df = df.dropna(how='all').fillna("")
151
  grouped = df.groupby("Номер таблицы")
152
+ sheet_tables = 0
153
 
154
  for table_number, group in grouped:
155
  group = group.reset_index(drop=True)
 
173
  sheet_data["data"].append(row_dict)
174
 
175
  result["sheets"].append(sheet_data)
176
+ sheet_tables += 1
177
+
178
+ total_tables += sheet_tables
179
+ log_message(f" Лист '{sheet_name}': обработано таблиц: {sheet_tables}")
180
 
181
  json_filename = os.path.basename(excel_path).replace('.xlsx', '.json').replace('.xls', '.json')
182
  json_path = os.path.join(output_dir, json_filename)
 
184
  with open(json_path, 'w', encoding='utf-8') as f:
185
  json.dump(result, f, ensure_ascii=False, indent=2)
186
 
187
+ log_message(f"Конвертация завершена. Всего таблиц обработано: {total_tables}")
188
+ log_message(f"Результат сохранен: {json_filename}")
189
+
190
  return json_path
191
 
192
  def convert_single_excel_to_csv(excel_path, output_dir):
193
  """Конвертация одного Excel файла в CSV для изображений"""
194
+ log_message(f"Конвертация Excel в CSV: {os.path.basename(excel_path)}")
195
+
196
  df = pd.read_excel(excel_path)
197
  csv_filename = os.path.basename(excel_path).replace('.xlsx', '.csv').replace('.xls', '.csv')
198
  csv_path = os.path.join(output_dir, csv_filename)
199
  df.to_csv(csv_path, index=False, encoding='utf-8')
200
+
201
+ log_message(f" Строк обработано: {len(df)}")
202
+ log_message(f" Колонок: {len(df.columns)}")
203
+ log_message(f" Результат сохранен: {csv_filename}")
204
+
205
+ return csv_path
documents_prep.py CHANGED
@@ -515,7 +515,7 @@ def load_table_documents(repo_id, hf_token, table_dir):
515
  log_message("Loading tables...")
516
  log_message("="*60)
517
  files = list_repo_files(repo_id=repo_id, repo_type="dataset", token=hf_token)
518
- table_files = [f for f in files if f.startswith(table_dir) and f.endswith('.json')]
519
 
520
  all_chunks = []
521
  tables_processed = 0
@@ -529,6 +529,16 @@ def load_table_documents(repo_id, hf_token, table_dir):
529
  token=hf_token
530
  )
531
 
 
 
 
 
 
 
 
 
 
 
532
  with open(local_path, 'r', encoding='utf-8') as f:
533
  data = json.load(f)
534
 
@@ -551,11 +561,12 @@ def load_table_documents(repo_id, hf_token, table_dir):
551
 
552
  return all_chunks
553
 
 
554
  def load_image_documents(repo_id, hf_token, image_dir):
555
  log_message("Loading images...")
556
 
557
  files = list_repo_files(repo_id=repo_id, repo_type="dataset", token=hf_token)
558
- csv_files = [f for f in files if f.startswith(image_dir) and f.endswith('.csv')]
559
 
560
  documents = []
561
  for file_path in csv_files:
@@ -567,6 +578,16 @@ def load_image_documents(repo_id, hf_token, image_dir):
567
  token=hf_token
568
  )
569
 
 
 
 
 
 
 
 
 
 
 
570
  df = pd.read_csv(local_path)
571
 
572
  for _, row in df.iterrows():
 
515
  log_message("Loading tables...")
516
  log_message("="*60)
517
  files = list_repo_files(repo_id=repo_id, repo_type="dataset", token=hf_token)
518
+ table_files = [f for f in files if f.startswith(table_dir) and (f.endswith('.json') or f.endswith('.xlsx') or f.endswith('.xls'))]
519
 
520
  all_chunks = []
521
  tables_processed = 0
 
529
  token=hf_token
530
  )
531
 
532
+ # Convert Excel to JSON if needed
533
+ if file_path.endswith(('.xlsx', '.xls')):
534
+ from converters.converter import convert_single_excel_to_json
535
+ import tempfile
536
+ import os
537
+
538
+ with tempfile.TemporaryDirectory() as temp_dir:
539
+ json_path = convert_single_excel_to_json(local_path, temp_dir)
540
+ local_path = json_path
541
+
542
  with open(local_path, 'r', encoding='utf-8') as f:
543
  data = json.load(f)
544
 
 
561
 
562
  return all_chunks
563
 
564
+
565
  def load_image_documents(repo_id, hf_token, image_dir):
566
  log_message("Loading images...")
567
 
568
  files = list_repo_files(repo_id=repo_id, repo_type="dataset", token=hf_token)
569
+ csv_files = [f for f in files if f.startswith(image_dir) and (f.endswith('.csv') or f.endswith('.xlsx') or f.endswith('.xls'))]
570
 
571
  documents = []
572
  for file_path in csv_files:
 
578
  token=hf_token
579
  )
580
 
581
+ # Convert Excel to CSV if needed
582
+ if file_path.endswith(('.xlsx', '.xls')):
583
+ from converters.converter import convert_single_excel_to_csv
584
+ import tempfile
585
+ import os
586
+
587
+ with tempfile.TemporaryDirectory() as temp_dir:
588
+ csv_path = convert_single_excel_to_csv(local_path, temp_dir)
589
+ local_path = csv_path
590
+
591
  df = pd.read_csv(local_path)
592
 
593
  for _, row in df.iterrows():
utils.py → main_utils.py RENAMED
File without changes