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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +96 -89
app.py CHANGED
@@ -3,147 +3,154 @@ 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 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 "[미지 변환 에러]"
 
 
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: main_t = all_tables[0]
68
-
69
- # 컬럼명 대소문자 구분 없이 chapter/category 찾기
70
- cols_info = pd.read_sql(f"PRAGMA table_info([{main_t}])", conn)
71
- cols_lower = [c.lower() for c in cols_info['name'].tolist()]
72
-
73
- if 'chapter' in cols_lower and 'category' in cols_lower:
74
- real_ch = cols_info['name'].tolist()[cols_lower.index('chapter')]
75
- real_cat = cols_info['name'].tolist()[cols_lower.index('category')]
76
- df_cat = pd.read_sql(f"SELECT DISTINCT [{real_ch}], [{real_cat}] FROM [{main_t}]", conn)
77
- cats = [f"{row[real_ch]}.{row[real_cat]}" for _, row in df_cat.iterrows() if row[real_ch]]
78
- cats.sort(key=natural_sort_key)
79
- choices.extend(cats)
80
-
81
- prefix = f"{standard}_{version}_"
82
- sub_tables = [t.replace(prefix, "") for t in all_tables if t != main_t]
83
- choices.extend(sorted(sub_tables))
84
- conn.close()
85
- except: pass
86
- return gr.Dropdown(choices=choices, value=None)
87
-
88
- # 3️⃣ 데이터 조회 로직 (정렬 지우고 이미지+DB 순서 유지)
89
  def display_data(standard, version, selection):
90
  if not all([standard, version, selection]): return None
91
  try:
92
  target_db = next(db for db in db_registry if db["standard"] == standard and db["version"] == version)
93
  conn = sqlite3.connect(target_db["path"])
94
  all_tables = pd.read_sql("SELECT name FROM sqlite_master WHERE type='table';", conn)['name'].tolist()
 
95
  main_t = f"{standard}_{version}"
96
  if main_t not in all_tables: main_t = all_tables[0]
97
 
98
  is_sub_table = False
99
- # ORDER BY rowid로 DB 저장 순서 그대로 가져오기
100
  if selection == "ALL":
101
- df = pd.read_sql(f"SELECT * FROM [{main_t}] ORDER BY rowid", conn)
102
  elif "." in selection:
103
  ch, ca = selection.split('.', 1)
104
- # 대소문자 대응을 위해 필터링 쿼리 작성
105
- cols_info = pd.read_sql(f"PRAGMA table_info([{main_t}])", conn)
106
- cols_lower = [c.lower() for c in cols_info['name'].tolist()]
107
- real_ch = cols_info['name'].tolist()[cols_lower.index('chapter')]
108
- real_cat = cols_info['name'].tolist()[cols_lower.index('category')]
109
- df = pd.read_sql(f"SELECT * FROM [{main_t}] WHERE [{real_ch}]=? AND [{real_cat}]=? ORDER BY rowid", conn, params=[ch, ca])
110
  else:
111
  is_sub_table = True
112
  actual_table = next((t for t in all_tables if t.endswith(selection)), selection)
113
- df = pd.read_sql(f"SELECT * FROM [{actual_table}] ORDER BY rowid", conn)
114
  conn.close()
115
 
116
  if not df.empty:
117
- # 모든 셀에 대해 이미지 변환 처리
118
  for col in df.columns:
119
  df[col] = df[col].apply(blob_to_base64_html)
120
 
121
- # 필터링: 본문 조회 시 주요 열 + 이미지가 포함된 열만 표시
 
 
 
 
 
122
  if not is_sub_table:
 
123
  base_cols = [c for c in ['section', 'description'] if c in df.columns]
124
- # 이미지가 들어있는 열(HTML 태그가 포함된 열)을 찾음
125
- image_cols = [c for c in df.columns if c not in base_cols and '<img' in str(df[col].iloc[0] if len(df)>0 else "")]
 
 
 
 
 
 
126
  df = df[base_cols + image_cols]
 
 
 
127
 
128
  return df
129
  except Exception as e:
130
  return pd.DataFrame({"Error": [f"조회 실패: {str(e)}"]})
131
-
132
  # 4️⃣ UI 구성
133
  with gr.Blocks() as demo:
134
- gr.Markdown("# 📜 Regulation Viewer")
135
 
136
- with gr.Row():
137
- standard_dd = gr.Dropdown(label="1. 법규 선택")
138
- version_dd = gr.Dropdown(label="2. Version 선택")
139
- category_dd = gr.Dropdown(label="3. Category / Table 선택")
140
 
141
- output_df = gr.Dataframe(wrap=True, interactive=False, datatype="html")
 
142
 
143
- demo.load(on_load, None, standard_dd)
144
- standard_dd.change(update_version_dd, standard_dd, version_dd)
145
- version_dd.change(update_category_dd, [standard_dd, version_dd], category_dd)
146
- category_dd.change(display_data, [standard_dd, version_dd, category_dd], output_df)
147
 
148
  if __name__ == "__main__":
149
- 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:
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:
88
  target_db = next(db for db in db_registry if db["standard"] == standard and db["version"] == version)
89
  conn = sqlite3.connect(target_db["path"])
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())