import io, json, sqlite3, collections, re con = sqlite3.connect(r"E:/ProgramData/.workbuddy/workbuddy.db"); con.row_factory = sqlite3.Row autos = {} for r in con.execute("select id,name,status,schedule_type,rrule,scheduled_at,cwds,created_at from automations"): autos[r["id"]] = dict(r) def walk(o, acc): """递归收集所有 usage 对象""" if isinstance(o, dict): u = o.get("usage") if isinstance(u, dict) and "inputTokens" in u: acc.append(u) for v in o.values(): walk(v, acc) elif isinstance(o, list): for v in o: walk(v, acc) rows = [] for r in con.execute("select automation_id, thread_id, runs_json, result_success, created_at from automation_runs order by created_at"): aid = r["automation_id"] acc = [] try: walk(json.loads(r["runs_json"] or "[]"), acc) except Exception: pass n_tool = len(re.findall(r'"toolName"', r["runs_json"] or "")) rows.append({"aid": aid, "t": r["created_at"], "usages": acc, "n_tool": n_tool, "name": (autos.get(aid) or {}).get("name", aid)}) print("=" * 96) print("%-34s %-8s %-8s %-9s %-8s %s" % ("自动化", "运行次", "工具次", "积分总计", "缓存命中", "请求数")) print("=" * 96) agg = collections.defaultdict(lambda: {"runs":0,"tools":0,"cost":0.0,"hit":0,"miss":0,"req":0,"cat":collections.Counter()}) for x in rows: a = agg[x["aid"]]; a["runs"] += 1; a["tools"] += x["n_tool"] for u in x["usages"]: a["req"] += 1 c = (u.get("cost") or {}).get("amount") or 0 a["cost"] += c d = u.get("details") or {} a["hit"] += d.get("promptCacheHitTokens", 0) or 0 a["miss"] += d.get("promptCacheMissTokens", 0) or 0 for k, v in (u.get("byCategory") or {}).items(): if isinstance(v, (int, float)): a["cat"][k] += v tot = {"cost":0.0,"hit":0,"miss":0,"tools":0,"req":0} for aid, a in sorted(agg.items(), key=lambda kv: -kv[1]["cost"]): nm = (autos.get(aid) or {}).get("name", aid)[:32] hr = a["hit"] / max(a["hit"] + a["miss"], 1) * 100 print("%-34s %-8d %-8d %-9.2f %-8s %d" % (nm, a["runs"], a["tools"], a["cost"], "%.1f%%" % hr, a["req"])) tot["cost"] += a["cost"]; tot["hit"] += a["hit"]; tot["miss"] += a["miss"]; tot["tools"] += a["tools"]; tot["req"] += a["req"] print("-" * 96) print("合计:运行 %d 次 | 工具调用 %d | 模型请求 %d | 积分 %.2f | 缓存命中率 %.1f%%" % (sum(a["runs"] for a in agg.values()), tot["tools"], tot["req"], tot["cost"], tot["hit"] / max(tot["hit"] + tot["miss"], 1) * 100)) print() print("== 固定注入构成(所有自动化请求的平均,token)==") cats = collections.Counter() for a in agg.values(): cats.update(a["cat"]) if cats: s = sum(v for k, v in cats.items() if k != "version") for k, v in cats.most_common(): if k == "version": continue print(" %-14s %8.0f (%4.1f%%)" % (k, v / max(len(rows), 1), v / max(s, 1) * 100)) print(" %-14s %8.0f" % ("合计/请求", s / max(len(rows), 1))) print() print("== 逐次请求明细(前 20 条:inputTokens / credit / 缓存命中率 / 工具数)==") n = 0 for x in rows: for u in x["usages"]: d = u.get("details") or {} h, m = d.get("promptCacheHitTokens", 0) or 0, d.get("promptCacheMissTokens", 0) or 0 c = (u.get("cost") or {}).get("amount") or 0 print(" %-30s in=%-8s credit=%-7s hit=%4.1f%% tools=%d [%s]" % (x["name"][:30], u.get("inputTokens"), round(c, 3), h / max(h + m, 1) * 100, x["n_tool"], __import__("datetime").datetime.fromtimestamp(x["t"] / 1000).strftime("%m-%d %H:%M"))) n += 1 if n >= 20: break if n >= 20: break print() print("== 仍在跑的自动化(按计划类型)==") for aid, a in autos.items(): if a["status"] != "ACTIVE": continue if a["rrule"]: per_day = {"HOURLY": 24}.get("HOURLY", 0) iv = re.search(r"INTERVAL=(\d+)", a["rrule"]) k = 24 / int(iv.group(1)) if iv else "?" print(" [周期] %-34s %s ⇒ 约 %.0f 次/天" % (a["name"][:34], a["rrule"], k)) else: print(" [一次] %-34s %s" % (a["name"][:34], a["scheduled_at"]))