dev-yuje commited on
Commit
d1f6f57
·
1 Parent(s): 38d9fac

feat: 투명 퍼플 포인트 에디션 디자인 테마 적용 및 FinGraph 브랜드 브랜딩 최적화

Browse files
Files changed (1) hide show
  1. app.py +148 -93
app.py CHANGED
@@ -134,12 +134,13 @@ def get_db_stats() -> Dict[str, Any]:
134
  """Neo4j 데이터베이스로부터 실시간 지식 그래프 통계 및 요약을 안전하게 조회합니다.
135
 
136
  Returns:
137
- Dict[str, Any]: 기사 건수, 기업 수, 기술 수, 세부 설명 목록
138
  """
139
  stats: Dict[str, Any] = {
140
  "articles": 0,
141
  "companies": 0,
142
  "technologies": 0,
 
143
  "companies_list": [],
144
  "techs_list": [],
145
  "recent_articles": [],
@@ -148,7 +149,7 @@ def get_db_stats() -> Dict[str, Any]:
148
  from src.retrieval.finRetrieval import get_neo4j_driver
149
  driver = get_neo4j_driver()
150
  with driver.session() as session:
151
- # 1. 각 노드 갯수 조회
152
  res_articles = session.run("MATCH (a:Article) RETURN count(a) as cnt").single()
153
  if res_articles:
154
  stats["articles"] = res_articles["cnt"]
@@ -161,6 +162,10 @@ def get_db_stats() -> Dict[str, Any]:
161
  if res_techs:
162
  stats["technologies"] = res_techs["cnt"]
163
 
 
 
 
 
164
  # 2. 기업 및 기술 목록 & 설명 조회 (상위 5개)
165
  res_comp_list = session.run(
166
  "MATCH (c:AICompany) "
@@ -208,7 +213,7 @@ def build_stats_html(stats: Dict[str, Any]) -> str:
208
  for t in stats.get("techs_list", []):
209
  tech_html += f"""
210
  <div class="definition-item">
211
- <span class="definition-name" style="color: #059669;">💡 {t['name']}</span>
212
  <span class="definition-desc">{t['desc']}</span>
213
  </div>
214
  """
@@ -231,25 +236,37 @@ def build_stats_html(stats: Dict[str, Any]) -> str:
231
  if not news_list_html:
232
  news_list_html = '<div style="font-size:10px; color:#94a3b8;">최근 수집된 기사가 없습니다.</div>'
233
 
 
 
234
  html: str = f"""
235
  <div class="dashboard-container">
236
- <div style="font-size: 15px; font-weight: 800; color: #4f46e5; margin-bottom: 4px; display: flex; align-items: center; gap: 6px;">
237
- 📊 <span>지식 그래프 대시보드</span>
 
 
 
238
  </div>
239
- <p style="font-size: 11px; color: #64748b; margin-top: -2px; margin-bottom: 12px;">실시간 연동 통계</p>
240
 
241
  <div class="stats-grid">
242
  <div class="stat-card">
243
- <div class="stat-lbl">📰 뉴스 기사</div>
244
  <div class="stat-val">{stats['articles']}건</div>
245
  </div>
246
  <div class="stat-card">
247
- <div class="stat-lbl">🏢 핵심 기업</div>
248
- <div class="stat-val">{stats['companies']}개</div>
249
  </div>
250
  <div class="stat-card">
251
- <div class="stat-lbl">💡 주요 기술</div>
252
- <div class="stat-val">{stats['technologies']}개</div>
 
 
 
 
 
 
 
253
  </div>
254
  </div>
255
 
@@ -285,101 +302,136 @@ except Exception:
285
  gradio_major = 4 # 기본값 백업
286
 
287
  theme_obj = gr.themes.Soft(
288
- font=[gr.themes.GoogleFont("Pretendard"), gr.themes.GoogleFont("Noto Sans KR"), "sans-serif"],
289
- primary_hue="indigo",
290
- secondary_hue="blue",
291
  )
292
 
293
  custom_css: str = """
294
- /* 대시보드 메인 컨테이너 */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  .dashboard-container {
296
- background-color: #f8fafc;
297
- border: 1px solid #e2e8f0;
 
 
298
  border-radius: 12px;
299
  padding: 12px;
300
- font-family: 'Pretendard', 'Noto Sans KR', sans-serif;
301
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03);
302
  }
303
  .dark .dashboard-container {
304
- background-color: #0f172a;
305
- border-color: #1e293b;
 
306
  }
307
 
308
- /* 통계 그리드 및 카드 */
309
  .stats-grid {
310
  display: grid;
311
- grid-template-columns: repeat(3, 1fr);
312
  gap: 6px;
313
- margin-bottom: 12px;
314
  }
315
  .stat-card {
316
- background: white;
317
- border: 1px solid #e2e8f0;
318
  border-radius: 6px;
319
- padding: 6px 4px;
320
  text-align: center;
321
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.02);
322
- transition: all 0.2s ease-in-out;
323
  }
