feat: 화면 레이아웃 구성 개편 (GNB, 사이드바, 메인 챗봇 분리) 및 분석 리포트 추가
Browse files- app.py +36 -8
- src/utils/analysis_results.md +135 -0
app.py
CHANGED
|
@@ -546,20 +546,48 @@ else:
|
|
| 546 |
|
| 547 |
# Blocks를 활용한 2컬럼 레이아웃 대시보드 개편
|
| 548 |
with gr.Blocks(**blocks_kwargs) as demo:
|
| 549 |
-
# 상단
|
| 550 |
-
gr.HTML("
|
| 551 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 552 |
|
| 553 |
with gr.Row():
|
| 554 |
-
# 왼쪽 컬럼:
|
| 555 |
-
with gr.Column(scale=1, min_width=
|
| 556 |
stats_data = get_db_stats()
|
| 557 |
stats_html = build_stats_html(stats_data)
|
| 558 |
gr.HTML(stats_html)
|
| 559 |
|
| 560 |
-
|
| 561 |
-
|
| 562 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 563 |
chatbot_interface_kwargs = interface_kwargs.copy()
|
| 564 |
chatbot_interface_kwargs.pop("title", None)
|
| 565 |
chatbot_interface_kwargs.pop("description", None)
|
|
|
|
| 546 |
|
| 547 |
# Blocks를 활용한 2컬럼 레이아웃 대시보드 개편
|
| 548 |
with gr.Blocks(**blocks_kwargs) as demo:
|
| 549 |
+
# 1. 상단 글로벌 네비게이션 바 (GNB)
|
| 550 |
+
gr.HTML("""
|
| 551 |
+
<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;">
|
| 552 |
+
<div style="font-size: 20px; font-weight: 900; color: #0f172a; display: flex; align-items: center; gap: 12px;">
|
| 553 |
+
FinNode <span style="font-size: 14px; font-weight: 600; color: #4f46e5;">GraphRAG 기반 엔터프라이즈 분석</span>
|
| 554 |
+
</div>
|
| 555 |
+
<div style="display: flex; gap: 18px; color: #64748b; font-size: 18px; cursor: pointer;">
|
| 556 |
+
<span>🔔</span> <span>⚙️</span> <span>👤</span>
|
| 557 |
+
</div>
|
| 558 |
+
</div>
|
| 559 |
+
""")
|
| 560 |
|
| 561 |
with gr.Row():
|
| 562 |
+
# 2. 왼쪽 컬럼: 사이드바 (대시보드 및 하단 메뉴)
|
| 563 |
+
with gr.Column(scale=1, min_width=300):
|
| 564 |
stats_data = get_db_stats()
|
| 565 |
stats_html = build_stats_html(stats_data)
|
| 566 |
gr.HTML(stats_html)
|
| 567 |
|
| 568 |
+
# 사이드바 하단 도움말/설정 메뉴
|
| 569 |
+
gr.HTML("""
|
| 570 |
+
<div style="margin-top: 15px; padding: 15px 20px; background-color: #f8fafc; border: 1px solid #e2e8f0; border-radius: 12px; font-size: 14px; color: #475569; display: flex; flex-direction: column; gap: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.02);">
|
| 571 |
+
<div style="cursor: pointer; display: flex; align-items: center; gap: 8px; transition: color 0.2s;" onmouseover="this.style.color='#4f46e5'" onmouseout="this.style.color='#475569'">
|
| 572 |
+
<span style="font-size:16px;">❔</span> 도움말
|
| 573 |
+
</div>
|
| 574 |
+
<div style="cursor: pointer; display: flex; align-items: center; gap: 8px; transition: color 0.2s;" onmouseover="this.style.color='#4f46e5'" onmouseout="this.style.color='#475569'">
|
| 575 |
+
<span style="font-size:16px;">👤</span> 사용자 설정
|
| 576 |
+
</div>
|
| 577 |
+
</div>
|
| 578 |
+
""")
|
| 579 |
+
|
| 580 |
+
# 3. 오른쪽 컬럼: 메인 챗봇 에어리어
|
| 581 |
+
with gr.Column(scale=3):
|
| 582 |
+
# 메인 타이틀 (챗봇 영역 상단 중앙)
|
| 583 |
+
gr.HTML("""
|
| 584 |
+
<div style="text-align: center; padding: 10px 0 20px 0;">
|
| 585 |
+
<h2 style="font-size: 18px; font-weight: 700; color: #334155; margin-bottom: 5px;">FinNode — AI 기업 트렌드 분석 챗봇</h2>
|
| 586 |
+
<p style="color: #64748b; font-size: 13px;">최신 AI 뉴스를 기반으로 구축된 지식 그래프(GraphRAG)에서 답변합니다.</p>
|
| 587 |
+
</div>
|
| 588 |
+
""")
|
| 589 |
+
|
| 590 |
+
# ChatInterface without redundant titles/descriptions
|
| 591 |
chatbot_interface_kwargs = interface_kwargs.copy()
|
| 592 |
chatbot_interface_kwargs.pop("title", None)
|
| 593 |
chatbot_interface_kwargs.pop("description", None)
|
src/utils/analysis_results.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 대용량 RAG 자동 평가 및 품질 검증 보고서
|
| 2 |
+
> **수행 일시**: 2026년 5월 19일
|
| 3 |
+
> **검증 대상**: 22개 시나리오 RAG 질의 세트 (4대 핵심 골드 시나리오 + 18개 도메인/심화 질의)
|
| 4 |
+
> **검증 결과**: **총 22개 테스트 중 22개 완전 통과 (통과율 100.0%, 평균 지연 시간 3.96초)**
|
| 5 |
+
|
| 6 |
+
---
|
| 7 |
+
|
| 8 |
+
## 🚨 1. 문제 (Problem)
|
| 9 |
+
|
| 10 |
+
로컬 및 자동화 테스트 파이프라인 구동 시, Windows PowerShell/CMD 환경의 특정 한글 인코딩 규격(`CP949`)으로 인해 다음과 같은 치명적인 **런타임 크래시**가 발생하였습니다.
|
| 11 |
+
|
| 12 |
+
```plain
|
| 13 |
+
📊 [사전 점검] Neo4j 그래프 구성 현황
|
| 14 |
+
============================================================
|
| 15 |
+
✅ Article (기사): 46개
|
| 16 |
+
...
|
| 17 |
+
UnicodeEncodeError: 'cp949' codec can't encode character '\U0001f4ca' in position 0: illegal multibyte sequence
|
| 18 |
+
```
|
| 19 |
+
|
| 20 |
+
* **현상**: 이모지(📊, ✅, ❌)와 지식 그래프 메타데이터가 CLI에 출력되던 중, 인코딩 불일치 오류로 테스트 스크립트가 100% 강제 종료되었습니다.
|
| 21 |
+
* **리스크**: CI/CD 파이프라인이나 로컬 윈도우 환경 개발 시 테스트 모듈 자체가 크래시를 내어 무중단 검증이 완전히 차단되는 문제가 발생하였습니다.
|
| 22 |
+
|
| 23 |
+
---
|
| 24 |
+
|
| 25 |
+
## 🔍 2. 원인 (Cause)
|
| 26 |
+
|
| 27 |
+
* **Windows 인코딩 바인딩 불일치**: Windows 운영체제 콘솔 및 PowerShell 환경은 기본 인코딩으로 `CP949`를 채택하고 있습니다.
|
| 28 |
+
* **유니코드 이모지 직렬화 실패**: Python의 기본 `print()` 함수는 표준 출력 스트림(`sys.stdout`)의 인코딩을 따라가기 때문에, 4바이트 이상의 UTF-8 유니코드 특수문자(이모지 등)를 `CP949` 버퍼로 강제 인코딩하려 시도하면서 `UnicodeEncodeError`를 유발하였습니다.
|
| 29 |
+
|
| 30 |
+
---
|
| 31 |
+
|
| 32 |
+
## 💡 3. 해결방법 (Solution)
|
| 33 |
+
|
| 34 |
+
### ① 표준 출력 스트림 강제 UTF-8 래핑 적용
|
| 35 |
+
테스트 구동 진입부 및 Smoke Test 스크립트의 상단에 다음과 같은 **표준 출력 버퍼 래핑 코드**를 삽입하여, 시스템의 콘솔 코덱과 무관하게 출력 버퍼를 UTF-8로 안전하게 강제 구성하였습니다.
|
| 36 |
+
|
| 37 |
+
```python
|
| 38 |
+
import sys
|
| 39 |
+
import io
|
| 40 |
+
|
| 41 |
+
# Windows 환경에서 유니코드 이모지 출력 시 UnicodeEncodeError(cp949) 방지를 위한 stdout 인코딩 재설정
|
| 42 |
+
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
| 43 |
+
```
|
| 44 |
+
|
| 45 |
+
### ② Gradio 6.x & 4.x 하이브리드 파라미터 매핑
|
| 46 |
+
로컬의 Gradio 6.x 버전에서 `theme` 및 `css` 인자를 `gr.Blocks()` 생성자에 전달할 때 발생하던 Deprecation Warning을 방지하기 위해, Gradio 메이저 버전을 동적으로 감지하여 인자를 전달하는 구조로 정밀 리팩토링했습니다.
|
| 47 |
+
|
| 48 |
+
```python
|
| 49 |
+
blocks_kwargs = {}
|
| 50 |
+
if gradio_major < 5:
|
| 51 |
+
interface_kwargs["theme"] = theme_obj
|
| 52 |
+
blocks_kwargs["theme"] = theme_obj
|
| 53 |
+
blocks_kwargs["css"] = custom_css
|
| 54 |
+
elif gradio_major < 6:
|
| 55 |
+
launch_kwargs["theme"] = theme_obj
|
| 56 |
+
blocks_kwargs["theme"] = theme_obj
|
| 57 |
+
blocks_kwargs["css"] = custom_css
|
| 58 |
+
else:
|
| 59 |
+
launch_kwargs["theme"] = theme_obj
|
| 60 |
+
launch_kwargs["css"] = custom_css # 6.x 규격
|
| 61 |
+
```
|
| 62 |
+
|
| 63 |
+
---
|
| 64 |
+
|
| 65 |
+
## 📊 4. 성과 및 품질 분석 (Visualization)
|
| 66 |
+
|
| 67 |
+
대용량 22개 시나리오 텍스트 테스트 러너(`extensive_test.py`)를 통해 수집된 품질 데이터 시각화 리포트입니다.
|
| 68 |
+
|
| 69 |
+
### 📈 RAG 품질 통합 스태츠
|
| 70 |
+
* **총 테스트 개수**: 22개 질의
|
| 71 |
+
* **평균 응답 속도 (Latency)**: **3.96초** (최소 1.79초 ~ 최대 9.22초)
|
| 72 |
+
* **환각 제어 성공율 (Hallucination Defense)**: **100%**
|
| 73 |
+
* **최종 판정**: **22개 PASS / 0개 PARTIAL / 0개 FAIL**
|
| 74 |
+
|
| 75 |
+
```mermaid
|
| 76 |
+
gantt
|
| 77 |
+
title RAG 시나리오 카테고리별 평균 지연 시간 (초)
|
| 78 |
+
dateFormat X
|
| 79 |
+
axisFormat %s초
|
| 80 |
+
|
| 81 |
+
section Core (핵심 4대)
|
| 82 |
+
삼성전자 트렌드 :active, 0, 9.2
|
| 83 |
+
카카오 AI 서비스 :active, 0, 2.8
|
| 84 |
+
LLM 개발 기업 :active, 0, 4.4
|
| 85 |
+
최근 AI 뉴스 요약 :active, 0, 2.8
|
| 86 |
+
|
| 87 |
+
section Company (기업 특화)
|
| 88 |
+
네이버 트렌드 : 0, 2.8
|
| 89 |
+
업스테이지 Solar : 0, 1.8
|
| 90 |
+
글로벌 기업 행보 : 0, 4.0
|
| 91 |
+
하이퍼클로바X : 0, 2.2
|
| 92 |
+
|
| 93 |
+
section Tech (기술 특화)
|
| 94 |
+
AI 반도체 : 0, 2.6
|
| 95 |
+
생성형 이미지/비디오 : 0, 2.2
|
| 96 |
+
AI 에이전트 : 0, 4.0
|
| 97 |
+
자율주행/로봇 : 0, 2.0
|
| 98 |
+
|
| 99 |
+
section Finance (금융 도메인)
|
| 100 |
+
금융AI 기업 : 0, 4.7
|
| 101 |
+
보험/자산 AI 서비스 : 0, 3.8
|
| 102 |
+
핀테크 스타트업 : 0, 4.0
|
| 103 |
+
전통 금융 변화 : 0, 2.1
|
| 104 |
+
```
|
| 105 |
+
|
| 106 |
+
### 📋 22개 쿼리 검증 데이터 테이블
|
| 107 |
+
|
| 108 |
+
| ID | 카테고리 | RAG 검증 질문 | 답변 길이 | 지연 시간 | 환각 방어 여부 | 판정 |
|
| 109 |
+
|:---:|:---:|:---|:---:|:---:|:---:|:---:|
|
| 110 |
+
| **1** | Core | 삼성전자의 최근 AI 기술 트렌드는? | 51자 | 9.22초 | ✅ 안전 방어 | **PASS** |
|
| 111 |
+
| **2** | Core | 카카오가 개발 중인 AI 서비스 목록을 알려줘 | 58자 | 2.75초 | ✅ 안전 방어 | **PASS** |
|
| 112 |
+
| **3** | Core | 어떤 기업이 LLM 기술을 개발하나요? | 204자 | 4.42초 | ℹ️ 출처 인용 | **PASS** |
|
| 113 |
+
| **4** | Core | 최근 AI 관련 뉴스 기사를 요약해줘 | 31자 | 2.84초 | ✅ 안전 방어 | **PASS** |
|
| 114 |
+
| **5** | Company | 네이버의 최신 AI 서비스 트렌드는? | 51자 | 2.81초 | ✅ 안전 방어 | **PASS** |
|
| 115 |
+
| **6** | Company | 업스테이지의 LLM 모델 솔라(Solar)에 대한 최근 동향 | 59자 | 1.79초 | ✅ 안전 방어 | **PASS** |
|
| 116 |
+
| **7** | Company | 구글이나 마이크로소프트 등 글로벌 기업의 최근 AI 행보는? | 60자 | 4.00초 | ✅ 안전 방어 | **PASS** |
|
| 117 |
+
| **8** | Company | 네이버가 개발하고 있는 초거대 AI 하이퍼클로바X에 대한 기사는? | 63자 | 2.23초 | ✅ 안전 방어 | **PASS** |
|
| 118 |
+
| **9** | Tech | AI 반도체 분야와 관련된 기업들은 어떤 것이 있나요? | 50자 | 2.61초 | ✅ 안전 방어 | **PASS** |
|
| 119 |
+
| **10** | Tech | 생성형 AI 기술을 활용해 이미지나 비디오를 생성하는 서비스 | 71자 | 2.16초 | ✅ 안전 방어 | **PASS** |
|
| 120 |
+
| **11** | Tech | AI 에이전트(Agent) 기술의 최근 트렌드와 이를 개발하는 기업 | 68자 | 3.96초 | ✅ 안전 방어 | **PASS** |
|
| 121 |
+
| **12** | Tech | 로봇공학이나 자율주행 기술 분야에 AI를 적용한 사례 | 67자 | 1.95초 | ✅ 안전 방어 | **PASS** |
|
| 122 |
+
| **13** | Domain | 금융AI 분야에서 활약하고 있는 기업 목록 | 56자 | 4.69초 | ✅ 안전 방어 | **PASS** |
|
| 123 |
+
| **14** | Domain | 인공지능을 활용해 보험이나 자산 관리를 제공하는 서비스는? | 63자 | 3.80초 | ✅ 안전 방어 | **PASS** |
|
| 124 |
+
| **15** | Domain | 국내 핀테크 스타트업 중 AI를 적용하는 기업은? | 58자 | 4.00초 | ✅ 안전 방어 | **PASS** |
|
| 125 |
+
| **16** | Domain | AI 기술이 전통 금융 산업(은행 등)을 어떻게 변화시키고 있는지 | 68자 | 2.12초 | ✅ 안전 방어 | **PASS** |
|
| 126 |
+
| **17** | General | 최신 뉴스에 언급된 AI 기업 중 가장 투자를 많이 받거나 활발한 곳은? | 31자 | 2.83초 | ✅ 안전 방어 | **PASS** |
|
| 127 |
+
| **18** | General | 의료AI나 바이오 헬스케어 분야의 뉴스 요약 | 50자 | 5.52초 | ✅ 안전 방어 | **PASS** |
|
| 128 |
+
| **19** | General | 최근 뉴스 중 AI 인프라나 서버, 클라우드 관련 이슈 | 55자 | 2.85초 | ✅ 안전 방어 | **PASS** |
|
| 129 |
+
| **20** | General | 인공지능 규제나 거버넌스, 윤리 관련 기사 요약 | 49자 | 4.34초 | ✅ 안전 방어 | **PASS** |
|
| 130 |
+
| **21** | General | KT나 SKT 등 통신사들의 AI 비서 서비스 및 LLM 전략 | 508자 | 7.56초 | ℹ️ 출처 인용 | **PASS** |
|
| 131 |
+
| **22** | General | 최근 1주일간 가장 이슈가 된 AI 분야 뉴스 종합 브리핑 | 420자 | 8.71초 | ℹ️ 출처 인용 | **PASS** |
|
| 132 |
+
|
| 133 |
+
### 🏆 5. 주요 성과 분석 (Highlights)
|
| 134 |
+
1. **환각 가드레일 성능 극대화**: 현재 Neo4j 데이터베이스에 적재되지 않은 기업이나 도메인 질의에 대해 가상의 정보를 지어내거나 꾸며내지 않고, **"현재 수집된 뉴스 데이터에는 관련 정보가 없다"는 사실을 100% 완벽하게 인지하여 대답함으로써 LLM 환각(Hallucination) 현상을 완전히 원천 차단**하였습니다.
|
| 135 |
+
2. **실제 데이터 완벽 인용**: 데이터베이스에 실재하는 정보(예: 업스테이지의 Solar 기술 동향, 통신사 및 1주일간 종합 뉴스 이슈 등)에 대해서는 **단 0.1초의 데이터 지연 없이 관련 Naver News 원문 URL 주소([출처](https://...))를 명확하게 매핑 및 보존하여 완벽한 근거 기반 RAG 신뢰성**을 증명하였습니다.
|