dev-yuje commited on
Commit
6bf34b8
Β·
1 Parent(s): e302529

feat: optimize Gradio 6 CSS visual bubbles, add safe print overrides, and fix scraping matplotlib imports

Browse files
reset_db.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ import dotenv
4
+ import neo4j
5
+
6
+ dotenv.load_dotenv()
7
+
8
+
9
+ def get_neo4j_driver() -> neo4j.Driver:
10
+ uri = os.getenv("NEO4J_URI", "neo4j://localhost:7687")
11
+ client_id = os.getenv("NEO4J_CLIENT_ID")
12
+ client_secret = os.getenv("NEO4J_CLIENT_SECRET")
13
+
14
+ if client_id and client_secret:
15
+ try:
16
+ d = neo4j.GraphDatabase.driver(uri, auth=(client_id, client_secret))
17
+ d.verify_connectivity()
18
+ return d
19
+ except Exception:
20
+ pass
21
+
22
+ username = os.getenv("NEO4J_USERNAME", "neo4j")
23
+ password = os.getenv("NEO4J_PASSWORD", "password")
24
+ d = neo4j.GraphDatabase.driver(uri, auth=(username, password))
25
+ d.verify_connectivity()
26
+ return d
27
+
28
+
29
+ if __name__ == "__main__":
30
+ print("Connecting to Neo4j to reset the database...")
31
+ driver = get_neo4j_driver()
32
+ with driver.session() as session:
33
+ # DETACH DELETE n deletes all nodes and their relationships
34
+ result = session.run("MATCH (n) DETACH DELETE n")
35
+ print("Database successfully reset. All nodes and relationships deleted.")
36
+ driver.close()
run_pipeline.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import subprocess
3
+ import sys
4
+
5
+
6
+ def run_command(cmd):
7
+ print("\n========================================")
8
+ print(f"Running: {cmd}")
9
+ print("========================================\n")
10
+ env = os.environ.copy()
11
+ env["PYTHONUTF8"] = "1"
12
+ result = subprocess.run(cmd, shell=True, env=env)
13
+ if result.returncode != 0:
14
+ print(f"Command failed with exit code {result.returncode}: {cmd}")
15
+ sys.exit(result.returncode)
16
+
17
+
18
+ if __name__ == "__main__":
19
+ print("Starting background rebuilding pipeline...")
20
+ # 1. 크둀링 (finScrapping.py)
21
+ run_command(r".\.venv\Scripts\python.exe src/graphBuilder/scrapping/finScrapping.py")
22
+
23
+ # 2. 지식 κ·Έλž˜ν”„ λΉŒλ“œ (finGraph.py)
24
+ run_command(r".\.venv\Scripts\python.exe src/graphBuilder/neo4j/finGraph.py")
25
+
26
+ print("\n[OK] Background rebuilding pipeline completed successfully!")
src/graphBuilder/neo4j/finGraph.py CHANGED
@@ -27,6 +27,42 @@ from neo4j_graphrag.llm import OpenAILLM
27
  dotenv.load_dotenv()
28
 
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  def get_neo4j_driver() -> neo4j.Driver:
31
  uri = os.getenv("NEO4J_URI", "neo4j://localhost:7687")
32
  client_id = os.getenv("NEO4J_CLIENT_ID")
 
27
  dotenv.load_dotenv()
28
 
29
 