324
  .stat-card:hover {
325
  transform: translateY(-1px);
326
- box-shadow: 0 3px 5px rgba(0, 0, 0, 0.04);
 
 
327
  }
328
  .dark .stat-card {
329
- background: #1e293b;
330
- border-color: #334155;
331
  color: #f1f5f9;
332
  }
 
 
 
333
  .stat-val {
334
  font-size: 13px;
335
  font-weight: 800;
336
- color: #4f46e5;
337
- margin-top: 2px;
338
  }
339
  .dark .stat-val {
340
- color: #818cf8;
341
  }
342
  .stat-lbl {
343
  font-size: 9px;
344
- color: #64748b;
345
  font-weight: 500;
346
  }
347
  .dark .stat-lbl {
348
  color: #94a3b8;
349
  }
350
 
351
- /* 주요 기업 및 기술 정의 리스트 스타일 */
352
  .definition-list {
353
  display: flex;
354
  flex-direction: column;
355
  gap: 4px;
356
- margin-bottom: 10px;
357
  }
358
  .definition-item {
359
- background-color: white;
360
- border: 1px solid #e2e8f0;
361
  border-radius: 5px;
362
  padding: 4px 6px;
363
  display: flex;
364
  flex-direction: column;
365
  gap: 1px;
366
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.01);
 
 
 
 
 
367
  }
368
  .dark .definition-item {
369
- background-color: #1e293b;
370
- border-color: #334155;
 
 
 
 
371
  }
372
  .definition-name {
373
  font-size: 10px;
374
- font-weight: 700;
375
- color: #4f46e5;
 
 
 
376
  }
377
  .dark .definition-name {
378
- color: #818cf8;
379
  }
380
  .definition-desc {
381
  font-size: 9px;
382
- color: #475569;
383
  line-height: 1.3;
384
  }
385
  .dark .definition-desc {
@@ -388,16 +440,16 @@ custom_css: str = """
388
 
389
  /* 최근 뉴스 타임라인 및 스크롤바 스타일 */
390
  .news-feed-container {
391
- max-height: 110px;
392
  overflow-y: auto;
393
- border: 1px solid #e2e8f0;
394
- border-radius: 6px;
395
- padding: 6px;
396
- background: white;
397
  }
398
  .dark .news-feed-container {
399
- background: #1e293b;
400
- border-color: #334155;
401
  }
402
  /* 스크롤바 커스텀 */
403
  .news-feed-container::-webkit-scrollbar {
@@ -407,26 +459,26 @@ custom_css: str = """
407
  background: transparent;
408
  }
409
  .news-feed-container::-webkit-scrollbar-thumb {
410
- background: #cbd5e1;
411
  border-radius: 2px;
412
  }
413
  .dark .news-feed-container::-webkit-scrollbar-thumb {
414
- background: #475569;
415
  }
416
 
417
  .news-item {
418
- border-left: 2px solid #6366f1;
419
- padding-left: 8px;
420
- margin-bottom: 6px;
421
  position: relative;
422
  }
423
  .news-item:last-child {
424
  margin-bottom: 0;
425
  }
