QIDNLF commited on
Commit
1de5296
ยท
verified ยท
1 Parent(s): 83872bd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +57 -111
app.py CHANGED
@@ -316,8 +316,18 @@ def fetch_database_records(standard, version, selection, table_type):
316
 
317
  def execute_unified_search(base_std, base_ver, base_cat, comp_std, comp_ver, comp_cat):
318
  try:
319
- is_main = base_cat == "ALL" or (base_cat and base_cat[0].isdigit() and "." in base_cat)
320
- table_type = "Main" if is_main else base_cat
 
 
 
 
 
 
 
 
 
 
321
 
322
  # ์‹œ๊ฐ์  ์ค‘๋ณต ์ œ๊ฑฐ (ํญํฌ์ˆ˜ ๋ฐฉ์‹)
323
  def apply_visual_merge(df, cols):
@@ -326,176 +336,112 @@ def execute_unified_search(base_std, base_ver, base_cat, comp_std, comp_ver, com
326
  for col in cols:
327
  if col in df.columns:
328
  curr = df[col].astype(str).str.strip()
329
- match = (curr == curr.shift(1)) & (~curr.isin(["", "nan", "None"]))
330
  is_dup = is_dup & match
331
- df.loc[is_dup, col] = ""
332
  return df
333
 
334
- # [ํ•ต์‹ฌ ์ถ”๊ฐ€] Code์™€ Description ์ปฌ๋Ÿผ์„ ์‹œ๊ฐ์ ์œผ๋กœ ์œ„์•„๋ž˜ ๋ณ‘ํ•ฉ
335
  def combine_code_desc(df):
336
  cols = list(df.columns)
337
  new_cols = []
338
  processed = set()
339
-
340
  for col in cols:
341
  if col in processed: continue
342
-
343
- # _Code ์™€ _Description ์ง๊ฟ ์ฐพ๊ธฐ
344
  if "_Code" in col:
345
  desc_col = col.replace("_Code", "_Description")
346
  if desc_col in cols:
347
  new_col_name = col.replace("_Code", "")
348
-
349
  def combine_cells(row):
350
- c = str(row[col]).strip()
351
- d = str(row[desc_col]).strip()
352
- if c in ["nan", "None", ""]: return d
353
- if d in ["nan", "None", ""]: return f"<span style='font-weight:bold; color:#1a73e8;'>{c}</span>"
354
-
355
- # Code๋Š” ํŒŒ๋ž€์ƒ‰ ๋ณผ๋“œ์ฒด๋กœ, Description์€ ๋ฐ”๋กœ ์•„๋žซ์ค„์— ์ถœ๋ ฅ
356
  return f"<span style='font-weight:bold; color:#1a73e8; display:block; margin-bottom:4px;'>{c}</span>{d}"
357
-
358
  df[new_col_name] = df.apply(combine_cells, axis=1)
359
  new_cols.append(new_col_name)
360
- processed.add(col)
361
- processed.add(desc_col)
362
- else:
363
- new_cols.append(col)
364
  elif "_Description" in col:
365
- code_col = col.replace("_Description", "_Code")
366
- if code_col not in cols:
367
- new_cols.append(col)
368
- else:
369
- new_cols.append(col)
370
-
371
  return df[new_cols]
372
 
373
- # ----------------------------------------
374
  # 1. ๋‹จ์ผ ์กฐํšŒ
375
- # ----------------------------------------
376
  if base_std and base_ver and base_cat and (not comp_std or not comp_ver or not comp_cat):
377
- df, _ = fetch_database_records(base_std, base_ver, base_cat, table_type)
378
- if "Error" in df.columns or "Info" in df.columns: return df
379
-
380
- df = combine_code_desc(df) # ๊ฒฐํ•ฉ ์ ์šฉ
381
  return apply_visual_merge(df, df.columns)
382
 
383
- # ----------------------------------------
384
- # 2. ๋น„๊ต ์กฐํšŒ
385
- # ----------------------------------------
386
  if all([base_std, base_ver, base_cat, comp_std, comp_ver, comp_cat]):
387
- df_base, real_anchors_b = fetch_database_records(base_std, base_ver, base_cat, table_type)
388
- df_comp, real_anchors_c = fetch_database_records(comp_std, comp_ver, comp_cat, table_type)
389
 
390
  if "Error" in df_base.columns: return df_base
391
  if "Error" in df_comp.columns: return df_comp
392
 
393
- for ra in real_anchors_b:
394
- if ra not in df_base.columns: return pd.DataFrame({"Error": [f"๊ธฐ์ค€ ์—ด '{ra}'์ด ๋ฐ์ดํ„ฐ์— ์—†์Šต๋‹ˆ๋‹ค."]})
395
- for ra in real_anchors_c:
396
- if ra not in df_comp.columns: return pd.DataFrame({"Error": [f"๋น„๊ต ์—ด '{ra}'์ด ๋ฐ์ดํ„ฐ์— ์—†์Šต๋‹ˆ๋‹ค."]})
397
-
398
  df_base['merge_key'] = df_base[real_anchors_b].apply(lambda row: '-'.join(row.values.astype(str)), axis=1).str.replace(" ", "")
399
  df_comp['merge_key'] = df_comp[real_anchors_c].apply(lambda row: '-'.join(row.values.astype(str)), axis=1).str.replace(" ", "")
400
 
 
401
  conn_map = sqlite3.connect(os.path.join(UPLOAD_DIR, "mapping.db"))
402
- 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)=?"
403
- df_fw = pd.read_sql(query_fw, conn_map, params=[base_std.strip(), base_ver.strip(), comp_std.strip(), comp_ver.strip()])
404
-
405
- 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)=?"
406
- df_rv = pd.read_sql(query_rv, conn_map, params=[base_std.strip(), base_ver.strip(), comp_std.strip(), comp_ver.strip()])
407
  conn_map.close()
