QIDNLF commited on
Commit
fe0bdf5
ยท
verified ยท
1 Parent(s): d0879fb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +34 -152
app.py CHANGED
@@ -245,11 +245,7 @@ def fetch_database_records(standard, version, selection):
245
  conn = sqlite3.connect(db_path)
246
  conn.text_factory = decode_sqlite_text
247
 
248
- # 1. ํ˜„์žฌ ์–ด๋–ค ์ข…๋ฅ˜์˜ ํ…Œ์ด๋ธ”์„ ๋ณด๋ ค๋Š”์ง€ ํŒ๋ณ„ (TableA, TableB_C ๋˜๋Š” Main)
249
- # selection์ด "ALL"์ด๊ฑฐ๋‚˜ "2.12" ๊ฐ™์€ ํ˜•ํƒœ๋ฉด "Main"์œผ๋กœ ๊ฐ„์ฃผ
250
  table_type = "Main" if selection == "ALL" or (selection and selection[0].isdigit() and "." in selection) else selection
251
-
252
- # 2. Table_Config์—์„œ ์„ค์ • ๊ฐ€์ ธ์˜ค๊ธฐ (๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ถ€๋ถ„!)
253
  anchor_col, display_setting = get_table_config(table_type)
254
 
255
  tables = pd.read_sql("SELECT name FROM sqlite_master WHERE type='table';", conn)['name'].tolist()
@@ -269,12 +265,9 @@ def fetch_database_records(standard, version, selection):
269
  target_table = t
270
  break
271
 
272
- # 3. ๋ฐ์ดํ„ฐ ๋กœ๋“œ ๋กœ์ง
273
  if target_table and target_table != main_table:
274
- # ๋ถ€์† ํ…Œ์ด๋ธ”(TableA ๋“ฑ) ์ฒ˜๋ฆฌ
275
  df = pd.read_sql(f"SELECT * FROM [{target_table}]", conn)
276
  else:
277
- # ๋ฉ”์ธ ํ…Œ์ด๋ธ” ์ฒ˜๋ฆฌ (ALL ๋˜๋Š” ์นดํ…Œ๊ณ ๋ฆฌ ํ•„ํ„ฐ๋ง)
278
  cursor = conn.cursor()
279
  cursor.execute(f"PRAGMA table_info([{main_table}])")
280
  cols_info = cursor.fetchall()
@@ -297,18 +290,14 @@ def fetch_database_records(standard, version, selection):
297
 
298
  df = pd.DataFrame(cursor.fetchall(), columns=cols)
299
 
300
- # 4. [์ˆ˜์ •๋จ] ์„ค์ •์— ๋”ฐ๋ฅธ ์ปฌ๋Ÿผ ํ•„ํ„ฐ๋ง (ํ•˜๋“œ์ฝ”๋”ฉ ์ œ๊ฑฐ)
301
  df = df.drop(columns=[c for c in df.columns if c.lower() == "version"], errors="ignore")
302
 
303
  if display_setting:
304
  cols_to_show = [c.strip() for c in display_setting.split(',')]
305
- # Anchor(๊ธฐ์ค€์—ด)๊ฐ€ ๋ฐ์ดํ„ฐ์— ์žˆ๋‹ค๋ฉด ๋ฐ˜๋“œ์‹œ ํฌํ•จ
306
  if anchor_col in df.columns and anchor_col not in cols_to_show:
307
  cols_to_show.insert(0, anchor_col)
308
- # ์กด์žฌํ•˜๋Š” ์ปฌ๋Ÿผ๋งŒ ํ•„ํ„ฐ๋ง
309
  df = df[[c for c in cols_to_show if c in df.columns]]
310
 
311
- # 5. ์ด๋ฏธ์ง€ ๋ Œ๋”๋ง ๋ฐ ์ •๋ฆฌ
312
  for col in df.columns:
313
  df[col] = df[col].apply(convert_blob_to_html_img)
314
 
@@ -317,142 +306,52 @@ def fetch_database_records(standard, version, selection):
317
 
318
  except Exception as e:
319
  import traceback
320
- traceback.print_exc() # ์—๋Ÿฌ ์›์ธ ์ถ”์ ์„ ์œ„ํ•ด ์ถ”๊ฐ€
321
  return pd.DataFrame({"Error": [str(e)]})
322
 
323
  def execute_unified_search(base_std, base_ver, base_cat, comp_std, comp_ver, comp_cat):
