xiaowei-system/scripts/newapi-weekly-report.py

93 lines
3.1 KiB
Python
Executable File
Raw Permalink 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
"""
NewAPI 周度评估报告 — 汇总观测数据,输出评估结论
每周日 18:00 由 cron 触发,输出可读报告(非静默,始终输出)
评估维度:可用性 / 延迟 / 路由一致性
替代 omniroute-weekly-report.pyOmniRoute 已于 2026-09-02 关停)
"""
import json
import os
import statistics
from datetime import datetime, timezone, timedelta
STATE_DIR = os.path.expanduser("~/.hermes/newapi-observe")
LOG = os.path.join(STATE_DIR, "observations.jsonl")
# 评估阈值
LATENCY_WARN_MS = 8000 # 平均延迟超 8s 警告
SUCCESS_RATE_MIN = 0.90 # 成功率低于 90% 警告
def load_observations(days=7):
if not os.path.exists(LOG):
return []
cutoff = datetime.now(timezone.utc) - timedelta(days=days)
obs = []
with open(LOG) as f:
for line in f:
try:
d = json.loads(line)
ts = datetime.fromisoformat(d["ts"])
if ts >= cutoff:
obs.append(d)
except Exception:
continue
return obs
def main():
obs = load_observations(7)
n = len(obs)
print(f"=== NewAPI 周度评估(最近 7 天)===")
print(f"观测次数: {n}")
print(f"生成时间: {datetime.now(timezone.utc).isoformat()}")
print()
if n == 0:
print("⚠️ 无观测数据cron 可能在观测脚本切换期间未运行)")
return
# 1. 服务可用性
svc_ok = sum(1 for o in obs if o.get("service") == "ok")
svc_rate = svc_ok / n
print(f"【服务可用性】 {svc_ok}/{n} = {svc_rate*100:.1f}%")
# 2. 按模型统计
by_model = {}
for o in obs:
for t in o.get("tests", []):
m = t["model"]
if m not in by_model:
by_model[m] = {"ok": 0, "total": 0, "latencies": []}
by_model[m]["total"] += 1
if t["ok"]:
by_model[m]["ok"] += 1
by_model[m]["latencies"].append(t["latency_ms"])
print(f"\n【按模型表现】")
for m, d in sorted(by_model.items()):
rate = d["ok"] / d["total"] * 100 if d["total"] else 0
if d["latencies"]:
avg = statistics.mean(d["latencies"])
p95 = sorted(d["latencies"])[int(len(d["latencies"])*0.95)] if len(d["latencies"]) > 1 else d["latencies"][0]
else:
avg = p95 = 0
status = "" if rate >= SUCCESS_RATE_MIN*100 and avg < LATENCY_WARN_MS else "⚠️"
print(f" {status} {m}: {d['ok']}/{d['total']} = {rate:.0f}%, 平均 {avg:.0f}ms, P95 {p95:.0f}ms")
# 3. 总体评估
total_tests = sum(d["total"] for d in by_model.values())
total_ok = sum(d["ok"] for d in by_model.values())
overall_rate = total_ok / total_tests * 100 if total_tests else 0
print(f"\n【总体】 {total_ok}/{total_tests} = {overall_rate:.1f}%")
if overall_rate < SUCCESS_RATE_MIN*100:
print("⚠️ 建议: 检查 NewAPI 上游 channel 健康度")
else:
print("✅ 评估: NewAPI 表现健康,可作为本地主网关")
if __name__ == "__main__":
main()