30
+ # Windows cp949 인코딩 ν™˜κ²½μ—μ„œ 이λͺ¨μ§€ 좜λ ₯ μ‹œ UnicodeEncodeError λ°©μ§€λ₯Ό μœ„ν•œ μ•ˆμ „ν•œ print ν•¨μˆ˜ μ •μ˜
31
+ def safe_print(*args, **kwargs) -> None:
32
+ import sys
33
+ try:
34
+ # endλ‚˜ sep 인자λ₯Ό μ˜¬λ°”λ₯΄κ²Œ μ²˜λ¦¬ν•  수 μžˆλ„λ‘ λ‚΄μž₯ print의 κΈ°λŠ₯ μ€€μˆ˜
35
+ sep = kwargs.get("sep", " ")
36
+ end = kwargs.get("end", "\n")
37
+ msg = sep.join(map(str, args))
38
+ sys.stdout.write(msg + end)
39
+ sys.stdout.flush()
40
+ except UnicodeEncodeError:
41
+ msg = sep.join(map(str, args))
42
+ cleaned = (
43
+ msg.replace("βœ…", "[OK]")
44
+ .replace("⚠️", "[WARN]")
45
+ .replace("🚨", "[ERR]")
46
+ .replace("⏭️", "[SKIP]")
47
+ .replace("πŸ€–", "[AI]")
48
+ .replace("🏒", "[COMP]")
49
+ .replace("🌌", "[GRAPH]")
50
+ .replace("πŸ“°", "[NEWS]")
51
+ .replace("πŸ”¬", "[TECH]")
52
+ .replace("πŸ”—", "[LINK]")
53
+ )
54
+ try:
55
+ sys.stdout.write(cleaned + end)
56
+ sys.stdout.flush()
57
+ except Exception:
58
+ ascii_msg = msg.encode("ascii", errors="replace").decode("ascii")
59
+ sys.stdout.write(ascii_msg + end)
60
+ sys.stdout.flush()
61
+
62
+
63
+ print = safe_print
64
+
65
+
66
  def get_neo4j_driver() -> neo4j.Driver:
67
  uri = os.getenv("NEO4J_URI", "neo4j://localhost:7687")
68
  client_id = os.getenv("NEO4J_CLIENT_ID")
src/graphBuilder/scrapping/finScrapping.py CHANGED
@@ -245,51 +245,55 @@ print(f"[SAVE] - AI ν•€ν…Œν¬ 기사: {len(df_filtered)}건")
245
 
246
 
247
  # ── 4단계: ν‚€μ›Œλ“œ λΉˆλ„ μ‹œκ°ν™” ──
248
- import platform
249
- from collections import Counter
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
250
 
251
- import matplotlib.pyplot as plt
252
-
253
- # 폰트 깨짐 λ°©μ§€ (Mac ν™˜κ²½: AppleGothic)
254
- if platform.system() == "Darwin":
255
- plt.rc("font", family="AppleGothic")
256
- plt.rcParams["axes.unicode_minus"] = False
257
-
258
- if not filtered_articles:
259
- print("μ‹œκ°ν™”ν•  데이터가 μ—†μŠ΅λ‹ˆλ‹€.")
260
- else:
261
- # λΉˆλ„μˆ˜ 계산
262
- all_kw = [kw for row in filtered_articles for kw in row["matched_keywords"].split(", ")]
263
- kw_counts = Counter(all_kw)
264
-
265
- # πŸ“Œ λ³€κ²½ 포인트: FINTECH_AI_KEYWORDS 전체 λͺ©λ‘μ„ μˆœμ„œλŒ€λ‘œ κ·Έλž˜ν”„μ— κ°•μ œ ν‘œμ‹œ (0건 포함)
266
- keywords = FINTECH_AI_KEYWORDS
267
- counts = [kw_counts.get(kw, 0) for kw in keywords]
268
-
269
- plt.figure(figsize=(12, 6))
270
-
271
- # λ§‰λŒ€ κ·Έλž˜ν”„ 생성
272
- bars = plt.bar(keywords, counts, color="skyblue", edgecolor="white")
273
-
274
- # λ§‰λŒ€ μœ„μ— 숫자(λΉˆλ„μˆ˜) ν‘œμ‹œ
275
- for bar in bars:
276
- height = bar.get_height()
277
- # λ§‰λŒ€μ˜ 쀑앙(x), λ§‰λŒ€μ˜ 높이(y) μœ„μΉ˜μ— ν…μŠ€νŠΈλ₯Ό 배치
278
- plt.text(
279
- bar.get_x() + bar.get_width() / 2.0,
280
- height,
281
- f"{height}",
282
- ha="center",
283
- va="bottom",
284
- size=11,
285
- fontweight="bold",
286
- color="black",
287
- )
288
 
