QIDNLF commited on
Commit
90db546
Β·
verified Β·
1 Parent(s): 9ac6adf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +82 -122
app.py CHANGED
@@ -5,62 +5,77 @@ 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
  # --------------------------
16
- # μœ ν‹Έ ν•¨μˆ˜ (κ·ΈλŒ€λ‘œ μœ μ§€)
17
  # --------------------------
18
  def blob_to_base64_html(blob_data):
19
  if blob_data is None or pd.isna(blob_data):
20
  return ""
21
  try:
22
  if isinstance(blob_data, (bytes, bytearray)):
23
- encoded_string = base64.b64encode(blob_data).decode('utf-8')
24
- return f'<img src="data:image/png;base64,{encoded_string}" width="200" />'
25
  return str(blob_data)
26
  except:
27
  return str(blob_data)
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
- db_files = [f for f in os.listdir(UPLOAD_DIR) if f.endswith(".db")]
38
 
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
 
49
- return sorted(list(set([db["standard"] for db in db_registry])))
 
 
 
 
 
 
 
50
 
51
  # --------------------------
52
- # λ“œλ‘­λ‹€μš΄ μ—…λ°μ΄νŠΈ
53
  # --------------------------
54
  def on_load():
55
- standards = refresh_registry_data()
56
- return gr.Dropdown(choices=standards)
57
 
58
  def update_version_dd(standard):
59
  if not standard:
60
  return gr.Dropdown(choices=[])
61
- versions = sorted(list(set([
62
- db["version"] for db in db_registry if db["standard"] == standard
63
- ])))
64
  return gr.Dropdown(choices=versions)
65
 
66
  def update_category_dd(standard, version):
@@ -70,29 +85,18 @@ def update_category_dd(standard, version):
70
  choices = ["ALL"]
71
 
72
  try:
73
- target_db = next(db for db in db_registry if db["standard"] == standard and db["version"] == version)
74
- conn = sqlite3.connect(target_db["path"])
75
-
76
- tables = pd.read_sql("SELECT name FROM sqlite_master WHERE type='table';", conn)['name'].tolist()
77
- main_t = f"{standard}_{version}"
78
-
79
- if main_t not in tables:
80
- main_t = tables[0]
81
-
82
- cols_info = pd.read_sql(f"PRAGMA table_info([{main_t}])", conn)
83
- cols = cols_info['name'].tolist()
84
- lower_cols = [c.lower() for c in cols]
85
-
86
- if 'chapter' in lower_cols and 'category' in lower_cols:
87
- ch = cols[lower_cols.index('chapter')]
88
- ca = cols[lower_cols.index('category')]
89
-
90
- df = pd.read_sql(f"SELECT DISTINCT [{ch}], [{ca}] FROM [{main_t}]", conn)
91
 
 
 
 
 
 
92
  for _, row in df.iterrows():
93
- c = str(row[ch])
94
- cat = str(row[ca])
95
- choices.append(f"{c}.{cat}")
96
 
97
  conn.close()
98
  except:
@@ -101,77 +105,45 @@ def update_category_dd(standard, version):
101
  return gr.Dropdown(choices=choices)
102
 
103
  # --------------------------
104
- # 데이터 쑰회
105
  # --------------------------
106
  def display_data(standard, version, selection):
107
  if not all([standard, version, selection]):
108
  return pd.DataFrame({"Info": ["선택을 μ™„λ£Œν•˜μ„Έμš”"]})
109
 
110
  try:
111
- target_db = next(db for db in db_registry if db["standard"] == standard and db["version"] == version)
112
- conn = sqlite3.connect(target_db["path"])
113
-
114
- # πŸ”₯ ν…Œμ΄λΈ” μ°ΎκΈ° (μ•ˆμ „ν•˜κ²Œ)
115
- tables = pd.read_sql("SELECT name FROM sqlite_master WHERE type='table';", conn)['name'].tolist()
116
- main_t = f"{standard}_{version}"
117
-
118
- if main_t not in tables:
119
- main_t = tables[0]
120
-
121
- # πŸ”₯ 컬럼 정보 κ°€μ Έμ˜€κΈ°
122
- cols_info = pd.read_sql(f"PRAGMA table_info([{main_t}])", conn)
123
- cols = cols_info['name'].tolist()
124
- lower_cols = [c.lower().strip() for c in cols]
125
-
126
- # πŸ”₯ μ‹€μ œ 컬럼λͺ… μ°ΎκΈ°
127
- real_section = None
128
- real_desc = None
129
- real_ch = None
130
- real_cat = None
131
-
132
- for c, lc in zip(cols, lower_cols):
133
- if lc == "section":
134
- real_section = c
135
- elif lc == "description":
136
- real_desc = c
137
- elif lc == "chapter":
138
- real_ch = c
139
- elif lc == "category":
140
- real_cat = c
141
-
142
- # --------------------------
143
- # 쑰회 둜직
144
- # --------------------------
145
  if selection == "ALL":
