QIDNLF commited on
Commit
2441c57
ยท
verified ยท
1 Parent(s): 90db546

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +122 -82
app.py CHANGED
@@ -5,77 +5,62 @@ import os
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,18 +70,29 @@ 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,45 +101,77 @@ def update_category_dd(standard, version):
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,7 +179,7 @@ def display_data(standard, version, selection):
151
  return pd.DataFrame({"Error": [str(e)]})
152
 
153
  # --------------------------
154
- # 5๏ธโƒฃ ํ†ตํ•ฉ ์กฐํšŒ
155
  # --------------------------
156
  def unified_search(bs, bv, bc, cs, cv, cc):
157
 
@@ -160,31 +188,38 @@ def unified_search(bs, bv, bc, cs, cv, cc):
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,7 +227,9 @@ with gr.Blocks() as demo:
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,18 +242,21 @@ with gr.Blocks() as demo:
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,7 +274,7 @@ with gr.Blocks() as demo:
234
  )
235
 
236
  # --------------------------
237
- # 7๏ธโƒฃ ์‹คํ–‰
238
  # --------------------------
239
  if __name__ == "__main__":
240
  demo.launch(
 
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
  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
  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
  return pd.DataFrame({"Error": [str(e)]})
180
 
181
  # --------------------------
182
+ # ๐Ÿ”ฅ ํ†ตํ•ฉ ์กฐํšŒ (ํ•ต์‹ฌ)
183
  # --------------------------
184
  def unified_search(bs, bv, bc, cs, cv, cc):
185
 
 
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
 
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
  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
  )
275
 
276
  # --------------------------
277
+ # ์‹คํ–‰
278
  # --------------------------
279
  if __name__ == "__main__":
280
  demo.launch(