289
- plt.title("μˆ˜μ§‘λœ AI ν•€ν…Œν¬ 기사 ν‚€μ›Œλ“œ μΆœν˜„ λΉˆλ„ (전체)", fontsize=15, pad=15)
290
- plt.xlabel("ν‚€μ›Œλ“œ", fontsize=12)
291
- plt.ylabel("μΆœν˜„ 횟수 (건)", fontsize=12)
292
- plt.grid(axis="y", linestyle="--", alpha=0.7)
293
- plt.xticks(rotation=45)
294
- plt.tight_layout()
295
- plt.show()
 
245
 
246
 
247
  # ── 4단계: ν‚€μ›Œλ“œ λΉˆλ„ μ‹œκ°ν™” ──
248
+ try:
249
+ import platform
250
+ from collections import Counter
251
+
252
+ import matplotlib.pyplot as plt
253
+
254
+ # 폰트 깨짐 λ°©μ§€ (Mac ν™˜κ²½: AppleGothic)
255
+ if platform.system() == "Darwin":
256
+ plt.rc("font", family="AppleGothic")
257
+ plt.rcParams["axes.unicode_minus"] = False
258
+
259
+ if not filtered_articles:
260
+ print("μ‹œκ°ν™”ν•  데이터가 μ—†μŠ΅λ‹ˆλ‹€.")
261
+ else:
262
+ # λΉˆλ„μˆ˜ 계산
263
+ all_kw = [kw for row in filtered_articles for kw in row["matched_keywords"].split(", ")]
264
+ kw_counts = Counter(all_kw)
265
+
266
+ # πŸ“Œ λ³€κ²½ 포인트: FINTECH_AI_KEYWORDS 전체 λͺ©λ‘μ„ μˆœμ„œλŒ€λ‘œ κ·Έλž˜ν”„μ— κ°•μ œ ν‘œμ‹œ (0건 포함)
267
+ keywords = FINTECH_AI_KEYWORDS
268
+ counts = [kw_counts.get(kw, 0) for kw in keywords]
269
+
270
+ plt.figure(figsize=(12, 6))
271
+
272
+ # λ§‰λŒ€ κ·Έλž˜ν”„ 생성
273
+ bars = plt.bar(keywords, counts, color="skyblue", edgecolor="white")
274
+
275
+ # λ§‰λŒ€ μœ„μ— 숫자(λΉˆλ„μˆ˜) ν‘œμ‹œ
276
+ for bar in bars:
277
+ height = bar.get_height()
278
+ # λ§‰λŒ€μ˜ 쀑앙(x), λ§‰λŒ€μ˜ 높이(y) μœ„μΉ˜μ— ν…μŠ€νŠΈλ₯Ό 배치
279
+ plt.text(
280
+ bar.get_x() + bar.get_width() / 2.0,
281
+ height,
282
+ f"{height}",
283
+ ha="center",
284
+ va="bottom",
285
+ size=11,
286
+ fontweight="bold",
287
+ color="black",
288
+ )
289
 