324
- # 1. ํ…Œ์ด๋ธ” ํƒ€์ž… ํŒ๋ณ„ (์„ ํƒ๋œ ์นดํ…Œ๊ณ ๋ฆฌ ๋ช…์นญ ๋“ฑ์œผ๋กœ ํŒ๋ณ„)
325
- table_type = "Main" if base_cat == "ALL" or "." in base_cat else base_cat
326
- anchor_col, _ = get_table_config(table_type)
327
-
328
- # 2. ์–‘์ธก ๋ฐ์ดํ„ฐ ๋กœ๋“œ (์ด์ œ 6์—ด์”ฉ ๊ฐ€๋“ ์ฐจ์„œ ์˜ต๋‹ˆ๋‹ค)
329
- df_base = fetch_database_records(base_std, base_ver, base_cat, table_type)
330
- df_comp = fetch_database_records(comp_std, comp_ver, comp_cat, table_type)
331
-
332
- # 3. ์ปฌ๋Ÿผ๋ช…์— ๋ฒ„์ „ ์ ‘๋ฏธ์‚ฌ ๋ถ™์—ฌ์„œ 12์—ด ์ค€๋น„
333
- df_base = df_base.add_suffix(f'_{base_ver}')
334
- df_comp = df_comp.add_suffix(f'_{comp_ver}')
335
-
336
- # 4. Anchor Column์„ ๊ธฐ์ค€์œผ๋กœ JOIN (์ด๊ฒŒ 6+6 ํ•ต์‹ฌ)
337
- final_df = pd.merge(
338
- df_base, df_comp,
339
- left_on=f"{anchor_col}_{base_ver}",
340
- right_on=f"{anchor_col}_{comp_ver}",
341
- how='outer'
342
- )
343
-
344
- return final_df
345
 
346
- # ๋น„๊ต ์กฐํšŒ
347
  if all([base_std, base_ver, base_cat, comp_std, comp_ver, comp_cat]):
348
  df_base = fetch_database_records(base_std, base_ver, base_cat)
349
  df_comp = fetch_database_records(comp_std, comp_ver, comp_cat)
350
 
351
  if "Error" in df_base.columns: return df_base
352
  if "Error" in df_comp.columns: return df_comp
353
- if 'section' not in df_base.columns or 'section' not in df_comp.columns:
354
- return pd.DataFrame({"Error": ["ํ•ด๋‹น ๋ฐ์ดํ„ฐ์— 'section' ์ปฌ๋Ÿผ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."]})
355
 
356
- df_base['merge_key'] = df_base['section'].astype(str).str.replace(" ", "")
357
- df_comp['merge_key'] = df_comp['section'].astype(str).str.replace(" ", "")
358
 
359
- df_b = df_base[['merge_key', 'section', 'description']].rename(columns={'section': 'sec_b', 'description': 'desc_b'})
360
- df_c = df_comp[['merge_key', 'section', 'description']].rename(columns={'section': 'sec_c', 'description': 'desc_c'})
361
 
362
- conn_map = sqlite3.connect(os.path.join(UPLOAD_DIR, "mapping.db"))
363
-
364
- query_fw = "SELECT Base_section, Comp_section FROM Mapping_table WHERE TRIM(Base_std)=? AND TRIM(Base_ver)=? AND TRIM(Comp_std)=? AND TRIM(Comp_ver)=?"
365
- df_fw = pd.read_sql(query_fw, conn_map, params=[base_std.strip(), base_ver.strip(), comp_std.strip(), comp_ver.strip()])
366
 