146
  df = pd.read_sql(f"SELECT * FROM [{main_t}]", conn)
147
 
148
- elif "." in selection and real_ch and real_cat:
149
  ch, ca = selection.split(".", 1)
150
  df = pd.read_sql(
151
- f"SELECT * FROM [{main_t}] WHERE CAST([{real_ch}] AS TEXT)=? AND CAST([{real_cat}] AS TEXT)=?",
 
 
 
 
152
  conn,
153
  params=[ch, ca]
154
  )
155
-
156
  else:
157
  df = pd.read_sql(f"SELECT * FROM [{main_t}]", conn)
158
 
159
  conn.close()
160
 
161
- # πŸ”₯ 데이터 없을 λ•Œ
162
- if df is None or df.empty:
163
  return pd.DataFrame({"Info": ["데이터 μ—†μŒ"]})
164
 
165
- # πŸ”₯ 컬럼 정리
166
  df.columns = [c.lower().strip() for c in df.columns]
167
 
168
- # πŸ”₯ ν•„μš”ν•œ 컬럼만
169
- if 'section' in df.columns and 'description' in df.columns:
170
  df = df[['section', 'description']]
171
 
172
- # πŸ”₯ 이미지 처리
173
- for col in df.columns:
174
- df[col] = df[col].apply(blob_to_base64_html)
175
 
176
  return df
177
 
@@ -179,7 +151,7 @@ def display_data(standard, version, selection):
179
  return pd.DataFrame({"Error": [str(e)]})
180
 
181
  # --------------------------
182
- # πŸ”₯ 톡합 쑰회 (핡심)
183
  # --------------------------
184
  def unified_search(bs, bv, bc, cs, cv, cc):
185
 
@@ -188,38 +160,31 @@ def unified_search(bs, bv, bc, cs, cv, cc):
188
  return display_data(bs, bv, bc)
189
 
190
  # 비ꡐ
191
- if bs and bv and bc and cs and cv and cc:
192
  df_base = display_data(bs, bv, bc)
193
  df_comp = display_data(cs, cv, cc)
194
 
195
- if df_base is None or df_comp is None:
196
  return pd.DataFrame({"Error": ["데이터 μ—†μŒ"]})
197
 
198
- if 'section' not in df_base.columns or 'section' not in df_comp.columns:
199
- return pd.DataFrame({
200
- "Error": ["section 컬럼이 μ—†μŠ΅λ‹ˆλ‹€"],
201
- "base_columns": [list(df_base.columns)],
202
- "comp_columns": [list(df_comp.columns)]
203
- })
204
-
205
- try:
206
- merged = pd.merge(
207
- df_base,
208
- df_comp,
209
- on="section",
210
- how="outer",
211
- suffixes=("_base", "_comp")
212
- )
213
 
214
- return merged
 
215
 
216
- except Exception as e:
217
- return pd.DataFrame({"Error": [str(e)]})
 
 
 
 
 
218
 
219
  return pd.DataFrame({"Info": ["선택을 μ™„λ£Œν•˜μ„Έμš”"]})
220
 
221
  # --------------------------
222
- # UI ꡬ성
223
  # --------------------------
224
  with gr.Blocks() as demo:
225
 
@@ -227,9 +192,7 @@ with gr.Blocks() as demo:
227
 
228
  with gr.Row():
229
 
230
- # μ™Όμͺ½
231
  with gr.Column(scale=1):
232
-
233
  with gr.Group():
234
  gr.Markdown("### πŸ“Œ κΈ°μ€€ λ²•κ·œ")
235
  base_standard = gr.Dropdown(label="Standard")
@@ -242,21 +205,18 @@ with gr.Blocks() as demo:
242
  comp_version = gr.Dropdown(label="Version")
243
  comp_category = gr.Dropdown(label="Category")
244
 
245
- # 였λ₯Έμͺ½
246
  with gr.Column(scale=4):
247
  gr.Markdown("### πŸ“Š λ‚΄μš©")
