新增系统健康快照并更新优化文档

This commit is contained in:
liuwei
2026-04-30 15:07:03 +08:00
parent ce38f66b7b
commit 83910b287b
3 changed files with 401 additions and 3 deletions

View File

@@ -14,6 +14,7 @@ import yaml
import toml
from utils.markdown_to_image import get_md2img_health_snapshot, warmup_md2img_browser_sync
from utils.ai.llm_registry import LLMRegistry
from base.plugin_common.plugin_interface import PluginStatus
# 创建系统信息蓝图
system_bp = Blueprint('system', __name__)
@@ -364,6 +365,129 @@ def api_system_info():
return jsonify({"success": False, "error": str(e)}), 500
@system_bp.route('/api/system_health_summary')
@login_required
def api_system_health_summary():
"""聚合首页可观测性所需的关键健康信号。"""
try:
server = current_app.dashboard_server
robot = getattr(server, "robot", None)
plugin_manager = getattr(server, "plugin_manager", None)
plugin_map = getattr(plugin_manager, "plugins", {}) or {}
# 统计插件运行状态,便于首页快速判断“加载了多少、真正跑起来多少、是否有异常插件”。
plugin_status_counter = {
"total": len(plugin_map),
"running": 0,
"loaded": 0,
"stopped": 0,
"error": 0,
"unloaded": 0,
"unknown": 0,
}
for plugin in plugin_map.values():
status = getattr(plugin, "status", None)
if status == PluginStatus.RUNNING:
plugin_status_counter["running"] += 1
elif status == PluginStatus.LOADED:
plugin_status_counter["loaded"] += 1
elif status == PluginStatus.STOPPED:
plugin_status_counter["stopped"] += 1
elif status == PluginStatus.ERROR:
plugin_status_counter["error"] += 1
elif status == PluginStatus.UNLOADED:
plugin_status_counter["unloaded"] += 1
else:
plugin_status_counter["unknown"] += 1
# 错误数量直接复用现有统计库,避免为了首页卡片再单独写一套 SQL。
_, recent_error_count = server.stats_db.get_error_logs(days=1, page=1, limit=1)
# md2img 健康快照已经有现成实现,这里只做聚合,不主动预热运行时。
md2img_snapshot = get_md2img_health_snapshot(ensure_runtime=False) or {}
browser_ready = bool(
md2img_snapshot.get("browser_ready")
or md2img_snapshot.get("playwright_ready")
or md2img_snapshot.get("ready")
)
runtime_ready = bool(
md2img_snapshot.get("runtime_ready")
or md2img_snapshot.get("runtime_initialized")
or md2img_snapshot.get("initialized")
)
md2img_healthy = runtime_ready and browser_ready
# 首页只需要“够判断”的轻量结论,因此统一产出 status + summary 文本,前端无需重复拼装业务规则。
robot_running = bool(getattr(robot, "ipad_running", False))
robot_nickname = str(getattr(robot, "nickname", "") or "").strip()
robot_wxid = str(getattr(robot, "wxid", "") or "").strip()
robot_summary = "已连接并正在处理消息" if robot_running else "未连接或主循环未运行"
if robot_nickname or robot_wxid:
robot_summary = f"{robot_summary} · {robot_nickname or robot_wxid}"
if plugin_status_counter["error"] > 0:
plugin_status = "warning"
plugin_summary = f"异常 {plugin_status_counter['error']} 个,运行中 {plugin_status_counter['running']} / {plugin_status_counter['total']}"
elif plugin_status_counter["running"] == 0 and plugin_status_counter["total"] > 0:
plugin_status = "warning"
plugin_summary = f"暂无运行中插件,共加载 {plugin_status_counter['total']}"
else:
plugin_status = "healthy"
plugin_summary = f"运行中 {plugin_status_counter['running']} / {plugin_status_counter['total']}"
if recent_error_count > 0:
error_status = "warning"
error_summary = f"近 24 小时记录到 {recent_error_count} 条异常"
else:
error_status = "healthy"
error_summary = "近 24 小时未记录到异常"
if md2img_healthy:
md2img_status = "healthy"
md2img_summary = "运行时与浏览器均已就绪"
elif runtime_ready or browser_ready:
md2img_status = "warning"
md2img_summary = "运行时部分可用,建议检查预热状态"
else:
md2img_status = "danger"
md2img_summary = "运行时未就绪,相关转图能力可能不可用"
return jsonify({
"success": True,
"data": {
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"robot": {
"status": "healthy" if robot_running else "danger",
"running": robot_running,
"nickname": robot_nickname,
"wxid": robot_wxid,
"summary": robot_summary,
},
"plugins": {
"status": plugin_status,
"summary": plugin_summary,
**plugin_status_counter,
},
"errors": {
"status": error_status,
"recent_24h_count": recent_error_count,
"summary": error_summary,
},
"md2img": {
"status": md2img_status,
"healthy": md2img_healthy,
"runtime_ready": runtime_ready,
"browser_ready": browser_ready,
"summary": md2img_summary,
"detail": md2img_snapshot,
},
}
})
except Exception as e:
logger.error(f"获取系统健康摘要失败: {e}")
return jsonify({"success": False, "error": str(e)}), 500
@system_bp.route('/api/wx_logs')
@login_required
def api_wx_logs():