QIDNLF commited on
Commit
52f088b
·
verified ·
1 Parent(s): 1c20d9c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +105 -99
app.py CHANGED
@@ -3,85 +3,102 @@ import sqlite3
3
  import pandas as pd
4
  import os
5
  import re
6
- import base64 # 추가됨
7
 
8
  # 1️⃣ 저장소 설정
9
  UPLOAD_DIR = "uploaded_dbs"
10
  if not os.path.exists(UPLOAD_DIR):
11
-     os.makedirs(UPLOAD_DIR)
12
 
13
  db_registry = []
14
 
15
- # BLOB 데이터를 Base64 HTML 이미지 태그로 변환하는 함수
16
  def blob_to_base64_html(blob_data):
17
-     if blob_data is None:
18
-         return ""
19
-     try:
20
-         # 데이터가 이미 바이트 형태인지 확인 (b'\x89PNG' )
21
-         if isinstance(blob_data, bytes):
22
-             encoded_string = base64.b64encode(blob_data).decode('utf-8')
23
-             # 너비(width)는 원하시는 대로 조절하세요.
24
-             return f'<img src="data:image/png;base64,{encoded_string}" width="150" />'
25
-         return str(blob_data) # 바이트가 아니면 그냥 문자열로 반환
26
-     except:
27
-         return "[이미지 변환 에러]"
28
 
29
  def natural_sort_key(s):
30
-     if s is None: return []
31
-     return [int(text) if text.isdigit() else text.lower()
32
-             for text in re.split(r'(\d+)', str(s))]
33
 
34
  def refresh_registry_data():
35
-     global db_registry
36
-     db_registry = []
37
-     if not os.path.exists(UPLOAD_DIR): return []
38
-     db_files = [f for f in os.listdir(UPLOAD_DIR) if f.endswith(".db")]
39
-     for filename in db_files:
40
-         name_only = filename.replace(".db", "")
41
-         parts = name_only.split("_")
42
-         if len(parts) >= 2:
43
-             db_registry.append({
44
-                 "path": os.path.join(UPLOAD_DIR, filename),
45
-                 "standard": parts[0],
46
-                 "version": parts[1]
47
-             })
48
-     return sorted(list(set([db["standard"] for db in db_registry])))
49
 
50
  # 2️⃣ UI 업데이트 함수
51
  def on_load():
52
-     standards = refresh_registry_data()
53
-     return gr.Dropdown(choices=standards, value=None)
54
 
55
  def update_version_dd(standard):
56
-     if not standard: return gr.Dropdown(choices=[], value=None)
57
-     versions = sorted(list(set([db["version"] for db in db_registry if db["standard"] == standard])))
58
-     return gr.Dropdown(choices=versions, value=None)
59
 
60
  def update_category_dd(standard, version):
61
-     if not standard or not version: return gr.Dropdown(choices=[], value=None)
62
-     choices = ["ALL"]
63
-     try:
64
-         target_db = next(db for db in db_registry if db["standard"] == standard and db["version"] == version)
65
-         conn = sqlite3.connect(target_db["path"])
66
-         all_tables = pd.read_sql("SELECT name FROM sqlite_master WHERE type='table';", conn)['name'].tolist()
67
-         main_t = f"{standard}_{version}"
68
-         if main_t not in all_tables: main_t = all_tables[0]
69
-         
70
-         cols = pd.read_sql(f"PRAGMA table_info([{main_t}])", conn)['name'].tolist()
71
-         if 'chapter' in cols and 'category' in cols:
72
-             df_cat = pd.read_sql(f"SELECT DISTINCT chapter, category FROM [{main_t}]", conn)
73
-             cats = [f"{row['chapter']}.{row['category']}" for _, row in df_cat.iterrows()]
74
-             cats.sort(key=natural_sort_key)
75
-             choices.extend(cats)
76
-         
77
-         prefix = f"{standard}_{version}_"
78
-         sub_tables = [t.replace(prefix, "") for t in all_tables if t != main_t]
79
-         choices.extend(sorted(sub_tables))
80
-         conn.close()
81
-     except: pass
82
-     return gr.Dropdown(choices=choices, value=None)
83
-
84
- # 3️⃣ 데이터 조회 로직 (BLOB 처리 추가)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  def display_data(standard, version, selection):
86
  if not all([standard, version, selection]): return None