367
- query_rv = "SELECT Comp_section AS Base_section, Base_section AS Comp_section FROM Mapping_table WHERE TRIM(Comp_std)=? AND TRIM(Comp_ver)=? AND TRIM(Base_std)=? AND TRIM(Base_ver)=?"
368
- df_rv = pd.read_sql(query_rv, conn_map, params=[base_std.strip(), base_ver.strip(), comp_std.strip(), comp_ver.strip()])
369
-
370
- conn_map.close()
371
-
372
- df_mapping = pd.concat([df_fw, df_rv], ignore_index=True)
373
-
374
- if not df_mapping.empty:
375
- df_mapping['Base_section'] = df_mapping['Base_section'].astype(str).str.replace('\n', ',').str.replace('\r', '')
376
- df_mapping['Comp_section'] = df_mapping['Comp_section'].astype(str).str.replace('\n', ',').str.replace('\r', '')
377
-
378
- df_mapping['Base_section'] = df_mapping['Base_section'].str.split(',')
379
- df_mapping['Comp_section'] = df_mapping['Comp_section'].str.split(',')
380
-
381
- df_mapping = df_mapping.explode('Base_section').explode('Comp_section')
382
-
383
- df_mapping['Base_section'] = df_mapping['Base_section'].astype(str).str.strip().str.replace(" ", "")
384
- df_mapping['Comp_section'] = df_mapping['Comp_section'].astype(str).str.strip().str.replace(" ", "")
385
-
386
- df_mapping = df_mapping[(df_mapping['Base_section'] != '') & (df_mapping['Base_section'] != 'nan')]
387
- df_mapping = df_mapping[(df_mapping['Comp_section'] != '') & (df_mapping['Comp_section'] != 'nan')]
388
- df_mapping = df_mapping.drop_duplicates()
389
- else:
390
- df_mapping = pd.DataFrame(columns=['Base_section', 'Comp_section'])
391
-
392
- explicit_b = set(df_mapping['Base_section'].dropna())
393
- explicit_c = set(df_mapping['Comp_section'].dropna())
394
-
395
- unmapped_b = set(df_b['merge_key']) - explicit_b
396
- unmapped_c = set(df_c['merge_key']) - explicit_c
397
- implicit_keys = unmapped_b.intersection(unmapped_c)
398
-
399
- df_implicit = pd.DataFrame({
400
- 'Base_section': list(implicit_keys),
401
- 'Comp_section': list(implicit_keys)
402
- })
403
-
404
- bridge = pd.concat([df_mapping, df_implicit], ignore_index=True)
405
-
406
- df_b_clean = df_b.rename(columns={'merge_key': 'Base_section'})
407
- df_c_clean = df_c.rename(columns={'merge_key': 'Comp_section'})
408
-
409
- df_b_clean['base_idx'] = range(len(df_b_clean))
410
- df_c_clean['comp_idx'] = range(len(df_c_clean))
411
-
412
- merged = pd.merge(bridge, df_b_clean, on='Base_section', how='outer')
413
- merged = pd.merge(merged, df_c_clean, on='Comp_section', how='outer')
414
-
415
- merged['base_idx'] = merged['base_idx'].fillna(float('inf'))
416
- merged['comp_idx'] = merged['comp_idx'].fillna(float('inf'))
417
-
418
- merged = merged.sort_values(['base_idx', 'comp_idx']).drop(columns=['base_idx', 'comp_idx'])
419
-
420
- result_rows = []
421
- for _, row in merged.iterrows():
422
- sec_b = "" if pd.isna(row.get('sec_b')) else str(row['sec_b'])
423
- sec_c = "" if pd.isna(row.get('sec_c')) else str(row['sec_c'])
424
- desc_b = "" if pd.isna(row.get('desc_b')) else str(row['desc_b'])
425
- desc_c = "" if pd.isna(row.get('desc_c')) else str(row['desc_c'])
426
-
427
- if desc_b and not desc_c:
428
- result_rows.append({f"Section_{base_ver}": sec_b, f"Description_{base_ver}": desc_b, f"Section_{comp_ver}": "", f"Description_{comp_ver}": ""})
429
- elif not desc_b and desc_c:
430
- result_rows.append({f"Section_{base_ver}": "", f"Description_{base_ver}": "", f"Section_{comp_ver}": sec_c, f"Description_{comp_ver}": desc_c})
431
- elif desc_b and desc_c:
432
- if "<img" in desc_b or "<img" in desc_c or desc_b == desc_c:
433
- b_final, c_final = desc_b, desc_c
434
- else:
435
- b_final, c_final = generate_html_diff(desc_b, desc_c)
436
-
437
- result_rows.append({f"Section_{base_ver}": sec_b, f"Description_{base_ver}": b_final, f"Section_{comp_ver}": sec_c, f"Description_{comp_ver}": c_final})
438
-
439
- final_df = pd.DataFrame(result_rows)
440
-
441
- base_sec_col = f"Section_{base_ver}"
442
- base_desc_col = f"Description_{base_ver}"
443
-
444
- duplicate_mask = final_df.duplicated(subset=[base_sec_col], keep='first') & (final_df[base_sec_col] != "")
445
-
446
- final_df.loc[duplicate_mask, base_sec_col] = ""
447
- final_df.loc[duplicate_mask, base_desc_col] = ""
448
 
