之前看到你们搞cursor都没用过,现在试了试windsurf,确实好用。
import platform
import psutil
import dash
from dash import html, dcc
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc
from datetime import datetime
import time
from collections import deque
from functools import lru_cache
import GPUtil
import os
import cpuinfo
import getpass
from dash.exceptions import PreventUpdate
import plotly.graph_objects as go
print("正在初始化系统监控程序...")
# 性能优化:初始化数据存储和缓存
last_update = time.time()
last_net_io = None
# 初始化时间序列数据
TIME_SERIES_LENGTH = 180 # 30分钟,每10秒一个点
network_times = deque(maxlen=TIME_SERIES_LENGTH)
network_sent = deque(maxlen=TIME_SERIES_LENGTH)
network_recv = deque(maxlen=TIME_SERIES_LENGTH)
# 初始化应用
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.LITERA])
app.title = "Windows 系统监控"
# 更新间隔(毫秒)
UPDATE_INTERVAL = 10000 # 10秒
CACHE_TIMEOUT = 10 # 缓存10秒
# 缓存装饰器
def cache_with_timeout(timeout):
def decorator(func):
last_call = {'time': 0, 'result': None}
def wrapper(*args, **kwargs):
current_time = time.time()
if current_time - last_call['time'] < timeout:
return last_call['result']
result = func(*args, **kwargs)
last_call['result'] = result
last_call['time'] = current_time
return result
return wrapper
return decorator
# 性能优化:初始化数据存储
cpu_times = deque(maxlen=TIME_SERIES_LENGTH)
cpu_percentages = deque(maxlen=TIME_SERIES_LENGTH)
memory_times = deque(maxlen=TIME_SERIES_LENGTH)
memory_percentages = deque(maxlen=TIME_SERIES_LENGTH)
gpu_times = {} # 每个GPU一个时间序列
gpu_loads = {} # 每个GPU的负载历史
gpu_memory_usages = {} # 每个GPU的显存使用历史
def initialize_gpu_queues():
"""初始化GPU数据队列"""
try:
gpus = GPUtil.getGPUs()
for gpu in gpus:
gpu_id = f"GPU_{gpu.id}"
if gpu_id not in gpu_times:
gpu_times[gpu_id] = deque(maxlen=TIME_SERIES_LENGTH)
gpu_loads[gpu_id] = deque(maxlen=TIME_SERIES_LENGTH)
gpu_memory_usages[gpu_id] = deque(maxlen=TIME_SERIES_LENGTH)
except Exception as e:
print(f"初始化GPU队列时出错: {e}")
# 初始化GPU队列
initialize_gpu_queues()
# 图表主题配置
chart_theme = {
'plot_bgcolor': 'rgba(0,0,0,0)',
'paper_bgcolor': 'rgba(0,0,0,0)',
'font': {
'family': 'system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
'color': '#2c3e50',
'size': 12
},
'xaxis': {
'gridcolor': '#edf2f7',
'linecolor': '#edf2f7',
'tickfont': {'size': 10},
'showgrid': True
},
'yaxis': {
'gridcolor': '#edf2f7',
'linecolor': '#edf2f7',
'tickfont': {'size': 10},
'showgrid': True
},
'margin': {'l': 40, 'r': 20, 't': 40, 'b': 40},
'hovermode': 'x unified',
'showlegend': True,
'legend': {'orientation': 'h', 'y': -0.2}
}
def get_disk_info():
"""获取磁盘信息"""
disk_info = []
for partition in psutil.disk_partitions():
try:
usage = psutil.disk_usage(partition.mountpoint)
disk_info.append({
'device': partition.device,
'mountpoint': partition.mountpoint,
'fstype': partition.fstype,
'total': usage.total,
'used': usage.used,
'free': usage.free,
'percent': usage.percent
})
except Exception as e:
print(f"获取磁盘信息错误 {partition.device}: {e}")
return disk_info
def get_gpu_info():
"""获取GPU信息"""
try:
gpus = GPUtil.getGPUs()
gpu_info = []
current_time = datetime.now()
for gpu in gpus:
gpu_id = f"GPU_{gpu.id}"
# 更新历史数据
gpu_times[gpu_id].append(current_time)
gpu_loads[gpu_id].append(gpu.load * 100)
gpu_memory_usages[gpu_id].append(gpu.memoryUtil * 100)
gpu_info.append({
'id': gpu.id,
'name': gpu.name,
'load': gpu.load * 100,
'memory_total': gpu.memoryTotal,
'memory_used': gpu.memoryUsed,
'memory_free': gpu.memoryFree,
'temperature': gpu.temperature,
'memory_util': gpu.memoryUtil * 100
})
return gpu_info
except Exception as e:
print(f"获取GPU信息错误: {e}")
return None
def get_progress_color(percent):
"""根据百分比返回合适的颜色"""
if percent >= 90:
return "linear-gradient(45deg, #ef4444, #dc2626)" # 红色渐变
elif percent >= 70:
return "linear-gradient(45deg, #f59e0b, #d97706)" # 黄色渐变
elif percent >= 50:
return "linear-gradient(45deg, #3b82f6, #2563eb)" # 蓝色渐变
else:
return "linear-gradient(45deg, #22c55e, #16a34a)" # 绿色渐变
@cache_with_timeout(CACHE_TIMEOUT)
def get_system_info():
"""获取系统信息"""
try:
cpu_info = cpuinfo.get_cpu_info()
memory = psutil.virtual_memory()
disk = psutil.disk_usage('/')
return dbc.Card([
dbc.CardBody([
html.H4([
html.I(className="fas fa-microchip me-2"),
"系统信息"
], className="card-title text-primary d-flex align-items-center"),
dbc.Row([
dbc.Col([
dbc.ListGroup([
dbc.ListGroupItem([
html.I(className="fas fa-desktop me-2"),
html.Strong("操作系统: "),
html.Span(f"{platform.system()} {platform.release()}")
], className="d-flex align-items-center"),
dbc.ListGroupItem([
html.I(className="fas fa-microchip me-2"),
html.Strong("处理器: "),
html.Span(cpu_info['brand_raw'])
], className="d-flex align-items-center"),
dbc.ListGroupItem([
html.I(className="fas fa-cogs me-2"),
html.Strong("CPU架构: "),
html.Span(f"{cpu_info['arch']} ({cpu_info['bits']}位)")
], className="d-flex align-items-center"),
dbc.ListGroupItem([
html.I(className="fas fa-memory me-2"),
html.Strong("内存大小: "),
html.Span(f"{memory.total / (1024**3):.1f} GB")
], className="d-flex align-items-center"),
], flush=True)
], width=6),
dbc.Col([
dbc.ListGroup([
dbc.ListGroupItem([
html.I(className="fas fa-hdd me-2"),
html.Strong("系统盘容量: "),
html.Span(f"{disk.total / (1024**3):.1f} GB")
], className="d-flex align-items-center"),
dbc.ListGroupItem([
html.I(className="fas fa-clock me-2"),
html.Strong("系统启动时间: "),
html.Span(f"{datetime.fromtimestamp(psutil.boot_time()).strftime('%Y-%m-%d %H:%M:%S')}")
], className="d-flex align-items-center"),
dbc.ListGroupItem([
html.I(className="fas fa-network-wired me-2"),
html.Strong("主机名: "),
html.Span(platform.node())
], className="d-flex align-items-center"),
dbc.ListGroupItem([
html.I(className="fas fa-user me-2"),
html.Strong("当前用户: "),
html.Span(getpass.getuser())
], className="d-flex align-items-center"),
], flush=True)
], width=6),
])
])
], className="mb-4 system-info-card")
except Exception as e:
print(f"获取系统信息错误: {e}")
return dbc.Card(dbc.CardBody([html.P("获取系统信息失败")]))
@cache_with_timeout(CACHE_TIMEOUT)
def get_resource_info():
"""获取资源使用情况"""
try:
# CPU信息 - 使用0.1秒的采样间隔以获得更准确的值
cpu_percent = psutil.cpu_percent(interval=0.1)
cpu_times.append(datetime.now())
cpu_percentages.append(cpu_percent)
# CPU核心信息 - 同样使用0.1秒的采样间隔
cpu_percents = psutil.cpu_percent(interval=0.1, percpu=True)
# 内存信息
memory = psutil.virtual_memory()
swap = psutil.swap_memory()
# 添加内存历史数据
memory_times.append(datetime.now())
memory_percentages.append(memory.percent)
# 更新网络速度数据
get_network_speed()
# GPU信息
gpu_info = get_gpu_info()
# 磁盘信息
disk_info = get_disk_info()
# CPU使用率图表
cpu_graph = dcc.Graph(
figure={
'data': [
go.Scatter(
x=list(cpu_times),
y=list(cpu_percentages),
name='CPU使用率',
fill='tozeroy',
line=dict(color='#3498db')
)
],
'layout': {
**chart_theme,
'title': 'CPU使用率历史',
'xaxis': {'title': '时间'},
'yaxis': {'title': '使用率 (%)', 'range': [0, 100]},
'margin': {'l': 50, 'r': 20, 't': 40, 'b': 50},
'showlegend': False
}
},
config={'displayModeBar': False},
className="shadow-sm"
)
# 内存使用率图表
memory_graph = dcc.Graph(
figure={
'data': [
go.Scatter(
x=list(memory_times),
y=list(memory_percentages),
name='内存使用率',
fill='tozeroy',
line=dict(color='#2ecc71')
)
],
'layout': {
**chart_theme,
'title': '内存使用率历史',
'xaxis': {'title': '时间'},
'yaxis': {'title': '使用率 (%)', 'range': [0, 100]},
'margin': {'l': 50, 'r': 20, 't': 40, 'b': 50},
'showlegend': False
}
},
config={'displayModeBar': False},
className="shadow-sm"
)
# CPU核心使用率表格
cores_table = dbc.Table(
[
html.Thead(
html.Tr([
html.Th("CPU核心", style={'width': '30%'}),
html.Th("使用率", style={'width': '70%'})
]),
className="table-light"
),
html.Tbody([
html.Tr([
html.Td(f"核心 {i}"),
html.Td([
html.Div(
className="progress",
children=[
html.Div(
className="progress-bar",
style={
"width": f"{percent}%",
"backgroundColor": "#007bff"
},
children=[
html.Span(
f"{percent:.1f}%",
className="progress-text"
)
]
)
]
)
])
]) for i, percent in enumerate(cpu_percents)
])
],
bordered=True,
hover=True,
responsive=True,
striped=True,
className="mt-3"
)
# 磁盘使用率表格
disk_table = dbc.Table(
[
html.Thead(
html.Tr([
html.Th("盘符"),
html.Th("总容量"),
html.Th("已用空间"),
html.Th("使用率")
]),
className="table-light"
),
html.Tbody([
html.Tr([
html.Td(f"{disk['mountpoint']}"),
html.Td(f"{disk['total'] / (1024**3):.1f} GB"),
html.Td(f"{disk['used'] / (1024**3):.1f} GB"),
html.Td([
html.Div(
className="progress",
children=[
html.Div(
className="progress-bar",
style={
"width": f"{disk['percent']}%",
"backgroundColor": "#007bff"
},
children=[
html.Span(
f"{disk['percent']:.1f}%",
className="progress-text"
)
]
)
]
)
])
]) for disk in disk_info
])
],
bordered=True,
hover=True,
responsive=True,
striped=True,
className="mt-3"
)
# 网络速度图表
network_graph = dcc.Graph(
figure={
'data': [
go.Scatter(
x=list(network_times),
y=list(network_sent),
name='上传速度',
line=dict(color='#e67e22')
),
go.Scatter(
x=list(network_times),
y=list(network_recv),
name='下载速度',
line=dict(color='#27ae60')
)
],
'layout': {
**chart_theme,
'title': '网络速度历史',
'xaxis': {'title': '时间'},
'yaxis': {'title': '速度 (MB/s)'},
'margin': {'l': 50, 'r': 20, 't': 40, 'b': 50},
'showlegend': True,
'legend': {'orientation': 'h', 'y': -0.2}
}
},
config={'displayModeBar': False},
className="shadow-sm"
)
# GPU信息和图表
if gpu_info:
gpu_cards = []
for gpu in gpu_info:
gpu_id = f"GPU_{gpu['id']}"
# GPU使用率历史图表
gpu_load_graph = dcc.Graph(
figure={
'data': [
go.Scatter(
x=list(gpu_times[gpu_id]),
y=list(gpu_loads[gpu_id]),
name='GPU使用率',
fill='tozeroy',
line=dict(color='#e74c3c')
)
],
'layout': {
**chart_theme,
'title': f'GPU {gpu["id"]} 使用率历史',
'xaxis': {'title': '时间'},
'yaxis': {'title': '使用率 (%)', 'range': [0, 100]},
'margin': {'l': 50, 'r': 20, 't': 40, 'b': 50},
'showlegend': False
}
},
config={'displayModeBar': False},
className="shadow-sm"
)
# GPU显存使用率历史图表
gpu_memory_graph = dcc.Graph(
figure={
'data': [
go.Scatter(
x=list(gpu_times[gpu_id]),
y=list(gpu_memory_usages[gpu_id]),
name='显存使用率',
fill='tozeroy',
line=dict(color='#9b59b6')
)
],
'layout': {
**chart_theme,
'title': f'GPU {gpu["id"]} 显存使用率历史',
'xaxis': {'title': '时间'},
'yaxis': {'title': '使用率 (%)', 'range': [0, 100]},
'margin': {'l': 50, 'r': 20, 't': 40, 'b': 50},
'showlegend': False
}
},
config={'displayModeBar': False},
className="shadow-sm"
)
gpu_cards.append(
dbc.ListGroupItem([
html.Strong(f"GPU {gpu['id']}: {gpu['name']}"),
html.Div([
html.Div([
html.Strong("总显存: "),
html.Span(f"{gpu['memory_total']:.1f} MB")
]),
html.Div([
html.Strong("已用显存: "),
html.Span(f"{gpu['memory_used']:.1f} MB")
]),
html.Div([
html.Strong("温度: "),
html.Span(f"{gpu['temperature']:.1f}°C")
]),
html.Div([
html.Strong("GPU使用率:"),
html.Div(
className="progress",
children=[
html.Div(
className="progress-bar",
style={
"width": f"{gpu['load']}%",
"backgroundColor": "#007bff"
},
children=[
html.Span(
f"{gpu['load']:.1f}%",
className="progress-text"
)
]
)
]
)
]),
html.Div([
html.Strong("显存使用率:"),
html.Div(
className="progress",
children=[
html.Div(
className="progress-bar",
style={
"width": f"{gpu['memory_util']}%",
"backgroundColor": "#007bff"
},
children=[
html.Span(
f"{gpu['memory_util']:.1f}%",
className="progress-text"
)
]
)
]
)
]),
html.Div([
dbc.Row([
dbc.Col([gpu_load_graph], width=12, className="mb-4"),
dbc.Col([gpu_memory_graph], width=12, className="mb-4")
])
])
])
], className="border-0")
)
memory_items = [
dbc.ListGroupItem([
html.Strong("物理内存"),
html.Div([
html.Div([
html.Strong("总内存: "),
html.Span(f"{memory.total / (1024**3):.1f} GB")
]),
html.Div([
html.Strong("已用内存: "),
html.Span(f"{(memory.total - memory.available) / (1024**3):.1f} GB")
]),
html.Div([
html.Strong("可用内存: "),
html.Span(f"{memory.available / (1024**3):.1f} GB")
]),
html.Div([
html.Div(
className="progress",
children=[
html.Div(
className="progress-bar",
style={
"width": f"{memory.percent}%",
"backgroundColor": "#007bff"
},
children=[
html.Span(
f"{memory.percent}%",
className="progress-text"
)
]
)
]
)
])
])
], className="border-0"),
dbc.ListGroupItem([
html.Strong("虚拟内存"),
html.Div([
html.Div([
html.Strong("总大小: "),
html.Span(f"{swap.total / (1024**3):.1f} GB")
]),
html.Div([
html.Strong("已用空间: "),
html.Span(f"{swap.used / (1024**3):.1f} GB")
]),
html.Div([
html.Strong("可用空间: "),
html.Span(f"{swap.free / (1024**3):.1f} GB")
]),
html.Div([
html.Div(
className="progress",
children=[
html.Div(
className="progress-bar",
style={
"width": f"{swap.percent}%",
"backgroundColor": "#007bff"
},
children=[
html.Span(
f"{swap.percent}%",
className="progress-text"
)
]
)
]
)
])
])
], className="border-0")
]
# 如果有GPU信息,添加到列表中
memory_items.extend(gpu_cards)
return dbc.Card([
dbc.CardBody([
html.H4("系统资源使用情况", className="card-title text-primary"),
dbc.Row([
dbc.Col([
dbc.ListGroup(memory_items, flush=True)
], md=12, lg=4),
dbc.Col([
dbc.Row([
dbc.Col([cpu_graph], width=12, className="mb-4"),
dbc.Col([memory_graph], width=12, className="mb-4"),
dbc.Col([network_graph], width=12, className="mb-4"),
dbc.Col([
html.H5("CPU核心使用率", className="mt-2 text-primary"),
cores_table
], width=12, className="mb-4"),
dbc.Col([
html.H5("磁盘使用情况", className="mt-2 text-primary"),
disk_table
], width=12, className="mb-4")
])
], md=12, lg=8)
])
])
], className="mb-4 shadow-sm")
else:
return dbc.Card([
dbc.CardBody([
html.H4("系统资源使用情况", className="card-title text-primary"),
dbc.Row([
dbc.Col([
dbc.ListGroup(memory_items, flush=True)
], md=12, lg=4),
dbc.Col([
dbc.Row([
dbc.Col([cpu_graph], width=12, className="mb-4"),
dbc.Col([memory_graph], width=12, className="mb-4"),
dbc.Col([network_graph], width=12, className="mb-4"),
dbc.Col([
html.H5("CPU核心使用率", className="mt-2 text-primary"),
cores_table
], width=12, className="mb-4"),
dbc.Col([
html.H5("磁盘使用情况", className="mt-2 text-primary"),
disk_table
], width=12, className="mb-4")
])
], md=12, lg=8)
])
])
], className="mb-4 shadow-sm")
except Exception as e:
print(f"获取资源信息错误: {e}")
return dbc.Card(dbc.CardBody([html.P("获取资源信息失败")]))
@cache_with_timeout(CACHE_TIMEOUT)
def get_process_info():
"""获取进程信息"""
try:
processes = []
cpu_count = psutil.cpu_count() # 获取CPU核心数
for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_percent', 'status']):
try:
# 获取进程信息
pinfo = proc.info
cpu_percent = pinfo['cpu_percent'] / cpu_count # 将CPU使用率除以核心数
if cpu_percent > 0: # 只显示有CPU使用的进程
processes.append({
'pid': pinfo['pid'],
'name': pinfo['name'],
'cpu_percent': cpu_percent,
'memory_percent': pinfo.get('memory_percent', 0),
'status': pinfo['status']
})
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass
# 按CPU使用率排序并获取前20个进程
processes.sort(key=lambda x: x['cpu_percent'], reverse=True)
top_processes = processes[:20]
# 创建进程表格
table_header = [
html.Thead(html.Tr([
html.Th("PID", className="text-center"),
html.Th("进程名", className="text-center"),
html.Th("CPU使用率", className="text-center"),
html.Th("内存使用率", className="text-center"),
html.Th("状态", className="text-center")
]), className="table-light")
]
table_body = []
for proc in top_processes:
status_class = {
'running': 'success',
'sleeping': 'info',
'stopped': 'warning',
'zombie': 'danger'
}.get(proc['status'].lower(), 'secondary')
row = html.Tr([
html.Td(str(proc['pid']), className="text-center value-display"),
html.Td(proc['name'], className="text-center"),
html.Td([
html.Div(className="progress", style={"height": "20px"},
children=[
html.Div(
className="progress-bar",
style={
"width": f"{min(proc['cpu_percent'], 100)}%",
"backgroundColor": get_progress_color(proc['cpu_percent'])
},
children=f"{proc['cpu_percent']:.1f}%"
)
]
)
], className="text-center"),
html.Td([
html.Div(className="progress", style={"height": "20px"},
children=[
html.Div(
className="progress-bar",
style={
"width": f"{min(proc['memory_percent'], 100)}%",
"backgroundColor": get_progress_color(proc['memory_percent'])
},
children=f"{proc['memory_percent']:.1f}%"
)
]
)
], className="text-center"),
html.Td(
html.Span(
proc['status'].capitalize(),
className=f"badge bg-{status_class}"
),
className="text-center"
)
])
table_body.append(row)
table = dbc.Table(
table_header + [html.Tbody(table_body)],
bordered=True,
hover=True,
responsive=True,
striped=True,
className="mt-3 align-middle"
)
return dbc.Card([
dbc.CardHeader([
html.H4([
html.I(className="fas fa-microchip me-2"),
"进程信息"
], className="card-title mb-0 d-flex align-items-center"),
html.Small("显示CPU使用率前20的进程", className="text-muted ms-2")
], className="d-flex align-items-center"),
dbc.CardBody([table], className="p-0")
], className="process-card shadow-sm")
except Exception as e:
print(f"获取进程信息错误: {e}")
return html.Div("无法获取进程信息")
def get_health_status():
"""获取系统健康状态"""
try:
cpu_percent = psutil.cpu_percent(interval=None)
memory = psutil.virtual_memory()
disk = psutil.disk_usage('/')
# 定义健康状态阈值
status = {
'cpu': {
'status': 'good' if cpu_percent < 70 else 'warning' if cpu_percent < 90 else 'danger',
'value': cpu_percent
},
'memory': {
'status': 'good' if memory.percent < 70 else 'warning' if memory.percent < 90 else 'danger',
'value': memory.percent
},
'disk': {
'status': 'good' if disk.percent < 70 else 'warning' if disk.percent < 90 else 'danger',
'value': disk.percent
}
}
# 确定整体状态
if any(s['status'] == 'danger' for s in status.values()):
overall = 'danger'
elif any(s['status'] == 'warning' for s in status.values()):
overall = 'warning'
else:
overall = 'good'
status_colors = {
'good': '#22c55e',
'warning': '#f59e0b',
'danger': '#ef4444'
}
return dbc.Card([
dbc.CardBody([
html.H4([
html.I(className="fas fa-heartbeat me-2"),
"系统健康状态"
], className="card-title text-primary d-flex align-items-center"),
html.Div([
html.Div([
html.Span("系统状态:", className="me-2"),
html.Span(
"良好" if overall == 'good' else "警告" if overall == 'warning' else "危险",
className=f"badge rounded-pill bg-{overall}"
)
], className="mb-3"),
dbc.Row([
dbc.Col([
html.Div([
html.I(className="fas fa-microchip me-2"),
"CPU负载",
html.Span(
f"{status['cpu']['value']:.1f}%",
className="float-end",
style={"color": status_colors[status['cpu']['status']]}
)
], className="d-flex justify-content-between align-items-center")
], width=4),
dbc.Col([
html.Div([
html.I(className="fas fa-memory me-2"),
"内存使用",
html.Span(
f"{status['memory']['value']:.1f}%",
className="float-end",
style={"color": status_colors[status['memory']['status']]}
)
], className="d-flex justify-content-between align-items-center")
], width=4),
dbc.Col([
html.Div([
html.I(className="fas fa-hdd me-2"),
"磁盘使用",
html.Span(
f"{status['disk']['value']:.1f}%",
className="float-end",
style={"color": status_colors[status['disk']['status']]}
)
], className="d-flex justify-content-between align-items-center")
], width=4)
])
], className="health-status-container")
])
], className="mb-4 health-status-card")
except Exception as e:
print(f"获取健康状态错误: {e}")
return html.Div()
def get_network_speed():
"""获取网络速度"""
global last_net_io
try:
net_io = psutil.net_io_counters()
current_time = datetime.now()
if last_net_io is not None and len(network_times) > 0:
# 计算时间差(秒)
time_diff = (current_time - network_times[-1]).total_seconds()
if time_diff > 0:
# 计算发送和接收速度(MB/s)
sent_speed = (net_io.bytes_sent - last_net_io.bytes_sent) / (1024 * 1024 * time_diff)
recv_speed = (net_io.bytes_recv - last_net_io.bytes_recv) / (1024 * 1024 * time_diff)
# 保持队列长度
if len(network_times) >= TIME_SERIES_LENGTH:
network_times.pop(0)
network_sent.pop(0)
network_recv.pop(0)
network_times.append(current_time)
network_sent.append(sent_speed)
network_recv.append(recv_speed)
# 返回当前速度值用于显示
return sent_speed, recv_speed
else:
# 第一次运行,添加0值
network_times.append(current_time)
network_sent.append(0)
network_recv.append(0)
last_net_io = net_io
return 0, 0
except Exception as e:
print(f"获取网络速度错误: {e}")
return 0, 0
def format_speed(speed):
"""格式化网络速度显示"""
if speed < 1:
return f"{speed * 1024:.1f} KB/s"
else:
return f"{speed:.1f} MB/s"
# 定义布局
app.layout = dbc.Container([
dbc.Row([
dbc.Col([
html.Div([
html.H1([
html.I(className="fas fa-chart-line me-3"),
"Windows 系统监控"
], className="text-center mb-4 text-primary d-flex align-items-center justify-content-center"),
html.Div(id='health-status', className="fade-in"),
html.Div(id='system-info', className="fade-in"),
html.Div(id='resource-info', className="fade-in"),
html.Div(id='process-info', className="fade-in")
], className="py-4")
], width=12)
]),
dcc.Interval(
id='interval-component',
interval=UPDATE_INTERVAL,
n_intervals=0
)
], fluid=True, className="pb-4")
# 添加自定义CSS
app.index_string = '''
<!DOCTYPE html>
<html>
<head>
{%metas%}
<title>{%title%}</title>
{%favicon%}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;500&display=swap" rel="stylesheet">
{%css%}
<style>
:root {
--primary-color: #4f46e5;
--success-color: #22c55e;
--warning-color: #f59e0b;
--danger-color: #ef4444;
--info-color: #3b82f6;
--background-color: #f8fafc;
--card-background: #ffffff;
--text-primary: #1e293b;
--text-secondary: #64748b;
}
body {
background-color: var(--background-color);
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
color: var(--text-primary);
}
.card {
border: none;
border-radius: 16px;
background: var(--card-background);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
margin-bottom: 1.5rem;
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
}
.table {
--bs-table-striped-bg: rgba(0, 0, 0, 0.02);
margin-bottom: 0;
}
.table th {
font-weight: 600;
color: var(--text-secondary);
border-bottom-width: 2px;
padding: 1rem;
}
.table td {
padding: 1rem;
vertical-align: middle;
color: var(--text-primary);
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.fade-in {
animation: fadeIn 0.5s ease forwards;
}
.badge {
padding: 0.5em 1em;
font-weight: 500;
border-radius: 9999px;
}
.badge.bg-success { background-color: var(--success-color) !important; }
.badge.bg-warning { background-color: var(--warning-color) !important; }
.badge.bg-danger { background-color: var(--danger-color) !important; }
.value-display {
font-family: 'Roboto Mono', monospace;
font-weight: 500;
}
.card-header {
background: transparent;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
padding: 1.25rem;
}
.card-body {
padding: 1.25rem;
}
@media (max-width: 768px) {
.container-fluid {
padding: 1rem;
}
.card {
margin-bottom: 1rem;
}
.table {
font-size: 0.875rem;
}
.badge {
font-size: 0.75rem;
}
}
</style>
</head>
<body>
{%app_entry%}
<footer>
{%config%}
{%scripts%}
{%renderer%}
</footer>
</body>
</html>
'''
# 性能优化:更新回调
@app.callback(
[
Output('health-status', 'children'),
Output('system-info', 'children'),
Output('resource-info', 'children'),
Output('process-info', 'children')
],
[Input('interval-component', 'n_intervals')]
)
def update_metrics(n):
"""更新所有指标"""
try:
return (
get_health_status(),
get_system_info(),
get_resource_info(),
get_process_info()
)
except Exception as e:
print(f"更新指标错误: {e}")
return (
html.Div("系统健康状态获取失败"),
html.Div("系统信息获取失败"),
html.Div("资源信息获取失败"),
html.Div("进程信息获取失败")
)
if __name__ == '__main__':
print("\n正在启动服务器...")
app.run_server(debug=False)
非实用程序,只是试试水。