Files
Agentswarm/scripts/render_swarm_terminal_snapshot.py
T
2026-06-08 17:32:34 +08:00

175 lines
5.2 KiB
Python

#!/usr/bin/env python3
"""Render a terminal-style HTML snapshot from a swarm poster summary JSON."""
from __future__ import annotations
import argparse
import json
from datetime import datetime, timezone
from pathlib import Path
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Render a terminal-style swarm snapshot HTML.")
parser.add_argument("summary_json", help="Path to the swarm poster summary JSON file.")
parser.add_argument(
"--output-html",
help="Optional output HTML path. Defaults next to the summary file.",
)
return parser.parse_args()
def fmt_ts(ts: float | None) -> str:
if not ts:
return "-"
return datetime.fromtimestamp(ts, tz=timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
def main() -> int:
args = parse_args()
summary_path = Path(args.summary_json).resolve()
data = json.loads(summary_path.read_text(encoding="utf-8"))
swarm = data["swarm"]
task = data["task"]
metrics = data["metrics"]
out_path = (
Path(args.output_html).resolve()
if args.output_html
else summary_path.with_name(summary_path.stem + "-terminal.html")
)
budget_ratio = metrics.get("budget", {}).get("duration_ratio")
budget_display = f"{budget_ratio * 100:.1f}%" if isinstance(budget_ratio, (int, float)) else "-"
transcript = [
"$ python3 scripts/run_swarm_poster_demo.py",
f"[swarm] deployment_id={swarm['deployment_id']}",
f"[swarm] swarm_id={swarm['swarm_id']}",
f"[task] task_id={task['task_id']}",
f"[task] status={task['status']}",
f"[task] assigned_agent={task.get('assigned_agent_id') or '-'}",
"",
"$ curl -H \"Authorization: Bearer ***\" /api/swarms/{swarm_id}/tasks",
f"task.started_at = {fmt_ts(data.get('started_at'))}",
f"task.halfway_at = {fmt_ts(data.get('halfway_at'))}",
f"halfway.observed_at = {fmt_ts(data.get('halfway_observed_at'))}",
"",
"$ curl -H \"Authorization: Bearer ***\" /api/swarms/{swarm_id}/metrics",
f"runtime.status = {metrics.get('status')}",
f"runtime.tasks_total = {metrics.get('tasks_total')}",
f"runtime.tasks_by_status = {json.dumps(metrics.get('tasks_by_status', {}), ensure_ascii=False)}",
f"runtime.agents_connected = {metrics.get('agents_connected')}",
f"runtime.budget.duration_seconds = {metrics.get('budget', {}).get('duration_seconds')}",
f"runtime.budget.duration_ratio = {budget_display}",
"",
"# milestone",
f"> 任务开始: {fmt_ts(data.get('started_at'))}",
f"> 任务过半: {fmt_ts(data.get('halfway_observed_at'))}",
]
lines_html = "\n".join(f"<div class='line'>{line}</div>" for line in transcript)
html = f"""<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Swarm Terminal Snapshot</title>
<style>
body {{
margin: 0;
background:
radial-gradient(circle at top right, rgba(74, 222, 128, 0.10), transparent 20%),
radial-gradient(circle at top left, rgba(96, 165, 250, 0.10), transparent 24%),
#0a0f14;
color: #d7e3ee;
font-family: Menlo, Monaco, "SFMono-Regular", "JetBrains Mono", monospace;
}}
.frame {{
width: 1600px;
min-height: 900px;
margin: 0 auto;
padding: 48px;
box-sizing: border-box;
}}
.window {{
background: #0b1220;
border: 1px solid rgba(148, 163, 184, 0.20);
border-radius: 18px;
overflow: hidden;
box-shadow: 0 30px 80px rgba(0, 0, 0, 0.45);
}}
.topbar {{
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 18px;
background: #121a2a;
border-bottom: 1px solid rgba(148, 163, 184, 0.12);
}}
.dots {{
display: flex;
gap: 8px;
}}
.dot {{
width: 12px;
height: 12px;
border-radius: 50%;
}}
.dot.red {{ background: #fb7185; }}
.dot.yellow {{ background: #fbbf24; }}
.dot.green {{ background: #4ade80; }}
.title {{
color: #93a4b8;
font-size: 15px;
letter-spacing: 0.02em;
}}
.terminal {{
padding: 28px 32px 36px;
font-size: 24px;
line-height: 1.7;
white-space: pre-wrap;
word-break: break-word;
}}
.line:nth-child(1),
.line:nth-child(8),
.line:nth-child(13) {{
color: #7dd3fc;
}}
.line:nth-last-child(2),
.line:nth-last-child(1) {{
color: #bef264;
font-weight: 600;
}}
</style>
</head>
<body>
<div class="frame">
<div class="window">
<div class="topbar">
<div class="dots">
<span class="dot red"></span>
<span class="dot yellow"></span>
<span class="dot green"></span>
</div>
<div class="title">swarm-terminal-snapshot</div>
<div class="title">{swarm['swarm_id']}</div>
</div>
<div class="terminal">
{lines_html}
</div>
</div>
</div>
</body>
</html>
"""
out_path.write_text(html, encoding="utf-8")
print(out_path)
return 0
if __name__ == "__main__":
raise SystemExit(main())