408
 
409
  df_mapping = pd.concat([df_fw, df_rv], ignore_index=True)
410
-
411
  if not df_mapping.empty:
412
- df_mapping['Base_section'] = df_mapping['Base_section'].astype(str).str.replace('\n', ',').str.replace('\r', '')
413
- df_mapping['Comp_section'] = df_mapping['Comp_section'].astype(str).str.replace('\n', ',').str.replace('\r', '')
414
- df_mapping['Base_section'] = df_mapping['Base_section'].str.split(',')
415
- df_mapping['Comp_section'] = df_mapping['Comp_section'].str.split(',')
416
  df_mapping = df_mapping.explode('Base_section').explode('Comp_section')
417
- df_mapping['Base_section'] = df_mapping['Base_section'].astype(str).str.strip().str.replace(" ", "")
418
- df_mapping['Comp_section'] = df_mapping['Comp_section'].astype(str).str.strip().str.replace(" ", "")
419
- df_mapping = df_mapping[(df_mapping['Base_section'] != '') & (df_mapping['Base_section'] != 'nan')]
420
- df_mapping = df_mapping[(df_mapping['Comp_section'] != '') & (df_mapping['Comp_section'] != 'nan')]
421
- df_mapping = df_mapping.drop_duplicates()
422
  else:
423
  df_mapping = pd.DataFrame(columns=['Base_section', 'Comp_section'])
424
 
425
- explicit_b = set(df_mapping['Base_section'].dropna())
426
- explicit_c = set(df_mapping['Comp_section'].dropna())
427
-
428
- unmapped_b = set(df_base['merge_key']) - explicit_b
429
- unmapped_c = set(df_comp['merge_key']) - explicit_c
430
- implicit_keys = unmapped_b.intersection(unmapped_c)
431
-
432
- df_implicit = pd.DataFrame({'Base_section': list(implicit_keys), 'Comp_section': list(implicit_keys)})
433
- bridge = pd.concat([df_mapping, df_implicit], ignore_index=True)
434
 
 
435
  rename_b = {c: f"{c}_{base_ver}" for c in df_base.columns if c != 'merge_key'}
436
  df_base = df_base.rename(columns=rename_b)
437
-
438
  rename_c = {c: f"{c}_{comp_ver}" for c in df_comp.columns if c != 'merge_key'}
439
  df_comp = df_comp.rename(columns=rename_c)
440
 
441
- df_base['base_idx'] = range(len(df_base))
442
- df_comp['comp_idx'] = range(len(df_comp))
443
-
444
  merged = pd.merge(bridge, df_base, left_on='Base_section', right_on='merge_key', how='outer')
445
  merged = pd.merge(merged, df_comp, left_on='Comp_section', right_on='merge_key', how='outer')
