refactor: 3:7 비율 적용, 고정 브리핑 마크다운 포맷 및 가독성 최적화, 전송 버튼 다크 슬레이트 통일
Browse files- app.py +42 -21
- src/retrieval/finRetrieval.py +21 -16
app.py
CHANGED
|
@@ -160,18 +160,18 @@ def get_db_stats() -> Dict[str, Any]:
|
|
| 160 |
if res_techs:
|
| 161 |
stats["technologies"] = res_techs["cnt"]
|
| 162 |
|
| 163 |
-
# 2. 기술 목록 & 설명 조회 (상위
|
| 164 |
res_tech_list = session.run(
|
| 165 |
"MATCH (t:AITechnology) "
|
| 166 |
-
"RETURN t.name as name, COALESCE(t.description, 'AI 혁신 기술 인프라') as desc LIMIT
|
| 167 |
)
|
| 168 |
stats["techs_list"] = [{"name": r["name"], "desc": r["desc"]} for r in res_tech_list]
|
| 169 |
|
| 170 |
-
# 3. 최근 기사 목록 조회 (최근
|
| 171 |
res_art_list = session.run(
|
| 172 |
"MATCH (a:Article) "
|
| 173 |
"RETURN a.title as title, a.published_date as date, a.url as url "
|
| 174 |
-
"ORDER BY a.published_date DESC LIMIT
|
| 175 |
)
|
| 176 |
stats["recent_articles"] = [
|
| 177 |
{"title": r["title"], "date": r["date"], "url": r["url"]}
|
|
@@ -193,7 +193,7 @@ def build_stats_html(stats: Dict[str, Any]) -> str:
|
|
| 193 |
if not keyword_html:
|
| 194 |
keyword_html = '<div style="font-size:12px; color:#94a3b8;">등록된 키워드가 없습니다.</div>'
|
| 195 |
|
| 196 |
-
# 2. 최근 기사 리스트 HTML 생성 (최대
|
| 197 |
news_list_html: str = ""
|
| 198 |
for a in stats.get("recent_articles", []):
|
| 199 |
title = a["title"]
|
|
@@ -218,28 +218,49 @@ def build_stats_html(stats: Dict[str, Any]) -> str:
|
|
| 218 |
<!-- Ambient background elements for beautiful glass effects -->
|
| 219 |
<div class="ambient-glow"></div>
|
| 220 |
|
| 221 |
-
<div style="font-size: 16px; font-weight: 850; color: #
|
| 222 |
📊 <span>FinGraph AI Terminal</span>
|
| 223 |
</div>
|
| 224 |
-
<p style="font-size: 11px; color: #
|
| 225 |
|
|
|
|
| 226 |
<div class="stats-grid">
|
| 227 |
<div class="stat-card">
|
| 228 |
-
<div class="stat-lbl">
|
| 229 |
-
<div class="stat-val">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
</div>
|
| 231 |
<div class="stat-card">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 232 |
<div class="stat-lbl">🧬 지식 노드</div>
|
| 233 |
-
<div class="stat-val">{node_count}개</div>
|
| 234 |
</div>
|
| 235 |
</div>
|
| 236 |
|
| 237 |
-
<div class="section-subtitle">💡 최신 뉴스 키워드</div>
|
| 238 |
<div class="keyword-container">
|
| 239 |
{keyword_html}
|
| 240 |
</div>
|
| 241 |
|
| 242 |
-
<div class="section-subtitle">📰 최신 뉴스 피드</div>
|
| 243 |
<div class="news-feed-container">
|
| 244 |
<div class="news-feed">
|
| 245 |
{news_list_html}
|
|
@@ -511,24 +532,24 @@ body {
|
|
| 511 |
border-color: rgba(129, 140, 248, 0.6) !important;
|
| 512 |
}
|
| 513 |
|
| 514 |
-
/* 챗봇 버튼
|
| 515 |
button.primary,
|
| 516 |
.primary-btn,
|
| 517 |
button.lg.primary,
|
| 518 |
button.sm.primary,
|
| 519 |
button.variant-primary {
|
| 520 |
-
background-color: #
|
| 521 |
color: white !important;
|
| 522 |
font-weight: 800 !important;
|
| 523 |
border: none !important;
|
| 524 |
-
box-shadow: 0 4px 6px rgba(
|
| 525 |
transition: all 0.2s ease-in-out !important;
|
| 526 |
}
|
| 527 |
button.primary:hover,
|
| 528 |
.primary-btn:hover,
|
| 529 |
button.variant-primary:hover {
|
| 530 |
-
background-color: #
|
| 531 |
-
box-shadow: 0 6px 12px rgba(
|
| 532 |
transform: translateY(-1px) !important;
|
| 533 |
}
|
| 534 |
|
|
@@ -691,14 +712,14 @@ with gr.Blocks(**blocks_kwargs) as demo:
|
|
| 691 |
""")
|
| 692 |
|
| 693 |
with gr.Row():
|
| 694 |
-
# 2. 왼쪽 컬럼: 사이드바 (대시보드 및 하단 메뉴) -
|
| 695 |
-
with gr.Column(scale=
|
| 696 |
stats_data = get_db_stats()
|
| 697 |
stats_html = build_stats_html(stats_data)
|
| 698 |
gr.HTML(stats_html)
|
| 699 |
|
| 700 |
-
# 3. 오른쪽 컬럼: 메인 챗봇 에어리어 -
|
| 701 |
-
with gr.Column(scale=
|
| 702 |
# 메인 타이틀 (챗봇 영역 상단 중앙)
|
| 703 |
gr.HTML("""
|
| 704 |
<div style="text-align: center; padding: 10px 0 20px 0;">
|
|
|
|
| 160 |
if res_techs:
|
| 161 |
stats["technologies"] = res_techs["cnt"]
|
| 162 |
|
| 163 |
+
# 2. 기술 목록 & 설명 조회 (상위 8개)
|
| 164 |
res_tech_list = session.run(
|
| 165 |
"MATCH (t:AITechnology) "
|
| 166 |
+
"RETURN t.name as name, COALESCE(t.description, 'AI 혁신 기술 인프라') as desc LIMIT 8"
|
| 167 |
)
|
| 168 |
stats["techs_list"] = [{"name": r["name"], "desc": r["desc"]} for r in res_tech_list]
|
| 169 |
|
| 170 |
+
# 3. 최근 기사 목록 조회 (최근 4개)
|
| 171 |
res_art_list = session.run(
|
| 172 |
"MATCH (a:Article) "
|
| 173 |
"RETURN a.title as title, a.published_date as date, a.url as url "
|
| 174 |
+
"ORDER BY a.published_date DESC LIMIT 4"
|
| 175 |
)
|
| 176 |
stats["recent_articles"] = [
|
| 177 |
{"title": r["title"], "date": r["date"], "url": r["url"]}
|
|
|
|
| 193 |
if not keyword_html:
|
| 194 |
keyword_html = '<div style="font-size:12px; color:#94a3b8;">등록된 키워드가 없습니다.</div>'
|
| 195 |
|
| 196 |
+
# 2. 최근 기사 리스트 HTML 생성 (최대 4개) - 전체 영역 클릭 시 이동하도록 a 태그로 래핑
|
| 197 |
news_list_html: str = ""
|
| 198 |
for a in stats.get("recent_articles", []):
|
| 199 |
title = a["title"]
|
|
|
|
| 218 |
<!-- Ambient background elements for beautiful glass effects -->
|
| 219 |
<div class="ambient-glow"></div>
|
| 220 |
|
| 221 |
+
<div style="font-size: 16px; font-weight: 850; color: #334155; margin-bottom: 2px; display: flex; align-items: center; gap: 6px; letter-spacing: -0.02em;">
|
| 222 |
📊 <span>FinGraph AI Terminal</span>
|
| 223 |
</div>
|
| 224 |
+
<p style="font-size: 11px; color: #475569; margin-top: -2px; margin-bottom: 12px; font-weight: 600;">GraphRAG 실시간 분석 엔진 상태</p>
|
| 225 |
|
| 226 |
+
<!-- 실시간 엔진 텔레메트리 (4개 메트릭) -->
|
| 227 |
<div class="stats-grid">
|
| 228 |
<div class="stat-card">
|
| 229 |
+
<div class="stat-lbl">💡 분석 모델</div>
|
| 230 |
+
<div class="stat-val" style="font-size: 13px !important; font-weight: 800 !important; color: #334155;">GPT-4o</div>
|
| 231 |
+
</div>
|
| 232 |
+
<div class="stat-card">
|
| 233 |
+
<div class="stat-lbl">🧬 검색 모드</div>
|
| 234 |
+
<div class="stat-val" style="font-size: 13px !important; font-weight: 800 !important; color: #334155;">Hybrid (Graph+Vector)</div>
|
| 235 |
+
</div>
|
| 236 |
+
<div class="stat-card">
|
| 237 |
+
<div class="stat-lbl">⚡ 응답 방식</div>
|
| 238 |
+
<div class="stat-val" style="font-size: 13px !important; font-weight: 800 !important; color: #334155;">Streaming</div>
|
| 239 |
</div>
|
| 240 |
<div class="stat-card">
|
| 241 |
+
<div class="stat-lbl">🔐 DB 연결</div>
|
| 242 |
+
<div class="stat-val" style="font-size: 13px !important; font-weight: 800 !important; color: #10b981;">AuraDB (Active)</div>
|
| 243 |
+
</div>
|
| 244 |
+
</div>
|
| 245 |
+
|
| 246 |
+
<!-- 수집된 데이터 규모 -->
|
| 247 |
+
<div class="stats-grid" style="margin-top: 10px; margin-bottom: 15px;">
|
| 248 |
+
<div class="stat-card" style="padding: 8px 10px;">
|
| 249 |
+
<div class="stat-lbl">📰 학습 기사</div>
|
| 250 |
+
<div class="stat-val" style="color: #334155;">{stats['articles']}건</div>
|
| 251 |
+
</div>
|
| 252 |
+
<div class="stat-card" style="padding: 8px 10px;">
|
| 253 |
<div class="stat-lbl">🧬 지식 노드</div>
|
| 254 |
+
<div class="stat-val" style="color: #334155;">{node_count}개</div>
|
| 255 |
</div>
|
| 256 |
</div>
|
| 257 |
|
| 258 |
+
<div class="section-subtitle" style="color: #334155;">💡 최신 뉴스 키워드</div>
|
| 259 |
<div class="keyword-container">
|
| 260 |
{keyword_html}
|
| 261 |
</div>
|
| 262 |
|
| 263 |
+
<div class="section-subtitle" style="color: #334155;">📰 최신 뉴스 피드</div>
|
| 264 |
<div class="news-feed-container">
|
| 265 |
<div class="news-feed">
|
| 266 |
{news_list_html}
|
|
|
|
| 532 |
border-color: rgba(129, 140, 248, 0.6) !important;
|
| 533 |
}
|
| 534 |
|
| 535 |
+
/* 챗봇 버튼 다크 슬레이트 스타일 (보라색 제거 및 세련된 네이비/슬레이트 통일) */
|
| 536 |
button.primary,
|
| 537 |
.primary-btn,
|
| 538 |
button.lg.primary,
|
| 539 |
button.sm.primary,
|
| 540 |
button.variant-primary {
|
| 541 |
+
background-color: #334155 !important;
|
| 542 |
color: white !important;
|
| 543 |
font-weight: 800 !important;
|
| 544 |
border: none !important;
|
| 545 |
+
box-shadow: 0 4px 6px rgba(51, 65, 85, 0.15) !important;
|
| 546 |
transition: all 0.2s ease-in-out !important;
|
| 547 |
}
|
| 548 |
button.primary:hover,
|
| 549 |
.primary-btn:hover,
|
| 550 |
button.variant-primary:hover {
|
| 551 |
+
background-color: #1e293b !important;
|
| 552 |
+
box-shadow: 0 6px 12px rgba(51, 65, 85, 0.25) !important;
|
| 553 |
transform: translateY(-1px) !important;
|
| 554 |
}
|
| 555 |
|
|
|
|
| 712 |
""")
|
| 713 |
|
| 714 |
with gr.Row():
|
| 715 |
+
# 2. 왼쪽 컬럼: 사이드바 (대시보드 및 하단 메뉴) - 3:7 split을 위해 scale=3 설정
|
| 716 |
+
with gr.Column(scale=3, min_width=320):
|
| 717 |
stats_data = get_db_stats()
|
| 718 |
stats_html = build_stats_html(stats_data)
|
| 719 |
gr.HTML(stats_html)
|
| 720 |
|
| 721 |
+
# 3. 오른쪽 컬럼: 메인 챗봇 에어리어 - 3:7 split을 위해 scale=7 설정
|
| 722 |
+
with gr.Column(scale=7, min_width=500):
|
| 723 |
# 메인 타이틀 (챗봇 영역 상단 중앙)
|
| 724 |
gr.HTML("""
|
| 725 |
<div style="text-align: center; padding: 10px 0 20px 0;">
|
src/retrieval/finRetrieval.py
CHANGED
|
@@ -173,40 +173,45 @@ _prompt_template = CustomRagTemplate(
|
|
| 173 |
template="""당신은 AI 및 핀테크 기술 트렌드 전문가이자, 취업 준비생의 역량 분석을 돕는 전략 컨설턴트입니다.
|
| 174 |
반드시 아래 제공된 [컨텍스트(Neo4j 지식 그래프 검색 결과)]에 기반해서만 답변하고, 컨텍스트에 근거하지 않은 사실을 지어내거나 가상의 링크(example.com 등)를 절대 생성하지 마세요.
|
| 175 |
|
| 176 |
-
답변은 대중이나 취업 준비생이 실질적으로 트렌드를 깊이 있게 파악하고 자소서/면접 등에 즉각 활용할 수 있도록, 아래의 [
|
| 177 |
|
| 178 |
-
★ [중요 - 가독성
|
| 179 |
-
|
| 180 |
|
| 181 |
---
|
| 182 |
|
| 183 |
-
#
|
| 184 |
|
| 185 |
-
|
| 186 |
|
| 187 |
-
- **
|
| 188 |
|
|
|
|
| 189 |
|
| 190 |
-
### 🔍 [상세 이슈 및 핵심 팩트 분석]
|
| 191 |
|
| 192 |
-
|
| 193 |
|
| 194 |
-
|
| 195 |
|
|
|
|
| 196 |
|
| 197 |
-
|
| 198 |
|
| 199 |
-
|
| 200 |
|
| 201 |
-
- **업계 시사점**: 기술 발전과 사회적 수용성(ESG, 인프라, 전력망 확보 등) 간의 균형적 관점 제시.
|
| 202 |
|
| 203 |
-
|
| 204 |
|
|
|
|
| 205 |
|
| 206 |
-
|
| 207 |
|
| 208 |
-
-
|
| 209 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
|
| 211 |
---
|
| 212 |
|
|
|
|
| 173 |
template="""당신은 AI 및 핀테크 기술 트렌드 전문가이자, 취업 준비생의 역량 분석을 돕는 전략 컨설턴트입니다.
|
| 174 |
반드시 아래 제공된 [컨텍스트(Neo4j 지식 그래프 검색 결과)]에 기반해서만 답변하고, 컨텍스트에 근거하지 않은 사실을 지어내거나 가상의 링크(example.com 등)를 절대 생성하지 마세요.
|
| 175 |
|
| 176 |
+
답변은 대중이나 취업 준비생이 실질적으로 트렌드를 깊이 있게 파악하고 자소서/면접 등에 즉각 활용할 수 있도록, 아래의 [고정 브리핑 보고서 포맷]을 **토씨 하나 틀리지 않고 엄격히 준수**하여 매우 체계적이고 깔끔한 마크다운 양식으로 정성스럽게 브리핑해 주세요.
|
| 177 |
|
| 178 |
+
★ [중요 - 가독성 및 개행 규칙]:
|
| 179 |
+
각 주요 섹션(###) 사이에는 무조건 빈 줄을 2줄 이상 추가하고, 모든 개별 목록 기호(- 및 **) 항목 사이사이에도 반드시 1줄 이상의 빈 줄(개행)을 삽입하여 시각적 가독성을 극대화해 주세요.
|
| 180 |
|
| 181 |
---
|
| 182 |
|
| 183 |
+
# 📋 [FinGraph AI 분석 브리핑]
|
| 184 |
|
| 185 |
+
### 1. 📊 한 줄 요약 & 핵심 트렌드
|
| 186 |
|
| 187 |
+
- **한 줄 요약**: [해당 트렌드의 핵심 요점을 단 한 줄로 명료하게 요약]
|
| 188 |
|
| 189 |
+
- **주요 인사이트**: [이 이슈가 현재 IT/AI 및 금융 핀테크 업계 전체에 던지는 핵심 화두 기재]
|
| 190 |
|
|
|
|
| 191 |
|
| 192 |
+
### 2. 🔍 상세 분석 및 팩트 정리
|
| 193 |
|
| 194 |
+
[컨텍스트에 기록된 실제 사실 관계들을 근거로 구체적 사실을 정리]
|
| 195 |
|
| 196 |
+
- **이슈 전개**: [구체적인 이슈 발생 배경 및 진행 경과]
|
| 197 |
|
| 198 |
+
- **기업 동향**: [관련 핵심 기업들의 실물 비즈니스 움직임 및 대응 행보]
|
| 199 |
|
| 200 |
+
- **인프라/사회적 요인**: [전력망 부족, 대중적 불안감, 하드웨어적 제약 사항 등 핵심 요인]
|
| 201 |
|
|
|
|
| 202 |
|
| 203 |
+
### 3. 💡 취업/자소서/면접 실전 가이드
|
| 204 |
|
| 205 |
+
[지원자가 면접이나 자기소개서에서 차별화된 통찰을 보여줄 수 있는 방법 제시]
|
| 206 |
|
| 207 |
+
- **금융/IT 업계 시사점**: [거시적인 파급효과와 지속가능성 관점 제시]
|
| 208 |
|
| 209 |
+
- **실전 자소서/면접 활용 Tip**: [지원동기나 역량 기술서 작성 시 본인의 역량과 어떻게 연계하여 풀어낼지에 대한 맞춤 가이드]
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
### 📰 4. 근거 뉴스 출처
|
| 213 |
+
|
| 214 |
+
- *[기사 제목](기사 URL)* - 보도일자/언론사
|
| 215 |
|
| 216 |
---
|
| 217 |
|