87
  try:
@@ -90,67 +107,56 @@ def display_data(standard, version, selection):
90
  all_tables = pd.read_sql("SELECT name FROM sqlite_master WHERE type='table';", conn)['name'].tolist()
91
 
92
  main_t = f"{standard}_{version}"
93
- if main_t not in all_tables: main_t = all_tables[0]
 
 
94
 
95
  is_sub_table = False
96
  if selection == "ALL":
97
- df = pd.read_sql(f"SELECT * FROM [{main_t}]", conn)
98
  elif "." in selection:
99
  ch, ca = selection.split('.', 1)
100
- df = pd.read_sql(f"SELECT * FROM [{main_t}] WHERE chapter=? AND category=?", conn, params=[ch, ca])
 
 
 
 
 
 
101
  else:
102
  is_sub_table = True
103
- actual_table = next((t for t in all_tables if t.endswith(selection)), selection)
104
- df = pd.read_sql(f"SELECT * FROM [{actual_table}]", conn)
105
  conn.close()
106
 
107
  if not df.empty:
108
- # 1. 먼저 BLOB(이미지) 데이터를 HTML로 변환
109
  for col in df.columns:
110
  df[col] = df[col].apply(blob_to_base64_html)
111
 
112
- # 2. 정렬 로직 적용
113
- sort_col = 'section' if 'section' in df.columns else df.columns[0]
114
- df['sort_key'] = df[sort_col].apply(natural_sort_key)
115
- df = df.sort_values(by='sort_key').drop(columns=['sort_key'])
116
-
117
- # 3. 💡 [열 필터링 로직]
118
  if not is_sub_table:
119
- # 기본적으로 보여줄 열 정의
120
  base_cols = [c for c in ['section', 'description'] if c in df.columns]
121
-
122
- # 만약 'image'나 'blob' 같은 다른 열에 이미지가 변환되어 들어갔다면 열도 포함
123
- image_cols = [
124
- c for c in df.columns
125
- if c not in base_cols and df[c].astype(str).str.contains('<img', na=False).any()
126
- ]
127
-
128
- # 최종적으로 section, description + 이미지 열만 표시
129
- df = df[base_cols + image_cols]
130
- else:
131
- # 부속 테이블(Table A 등)은 모든 열을 보여주되, 정렬용 임시 열만 제거
132
- df = df[[c for c in df.columns if not c.startswith('sort_')]]
133
 
134
  return df
135
  except Exception as e:
136
  return pd.DataFrame({"Error": [f"조회 실패: {str(e)}"]})
137
-
138
  # 4️⃣ UI 구성
139
- with gr.Blocks() as demo:
140
-     gr.Markdown("# 📜 Regulation Viewer (Image Support)")
141
 
142
-     with gr.Row():
143
-         standard_dd = gr.Dropdown(label="1. 법규 선택")
144
-         version_dd = gr.Dropdown(label="2. Version 선택")
145
-         category_dd = gr.Dropdown(label="3. Category / Table 선택")
146
 
147
-     # 💡 [중요] datatype="html"을 추가하여 <img> 태그가 이미지로 보이게 함
148
-     output_df = gr.Dataframe(wrap=True, interactive=False, datatype="html")
149
 
150
-     demo.load(on_load, None, standard_dd)
151
-     standard_dd.change(update_version_dd, standard_dd, version_dd)
152
-     version_dd.change(update_category_dd, [standard_dd, version_dd], category_dd)
153
-     category_dd.change(display_data, [standard_dd, version_dd, category_dd], output_df)
154
 
155
  if __name__ == "__main__":
