重构系统界面与页面命名,全面清除emoji元素并规范专业展示
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
供应链知识图谱页面
|
||||
交互式图谱展示 + 供应链风险传染路径 + 实体清单命中标记
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
import streamlit as st
|
||||
import streamlit.components.v1 as components
|
||||
|
||||
from collectors.financial_collector import get_all_companies
|
||||
from knowledge_graph.graph_builder import build_graph, get_graph_stats
|
||||
from knowledge_graph.contagion_analyzer import analyze_contagion
|
||||
from knowledge_graph.graph_visualizer import (
|
||||
generate_interactive_graph,
|
||||
get_subgraph_for_company,
|
||||
)
|
||||
|
||||
st.set_page_config(page_title="供应链知识图谱", layout="wide")
|
||||
|
||||
st.markdown("# 供应链风险传染知识图谱")
|
||||
st.markdown("可视化科创企业供应链网络,识别风险传染路径和关键断裂节点。")
|
||||
|
||||
# 构建图谱
|
||||
@st.cache_resource
|
||||
def get_graph():
|
||||
return build_graph()
|
||||
|
||||
G = get_graph()
|
||||
stats = get_graph_stats(G)
|
||||
|
||||
# ============================================================
|
||||
# 图谱统计
|
||||
# ============================================================
|
||||
col1, col2, col3, col4 = st.columns(4)
|
||||
with col1:
|
||||
st.metric("总节点数", stats["total_nodes"])
|
||||
with col2:
|
||||
st.metric("总边数", stats["total_edges"])
|
||||
with col3:
|
||||
st.metric("受制裁节点", stats["sanctioned_nodes"])
|
||||
with col4:
|
||||
st.metric("图密度", f"{stats['density']:.4f}")
|
||||
|
||||
# 节点类型分布
|
||||
with st.expander("节点类型分布"):
|
||||
for ntype, count in stats["node_types"].items():
|
||||
st.markdown(f"- **{ntype}**: {count} 个")
|
||||
|
||||
st.markdown("---")
|
||||
|
||||
# ============================================================
|
||||
# 图谱视图选择
|
||||
# ============================================================
|
||||
view_mode = st.radio(
|
||||
"视图模式",
|
||||
["全局图谱", "企业中心视图(推荐)"],
|
||||
horizontal=True,
|
||||
)
|
||||
|
||||
from utils.session_helper import render_company_selector, render_sidebar_global_company_selector
|
||||
|
||||
with st.sidebar:
|
||||
render_sidebar_global_company_selector()
|
||||
st.markdown("---")
|
||||
|
||||
if view_mode == "企业中心视图(推荐)":
|
||||
target_company = render_company_selector("选择中心企业", key_suffix="graph_page")
|
||||
selected_company = target_company["short_name"] if target_company else "寒武纪"
|
||||
|
||||
depth = st.slider("穿透深度", 1, 3, 2)
|
||||
|
||||
# 提取子图
|
||||
subgraph = get_subgraph_for_company(G, selected_company, depth=depth)
|
||||
|
||||
if subgraph.number_of_nodes() > 0:
|
||||
html_content = generate_interactive_graph(
|
||||
subgraph,
|
||||
highlight_company=selected_company,
|
||||
height="550px",
|
||||
)
|
||||
components.html(html_content, height=600, scrolling=True)
|
||||
|
||||
# ============================================================
|
||||
# 供应链风险传染分析
|
||||
# ============================================================
|
||||
st.markdown("---")
|
||||
st.markdown(f"### {selected_company} 供应链风险传染分析")
|
||||
|
||||
contagion = analyze_contagion(G, selected_company)
|
||||
|
||||
# 风险评分
|
||||
supply_risk_score = contagion.get("risk_score", 0)
|
||||
if supply_risk_score >= 60:
|
||||
st.error(f"供应链风险评分: **{supply_risk_score}/100** — 供应链断裂风险极高")
|
||||
elif supply_risk_score >= 30:
|
||||
st.warning(f"供应链风险评分: **{supply_risk_score}/100** — 存在一定供应链风险")
|
||||
else:
|
||||
st.success(f"供应链风险评分: **{supply_risk_score}/100** — 供应链风险可控")
|
||||
|
||||
# 直接风险
|
||||
if contagion.get("direct_risks"):
|
||||
st.markdown("#### 直接风险(一度关联)")
|
||||
for risk in contagion["direct_risks"]:
|
||||
status_tag = "[受限]" if risk.get("status") == "受限" else "[关注]"
|
||||
critical_tag = " [关键供应]" if risk.get("is_critical") else ""
|
||||
st.markdown(
|
||||
f"- {status_tag} **{risk['entity']}** ({risk['node_type']}) — "
|
||||
f"{risk['relation']} — 状态: {risk.get('status', '未知')}{critical_tag}"
|
||||
)
|
||||
|
||||
# 间接风险
|
||||
if contagion.get("indirect_risks"):
|
||||
st.markdown("#### 间接风险(二度及以上关联)")
|
||||
for risk in contagion["indirect_risks"]:
|
||||
st.markdown(
|
||||
f"- [间接传导] **{risk['entity']}** (距离: {risk['distance']}层) — {risk['relation']}"
|
||||
)
|
||||
|
||||
# 传染路径
|
||||
if contagion.get("contagion_paths"):
|
||||
st.markdown("#### 风险传染路径")
|
||||
for path in contagion["contagion_paths"]:
|
||||
severity_tag = "[高风险]" if path["severity"] == "高" else "[中风险]"
|
||||
st.markdown(f"- {severity_tag} `{path['path_str']}` (长度: {path['length']})")
|
||||
|
||||
# 关键断裂节点
|
||||
if contagion.get("critical_nodes"):
|
||||
st.markdown("#### 关键断裂节点")
|
||||
for node in contagion["critical_nodes"]:
|
||||
alt_info = f"有 {node['alternative_count']} 个替代方案" if node["has_alternative"] else "无替代方案"
|
||||
st.markdown(
|
||||
f"- **{node['node']}** — {node['relation']} — "
|
||||
f"状态: {node['status']} — {alt_info}"
|
||||
)
|
||||
else:
|
||||
st.warning(f"未找到 {selected_company} 的相关图谱数据")
|
||||
|
||||
else:
|
||||
# 全局视图
|
||||
st.info("全局图谱节点较多,加载可能需要几秒钟。推荐使用“企业中心视图”获得更好的体验。")
|
||||
html_content = generate_interactive_graph(G, height="650px")
|
||||
components.html(html_content, height=700, scrolling=True)
|
||||
|
||||
# ============================================================
|
||||
# 图例
|
||||
# ============================================================
|
||||
st.markdown("---")
|
||||
st.markdown("#### 图例说明")
|
||||
col_l1, col_l2, col_l3 = st.columns(3)
|
||||
with col_l1:
|
||||
st.markdown("""
|
||||
**节点颜色**
|
||||
- 绿色: 科创企业 (正常)
|
||||
- 金色: 选中的中心企业
|
||||
- 橙色: 供应商
|
||||
- 紫色: 客户
|
||||
- 蓝色: 核心人员
|
||||
- 红色: 受制裁实体
|
||||
""")
|
||||
with col_l2:
|
||||
st.markdown("""
|
||||
**边类型**
|
||||
- 实线: 正常关系
|
||||
- 红色虚线: 受限关系
|
||||
- 黄色粗线: 关键供应关系
|
||||
""")
|
||||
with col_l3:
|
||||
st.markdown("""
|
||||
**交互操作**
|
||||
- 鼠标悬浮: 查看节点详情
|
||||
- 拖拽: 移动节点
|
||||
- 滚轮: 缩放图谱
|
||||
- 双击: 聚焦节点
|
||||
""")
|
||||
Reference in New Issue
Block a user