121 lines
4.6 KiB
Bash
Executable File
121 lines
4.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# OpenClaw 状态监控 - 生成静态 HTML
|
|
OUT="${1:-/tmp/oc-status.html}"
|
|
CONFIG="$HOME/.openclaw/openclaw.json"
|
|
|
|
# 获取基础信息
|
|
GW_PID=$(pgrep -f "openclaw.*gateway" | head -1)
|
|
GW_STATUS="offline"; GW_UPTIME=""
|
|
if [ -n "$GW_PID" ]; then
|
|
GW_STATUS="online"
|
|
if [ "$(uname)" = "Darwin" ]; then
|
|
GW_START=$(ps -o lstart= -p "$GW_PID" 2>/dev/null)
|
|
else
|
|
GW_START=$(ps -o etimes= -p "$GW_PID" 2>/dev/null | xargs)
|
|
fi
|
|
fi
|
|
|
|
# 获取 session 信息
|
|
SESSIONS=$(cat ~/.openclaw/agents/main/sessions/sessions.json 2>/dev/null)
|
|
SESSION_COUNT=$(echo "$SESSIONS" | python3 -c "import json,sys;d=json.load(sys.stdin);print(len(d.get('sessions',{})))" 2>/dev/null || echo "?")
|
|
|
|
# 获取模型信息
|
|
MODEL_JSON=$(python3 -c "
|
|
import json
|
|
with open('$CONFIG') as f: c=json.load(f)
|
|
m=c.get('models',{})
|
|
default=m.get('default','')
|
|
providers=[]
|
|
for name,p in m.get('providers',{}).items():
|
|
if not isinstance(p,dict): continue
|
|
for mod in p.get('models',[]):
|
|
providers.append({
|
|
'provider':name,
|
|
'model':mod.get('id',''),
|
|
'name':mod.get('name',''),
|
|
'api':p.get('api',''),
|
|
'ctx':mod.get('contextWindow',0),
|
|
'maxTok':mod.get('maxTokens',0),
|
|
'base':p.get('baseUrl','')[:60]
|
|
})
|
|
print(json.dumps({'default':default,'providers':providers}))
|
|
" 2>/dev/null)
|
|
|
|
# 生成 HTML
|
|
python3 << 'PYEOF' > "$OUT"
|
|
import json,datetime,os
|
|
|
|
gw_status = os.environ.get("GW_STATUS","offline")
|
|
session_count = os.environ.get("SESSION_COUNT","?")
|
|
model_json = os.environ.get("MODEL_JSON","{}")
|
|
|
|
try:
|
|
data = json.loads(model_json)
|
|
except:
|
|
data = {"default":"","providers":[]}
|
|
|
|
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
rows = ""
|
|
for p in data.get("providers",[]):
|
|
badge = "primary" if p["provider"] in ["newcli","terminalpub","bookapi"] else "secondary"
|
|
rows += f"""<tr>
|
|
<td><span class="badge {badge}">{p['provider']}</span></td>
|
|
<td><code>{p['model']}</code></td>
|
|
<td>{p['name']}</td>
|
|
<td>{p['api']}</td>
|
|
<td>{p['ctx']//1000}k</td>
|
|
<td>{p['maxTok']//1000}k</td>
|
|
<td class="url">{p['base']}</td>
|
|
</tr>"""
|
|
|
|
dot = "green" if gw_status == "online" else "red"
|
|
|
|
print(f"""<!DOCTYPE html>
|
|
<html lang="zh">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
<title>OpenClaw Monitor</title>
|
|
<style>
|
|
*{{margin:0;padding:0;box-sizing:border-box}}
|
|
body{{font-family:-apple-system,system-ui,sans-serif;background:#0d1117;color:#c9d1d9;padding:20px}}
|
|
.container{{max-width:1000px;margin:0 auto}}
|
|
h1{{font-size:1.5em;margin-bottom:20px;color:#58a6ff}}
|
|
.cards{{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-bottom:24px}}
|
|
.card{{background:#161b22;border:1px solid #30363d;border-radius:8px;padding:16px}}
|
|
.card .label{{font-size:.8em;color:#8b949e;margin-bottom:4px}}
|
|
.card .value{{font-size:1.4em;font-weight:600}}
|
|
.dot{{display:inline-block;width:10px;height:10px;border-radius:50%;margin-right:6px}}
|
|
.dot.green{{background:#3fb950}}.dot.red{{background:#f85149}}
|
|
table{{width:100%;border-collapse:collapse;background:#161b22;border:1px solid #30363d;border-radius:8px;overflow:hidden}}
|
|
th{{background:#21262d;text-align:left;padding:10px 12px;font-size:.85em;color:#8b949e}}
|
|
td{{padding:8px 12px;border-top:1px solid #30363d;font-size:.85em}}
|
|
code{{background:#30363d;padding:2px 6px;border-radius:4px;font-size:.85em}}
|
|
.badge{{padding:2px 8px;border-radius:10px;font-size:.75em;font-weight:600}}
|
|
.badge.primary{{background:#1f6feb;color:#fff}}.badge.secondary{{background:#30363d;color:#8b949e}}
|
|
.url{{color:#8b949e;font-size:.75em;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}}
|
|
.footer{{margin-top:16px;font-size:.75em;color:#484f58;text-align:center}}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>🐾 OpenClaw Monitor</h1>
|
|
<div class="cards">
|
|
<div class="card"><div class="label">Gateway</div><div class="value"><span class="dot {dot}"></span>{gw_status}</div></div>
|
|
<div class="card"><div class="label">Sessions</div><div class="value">{session_count}</div></div>
|
|
<div class="card"><div class="label">Default Model</div><div class="value" style="font-size:1em">{data.get('default','auto')}</div></div>
|
|
<div class="card"><div class="label">Providers</div><div class="value">{len(data.get('providers',[]))}</div></div>
|
|
</div>
|
|
<table>
|
|
<thead><tr><th>Provider</th><th>Model ID</th><th>Name</th><th>API</th><th>Context</th><th>Max Out</th><th>Endpoint</th></tr></thead>
|
|
<tbody>{rows}</tbody>
|
|
</table>
|
|
<div class="footer">Updated: {now} · OpenClaw Status Monitor</div>
|
|
</div>
|
|
</body>
|
|
</html>""")
|
|
PYEOF
|
|
|
|
echo "Generated: $OUT"
|