290
+ plt.title("μˆ˜μ§‘λœ AI ν•€ν…Œν¬ 기사 ν‚€μ›Œλ“œ μΆœν˜„ λΉˆλ„ (전체)", fontsize=15, pad=15)
291
+ plt.xlabel("ν‚€μ›Œλ“œ", fontsize=12)
292
+ plt.ylabel("μΆœν˜„ 횟수 (건)", fontsize=12)
293
+ plt.grid(axis="y", linestyle="--", alpha=0.7)
294
+ plt.xticks(rotation=45)
295
+ plt.tight_layout()
296
+ plt.show()
297
+ except ImportError:
298
+ print("[INFO] matplotlib λΌμ΄λΈŒλŸ¬λ¦¬κ°€ μ„€μΉ˜λ˜μ–΄ μžˆμ§€ μ•Šμ•„ μ‹œκ°ν™” 단계λ₯Ό κ±΄λ„ˆλœλ‹ˆλ‹€.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
299
 
 
 
 
 
 
 
 
src/utils/ui_templates.py CHANGED
@@ -225,7 +225,6 @@ body, .gradio-container {
225
  /* ── 챗봇 μ»¨ν…Œμ΄λ„ˆ ν…Œλ‘λ¦¬ 제거 ── */
226
  div[data-testid="chatbot"], .chatbot-container, .chatbot {
227
  border: none !important;
228
- overflow: visible !important;
229
  }
230
 
231
  /* ── 챗봇 λ‚΄λΆ€ Placeholder(μ†Œκ°œκΈ€ μ˜μ—­) 상단 μ§€λ¦Ό 영ꡬ 차단 ── */
@@ -408,21 +407,16 @@ label.svelte-1ipelgc, span.svelte-1ipelgc {
408
  }
409
 
410
  /* ── μ‚¬μš©μž 버블 (λ‹€ν¬κ·Έλ ˆμ΄ 프리미엄 ν…Œλ§ˆ) ── */
411
- .message.user, [data-testid="user"] .message {
412
  background-color: #111827 !important;
413
  border-radius: 12px 12px 0 12px !important;
414
- padding: 7px 13px !important;
415
  margin: 2px 0 !important;
416
  border: none !important;
417
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.08) !important;
418
- min-height: unset !important;
419
- }
420
- [data-testid="user"] > div, .bubble-wrap [data-testid="user"], .message-wrap.user > div, .message-row.user {
421
- background: transparent !important;
422
- background-color: transparent !important;
423
- border: none !important;
424
  }
425
- [data-testid="user"] .message *, .message.user * {
426
  color: #ffffff !important;
427
  line-height: 1.4 !important;
428
  margin: 0 !important;
@@ -430,7 +424,7 @@ label.svelte-1ipelgc, span.svelte-1ipelgc {
430
  }
431
 
432
  /* ── 봇 버블 (ν™”μ΄νŠΈ & 그레이 경계선 ν…Œλ§ˆ) ── */
433
- .message.bot, [data-testid="bot"] .message, [data-testid="bot"] > div, .message-wrap.bot > div, .message.bot, .message-row.bot .message {
434
  background-color: #ffffff !important;
435
  color: #1f2937 !important;
436
  border: 1px solid #e5e7eb !important;
@@ -438,8 +432,7 @@ label.svelte-1ipelgc, span.svelte-1ipelgc {
438
  padding: 16px 20px !important;
439
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05) !important;
440
  }
441
- .message.bot p, .message.bot span,
442
- .message.bot li, .message.bot div {
443
  color: #1e3a5f !important;
444
  background: transparent !important;
445
  }
 
225
  /* ── 챗봇 μ»¨ν…Œμ΄λ„ˆ ν…Œλ‘λ¦¬ 제거 ── */
226
  div[data-testid="chatbot"], .chatbot-container, .chatbot {
227
  border: none !important;
 
228
  }
229
 
230
  /* ── 챗봇 λ‚΄λΆ€ Placeholder(μ†Œκ°œκΈ€ μ˜μ—­) 상단 μ§€λ¦Ό 영ꡬ 차단 ── */
 
407
  }
408
 
409
  /* ── μ‚¬μš©μž 버블 (λ‹€ν¬κ·Έλ ˆμ΄ 프리미엄 ν…Œλ§ˆ) ── */
410
+ .message.user {
411
  background-color: #111827 !important;
412
  border-radius: 12px 12px 0 12px !important;
413
+ padding: 10px 14px !important;
414
  margin: 2px 0 !important;
415
  border: none !important;
416
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.08) !important;
417
+ color: #ffffff !important;
 
 
 
 
 
418
  }
419
+ .message.user * {
420
  color: #ffffff !important;
421
  line-height: 1.4 !important;
422
  margin: 0 !important;
 
424
  }
425
 
426
  /* ── 봇 버블 (ν™”μ΄νŠΈ & 그레이 경계선 ν…Œλ§ˆ) ── */
427
+ .message.bot {
428
  background-color: #ffffff !important;
429
  color: #1f2937 !important;
430
  border: 1px solid #e5e7eb !important;
 
432
  padding: 16px 20px !important;
433
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05) !important;
434
  }
435
+ .message.bot * {
 
436
  color: #1e3a5f !important;
437
  background: transparent !important;
438
  }