Files
edict/scripts/refresh_live_data.py
cft0808 5b46f67603 🏛️ init: 三省六部 OpenClaw Multi-Agent Orchestration System
Features:
- 9 specialized agents (中书省·门下省·尚书省 + 六部)
- Real-time dashboard with 6 tabs (Overview/Kanban/History/Timeline/Models/Skills)
- Model configuration with live-apply via local API server
- One-click install script
- Data sync pipeline (15s refresh loop)
- Full audit trail via flow_log
2026-02-23 22:34:55 +08:00

105 lines
4.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
import json, pathlib, datetime
BASE = pathlib.Path(__file__).parent.parent
DATA = BASE / 'data'
def read_json(path, default):
try:
return json.loads(path.read_text())
except Exception:
return default
def output_meta(path):
p = pathlib.Path(path)
if not p.exists():
return {"exists": False, "lastModified": None}
ts = datetime.datetime.fromtimestamp(p.stat().st_mtime).strftime('%Y-%m-%d %H:%M:%S')
return {"exists": True, "lastModified": ts}
def main():
officials = read_json(DATA / 'officials.json', [])
# 任务源优先tasks_source.json可对接外部系统同步写入
tasks = read_json(DATA / 'tasks_source.json', [])
if not tasks:
tasks = read_json(DATA / 'tasks.json', [])
sync_status = read_json(DATA / 'sync_status.json', {})
org_map = {o['name']: o.get('org', '') for o in officials}
now_ts = datetime.datetime.now(datetime.timezone.utc)
for t in tasks:
t['org'] = t.get('org') or org_map.get(t.get('official', ''), '')
t['outputMeta'] = output_meta(t.get('output', ''))
# 心跳时效检测:对 Doing/Assigned 状态的任务标注活跃度
if t.get('state') in ('Doing', 'Assigned', 'Review'):
updated_raw = t.get('updatedAt') or t.get('sourceMeta', {}).get('updatedAt')
age_sec = None
if updated_raw:
try:
if isinstance(updated_raw, (int, float)):
updated_dt = datetime.datetime.fromtimestamp(updated_raw / 1000, tz=datetime.timezone.utc)
else:
updated_dt = datetime.datetime.fromisoformat(str(updated_raw).replace('Z', '+00:00'))
age_sec = (now_ts - updated_dt).total_seconds()
except Exception:
pass
if age_sec is None:
t['heartbeat'] = {'status': 'unknown', 'label': '⚪ 未知', 'ageSec': None}
elif age_sec < 180:
t['heartbeat'] = {'status': 'active', 'label': f'🟢 活跃 {int(age_sec//60)}分钟前', 'ageSec': int(age_sec)}
elif age_sec < 600:
t['heartbeat'] = {'status': 'warn', 'label': f'🟡 可能停滞 {int(age_sec//60)}分钟前', 'ageSec': int(age_sec)}
else:
t['heartbeat'] = {'status': 'stalled', 'label': f'🔴 已停滞 {int(age_sec//60)}分钟', 'ageSec': int(age_sec)}
else:
t['heartbeat'] = None
today_done = sum(1 for t in tasks if t.get('state') == 'Done')
in_progress = sum(1 for t in tasks if t.get('state') in ['Doing', 'Review', 'Next', 'Blocked'])
blocked = sum(1 for t in tasks if t.get('state') == 'Blocked')
history = []
for t in tasks:
if t.get('state') == 'Done':
lm = t.get('outputMeta', {}).get('lastModified')
history.append({
'at': lm or '未知',
'official': t.get('official'),
'task': t.get('title'),
'out': t.get('output'),
'qa': '通过' if t.get('outputMeta', {}).get('exists') else '待补成果'
})
payload = {
'generatedAt': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'taskSource': 'tasks_source.json' if (DATA / 'tasks_source.json').exists() else 'tasks.json',
'officials': officials,
'tasks': tasks,
'history': history,
'metrics': {
'officialCount': len(officials),
'todayDone': today_done,
'inProgress': in_progress,
'blocked': blocked
},
'syncStatus': sync_status,
'health': {
'syncOk': bool(sync_status.get('ok', False)),
'syncLatencyMs': sync_status.get('durationMs'),
'missingFieldCount': len(sync_status.get('missingFields', {})),
}
}
(DATA / 'live_status.json').write_text(json.dumps(payload, ensure_ascii=False, indent=2))
print('updated live_status.json')
if __name__ == '__main__':
main()