426
  .news-title {
427
- font-size: 11px;
428
  font-weight: 600;
429
- color: #1e293b;
430
  text-decoration: none;
431
  line-height: 1.3;
432
  display: block;
@@ -435,56 +487,56 @@ custom_css: str = """
435
  text-overflow: ellipsis;
436
  }
437
  .news-title:hover {
438
- color: #4f46e5;
439
  text-decoration: underline;
440
  }
441
  .dark .news-title {
442
  color: #cbd5e1;
443
  }
444
  .dark .news-title:hover {
445
- color: #818cf8;
446
  }
447
  .news-meta {
448
- font-size: 9px;
449
  color: #94a3b8;
450
  margin-top: 1px;
451
  }
452
 
453
  /* 서브타이틀 헤더 스타일 */
454
  .section-subtitle {
455
- font-size: 12px;
456
  font-weight: 700;
457
- color: #0f172a;
458
- margin: 10px 0 6px 0;
459
- border-bottom: 1px solid #e2e8f0;
460
- padding-bottom: 4px;
461
  display: flex;
462
  align-items: center;
463
  gap: 4px;
464
  }
465
  .dark .section-subtitle {
466
  color: #f8fafc;
467
- border-color: #334155;
468
  }
469
 
470
- /* 챗봇 버튼 고대비화 스타일 (흰색으로 안 보이던 현상 해결) */
471
  button.primary,
472
  .primary-btn,
473
  button.lg.primary,
474
  button.sm.primary,
475
  button.variant-primary {
476
- background-color: #4f46e5 !important;
477
  color: white !important;
478
  font-weight: 800 !important;
479
  border: none !important;
480
- box-shadow: 0 4px 6px rgba(79, 70, 229, 0.2) !important;
481
  transition: all 0.2s ease-in-out !important;
482
  }
483
  button.primary:hover,
484
  .primary-btn:hover,
485
  button.variant-primary:hover {
486
- background-color: #4338ca !important;
487
- box-shadow: 0 6px 12px rgba(79, 70, 229, 0.3) !important;
488
  transform: translateY(-1px) !important;
489
  }
490
 
@@ -495,29 +547,32 @@ button.sm.secondary,
495
  button.wrap,
496
  button.variant-secondary,
497
  .secondary-btn {
498
- background-color: #f1f5f9 !important;
499
- color: #334155 !important;
500
- border: 1px solid #cbd5e1 !important;
501
  font-weight: 700 !important;
502
  transition: all 0.2s ease-in-out !important;
 
503
  }
504
  .dark button.secondary,
505
  .dark button.variant-secondary,
506
  .dark .secondary-btn {
507
- background-color: #1e293b !important;
508
  color: #f1f5f9 !important;
509
- border-color: #475569 !important;
510
  }
511
  button.secondary:hover,
512
  button.variant-secondary:hover,
513
  .secondary-btn:hover {
514
- background-color: #e2e8f0 !important;
515
- color: #0f172a !important;
 
516
  }
517
  .dark button.secondary:hover,
518
  .dark button.variant-secondary:hover {
519
- background-color: #334155 !important;
520
  color: white !important;
 
521
  }
522
  """
523
 
@@ -529,13 +584,13 @@ interface_kwargs = {
529
  container=False,
530
  scale=7,
531
  ),
532
- "title": "FinNode — AI 기업 트렌드 분석 챗봇",
533
  "description": "> 최신 AI 뉴스를 기반으로 구축된 지식 그래프(GraphRAG)에서 답변합니다.",
534
  "examples": [
 
 
535
  "어떤 기업이 LLM 기술을 개발하나요?",
536
- "KT나 SKT 등 통신사들의 AI 비서 서비 LLM 전략",
537
- "최근 1주일간 가장 이슈가 된 AI 분야 뉴스 종합 브리핑",
538
- "국내 주요 기업들의 최신 생성형 AI 서비스 출시 동향은?",
539
  ],
540
  "cache_examples": False,
541
  }
@@ -564,11 +619,11 @@ else:
564
  with gr.Blocks(**blocks_kwargs) as demo:
565
  # 1. 상단 글로벌 네비게이션 바 (GNB)
