feat: template-based message display, remove all emoji

This commit is contained in:
snowy-yang committed 2026-09-12 19:49:13 +08:00
1 parent 570eb0df70
commit 2e077eab33
11 files changed
+126 -68

No files matched your search

+62 -55
View File
@@ -4,6 +4,7 @@ import logging
import sys
import monitor
import templates
from alerter import Alerter
from onebot import OneBotServer
@@ -29,7 +30,7 @@ def load_config() -> dict:
sys.exit(1)
# ---------- 消息格式化 ----------
# ---------- 消息格式化(模板见 templates/) ----------
def _fmt_uptime(seconds: float) -> str:
d, r = divmod(int(seconds), 86400)
@@ -38,76 +39,83 @@ def _fmt_uptime(seconds: float) -> str:
return f"{d}天{h}小时{m}分" if d else f"{h}小时{m}分"
def _power_str(p: dict) -> str:
if p["total_watts"] is None:
return "不支持(需要电池或Intel RAPL)"
src = {"battery": "电池", "rapl": "RAPL"}.get(p["source"], p["source"])
extra = f" (电池 {p['battery']}W)" if p["battery"] is not None and p["source"] == "rapl" else ""
return f"{p['total_watts']}W [{src}]{extra}"
def _hottest(temps: dict):
flat = [t for entries in temps.values() for t in entries]
return max(flat, key=lambda t: t["current"]) if flat else None
def fmt_status(s: dict) -> str:
p, c, m = s["power"], s["cpu"], s["memory"]
lines = ["📊 服务器状态"]
power_str = "不支持"
if p["total_watts"] is not None:
src = {"battery": "🔋电池", "rapl": "RAPL"}.get(p["source"], p["source"])
extra = f" (电池 {p['battery']}W)" if p["battery"] is not None and p["source"] == "rapl" else ""
power_str = f"{p['total_watts']}W [{src}]{extra}"
lines.append(f"⚡ 功耗: {power_str}")
load = c["load"]
total_pct = sum(c["per_core"])
lines.append(f"🖥 CPU: {total_pct:.1f}% / {c['cores'] * 100}% "
f"(单核均值 {c['percent']}%) 核心 {c['cores']} "
f"负载 {load[0]:.2f}/{load[1]:.2f}/{load[2]:.2f}")
lines.append(f"💾 内存: {m['used_gb']}/{m['total_gb']}GB ({m['percent']}%) Swap {m['swap_percent']}%")
if s["temps"]:
flat = [t for entries in s["temps"].values() for t in entries]
hottest = max(flat, key=lambda t: t["current"])
lines.append(f"🌡 温度: 最高 {hottest['label']} {hottest['current']}°C")
if s["net"]["up_mbps"] is not None:
lines.append(f"🌐 网络: ↑{s['net']['up_mbps']}Mbps ↓{s['net']['down_mbps']}Mbps")
lines.append(f"⏱ 运行: {_fmt_uptime(s['uptime_s'])}")
if s["disk"]:
d = s["disk"][0]
lines.append(f"🗄 磁盘 {d['mount']}: {d['used_gb']}/{d['total_gb']}GB ({d['percent']}%)")
return "\n".join(lines)
c, m = s["cpu"], s["memory"]
hot = _hottest(s["temps"])
net = s["net"]
d = s["disk"][0] if s["disk"] else None
return templates.render(
"status",
power=_power_str(s["power"]),
cpu_total=f"{sum(c['per_core']):.1f}%",
cpu_max=f"{c['cores'] * 100}%",
cpu_avg=f"{c['percent']}",
cores=c["cores"],
load=f"{c['load'][0]:.2f}/{c['load'][1]:.2f}/{c['load'][2]:.2f}",
memory=f"{m['used_gb']}/{m['total_gb']}GB ({m['percent']}%) Swap {m['swap_percent']}%",
temp=f"{hot['label']} {hot['current']}C" if hot else "无数据",
net=(f"上行 {net['up_mbps']}Mbps / 下行 {net['down_mbps']}Mbps"
if net["up_mbps"] is not None else "无数据"),
disk_mount=d["mount"] if d else "-",
disk_used=f"{d['used_gb']}/{d['total_gb']}GB" if d else "-",
disk_percent=f"{d['percent']}%" if d else "-",
uptime=_fmt_uptime(s["uptime_s"]),
)
def fmt_power(s: dict) -> str:
p = s["power"]
if p["total_watts"] is None and p["battery"] is None:
return ("⚡ 未获取到功耗数据。\n"
"支持的来源:笔记本电池 /sys/class/power_supply,"
"Intel RAPL /sys/class/powercap(AMD/部分虚拟机不支持)。")
lines = ["⚡ 功耗详情"]
return templates.render(
"power",
power=("未获取到功耗数据。支持的来源:笔记本电池 /sys/class/power_supply,"
"Intel RAPL /sys/class/powercap (AMD/多数虚拟机不支持)。"),
)
lines = []
if p["battery"] is not None:
lines.append(f"🔋 电池功率: {p['battery']}W")
lines.append(f"电池功率: {p['battery']}W")
if p["domains"]:
lines.append("RAPL 域:")
for name, watts in p["domains"].items():
lines.append(f" {name}: {watts}W")
return "\n".join(lines)
lines += [f" {name}: {watts}W" for name, watts in p["domains"].items()]
return templates.render("power", power="\n".join(lines) or "无数据")
def fmt_top(s: dict) -> str:
if not s["top"]:
return "🔝 未获取到进程数据"
lines = ["🔝 CPU 占用 TOP10:"]
for i, p in enumerate(s["top"], 1):
lines.append(f"{i}. {p['name']} (PID {p['pid']}) CPU {p['cpu']}% 内存 {p['mem_mb']}MB")
return "\n".join(lines)
return templates.render("top", top_n=10, top_list="无数据")
lines = [
f"{i}. {p['name']} (PID {p['pid']}) CPU {p['cpu']}% 内存 {p['mem_mb']}MB"
for i, p in enumerate(s["top"], 1)
]
return templates.render("top", top_n=len(s["top"]), top_list="\n".join(lines))
def fmt_temps(s: dict) -> str:
if not s["temps"]:
return "🌡 未获取到温度数据(需要 lm-sensors 或 psutil 支持,虚拟机通常不支持)"
lines = ["🌡 温度:"]
for name, entries in s["temps"].items():
for t in entries:
lines.append(f" {name}/{t['label']}: {t['current']}°C")
return "\n".join(lines)
return templates.render("temps", temp_list="未获取到 (需要 lm-sensors,虚拟机通常不支持)")
lines = [
f" {name}/{t['label']}: {t['current']}C"
for name, entries in s["temps"].items() for t in entries
]
return templates.render("temps", temp_list="\n".join(lines))
HELP = """📖 可用命令(/ 或 ! 前缀均可):
/status 状态 - 总览(功耗/CPU/内存/温度/网络)
/power 功耗 - 功耗详情(RAPL/电池)
/top 进程 - CPU TOP10 进程
/temp 温度 - 传感器温度
/net 网络 - 网络速率
/help 帮助 - 本帮助"""
def fmt_net(net: dict) -> str:
return templates.render(
"net", up=f"{net['up_mbps']}Mbps", down=f"{net['down_mbps']}Mbps")
# ---------- 命令处理 ----------
@@ -177,10 +185,9 @@ class Bot:
if cmd in ("temp", "温度"):
return fmt_temps({"temps": monitor.get_temps()})
if cmd in ("net", "网络"):
net = monitor.get_net(interval=1.0)
return f"🌐 网络速率: ↑{net['up_mbps']}Mbps ↓{net['down_mbps']}Mbps"
return fmt_net(monitor.get_net(interval=1.0))
if cmd in ("help", "帮助"):
return HELP
return templates.render("help")
return None
except Exception:
log.exception("处理命令失败: %s", text)