from typing import Any, Dict from sqlmodel import Session, select from models.bot import BotInstance, NanobotImage from services.bot_storage_service import get_bot_resource_limits, get_bot_workspace_snapshot from services.platform_activity_service import ( get_bot_activity_stats, list_activity_events, prune_expired_activity_events, ) from services.platform_settings_service import get_platform_settings from services.platform_usage_service import list_usage def build_platform_overview(session: Session, docker_manager: Any) -> Dict[str, Any]: deleted = prune_expired_activity_events(session, force=False) if deleted > 0: session.commit() bots = session.exec( select(BotInstance).order_by(BotInstance.created_at.desc(), BotInstance.id.asc()) ).all() images = session.exec(select(NanobotImage).order_by(NanobotImage.created_at.desc())).all() settings = get_platform_settings(session) running = 0 stopped = 0 disabled = 0 configured_cpu_total = 0.0 configured_memory_total = 0 configured_storage_total = 0 workspace_used_total = 0 workspace_limit_total = 0 live_cpu_percent_total = 0.0 live_memory_used_total = 0 live_memory_limit_total = 0 for bot in bots: enabled = bool(getattr(bot, "enabled", True)) runtime_status = docker_manager.get_bot_status(bot.id) if docker_manager else str(bot.docker_status or "STOPPED") resources = get_bot_resource_limits(bot.id) runtime = ( docker_manager.get_bot_resource_snapshot(bot.id) if docker_manager else {"usage": {}, "limits": {}, "docker_status": runtime_status} ) workspace = get_bot_workspace_snapshot(bot.id, config_data=None) workspace_used = int(workspace.get("usage_bytes") or 0) workspace_limit = int(workspace.get("configured_limit_bytes") or 0) configured_cpu_total += float(resources["cpu_cores"] or 0) configured_memory_total += int(resources["memory_mb"] or 0) * 1024 * 1024 configured_storage_total += workspace_limit workspace_used_total += workspace_used workspace_limit_total += workspace_limit live_cpu_percent_total += float((runtime.get("usage") or {}).get("cpu_percent") or 0.0) live_memory_used_total += int((runtime.get("usage") or {}).get("memory_bytes") or 0) live_memory_limit_total += int((runtime.get("usage") or {}).get("memory_limit_bytes") or 0) if not enabled: disabled += 1 elif runtime_status == "RUNNING": running += 1 else: stopped += 1 usage = list_usage(session, limit=20) events = list_activity_events(session, limit=20) activity_stats = get_bot_activity_stats(session) return { "summary": { "bots": { "total": len(bots), "running": running, "stopped": stopped, "disabled": disabled, }, "images": { "total": len(images), "ready": len([row for row in images if row.status == "READY"]), "abnormal": len([row for row in images if row.status != "READY"]), }, "resources": { "configured_cpu_cores": round(configured_cpu_total, 2), "configured_memory_bytes": configured_memory_total, "configured_storage_bytes": configured_storage_total, "live_cpu_percent": round(live_cpu_percent_total, 2), "live_memory_used_bytes": live_memory_used_total, "live_memory_limit_bytes": live_memory_limit_total, "workspace_used_bytes": workspace_used_total, "workspace_limit_bytes": workspace_limit_total, }, }, "images": [ { "tag": row.tag, "version": row.version, "status": row.status, "source_dir": row.source_dir, "created_at": row.created_at.isoformat() + "Z", } for row in images ], "settings": settings.model_dump(), "usage": usage, "events": events, "activity_stats": activity_stats, }