446
-
447
- merged['base_idx'] = merged['base_idx'].fillna(float('inf'))
448
- merged['comp_idx'] = merged['comp_idx'].fillna(float('inf'))
449
  merged = merged.sort_values(['base_idx', 'comp_idx'])
450
 
 
451
  result_rows = []
452
- b_cols_renamed = list(rename_b.values())
453
- c_cols_renamed = list(rename_c.values())
454
-
455
  for _, row in merged.iterrows():
456
  row_dict = {}
457
- has_b = not pd.isna(row.get('base_idx')) and row.get('base_idx') != float('inf')
458
- has_c = not pd.isna(row.get('comp_idx')) and row.get('comp_idx') != float('inf')
459
-
460
- for c in b_cols_renamed:
461
- row_dict[c] = str(row.get(c)) if has_b and not pd.isna(row.get(c)) else ""
462
- for c in c_cols_renamed:
463
- row_dict[c] = str(row.get(c)) if has_c and not pd.isna(row.get(c)) else ""
464
-
465
- # Diff ์ฒ˜๋ฆฌ (Description ์ง๊ฟ ์ฐพ์•„์„œ ํ•˜์ด๋ผ์ดํŒ…)
466
  if has_b and has_c:
467
  for orig_col in rename_b.keys():
468
- if 'description' in orig_col.lower():
469
- b_col_name = rename_b[orig_col]
470
- c_col_name = rename_c.get(orig_col)
471
-
472
- if c_col_name and c_col_name in row_dict:
473
- b_val, c_val = row_dict[b_col_name], row_dict[c_col_name]
474
- if b_val and c_val and "<img" not in b_val and "<img" not in c_val and b_val != c_val:
475
- row_dict[b_col_name], row_dict[c_col_name] = generate_html_diff(b_val, c_val)
476
-
477
  result_rows.append(row_dict)
478
 
479
- final_df = pd.DataFrame(result_rows)
480
-
481
- # [ํ•ต์‹ฌ] Diff ์ฒ˜๋ฆฌ๋œ ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„์˜ Code์™€ Desc๋ฅผ ํ•œ ์—ด๋กœ ๋ณ‘ํ•ฉ!
482
- final_df = combine_code_desc(final_df)
483
-
484
- # ๋ณ€๊ฒฝ๋œ ์ปฌ๋Ÿผ๋ช… ๊ธฐ์ค€์œผ๋กœ ์ขŒ/์šฐ ์‹œ๊ฐ์  ๋ณ‘ํ•ฉ(Cascading Blanking) ๋”ฐ๋กœ ์ ์šฉ
485
- b_cols_final = [c for c in final_df.columns if c.endswith(f"_{base_ver}")]
486
- c_cols_final = [c for c in final_df.columns if c.endswith(f"_{comp_ver}")]
487
-
488
- final_df = apply_visual_merge(final_df, b_cols_final)
489
- final_df = apply_visual_merge(final_df, c_cols_final)
490
-
491
- return final_df
492
-
493
- return pd.DataFrame({"Info": ["์กฐํšŒ ์กฐ๊ฑด์„ ๋ชจ๋‘ ์„ ํƒํ•ด ์ฃผ์„ธ์š”."] })
494
 
 
495
  except Exception as e:
496
- import traceback
497
  traceback.print_exc()
498
- return pd.DataFrame({"Error": [f"๋น„๊ต ์กฐํšŒ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"]})
499
 
500
 
501
  # ==========================================
 
316
 
317
  def execute_unified_search(base_std, base_ver, base_cat, comp_std, comp_ver, comp_cat):
318
  try:
319
+ # [ํ•ต์‹ฌ ์ˆ˜์ •] ์™ผ์ชฝ(Base)๊ณผ ์˜ค๋ฅธ์ชฝ(Comp)์˜ ํƒ€์ž…์„ ๊ฐ๊ฐ ๋…๋ฆฝ์ ์œผ๋กœ ํŒ๋‹จ
320
+ def get_type_by_cat(cat):
321
+ if not cat: return "Main"
322
+ is_main = cat == "ALL" or (cat[0].isdigit() and "." in cat)
323
+ return "Main" if is_main else cat
324
+
325
+ type_b = get_type_by_cat(base_cat)
326
+ type_c = get_type_by_cat(comp_cat)
327
+
328
+ # ๊ฐ๊ฐ์˜ ๊ธฐ์ค€ ์—ด(Anchor) ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ด
329
+ anchor_col_b, _ = get_table_config(type_b)
330
+ anchor_col_c, _ = get_table_config(type_c)
331
 