449
  return final_df
450
 
451
- return pd.DataFrame({"Info": ["์กฐํšŒ ์กฐ๊ฑด์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค."]})
452
 
453
  except Exception as e:
 
454
  traceback.print_exc()
455
- return pd.DataFrame({"Error": [f"์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"]})
456
 
457
 
458
  # ==========================================
@@ -513,33 +412,14 @@ with gr.Blocks() as demo:
513
  css = """
514
  table {
515
  table-layout: fixed !important;
516
- width: 100% !important;
 
517
  }
518
 
519
- /* 2์ปฌ๋Ÿผ */
520
- table th:nth-last-child(2):first-child, table td:nth-last-child(2):first-child { width: 15% !important; }
521
- table th:nth-last-child(1), table td:nth-last-child(1) { width: 85% !important; }
522
-
523
- /* 4์ปฌ๋Ÿผ */
524
- table th:nth-child(1):nth-last-child(4), table td:nth-child(1):nth-last-child(4) { width: 7% !important; }
525
- table th:nth-child(2):nth-last-child(3), table td:nth-child(2):nth-last-child(3) { width: 43% !important; }
526
- table th:nth-child(3):nth-last-child(2), table td:nth-child(3):nth-last-child(2) { width: 7% !important; }
527
- table th:nth-child(4):nth-last-child(1), table td:nth-child(4):nth-last-child(1) { width: 43% !important; }
528
-
529
- /* 5์ปฌ๋Ÿผ */
530
- table th:nth-child(1):nth-last-child(5), table td:nth-child(1):nth-last-child(5) { width: 15% !important; }
531
- table th:nth-child(2):nth-last-child(4), table td:nth-child(2):nth-last-child(4) { width: 10% !important; }
532
- table th:nth-child(3):nth-last-child(3), table td:nth-child(3):nth-last-child(3) { width: 30% !important; }
533
- table th:nth-child(4):nth-last-child(2), table td:nth-child(4):nth-last-child(2) { width: 10% !important; }
534
- table th:nth-child(5):nth-last-child(1), table td:nth-child(5):nth-last-child(1) { width: 35% !important; }
535
-
536
- /* 6์ปฌ๋Ÿผ */
537
- table th:nth-child(1):nth-last-child(6), table td:nth-child(1):nth-last-child(6) { width: 8% !important; }
538
- table th:nth-child(2):nth-last-child(5), table td:nth-child(2):nth-last-child(5) { width: 25% !important; }
539
- table th:nth-child(3):nth-last-child(4), table td:nth-child(3):nth-last-child(4) { width: 8% !important; }
540
- table th:nth-child(4):nth-last-child(3), table td:nth-child(4):nth-last-child(3) { width: 25% !important; }
541
- table th:nth-child(5):nth-last-child(2), table td:nth-child(5):nth-last-child(2) { width: 8% !important; }
542
- table th:nth-child(6):nth-last-child(1), table td:nth-child(6):nth-last-child(1) { width: 26% !important; }
543
 
544
  /* ๊ธฐ๋ณธ ํ…Œ์ด๋ธ” & ์Šคํฌ๋กค ์„ค์ • */
545
  thead th {
@@ -552,6 +432,8 @@ thead th {
552
  .dataframe {
553
  max-height: none !important;
554
  overflow-y: visible !important;
 
 
555
  }
556
  .dataframe > div {
557
  max-height: none !important;
 
245
  conn = sqlite3.connect(db_path)
246
  conn.text_factory = decode_sqlite_text
247
 
 
 
248
  table_type = "Main" if selection == "ALL" or (selection and selection[0].isdigit() and "." in selection) else selection
 
 
249
  anchor_col, display_setting = get_table_config(table_type)
250
 
251
  tables = pd.read_sql("SELECT name FROM sqlite_master WHERE type='table';", conn)['name'].tolist()
 
265
  target_table = t
266
  break
267
 
 
268
  if target_table and target_table != main_table:
 
269
  df = pd.read_sql(f"SELECT * FROM [{target_table}]", conn)
270
  else:
 
271
  cursor = conn.cursor()
272
  cursor.execute(f"PRAGMA table_info([{main_table}])")
273
  cols_info = cursor.fetchall()
 
290
 
291
  df = pd.DataFrame(cursor.fetchall(), columns=cols)
292
 
 
293
  df = df.drop(columns=[c for c in df.columns if c.lower() == "version"], errors="ignore")
294
 
295
  if display_setting:
296
  cols_to_show = [c.strip() for c in display_setting.split(',')]
 
297
  if anchor_col in df.columns and anchor_col not in cols_to_show:
298
  cols_to_show.insert(0, anchor_col)
 
299
  df = df[[c for c in cols_to_show if c in df.columns]]
300
 
 
301
  for col in df.columns:
302
  df[col] = df[col].apply(convert_blob_to_html_img)
303
 
 
306
 
307
  except Exception as e:
308
  import traceback
309
+ traceback.print_exc()
310
  return pd.DataFrame({"Error": [str(e)]})
311
 
312
  def execute_unified_search(base_std, base_ver, base_cat, comp_std, comp_ver, comp_cat):
313
+ try:
314
+ is_main = base_cat == "ALL" or (base_cat and base_cat[0].isdigit())
315
+ table_type = "Main" if is_main else base_cat
316
+ anchor_col, _ = get_table_config(table_type)
317
+
318
+ # ๋‹จ์ผ ์กฐํšŒ (๋น„๊ต๋ฒ•๊ทœ ๋ฏธ์„ ํƒ)
319
+ if base_std and base_ver and base_cat and (not comp_std or not comp_ver or not comp_cat):
320
+ return fetch_database_records(base_std, base_ver, base_cat)
 
 
 
 
 
 
 
 
 
 
 
 
 
321
 
322
+ # ๋น„๊ต ์กฐํšŒ (6+6 ๋ณ‘ํ•ฉ ๋กœ์ง)
323
  if all([base_std, base_ver, base_cat, comp_std, comp_ver, comp_cat]):
324
  df_base = fetch_database_records(base_std, base_ver, base_cat)
325
  df_comp = fetch_database_records(comp_std, comp_ver, comp_cat)
326
 
327
  if "Error" in df_base.columns: return df_base
328
  if "Error" in df_comp.columns: return df_comp
 
 
329
 
330
+ df_base = df_base.add_suffix(f'_{base_ver}')
331
+ df_comp = df_comp.add_suffix(f'_{comp_ver}')
332
 
333
+ base_anchor = f"{anchor_col}_{base_ver}"
334
+ comp_anchor = f"{anchor_col}_{comp_ver}"
335
 
336
+ if base_anchor not in df_base.columns or comp_anchor not in df_comp.columns:
337
+ return pd.DataFrame({"Error": [f"๊ธฐ์ค€ ์—ด '{anchor_col}'์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์„ค์ •์„ ํ™•์ธํ•˜์„ธ์š”."]})
 
 
338
 
339
+ final_df = pd.merge(
340
+ df_base,
341
+ df_comp,
342
+ left_on=base_anchor,
343
+ right_on=comp_anchor,
344
+ how='outer'
345
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
 
347
  return final_df
348
 
349
+ return pd.DataFrame({"Info": ["์กฐํšŒ ์กฐ๊ฑด์„ ๋ชจ๋‘ ์„ ํƒํ•ด ์ฃผ์„ธ์š”."] })
350
 
351
  except Exception as e:
352
+ import traceback
353
  traceback.print_exc()
354
+ return pd.DataFrame({"Error": [f"๋น„๊ต ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"]})
355
 
356
 
357
  # ==========================================
 
412
  css = """
413
  table {
414
  table-layout: fixed !important;
415
+ width: auto !important;
416
+ min-width: 100%;
417
  }
418
 
419
+ /* ํ…Œ์ด๋ธ”์˜ ์—ด ๋„ˆ๋น„๋ฅผ ๊ท ๋“ฑํ•˜๊ฒŒ ๋ถ„๋ฐฐ (๊ฐ€๋ณ€ ์—ด ๋Œ€๋น„) */
420
+ th, td {
421
+ min-width: 150px;
422
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
423
 
424
  /* ๊ธฐ๋ณธ ํ…Œ์ด๋ธ” & ์Šคํฌ๋กค ์„ค์ • */
425
  thead th {
 
432
  .dataframe {
433
  max-height: none !important;
434
  overflow-y: visible !important;
435
+ overflow-x: auto !important; /* ๊ฐ€๋กœ ์Šคํฌ๋กค ํ™œ์„ฑํ™” */
436
+ display: block;
437
  }
438
  .dataframe > div {
439
  max-height: none !important;