248
-
249
  output_df = gr.Dataframe(
250
  wrap=True,
251
  interactive=False,
252
  datatype="html"
253
  )
254
 
255
-
256
  with gr.Row():
257
  search_btn = gr.Button("πŸ” 쑰회")
258
 
259
- # 이벀트 μ—°κ²°
260
  demo.load(on_load, None, base_standard)
261
  demo.load(on_load, None, comp_standard)
262
 
@@ -274,7 +234,7 @@ with gr.Blocks() as demo:
274
  )
275
 
276
  # --------------------------
277
- # μ‹€ν–‰
278
  # --------------------------
279
  if __name__ == "__main__":
280
  demo.launch(
 
5
  import re
6
  import base64
7
 
8
+ # --------------------------
9
+ # 1️⃣ κΈ°λ³Έ μ„€μ •
10
+ # --------------------------
11
  UPLOAD_DIR = "uploaded_dbs"
12
+ os.makedirs(UPLOAD_DIR, exist_ok=True)
 
13
 
14
  db_registry = []
15
 
16
  # --------------------------
17
+ # 2️⃣ μœ ν‹Έ ν•¨μˆ˜
18
  # --------------------------
19
  def blob_to_base64_html(blob_data):
20
  if blob_data is None or pd.isna(blob_data):
21
  return ""
22
  try:
23
  if isinstance(blob_data, (bytes, bytearray)):
24
+ encoded = base64.b64encode(blob_data).decode('utf-8')
25
+ return f'<img src="data:image/png;base64,{encoded}" width="200"/>'
26
  return str(blob_data)
27
  except:
28
  return str(blob_data)
29
 
30
  def natural_sort_key(s):
31
+ return [int(t) if t.isdigit() else t.lower()
32
+ for t in re.split(r'(\d+)', str(s))] if s else []
 
33
 
34
  def refresh_registry_data():
35
  global db_registry
36
  db_registry = []
 
37
 
38
+ for f in os.listdir(UPLOAD_DIR):
39
+ if f.endswith(".db"):
40
+ name = f.replace(".db", "")
41
+ parts = name.split("_")
42
+ if len(parts) >= 2:
43
+ db_registry.append({
44
+ "path": os.path.join(UPLOAD_DIR, f),
45
+ "standard": parts[0],
46
+ "version": parts[1]
47
+ })
48
+
49
+ return sorted({db["standard"] for db in db_registry})
50
+
51
+ def get_db_path(standard, version):
52
+ return next(db["path"] for db in db_registry
53
+ if db["standard"] == standard and db["version"] == version)
54
+
55
+ def get_main_table_and_columns(conn, standard, version):
56
+ tables = pd.read_sql(
57
+ "SELECT name FROM sqlite_master WHERE type='table';", conn
58
+ )['name'].tolist()
59
 
60
+ main_t = f"{standard}_{version}"
61
+ if main_t not in tables:
62
+ main_t = tables[0]
63
+
64
+ cols = pd.read_sql(f"PRAGMA table_info([{main_t}])", conn)['name'].tolist()
65
+ col_map = {c.lower().strip(): c for c in cols}
66
+
67
+ return main_t, col_map
68
 
69
  # --------------------------
70
+ # 3️⃣ λ“œλ‘­λ‹€μš΄
71
  # --------------------------
72
  def on_load():
73
+ return gr.Dropdown(choices=refresh_registry_data())
 
74
 
75
  def update_version_dd(standard):
76
  if not standard:
77
  return gr.Dropdown(choices=[])
78
+ versions = sorted({db["version"] for db in db_registry if db["standard"] == standard})
 
 
79
  return gr.Dropdown(choices=versions)
80
 
81
  def update_category_dd(standard, version):
 
85
  choices = ["ALL"]
86
 
87
  try:
88
+ conn = sqlite3.connect(get_db_path(standard, version))
89
+ main_t, col_map = get_main_table_and_columns(conn, standard, version)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
+ if 'chapter' in col_map and 'category' in col_map:
92
+ df = pd.read_sql(
93
+ f"SELECT DISTINCT [{col_map['chapter']}], [{col_map['category']}] FROM [{main_t}]",
94
+ conn
95
+ )
96
  for _, row in df.iterrows():
97
+ ch = str(row.iloc[0])
98
+ ca = str(row.iloc[1])
99
+ choices.append(f"{ch}.{ca}")
100
 
101
  conn.close()
102
  except:
 
105
  return gr.Dropdown(choices=choices)
106
 
107
  # --------------------------
108
+ # 4️⃣ 데이터 쑰회
109
  # --------------------------
110
  def display_data(standard, version, selection):
111
  if not all([standard, version, selection]):
112
  return pd.DataFrame({"Info": ["선택을 μ™„λ£Œν•˜μ„Έμš”"]})
113
 
114
  try:
115
+ conn = sqlite3.connect(get_db_path(standard, version))
116
+ main_t, col_map = get_main_table_and_columns(conn, standard, version)
117
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  if selection == "ALL":
119
  df = pd.read_sql(f"SELECT * FROM [{main_t}]", conn)
120
 
121
+ elif "." in selection and 'chapter' in col_map and 'category' in col_map:
122
  ch, ca = selection.split(".", 1)
123
  df = pd.read_sql(
124
+ f"""
125
+ SELECT * FROM [{main_t}]
126
+ WHERE CAST([{col_map['chapter']}] AS TEXT)=?
127
+ AND CAST([{col_map['category']}] AS TEXT)=?
128
+ """,
129
  conn,
130
  params=[ch, ca]
131
  )
 
132
  else:
133
  df = pd.read_sql(f"SELECT * FROM [{main_t}]", conn)
134
 
135
  conn.close()
136
 
137
+ if df.empty:
 
138
  return pd.DataFrame({"Info": ["데이터 μ—†μŒ"]})
139
 
140
+ # 곡톡 처리
141
  df.columns = [c.lower().strip() for c in df.columns]
142
 
143
+ if {'section', 'description'}.issubset(df.columns):
 
144
  df = df[['section', 'description']]
145
 
146
+ df = df.applymap(blob_to_base64_html)
 
 
147
 
148
  return df
149
 
 
151
  return pd.DataFrame({"Error": [str(e)]})
152
 
153
  # --------------------------
154
+ # 5️⃣ 톡합 쑰회
155
  # --------------------------
156
  def unified_search(bs, bv, bc, cs, cv, cc):
157
 
 
160
  return display_data(bs, bv, bc)
161
 
162
  # 비ꡐ
163
+ if all([bs, bv, bc, cs, cv, cc]):
164
  df_base = display_data(bs, bv, bc)
165
  df_comp = display_data(cs, cv, cc)
166
 
167
+ if df_base.empty or df_comp.empty:
168
  return pd.DataFrame({"Error": ["데이터 μ—†μŒ"]})
169
 
170
+ df_base.columns = [c.lower() for c in df_base.columns]
171
+ df_comp.columns = [c.lower() for c in df_comp.columns]
 
 
 
 
 
 
 
 
 
 
 
 
 
172
 
173
+ if 'section' not in df_base or 'section' not in df_comp:
174
+ return pd.DataFrame({"Error": ["section 컬럼 μ—†μŒ"]})
175
 
176
+ return pd.merge(
177
+ df_base,
178
+ df_comp,
179
+ on="section",
180
+ how="outer",
181
+ suffixes=("_base", "_comp")
182
+ )
183
 
184
  return pd.DataFrame({"Info": ["선택을 μ™„λ£Œν•˜μ„Έμš”"]})
185
 
186
  # --------------------------
187
+ # 6️⃣ UI
188
  # --------------------------
189
  with gr.Blocks() as demo:
190
 
 
192
 
193
  with gr.Row():
194
 
 
195
  with gr.Column(scale=1):
 
196
  with gr.Group():
197
  gr.Markdown("### πŸ“Œ κΈ°μ€€ λ²•κ·œ")
198
  base_standard = gr.Dropdown(label="Standard")
 
205
  comp_version = gr.Dropdown(label="Version")
206
  comp_category = gr.Dropdown(label="Category")
207
 
 
208
  with gr.Column(scale=4):
209
  gr.Markdown("### πŸ“Š λ‚΄μš©")
 
210
  output_df = gr.Dataframe(
211
  wrap=True,
212
  interactive=False,
213
  datatype="html"
214
  )
215
 
 
216
  with gr.Row():
217
  search_btn = gr.Button("πŸ” 쑰회")
218
 
219
+ # 이벀트
220
  demo.load(on_load, None, base_standard)
221
  demo.load(on_load, None, comp_standard)
222
 
 
234
  )
235
 
236
  # --------------------------
237
+ # 7️⃣ μ‹€ν–‰
238
  # --------------------------
239
  if __name__ == "__main__":
240
  demo.launch(