156
-     demo.launch(theme=gr.themes.Soft())
 
3
  import pandas as pd
4
  import os
5
  import re
6
+ import base64
7
 
8
  # 1️⃣ 저장소 설정
9
  UPLOAD_DIR = "uploaded_dbs"
10
  if not os.path.exists(UPLOAD_DIR):
11
+ os.makedirs(UPLOAD_DIR)
12
 
13
  db_registry = []
14
 
15
+ # BLOB 데이터를 Base64 HTML 이미지 태그로 변환
16
  def blob_to_base64_html(blob_data):
17
+ if blob_data is None or pd.isna(blob_data):
18
+ return ""
19
+ try:
20
+ if isinstance(blob_data, (bytes, bytearray)):
21
+ encoded_string = base64.b64encode(blob_data).decode('utf-8')
22
+ return f'<img src="data:image/png;base64,{encoded_string}" width="200" height="auto" />'
23
+ return str(blob_data)
24
+ except:
25
+ return str(blob_data)
 
 
26
 
27
  def natural_sort_key(s):
28
+ if s is None: return []
29
+ return [int(text) if text.isdigit() else text.lower()
30
+ for text in re.split(r'(\d+)', str(s))]
31
 
32
  def refresh_registry_data():
33
+ global db_registry
34
+ db_registry = []
35
+ if not os.path.exists(UPLOAD_DIR): return []
36
+ db_files = [f for f in os.listdir(UPLOAD_DIR) if f.endswith(".db")]
37
+ for filename in db_files:
38
+ name_only = filename.replace(".db", "")
39
+ parts = name_only.split("_")
40
+ if len(parts) >= 2:
41
+ db_registry.append({
42
+ "path": os.path.join(UPLOAD_DIR, filename),
43
+ "standard": parts[0],
44
+ "version": parts[1]
45
+ })
46
+ return sorted(list(set([db["standard"] for db in db_registry])))
47
 
48
  # 2️⃣ UI 업데이트 함수
49
  def on_load():
50
+ standards = refresh_registry_data()
51
+ return gr.Dropdown(choices=standards, value=None)
52
 
53
  def update_version_dd(standard):
54
+ if not standard: return gr.Dropdown(choices=[], value=None)
55
+ versions = sorted(list(set([db["version"] for db in db_registry if db["standard"] == standard])))
56
+ return gr.Dropdown(choices=versions, value=None)
57
 
58
  def update_category_dd(standard, version):
59
+ if not standard or not version: return gr.Dropdown(choices=[], value=None)
60
+ choices = ["ALL"]
61
+ try:
62
+ target_db = next(db for db in db_registry if db["standard"] == standard and db["version"] == version)
63
+ conn = sqlite3.connect(target_db["path"])
64
+ all_tables = pd.read_sql("SELECT name FROM sqlite_master WHERE type='table';", conn)['name'].tolist()
65
+
66
+ main_t = f"{standard}_{version}"
67
+ if main_t not in all_tables:
68
+ candidates = [t for t in all_tables if standard.lower() in t.lower() and version.lower() in t.lower()]
69
+ main_t = candidates[0] if candidates else all_tables[0]
70
+
71
+ cols_info = pd.read_sql(f"PRAGMA table_info([{main_t}])", conn)
72
+ orig_cols = cols_info['name'].tolist()
73
+ lower_cols = [c.lower() for c in orig_cols]
74
+
75
+ if 'chapter' in lower_cols and 'category' in lower_cols:
76
+ real_ch = orig_cols[lower_cols.index('chapter')]
77
+ real_cat = orig_cols[lower_cols.index('category')]
78
+ query = f"SELECT DISTINCT [{real_ch}], [{real_cat}] FROM [{main_t}] WHERE [{real_ch}] IS NOT NULL"
79
+ df_cat = pd.read_sql(query, conn)
80
+
81
+ cats = []
82
+ for _, row in df_cat.iterrows():
83
+ val_ch = str(row[real_ch]).strip()
84
+ val_cat = str(row[real_cat]).strip()
85
+ if val_ch:
86
+ cats.append(f"{val_ch}.{val_cat}")
87
+
88
+ cats.sort(key=natural_sort_key)
89
+ choices.extend(cats)
90
+
91
+ for t in all_tables:
92
+ if t == main_t: continue
93
+ clean_name = t.replace(f"{standard}_{version}_", "").replace(f"{standard}{version}_", "")
94
+ choices.append(clean_name)
95
+
96
+ conn.close()
97
+ except:
98
+ pass
99
+ return gr.Dropdown(choices=choices, value=None)
100
+
101
+ # 3️⃣ 데이터 조회 로직
102
  def display_data(standard, version, selection):