332
  # ์‹œ๊ฐ์  ์ค‘๋ณต ์ œ๊ฑฐ (ํญํฌ์ˆ˜ ๋ฐฉ์‹)
333
  def apply_visual_merge(df, cols):
 
336
  for col in cols:
337
  if col in df.columns:
338
  curr = df[col].astype(str).str.strip()
339
+ match = (curr == curr.shift(1)) & (~curr.isin(["", "nan", "None", "&nbsp;"]))
340
  is_dup = is_dup & match
341
+ df.loc[is_dup, col] = "&nbsp;"
342
  return df
343
 
344
+ # Code/Description ๊ฒฐํ•ฉ ๋กœ์ง
345
  def combine_code_desc(df):
346
  cols = list(df.columns)
347
  new_cols = []
348
  processed = set()
 
349
  for col in cols:
350
  if col in processed: continue
 
 
351
  if "_Code" in col:
352
  desc_col = col.replace("_Code", "_Description")
353
  if desc_col in cols:
354
  new_col_name = col.replace("_Code", "")
 
355
  def combine_cells(row):
356
+ c, d = str(row[col]).strip(), str(row[desc_col]).strip()
357
+ if c in ["nan", "None", "", "&nbsp;"]: return d
358
+ if d in ["nan", "None", "", "&nbsp;"]: return f"<span style='font-weight:bold; color:#1a73e8;'>{c}</span>"
 
 
 
359
  return f"<span style='font-weight:bold; color:#1a73e8; display:block; margin-bottom:4px;'>{c}</span>{d}"
 
360
  df[new_col_name] = df.apply(combine_cells, axis=1)
361
  new_cols.append(new_col_name)
362
+ processed.update([col, desc_col])
363
+ else: new_cols.append(col)
 
 
364
  elif "_Description" in col:
365
+ if col.replace("_Description", "_Code") not in cols: new_cols.append(col)
366
+ else: new_cols.append(col)
 
 
 
 
367
  return df[new_cols]
368
 
 
369
  # 1. ๋‹จ์ผ ์กฐํšŒ
 
370
  if base_std and base_ver and base_cat and (not comp_std or not comp_ver or not comp_cat):
371
+ df, _ = fetch_database_records(base_std, base_ver, base_cat, type_b)
372
+ if "Error" in df.columns: return df
373
+ df = combine_code_desc(df)
 
374
  return apply_visual_merge(df, df.columns)
375
 
376
+ # 2. ๋น„๊ต ์กฐํšŒ (์„œ๋กœ ๋‹ค๋ฅธ ํƒ€์ž… ์ง€์›)
 
 
377
  if all([base_std, base_ver, base_cat, comp_std, comp_ver, comp_cat]):
378
+ df_base, real_anchors_b = fetch_database_records(base_std, base_ver, base_cat, type_b)
379
+ df_comp, real_anchors_c = fetch_database_records(comp_std, comp_ver, comp_cat, type_c)
380
 
381
  if "Error" in df_base.columns: return df_base
382
  if "Error" in df_comp.columns: return df_comp
383
 
384
+ # ๊ฐ์ž์˜ ์•ต์ปค ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ merge_key ์ƒ์„ฑ
 
 
 
 
385
  df_base['merge_key'] = df_base[real_anchors_b].apply(lambda row: '-'.join(row.values.astype(str)), axis=1).str.replace(" ", "")
386
  df_comp['merge_key'] = df_comp[real_anchors_c].apply(lambda row: '-'.join(row.values.astype(str)), axis=1).str.replace(" ", "")
387
 
388
+ # ๋งคํ•‘ ๋ธŒ๋ฆฟ์ง€ ๋กœ๋“œ
389
  conn_map = sqlite3.connect(os.path.join(UPLOAD_DIR, "mapping.db"))
390
+ q = "SELECT Base_section, Comp_section FROM Mapping_table WHERE TRIM(Base_std)=? AND TRIM(Base_ver)=? AND TRIM(Comp_std)=? AND TRIM(Comp_ver)=?"
391
+ df_fw = pd.read_sql(q, conn_map, params=[base_std.strip(), base_ver.strip(), comp_std.strip(), comp_ver.strip()])
392
+ q_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)=?"
393
+ df_rv = pd.read_sql(q_rv, conn_map, params=[base_std.strip(), base_ver.strip(), comp_std.strip(), comp_ver.strip()])
 
