305 lines
9.3 KiB
Python
305 lines
9.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
🛡️ 科创企业智能风控与核保系统 - 首页 / 风控大屏入口
|
|
"""
|
|
import sys
|
|
import os
|
|
import streamlit as st
|
|
import pandas as pd
|
|
import plotly.express as px
|
|
import plotly.graph_objects as go
|
|
|
|
# 确保项目根目录在 Python 路径中
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
from config import PAGE_TITLE, PAGE_ICON, LAYOUT
|
|
from collectors.financial_collector import get_all_companies
|
|
from risk_engine.risk_scorer import calculate_six_dimension_scores, get_risk_level
|
|
|
|
# ============================================================
|
|
# 页面配置
|
|
# ============================================================
|
|
st.set_page_config(
|
|
page_title=PAGE_TITLE,
|
|
page_icon=PAGE_ICON,
|
|
layout=LAYOUT,
|
|
initial_sidebar_state="expanded",
|
|
)
|
|
|
|
# ============================================================
|
|
# 自定义样式
|
|
# ============================================================
|
|
st.markdown("""
|
|
<style>
|
|
/* 主标题渐变 */
|
|
.main-title {
|
|
background: linear-gradient(120deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
|
|
padding: 30px;
|
|
border-radius: 15px;
|
|
text-align: center;
|
|
margin-bottom: 30px;
|
|
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
|
|
}
|
|
.main-title h1 {
|
|
color: #e94560;
|
|
font-size: 2.2em;
|
|
margin: 0;
|
|
}
|
|
.main-title p {
|
|
color: #a8a8b3;
|
|
font-size: 1.1em;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
/* 统计卡片 */
|
|
.stat-card {
|
|
background: linear-gradient(135deg, #1a1a2e, #16213e);
|
|
padding: 20px;
|
|
border-radius: 12px;
|
|
text-align: center;
|
|
border: 1px solid #2a2a4a;
|
|
transition: transform 0.2s;
|
|
}
|
|
.stat-card:hover {
|
|
transform: translateY(-2px);
|
|
}
|
|
.stat-card .number {
|
|
font-size: 2.5em;
|
|
font-weight: bold;
|
|
color: #e94560;
|
|
}
|
|
.stat-card .label {
|
|
color: #a8a8b3;
|
|
font-size: 0.95em;
|
|
margin-top: 5px;
|
|
}
|
|
|
|
/* 企业卡片 */
|
|
.company-card {
|
|
background: #16213e;
|
|
padding: 15px;
|
|
border-radius: 10px;
|
|
margin: 8px 0;
|
|
border-left: 4px solid;
|
|
}
|
|
|
|
/* 侧边栏 */
|
|
[data-testid="stSidebar"] {
|
|
background: linear-gradient(180deg, #1a1a2e 0%, #0f0f23 100%);
|
|
}
|
|
</style>
|
|
""", unsafe_allow_html=True)
|
|
|
|
from utils.session_helper import render_sidebar_global_company_selector
|
|
|
|
# ============================================================
|
|
# 侧边栏
|
|
# ============================================================
|
|
with st.sidebar:
|
|
render_sidebar_global_company_selector()
|
|
st.markdown("---")
|
|
st.markdown("### 🛡️ 系统导航")
|
|
st.markdown("---")
|
|
st.markdown("""
|
|
**功能模块**
|
|
- 🏠 系统首页
|
|
- 📊 企业风险概览
|
|
- 🕸️ 供应链知识图谱
|
|
- ⚖️ 多智能体辩论诊断
|
|
- 💰 动态定价与核保
|
|
""")
|
|
st.markdown("---")
|
|
st.markdown("""
|
|
**技术栈**
|
|
- 🤖 DeepSeek API (LLM)
|
|
- 🕸️ NetworkX (知识图谱)
|
|
- 📊 Plotly (可视化)
|
|
- 🔧 Streamlit (Web框架)
|
|
""")
|
|
st.markdown("---")
|
|
st.caption("中国平安 × 挑战杯 · 科创风控原型")
|
|
|
|
# ============================================================
|
|
# 主页内容
|
|
# ============================================================
|
|
|
|
# 标题
|
|
st.markdown("""
|
|
<div class="main-title">
|
|
<h1>🛡️ 科创企业智能风控与核保系统</h1>
|
|
<p>基于多智能体辩论 × 知识图谱 × 动态定价的全链条风控平台</p>
|
|
<p style="font-size: 0.85em; color: #666;">中国青基会平安励志计划 · XH-202626 · 科创企业特有风险的识别与管理</p>
|
|
</div>
|
|
""", unsafe_allow_html=True)
|
|
|
|
# 加载企业数据
|
|
companies = get_all_companies()
|
|
|
|
# ============================================================
|
|
# 统计概览卡片
|
|
# ============================================================
|
|
st.markdown("### 📊 系统概览")
|
|
|
|
# 计算所有企业的风险评分
|
|
risk_data = []
|
|
for comp in companies:
|
|
scores = calculate_six_dimension_scores(comp)
|
|
risk_data.append({
|
|
"company": comp["short_name"],
|
|
"stock_code": comp["stock_code"],
|
|
"industry": comp["industry"],
|
|
"sector": comp["sector"],
|
|
"comprehensive_score": scores["comprehensive_score"],
|
|
"risk_level": scores["risk_level"]["level"],
|
|
**scores["scores"],
|
|
})
|
|
|
|
df = pd.DataFrame(risk_data)
|
|
|
|
# 统计卡片
|
|
col1, col2, col3, col4, col5 = st.columns(5)
|
|
|
|
with col1:
|
|
st.markdown(f"""
|
|
<div class="stat-card">
|
|
<div class="number">{len(companies)}</div>
|
|
<div class="label">监控企业总数</div>
|
|
</div>
|
|
""", unsafe_allow_html=True)
|
|
|
|
with col2:
|
|
high_risk = len(df[df["comprehensive_score"] >= 70])
|
|
st.markdown(f"""
|
|
<div class="stat-card">
|
|
<div class="number" style="color: #F44336;">{high_risk}</div>
|
|
<div class="label">⚠️ 高风险企业</div>
|
|
</div>
|
|
""", unsafe_allow_html=True)
|
|
|
|
with col3:
|
|
med_risk = len(df[(df["comprehensive_score"] >= 40) & (df["comprehensive_score"] < 70)])
|
|
st.markdown(f"""
|
|
<div class="stat-card">
|
|
<div class="number" style="color: #FF9800;">{med_risk}</div>
|
|
<div class="label">🟡 中风险企业</div>
|
|
</div>
|
|
""", unsafe_allow_html=True)
|
|
|
|
with col4:
|
|
low_risk = len(df[df["comprehensive_score"] < 40])
|
|
st.markdown(f"""
|
|
<div class="stat-card">
|
|
<div class="number" style="color: #4CAF50;">{low_risk}</div>
|
|
<div class="label">🟢 低风险企业</div>
|
|
</div>
|
|
""", unsafe_allow_html=True)
|
|
|
|
with col5:
|
|
sanctioned = len([c for c in companies if "被列入" in c.get("compliance", {}).get("entity_list_status", "")])
|
|
st.markdown(f"""
|
|
<div class="stat-card">
|
|
<div class="number" style="color: #B71C1C;">{sanctioned}</div>
|
|
<div class="label">⛔ 受制裁企业</div>
|
|
</div>
|
|
""", unsafe_allow_html=True)
|
|
|
|
st.markdown("<br>", unsafe_allow_html=True)
|
|
|
|
# ============================================================
|
|
# 风险分布图
|
|
# ============================================================
|
|
col_left, col_right = st.columns([3, 2])
|
|
|
|
with col_left:
|
|
st.markdown("#### 🎯 企业综合风险评分分布")
|
|
|
|
# 水平柱状图,按风险排序
|
|
df_sorted = df.sort_values("comprehensive_score", ascending=True)
|
|
|
|
colors = []
|
|
for score in df_sorted["comprehensive_score"]:
|
|
if score >= 70:
|
|
colors.append("#F44336")
|
|
elif score >= 50:
|
|
colors.append("#FF9800")
|
|
elif score >= 30:
|
|
colors.append("#FFC107")
|
|
else:
|
|
colors.append("#4CAF50")
|
|
|
|
fig = go.Figure(go.Bar(
|
|
x=df_sorted["comprehensive_score"],
|
|
y=df_sorted["company"],
|
|
orientation="h",
|
|
marker_color=colors,
|
|
text=df_sorted["comprehensive_score"],
|
|
textposition="outside",
|
|
))
|
|
fig.update_layout(
|
|
height=400,
|
|
margin=dict(l=0, r=30, t=10, b=10),
|
|
plot_bgcolor="rgba(0,0,0,0)",
|
|
paper_bgcolor="rgba(0,0,0,0)",
|
|
font=dict(color="white"),
|
|
xaxis=dict(
|
|
title="综合风险评分",
|
|
range=[0, 105],
|
|
gridcolor="rgba(255,255,255,0.1)",
|
|
),
|
|
yaxis=dict(gridcolor="rgba(255,255,255,0.1)"),
|
|
)
|
|
# 添加阈值线
|
|
fig.add_vline(x=70, line_dash="dash", line_color="#F44336",
|
|
annotation_text="高风险线(70)", annotation_position="top right")
|
|
fig.add_vline(x=40, line_dash="dash", line_color="#FF9800",
|
|
annotation_text="中风险线(40)", annotation_position="top right")
|
|
st.plotly_chart(fig, use_container_width=True)
|
|
|
|
with col_right:
|
|
st.markdown("#### 🏷️ 行业风险热力")
|
|
|
|
# 按行业汇总
|
|
sector_risk = df.groupby("sector")["comprehensive_score"].mean().reset_index()
|
|
sector_risk.columns = ["行业", "平均风险"]
|
|
sector_risk = sector_risk.sort_values("平均风险", ascending=False)
|
|
|
|
fig2 = px.bar(
|
|
sector_risk, x="行业", y="平均风险",
|
|
color="平均风险",
|
|
color_continuous_scale=["#4CAF50", "#FFC107", "#F44336"],
|
|
range_color=[0, 100],
|
|
)
|
|
fig2.update_layout(
|
|
height=400,
|
|
margin=dict(l=0, r=0, t=10, b=10),
|
|
plot_bgcolor="rgba(0,0,0,0)",
|
|
paper_bgcolor="rgba(0,0,0,0)",
|
|
font=dict(color="white"),
|
|
showlegend=False,
|
|
coloraxis_showscale=False,
|
|
)
|
|
st.plotly_chart(fig2, use_container_width=True)
|
|
|
|
# ============================================================
|
|
# 企业列表
|
|
# ============================================================
|
|
st.markdown("### 📋 企业风险速览")
|
|
|
|
# 格式化数据表格
|
|
display_df = df[["company", "stock_code", "industry", "comprehensive_score", "risk_level"]].copy()
|
|
display_df.columns = ["企业名称", "股票代码", "行业", "综合风险评分", "风险等级"]
|
|
|
|
st.dataframe(display_df, use_container_width=True, height=400)
|
|
|
|
# ============================================================
|
|
# 底部信息
|
|
# ============================================================
|
|
st.markdown("---")
|
|
st.markdown("""
|
|
<div style="text-align: center; color: #666; font-size: 0.85em;">
|
|
<p>🛡️ 科创企业智能风控与核保系统 v1.0</p>
|
|
<p>技术架构: Multi-Agent 交叉验证 × 供应链知识图谱 × 动态保险定价</p>
|
|
<p>数据来源: 科创板公开年报 · BIS 实体清单 · 网信办算法备案公示</p>
|
|
</div>
|
|
""", unsafe_allow_html=True)
|