Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -22,31 +22,28 @@ class KDChecker:
|
|
| 22 |
log = [f"[{datetime.now().strftime('%H:%M:%S')}] Старт функции загрузки"]
|
| 23 |
|
| 24 |
if excel_path is None:
|
| 25 |
-
return "Файл не передан (excel_path is None)", gr.
|
| 26 |
|
| 27 |
log.append(f"Путь к файлу: {excel_path}")
|
| 28 |
|
| 29 |
-
# Проверка размера файла (чтобы убедиться, что он загрузился)
|
| 30 |
try:
|
| 31 |
size = os.path.getsize(excel_path)
|
| 32 |
log.append(f"Размер файла: {size} байт")
|
| 33 |
except Exception as e:
|
| 34 |
log.append(f"Ошибка доступа к файлу: {e}")
|
| 35 |
-
return "\n".join(log), gr.
|
| 36 |
|
| 37 |
-
# Проверка наличия движка
|
| 38 |
try:
|
| 39 |
import openpyxl
|
| 40 |
log.append("Библиотека openpyxl найдена.")
|
| 41 |
except ImportError:
|
| 42 |
-
return "ОШИБКА: Библиотека openpyxl не установлена на сервере!", gr.
|
| 43 |
|
| 44 |
all_data = []
|
| 45 |
sheets_log = []
|
| 46 |
|
| 47 |
try:
|
| 48 |
log.append("Попытка чтения Excel через pandas...")
|
| 49 |
-
# Явно указываем движок
|
| 50 |
xls = pd.read_excel(excel_path, sheet_name=None, header=None, engine='openpyxl')
|
| 51 |
log.append(f"Файл прочитан. Найдены листы: {list(xls.keys())}")
|
| 52 |
|
|
@@ -71,36 +68,43 @@ class KDChecker:
|
|
| 71 |
|
| 72 |
if header_row_index != -1:
|
| 73 |
df = pd.read_excel(excel_path, sheet_name=sheet_name, header=header_row_index, engine='openpyxl')
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
else:
|
| 87 |
sheets_log.append(f"Лист '{sheet_name}': заголовки не найдены")
|
| 88 |
|
| 89 |
if not all_data:
|
| 90 |
log.append("Не найдены данные ни на одном листе.")
|
| 91 |
-
return "\n".join(log), gr.
|
| 92 |
|
| 93 |
self.excel_db = pd.concat(all_data, ignore_index=True)
|
| 94 |
self.cabinet_list = sorted(self.excel_db["Cabinet"].unique().tolist())
|
| 95 |
|
| 96 |
log.append("Успешно объединили данные.")
|
| 97 |
msg = f"✅ База знаний загружена успешно!\nВсего записей: {len(self.excel_db)}\nОбработаны листы: {', '.join(sheets_log)}"
|
| 98 |
-
|
|
|
|
|
|
|
| 99 |
|
| 100 |
except Exception as e:
|
| 101 |
-
# Возвращаем полный лог ошибки
|
| 102 |
log.append(f"КРИТИЧЕСКАЯ ОШИБКА: {str(e)}")
|
| 103 |
-
|
|
|
|
|
|
|
| 104 |
|
| 105 |
def extract_text(self, pdf_path):
|
| 106 |
try:
|
|
@@ -239,7 +243,6 @@ class KDChecker:
|
|
| 239 |
pdf_title = detected_cabinet
|
| 240 |
if is_manual: pdf_title += " (Выбор вручную)"
|
| 241 |
|
| 242 |
-
# Создание PDF с защитой от отсутствия шрифта
|
| 243 |
try:
|
| 244 |
pdf = self.create_pdf(pdf_title, checklist)
|
| 245 |
except Exception as e:
|
|
@@ -258,21 +261,19 @@ class KDChecker:
|
|
| 258 |
form = c.acroForm
|
| 259 |
width, height = A4
|
| 260 |
|
| 261 |
-
# Ищем шрифт на сервере
|
| 262 |
font_name = 'Helvetica'
|
| 263 |
-
font_path = "arial.ttf"
|
| 264 |
|
| 265 |
if os.path.exists(font_path):
|
| 266 |
try:
|
| 267 |
pdfmetrics.registerFont(TTFont('Arial', font_path))
|
| 268 |
font_name = 'Arial'
|
| 269 |
except:
|
| 270 |
-
pass
|
| 271 |
|
| 272 |
y = height - 50
|
| 273 |
c.setFont(font_name, 16)
|
| 274 |
|
| 275 |
-
# Безопасная печать заголовка
|
| 276 |
try:
|
| 277 |
c.drawString(50, y, f"ЧЕК-ЛИСТ ПРОВЕРКИ КД")
|
| 278 |
except:
|
|
@@ -352,7 +353,7 @@ class KDChecker:
|
|
| 352 |
try:
|
| 353 |
c.drawString(65, text_start_y, l.strip())
|
| 354 |
except:
|
| 355 |
-
pass
|
| 356 |
text_start_y -= 12
|
| 357 |
|
| 358 |
y = text_start_y - 8
|
|
@@ -376,16 +377,18 @@ def create_app():
|
|
| 376 |
with gr.Row():
|
| 377 |
with gr.Column():
|
| 378 |
gr.Markdown("### 1. База знаний")
|
| 379 |
-
|
| 380 |
db_in = gr.File(label="Загрузить Excel (.xlsx)", type="filepath")
|
| 381 |
-
|
|
|
|
|
|
|
|
|
|
| 382 |
db_out = gr.Textbox(label="Статус загрузки", lines=8, max_lines=30)
|
| 383 |
|
| 384 |
db_in.upload(checker.load_excel_db, inputs=[db_in], outputs=[db_out, manual_cab])
|
| 385 |
|
| 386 |
with gr.Column():
|
| 387 |
gr.Markdown("### 2. Документация (PDF)")
|
| 388 |
-
# type="filepath" ОБЯЗАТЕЛЬНО ДЛЯ СЕРВЕРА
|
| 389 |
files_in = gr.File(label="Загрузить чертежи", file_count="multiple", type="filepath")
|
| 390 |
btn = gr.Button("Сформировать чек-лист", variant="primary")
|
| 391 |
|
|
|
|
| 22 |
log = [f"[{datetime.now().strftime('%H:%M:%S')}] Старт функции загрузки"]
|
| 23 |
|
| 24 |
if excel_path is None:
|
| 25 |
+
return "Файл не передан (excel_path is None)", gr.Dropdown(choices=[], value=None)
|
| 26 |
|
| 27 |
log.append(f"Путь к файлу: {excel_path}")
|
| 28 |
|
|
|
|
| 29 |
try:
|
| 30 |
size = os.path.getsize(excel_path)
|
| 31 |
log.append(f"Размер файла: {size} байт")
|
| 32 |
except Exception as e:
|
| 33 |
log.append(f"Ошибка доступа к файлу: {e}")
|
| 34 |
+
return "\n".join(log), gr.Dropdown(choices=[], value=None)
|
| 35 |
|
|
|
|
| 36 |
try:
|
| 37 |
import openpyxl
|
| 38 |
log.append("Библиотека openpyxl найдена.")
|
| 39 |
except ImportError:
|
| 40 |
+
return "ОШИБКА: Библиотека openpyxl не установлена на сервере!", gr.Dropdown(choices=[], value=None)
|
| 41 |
|
| 42 |
all_data = []
|
| 43 |
sheets_log = []
|
| 44 |
|
| 45 |
try:
|
| 46 |
log.append("Попытка чтения Excel через pandas...")
|
|
|
|
| 47 |
xls = pd.read_excel(excel_path, sheet_name=None, header=None, engine='openpyxl')
|
| 48 |
log.append(f"Файл прочитан. Найдены листы: {list(xls.keys())}")
|
| 49 |
|
|
|
|
| 68 |
|
| 69 |
if header_row_index != -1:
|
| 70 |
df = pd.read_excel(excel_path, sheet_name=sheet_name, header=header_row_index, engine='openpyxl')
|
| 71 |
+
# Проверяем, что индексы колонок существуют в этом df
|
| 72 |
+
if cab_col_idx < len(df.columns) and rem_col_idx < len(df.columns):
|
| 73 |
+
df_subset = df.iloc[:, [cab_col_idx, rem_col_idx]]
|
| 74 |
+
df_subset.columns = ["Cabinet", "Remark"]
|
| 75 |
+
|
| 76 |
+
df_subset["Cabinet"] = df_subset["Cabinet"].ffill()
|
| 77 |
+
df_subset = df_subset.dropna(subset=["Remark"]).astype(str)
|
| 78 |
+
|
| 79 |
+
df_subset["Cabinet_Clean"] = df_subset["Cabinet"].apply(
|
| 80 |
+
lambda x: x.strip().replace(" ", "").replace("\n", "").replace("\r", "")
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
all_data.append(df_subset)
|
| 84 |
+
sheets_log.append(f"Лист '{sheet_name}': {len(df_subset)} стр.")
|
| 85 |
+
else:
|
| 86 |
+
sheets_log.append(f"Лист '{sheet_name}': ошибка индексов колонок")
|
| 87 |
else:
|
| 88 |
sheets_log.append(f"Лист '{sheet_name}': заголовки не найдены")
|
| 89 |
|
| 90 |
if not all_data:
|
| 91 |
log.append("Не найдены данные ни на одном листе.")
|
| 92 |
+
return "\n".join(log), gr.Dropdown(choices=[], value=None)
|
| 93 |
|
| 94 |
self.excel_db = pd.concat(all_data, ignore_index=True)
|
| 95 |
self.cabinet_list = sorted(self.excel_db["Cabinet"].unique().tolist())
|
| 96 |
|
| 97 |
log.append("Успешно объединили данные.")
|
| 98 |
msg = f"✅ База знаний загружена успешно!\nВсего записей: {len(self.excel_db)}\nОбработаны листы: {', '.join(sheets_log)}"
|
| 99 |
+
|
| 100 |
+
# Возвращаем новый Dropdown с обновленным списком
|
| 101 |
+
return msg, gr.Dropdown(choices=self.cabinet_list, value=None, interactive=True)
|
| 102 |
|
| 103 |
except Exception as e:
|
|
|
|
| 104 |
log.append(f"КРИТИЧЕСКАЯ ОШИБКА: {str(e)}")
|
| 105 |
+
import traceback
|
| 106 |
+
log.append(traceback.format_exc())
|
| 107 |
+
return "\n".join(log), gr.Dropdown(choices=[], value=None)
|
| 108 |
|
| 109 |
def extract_text(self, pdf_path):
|
| 110 |
try:
|
|
|
|
| 243 |
pdf_title = detected_cabinet
|
| 244 |
if is_manual: pdf_title += " (Выбор вручную)"
|
| 245 |
|
|
|
|
| 246 |
try:
|
| 247 |
pdf = self.create_pdf(pdf_title, checklist)
|
| 248 |
except Exception as e:
|
|
|
|
| 261 |
form = c.acroForm
|
| 262 |
width, height = A4
|
| 263 |
|
|
|
|
| 264 |
font_name = 'Helvetica'
|
| 265 |
+
font_path = "arial.ttf"
|
| 266 |
|
| 267 |
if os.path.exists(font_path):
|
| 268 |
try:
|
| 269 |
pdfmetrics.registerFont(TTFont('Arial', font_path))
|
| 270 |
font_name = 'Arial'
|
| 271 |
except:
|
| 272 |
+
pass
|
| 273 |
|
| 274 |
y = height - 50
|
| 275 |
c.setFont(font_name, 16)
|
| 276 |
|
|
|
|
| 277 |
try:
|
| 278 |
c.drawString(50, y, f"ЧЕК-ЛИСТ ПРОВЕРКИ КД")
|
| 279 |
except:
|
|
|
|
| 353 |
try:
|
| 354 |
c.drawString(65, text_start_y, l.strip())
|
| 355 |
except:
|
| 356 |
+
pass
|
| 357 |
text_start_y -= 12
|
| 358 |
|
| 359 |
y = text_start_y - 8
|
|
|
|
| 377 |
with gr.Row():
|
| 378 |
with gr.Column():
|
| 379 |
gr.Markdown("### 1. База знаний")
|
| 380 |
+
|
| 381 |
db_in = gr.File(label="Загрузить Excel (.xlsx)", type="filepath")
|
| 382 |
+
|
| 383 |
+
# Инициализируем с choices=None, чтобы Gradio не ругался на пустой список при старте
|
| 384 |
+
manual_cab = gr.Dropdown(label="Или выберите шкаф-аналог вручную", choices=None, interactive=True)
|
| 385 |
+
|
| 386 |
db_out = gr.Textbox(label="Статус загрузки", lines=8, max_lines=30)
|
| 387 |
|
| 388 |
db_in.upload(checker.load_excel_db, inputs=[db_in], outputs=[db_out, manual_cab])
|
| 389 |
|
| 390 |
with gr.Column():
|
| 391 |
gr.Markdown("### 2. Документация (PDF)")
|
|
|
|
| 392 |
files_in = gr.File(label="Загрузить чертежи", file_count="multiple", type="filepath")
|
| 393 |
btn = gr.Button("Сформировать чек-лист", variant="primary")
|
| 394 |
|