394
  conn_map.close()
395
 
396
  df_mapping = pd.concat([df_fw, df_rv], ignore_index=True)
 
397
  if not df_mapping.empty:
398
+ df_mapping['Base_section'] = df_mapping['Base_section'].astype(str).str.replace('\n', ',').str.split(',')
399
+ df_mapping['Comp_section'] = df_mapping['Comp_section'].astype(str).str.replace('\n', ',').str.split(',')
 
 
400
  df_mapping = df_mapping.explode('Base_section').explode('Comp_section')
401
+ df_mapping[['Base_section', 'Comp_section']] = df_mapping[['Base_section', 'Comp_section']].apply(lambda x: x.str.strip().str.replace(" ", ""))
402
+ df_mapping = df_mapping.dropna().drop_duplicates()
 
 
 
403
  else:
404
  df_mapping = pd.DataFrame(columns=['Base_section', 'Comp_section'])
405
 
406
+ # ์•”์‹œ์  ๋งคํ•‘ (ํ‚ค๊ฐ€ ์™„์ „ํžˆ ๋˜‘๊ฐ™์€ ๊ฒฝ์šฐ)
407
+ implicit = pd.DataFrame({'Base_section': list(set(df_base['merge_key']) & set(df_comp['merge_key'])),
408
+ 'Comp_section': list(set(df_base['merge_key']) & set(df_comp['merge_key']))})
409
+ bridge = pd.concat([df_mapping, implicit], ignore_index=True).drop_duplicates()
 
 
 
 
 
410
 
411
+ # ์ปฌ๋Ÿผ๋ช… ์ •๋ฆฌ ๋ฐ ๋ณ‘ํ•ฉ
412
  rename_b = {c: f"{c}_{base_ver}" for c in df_base.columns if c != 'merge_key'}
413
  df_base = df_base.rename(columns=rename_b)
 
414
  rename_c = {c: f"{c}_{comp_ver}" for c in df_comp.columns if c != 'merge_key'}
415
  df_comp = df_comp.rename(columns=rename_c)
416
 
417
+ df_base['base_idx'], df_comp['comp_idx'] = range(len(df_base)), range(len(df_comp))
 
 
418
  merged = pd.merge(bridge, df_base, left_on='Base_section', right_on='merge_key', how='outer')
419
  merged = pd.merge(merged, df_comp, left_on='Comp_section', right_on='merge_key', how='outer')
 
 
 
420
  merged = merged.sort_values(['base_idx', 'comp_idx'])
421
 
422
+ # ๊ฒฐ๊ณผ ํ–‰ ์กฐ๋ฆฝ ๋ฐ Diff
423
  result_rows = []
 
 
 
424
  for _, row in merged.iterrows():
425
  row_dict = {}
426
+ has_b, has_c = not pd.isna(row.get('base_idx')), not pd.isna(row.get('comp_idx'))
427
+ for c in rename_b.values(): row_dict[c] = str(row[c]) if has_b and not pd.isna(row[c]) else ""
428
+ for c in rename_c.values(): row_dict[c] = str(row[c]) if has_c and not pd.isna(row[c]) else ""
429
+
 
 
 
 
 
430
  if has_b and has_c:
431
  for orig_col in rename_b.keys():
432
+ if 'description' in orig_col.lower() and rename_c.get(orig_col) in row_dict:
433
+ b_v, c_v = row_dict[rename_b[orig_col]], row_dict[rename_c[orig_col]]
434
+ if b_v and c_v and "<img" not in b_v and "<img" not in c_v and b_v != c_v:
435
+ row_dict[rename_b[orig_col]], row_dict[rename_c[orig_col]] = generate_html_diff(b_v, c_v)
 
 
 
 
 
436
  result_rows.append(row_dict)
437
 
438
+ final_df = combine_code_desc(pd.DataFrame(result_rows))
439
+ return apply_visual_merge(final_df, final_df.columns)
 
 
 
 
 
 
 
 
 
 
 
 
 
440
 
441
+ return pd.DataFrame({"Info": ["์กฐ๊ฑด์„ ์„ ํƒํ•˜์„ธ์š”."]})
442
  except Exception as e:
 
443
  traceback.print_exc()
444
+ return pd.DataFrame({"Error": [str(e)]})
445
 
446
 
447
  # ==========================================