566
  gr.HTML("""
567
- <div style="display: flex; justify-content: space-between; align-items: center; padding: 15px 20px; border-bottom: 1px solid #e2e8f0; background-color: white; margin: -20px -20px 20px -20px;">
568
- <div style="font-size: 20px; font-weight: 900; color: #0f172a; display: flex; align-items: center; gap: 12px;">
569
- FinNode <span style="font-size: 14px; font-weight: 600; color: #4f46e5;">GraphRAG 기반 엔터프라이즈 분석</span>
570
  </div>
571
- <div style="display: flex; gap: 18px; color: #64748b; font-size: 18px; cursor: pointer;">
572
  <span>🔔</span> <span>⚙️</span> <span>👤</span>
573
  </div>
574
  </div>
@@ -586,8 +641,8 @@ with gr.Blocks(**blocks_kwargs) as demo:
586
  # 메인 타이틀 (챗봇 영역 상단 중앙)
587
  gr.HTML("""
588
  <div style="text-align: center; padding: 10px 0 20px 0;">
589
- <h2 style="font-size: 18px; font-weight: 700; color: #334155; margin-bottom: 5px;">FinNode — AI 기업 트렌드 분석 챗봇</h2>
590
- <p style="color: #64748b; font-size: 13px;">최신 AI 뉴스를 기반으로 구축된 지식 그래프(GraphRAG)에서 답변합니다.</p>
591
  </div>
592
  """)
593
 
 
134
  """Neo4j 데이터베이스로부터 실시간 지식 그래프 통계 및 요약을 안전하게 조회합니다.
135
 
136
  Returns:
137
+ Dict[str, Any]: 기사 건수, 기업 수, 기술 수, 관계 수, 세부 설명 목록
138
  """
139
  stats: Dict[str, Any] = {
140
  "articles": 0,
141
  "companies": 0,
142
  "technologies": 0,
143
+ "relationships": 0,
144
  "companies_list": [],
145
  "techs_list": [],
146
  "recent_articles": [],
 
149
  from src.retrieval.finRetrieval import get_neo4j_driver
150
  driver = get_neo4j_driver()
151
  with driver.session() as session:
152
+ # 1. 각 노드 및 에지 갯수 조회
153
  res_articles = session.run("MATCH (a:Article) RETURN count(a) as cnt").single()
154
  if res_articles:
155
  stats["articles"] = res_articles["cnt"]
 
162
  if res_techs:
163
  stats["technologies"] = res_techs["cnt"]
164
 
165
+ res_edges = session.run("MATCH ()-[r]->() RETURN count(r) as cnt").single()
166
+ if res_edges:
167
+ stats["relationships"] = res_edges["cnt"]
168
+
169
  # 2. 기업 및 기술 목록 & 설명 조회 (상위 5개)
170
  res_comp_list = session.run(
171
  "MATCH (c:AICompany) "
 
213
  for t in stats.get("techs_list", []):
214
  tech_html += f"""
215
  <div class="definition-item">
216
+ <span class="definition-name">💡 {t['name']}</span>
217
  <span class="definition-desc">{t['desc']}</span>
218
  </div>
219
  """
 
236
  if not news_list_html:
237
  news_list_html = '<div style="font-size:10px; color:#94a3b8;">최근 수집된 기사가 없습니다.</div>'
238
 
239
+ node_count = stats['companies'] + stats['technologies']
240
+
241
  html: str = f"""
242
  <div class="dashboard-container">
243
+ <!-- Ambient background elements for beautiful glass effects -->
244
+ <div class="ambient-glow"></div>
245
+
246
+ <div style="font-size: 14px; font-weight: 850; color: #5b5b7f; margin-bottom: 2px; display: flex; align-items: center; gap: 5px; letter-spacing: -0.02em;">
247
+ 📊 <span>FinGraph AI Terminal</span>
248
  </div>
249
+ <p style="font-size: 9px; color: #47464e; margin-top: -2px; margin-bottom: 10px; font-weight: 500;">GraphRAG 실시간 분석 엔진</p>
250
 
251
  <div class="stats-grid">
252
  <div class="stat-card">
253
+ <div class="stat-lbl">📰 학습 기사</div>
254
  <div class="stat-val">{stats['articles']}건</div>
255
  </div>
256
  <div class="stat-card">
257
+ <div class="stat-lbl">🧬 지식 노드</div>
258
+ <div class="stat-val">{node_count}개</div>
259
  </div>
260
  <div class="stat-card">
261
+ <div class="stat-lbl">⛓️ 관계 연결</div>
262
+ <div class="stat-val">{stats['relationships']}개</div>
263
+ </div>
264
+ <div class="stat-card">
265
+ <div class="stat-lbl">⚡ 엔진 상태</div>
266
+ <div class="stat-val" style="color: #4d6075; display: flex; align-items: center; justify-content: center; gap: 3px;">
267
+ <span style="width: 6px; height: 6px; background-color: #5b5b7f; border-radius: 50%; display: inline-block; box-shadow: 0 0 6px #5b5b7f;"></span>
268
+ Active
269
+ </div>
270
  </div>
271
  </div>
272
 
 
302
  gradio_major = 4 # 기본값 백업
303
 
304
  theme_obj = gr.themes.Soft(
305
+ font=["Pretendard", "-apple-system", "BlinkMacSystemFont", "system-ui", "sans-serif"],
306
+ primary_hue="purple",
307
+ secondary_hue="slate",
308
  )
309
 
310
  custom_css: str = """
311
+ body {
312
+ background-color: #fbf9f6;
313
+ font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
314
+ }
315
+
316
+ /* Ambient glow point backgrounds */
317
+ .ambient-glow {
318
+ position: fixed;
319
+ top: 0; left: 0; right: 0; bottom: 0;
320
+ background: radial-gradient(circle at 85% 15%, rgba(196, 195, 236, 0.35) 0%, transparent 45%),
321
+ radial-gradient(circle at 15% 85%, rgba(180, 200, 225, 0.3) 0%, transparent 45%);
322
+ z-index: -1;
323
+ pointer-events: none;
324
+ }
325
+
326
+ /* 대시보드 투명 퍼플 글래스모피즘 컨테이너 */
327
  .dashboard-container {
328
+ background: rgba(245, 243, 240, 0.45) !important;
329
+ backdrop-filter: blur(24px) !important;
330
+ -webkit-backdrop-filter: blur(24px) !important;
331
+ border: 1px solid rgba(196, 195, 236, 0.45) !important;
332
  border-radius: 12px;
333
  padding: 12px;
334
+ box-shadow: 0 4px 12px -2px rgba(88, 89, 125, 0.05) !important;
335
+ font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, sans-serif;
336
  }
337
  .dark .dashboard-container {
338
+ background: rgba(15, 23, 42, 0.55) !important;
339
+ border-color: rgba(129, 140, 248, 0.25) !important;
340
+ box-shadow: 0 4px 12px -2px rgba(0, 0, 0, 0.3) !important;
341
  }
342
 
343
+ /* 통계 그리드 및 글래스 카드 */
344
  .stats-grid {
345
  display: grid;
346
+ grid-template-columns: repeat(2, 1fr);
347
  gap: 6px;
348
+ margin-bottom: 10px;
349
  }
350
  .stat-card {
351
+ background: rgba(255, 255, 255, 0.7);
352
+ border: 1px solid rgba(196, 195, 236, 0.4);
353
  border-radius: 6px;
354
+ padding: 5px 6px;
355
  text-align: center;
356
+ box-shadow: 0 1px 3px rgba(88, 89, 125, 0.02);
357
+ transition: all 0.25s ease-in-out;
358
  }
359
  .stat-card:hover {
360
  transform: translateY(-1px);
361
+ background: rgba(255, 255, 255, 0.9);
362
+ border-color: rgba(91, 91, 127, 0.6);
363
+ box-shadow: 0 4px 8px -2px rgba(88, 89, 125, 0.1);
364
  }
365
  .dark .stat-card {
366
+ background: rgba(30, 41, 59, 0.7);
367
+ border-color: rgba(129, 140, 248, 0.2);
368
  color: #f1f5f9;
369
  }
370
+ .dark .stat-card:hover {
371
+ border-color: rgba(129, 140, 248, 0.5);
372
+ }
373
  .stat-val {
374
  font-size: 13px;
375
  font-weight: 800;
376
+ color: #5b5b7f; /* 투명 퍼플 에디션 포인트 색상 */
377
+ margin-top: 1px;
378
  }
379
  .dark .stat-val {
380
+ color: #c4c3ec;
381
  }
382
  .stat-lbl {
383
  font-size: 9px;
384
+ color: #47464e;
385
  font-weight: 500;
386
  }
387
  .dark .stat-lbl {
388
  color: #94a3b8;
389
  }
390
 
391
+ /* 주요 기업 및 기술 정의 리스트 글래모피즘 스타일 */
392
  .definition-list {
393
  display: flex;
394
  flex-direction: column;
395
  gap: 4px;
396
+ margin-bottom: 8px;
397
  }
398
  .definition-item {
399
+ background: rgba(255, 255, 255, 0.5);
400
+ border: 1px solid rgba(196, 195, 236, 0.3);
401
  border-radius: 5px;
402
  padding: 4px 6px;
403
  display: flex;
404
  flex-direction: column;
405
  gap: 1px;
406
+ box-shadow: 0 1px 2px rgba(88, 89, 125, 0.01);
407
+ transition: all 0.2s ease;
408
+ }
409
+ .definition-item:hover {
410
+ background: rgba(255, 255, 255, 0.85);
411
+ border-color: rgba(91, 91, 127, 0.45);
412
  }
413
  .dark .definition-item {
414
+ background: rgba(30, 41, 59, 0.5);
415
+ border-color: rgba(129, 140, 248, 0.15);
416
+ }
417
+ .dark .definition-item:hover {
418
+ background: rgba(30, 41, 59, 0.8);
419
+ border-color: rgba(129, 140, 248, 0.4);
420
  }
421
  .definition-name {
422
  font-size: 10px;
423
+ font-weight: 800;
424
+ color: #5b5b7f; /* 퍼플 포인트 */
425
+ display: flex;
426
+ align-items: center;
427
+ gap: 3px;
428
  }
429
  .dark .definition-name {
430
+ color: #c4c3ec;
431
  }
432
  .definition-desc {
433
  font-size: 9px;
434
+ color: #47464e;
435
  line-height: 1.3;
436
  }
437
  .dark .definition-desc {
 
440
 
441
  /* 최근 뉴스 타임라인 및 스크롤바 스타일 */
442
  .news-feed-container {
443
+ max-height: 100px;
444
  overflow-y: auto;
445
+ border: 1px solid rgba(196, 195, 236, 0.35);
446
+ border-radius: 5px;
447
+ padding: 5px;
448
+ background: rgba(255, 255, 255, 0.5);
449
  }
450
  .dark .news-feed-container {
451
+ background: rgba(30, 41, 59, 0.5);
452
+ border-color: rgba(129, 140, 248, 0.15);
453
  }
454
  /* 스크롤바 커스텀 */
455
  .news-feed-container::-webkit-scrollbar {
 
459
  background: transparent;
460
  }
461
  .news-feed-container::-webkit-scrollbar-thumb {
462
+ background: rgba(91, 91, 127, 0.3);
463
  border-radius: 2px;
464
  }
465
  .dark .news-feed-container::-webkit-scrollbar-thumb {
466
+ background: rgba(196, 195, 236, 0.3);
467
  }
468
 
469
  .news-item {
470
+ border-left: 2px solid #5b5b7f; /* 퍼플 포인트 */
471
+ padding-left: 6px;
472
+ margin-bottom: 5px;
473
  position: relative;
474
  }
475
  .news-item:last-child {
476
  margin-bottom: 0;
477
  }
478
  .news-title {
479
+ font-size: 10px;
480
  font-weight: 600;
481
+ color: #1b1c1a;
482
  text-decoration: none;
483
  line-height: 1.3;
484
  display: block;
 
487
  text-overflow: ellipsis;
488
  }
489
  .news-title:hover {
490
+ color: #5b5b7f;
491
  text-decoration: underline;
492
  }
493
  .dark .news-title {
494
  color: #cbd5e1;
495
  }
496
  .dark .news-title:hover {
497
+ color: #c4c3ec;
498
  }
499
  .news-meta {
500
+ font-size: 8px;
501
  color: #94a3b8;
502
  margin-top: 1px;
503
  }
504
 
505
  /* 서브타이틀 헤더 스타일 */
506
  .section-subtitle {
507
+ font-size: 11px;
508
  font-weight: 700;
509
+ color: #1b1c1a;
510
+ margin: 8px 0 4px 0;
511
+ border-bottom: 1px solid rgba(196, 195, 236, 0.35);
512
+ padding-bottom: 3px;
513
  display: flex;
514
  align-items: center;
515
  gap: 4px;
516
  }
517
  .dark .section-subtitle {
518
  color: #f8fafc;
519
+ border-color: rgba(129, 140, 248, 0.2);
520
  }
521
 
522
+ /* 챗봇 버튼 퍼플 포인트 스타일 (흰색으로 안 보이던 현상 해결) */
523
  button.primary,
524
  .primary-btn,
525
  button.lg.primary,
526
  button.sm.primary,
527
  button.variant-primary {
528
+ background-color: #5b5b7f !important;
529
  color: white !important;
530
  font-weight: 800 !important;
531
  border: none !important;
532
+ box-shadow: 0 4px 6px rgba(91, 91, 127, 0.2) !important;
533
  transition: all 0.2s ease-in-out !important;
534
  }
535
  button.primary:hover,
536
  .primary-btn:hover,
537
  button.variant-primary:hover {
538
+ background-color: #434466 !important;
539
+ box-shadow: 0 6px 12px rgba(91, 91, 127, 0.3) !important;
540
  transform: translateY(-1px) !important;
541
  }
542
 
 
547
  button.wrap,
548
  button.variant-secondary,
549
  .secondary-btn {
550
+ background-color: rgba(255, 255, 255, 0.6) !important;
551
+ color: #47464e !important;
552
+ border: 1px solid rgba(196, 195, 236, 0.45) !important;
553
  font-weight: 700 !important;
554
  transition: all 0.2s ease-in-out !important;
555
+ backdrop-filter: blur(8px);
556
  }
557
  .dark button.secondary,
558
  .dark button.variant-secondary,
559
  .dark .secondary-btn {
560
+ background-color: rgba(30, 41, 59, 0.6) !important;
561
  color: #f1f5f9 !important;
562
+ border-color: rgba(129, 140, 248, 0.2) !important;
563
  }
564
  button.secondary:hover,
565
  button.variant-secondary:hover,
566
  .secondary-btn:hover {
567
+ background-color: rgba(255, 255, 255, 0.95) !important;
568
+ color: #1b1c1a !important;
569
+ border-color: rgba(91, 91, 127, 0.5) !important;
570
  }
571
  .dark button.secondary:hover,
572
  .dark button.variant-secondary:hover {
573
+ background-color: rgba(30, 41, 59, 0.95) !important;
574
  color: white !important;
575
+ border-color: rgba(129, 140, 248, 0.4) !important;
576
  }
577
  """
578
 
 
584
  container=False,
585
  scale=7,
586
  ),