103
  if not all([standard, version, selection]): return None
104
  try:
 
107
  all_tables = pd.read_sql("SELECT name FROM sqlite_master WHERE type='table';", conn)['name'].tolist()
108
 
109
  main_t = f"{standard}_{version}"
110
+ if main_t not in all_tables:
111
+ candidates = [t for t in all_tables if standard.lower() in t.lower() and version.lower() in t.lower()]
112
+ main_t = candidates[0] if candidates else all_tables[0]
113
 
114
  is_sub_table = False
115
  if selection == "ALL":
116
+ df = pd.read_sql(f"SELECT * FROM [{main_t}] ORDER BY rowid", conn)
117
  elif "." in selection:
118
  ch, ca = selection.split('.', 1)
119
+ cols_info = pd.read_sql(f"PRAGMA table_info([{main_t}])", conn)
120
+ cols_lower = [c.lower() for c in cols_info['name'].tolist()]
121
+ real_ch = cols_info['name'].tolist()[cols_lower.index('chapter')]
122
+ real_cat = cols_info['name'].tolist()[cols_lower.index('category')]
123
+
124
+ df = pd.read_sql(f"SELECT * FROM [{main_t}] WHERE CAST([{real_ch}] AS TEXT)=? AND CAST([{real_cat}] AS TEXT)=? ORDER BY rowid",
125
+ conn, params=[ch, ca])
126
  else:
127
  is_sub_table = True
128
+ actual_table = next((t for t in all_tables if selection in t), selection)
129
+ df = pd.read_sql(f"SELECT * FROM [{actual_table}] ORDER BY rowid", conn)
130
  conn.close()
131
 
132
  if not df.empty:
 
133
  for col in df.columns:
134
  df[col] = df[col].apply(blob_to_base64_html)
135
 
 
 
 
 
 
 
136
  if not is_sub_table:
 
137
  base_cols = [c for c in ['section', 'description'] if c in df.columns]
138
+ image_cols = [c for c in df.columns if c not in base_cols and '<img' in str(df[c].tolist())]
139
+ df = df[base_cols + [c for c in image_cols if c not in base_cols]]
 
 
 
 
 
 
 
 
 
 
140
 
141
  return df
142
  except Exception as e:
143
  return pd.DataFrame({"Error": [f"조회 실패: {str(e)}"]})
144
+
145
  # 4️⃣ UI 구성
146
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
147
+ gr.Markdown("# 📜 Regulation Viewer")
148
 
149
+ with gr.Row():
150
+ standard_dd = gr.Dropdown(label="1. 법규 선택")
151
+ version_dd = gr.Dropdown(label="2. Version 선택")
152
+ category_dd = gr.Dropdown(label="3. Category / Table 선택")
153
 
154
+ output_df = gr.Dataframe(wrap=True, interactive=False, datatype="html")
 
155
 
156
+ demo.load(on_load, None, standard_dd)
157
+ standard_dd.change(update_version_dd, standard_dd, version_dd)
158
+ version_dd.change(update_category_dd, [standard_dd, version_dd], category_dd)
159
+ category_dd.change(display_data, [standard_dd, version_dd, category_dd], output_df)
160
 
161
  if __name__ == "__main__":
162
+ demo.launch()