587
+ "title": "FinGraphGraphRAG AI Terminal",
588
  "description": "> 최신 AI 뉴스를 기반으로 구축된 지식 그래프(GraphRAG)에서 답변합니다.",
589
  "examples": [
590
+ "삼성전자의 최근 AI 기술 트렌드는?",
591
+ "카카오가 개발 중인 AI 서비스 목록을 알려줘",
592
  "어떤 기업이 LLM 기술을 개발하나요?",
593
+ "최근 AI 관련 기사를 요약해줘",
 
 
594
  ],
595
  "cache_examples": False,
596
  }
 
619
  with gr.Blocks(**blocks_kwargs) as demo:
620
  # 1. 상단 글로벌 네비게이션 바 (GNB)
621
  gr.HTML("""
622
+ <div style="display: flex; justify-content: space-between; align-items: center; padding: 15px 20px; border-bottom: 1px solid rgba(196, 195, 236, 0.45); background-color: rgba(255, 255, 255, 0.65); backdrop-filter: blur(12px); margin: -20px -20px 20px -20px;">
623
+ <div style="font-size: 20px; font-weight: 900; color: #5b5b7f; display: flex; align-items: center; gap: 12px;">
624
+ FinGraph <span style="font-size: 14px; font-weight: 600; color: #5b5b7f;">GraphRAG Enhanced AI Terminal</span>
625
  </div>
626
+ <div style="display: flex; gap: 18px; color: #5b5b7f; font-size: 18px; cursor: pointer;">
627
  <span>🔔</span> <span>⚙️</span> <span>👤</span>
628
  </div>
629
  </div>
 
641
  # 메인 타이틀 (챗봇 영역 상단 중앙)
642
  gr.HTML("""
643
  <div style="text-align: center; padding: 10px 0 20px 0;">
644
+ <h2 style="font-size: 18px; font-weight: 800; color: #5b5b7f; margin-bottom: 5px;">FinGraphGraphRAG AI Terminal</h2>
645
+ <p style="color: #47464e; font-size: 13px;">최신 AI 뉴스를 기반으로 구축된 지식 그래프(GraphRAG)에서 답변합니다.</p>
646
  </div>
647
  """)
648