Initial commit
This commit is contained in:
commit
d5c932d8e1
710 changed files with 50282 additions and 0 deletions
91
STELLAR-GAUGE-20260807/collector.py
Executable file
91
STELLAR-GAUGE-20260807/collector.py
Executable file
|
|
@ -0,0 +1,91 @@
|
|||
#!/usr/bin/env python3
|
||||
"""collector.py · Qoder CN 用量采集器
|
||||
扫会话日志聚合每模型调用量,输出 ~/.stellar-gauge/usage.json。
|
||||
只读宿主日志,不写宿主任何东西。
|
||||
"""
|
||||
import json, os, re, glob, time
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
LOGS_ROOT = os.path.expanduser(
|
||||
"~/Library/Application Support/QoderCN/logs")
|
||||
STATE_FILE = os.path.expanduser("~/.stellar-gauge/usage.json")
|
||||
OFFSETS_FILE = os.path.expanduser("~/.stellar-gauge/offsets.json")
|
||||
|
||||
RE_CTX = re.compile(
|
||||
r"(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+).*Context usage update: "
|
||||
r"\{.*?\"usedTokens\":(\d+)")
|
||||
RE_MODEL = re.compile(r"applyModelRuntimeMeta: model=([A-Za-z0-9_.-]+)")
|
||||
|
||||
# Qoder 内部别名 → 展示名
|
||||
ALIAS = {
|
||||
"qmodel_38max": "Qwen3.8-Max",
|
||||
"qmodel_37max": "Qwen3.7-Max",
|
||||
"dsmodel_v4pro": "DeepSeek-v4-Pro",
|
||||
}
|
||||
|
||||
|
||||
def load(path, default):
|
||||
try:
|
||||
with open(path) as f:
|
||||
return json.load(f)
|
||||
except Exception:
|
||||
return default
|
||||
|
||||
|
||||
def scan():
|
||||
offsets = load(OFFSETS_FILE, {})
|
||||
usage = load(STATE_FILE, {"requests": {}, "tokens": {},
|
||||
"daily": {}, "meta": {}})
|
||||
now = datetime.now()
|
||||
for f in glob.glob(os.path.join(LOGS_ROOT, "*", "questWindow", "agent.log")):
|
||||
try:
|
||||
size = os.path.getsize(f)
|
||||
off = offsets.get(f, 0)
|
||||
if size < off: # 日志轮转
|
||||
off = 0
|
||||
if size == off:
|
||||
continue
|
||||
with open(f, errors="ignore") as fh:
|
||||
fh.seek(off)
|
||||
chunk = fh.read()
|
||||
offsets[f] = size
|
||||
except Exception:
|
||||
continue
|
||||
cur_model = "unknown"
|
||||
prev_used = None
|
||||
for line in chunk.splitlines():
|
||||
m = RE_MODEL.search(line)
|
||||
if m:
|
||||
cur_model = ALIAS.get(m.group(1), m.group(1))
|
||||
continue
|
||||
m = RE_CTX.search(line)
|
||||
if m:
|
||||
ts, used = m.group(1), int(m.group(2))
|
||||
# 增量估算:两次上报差值近似为本轮新增 token
|
||||
delta = used - prev_used if prev_used else min(used, 8000)
|
||||
prev_used = used
|
||||
day = ts[:10]
|
||||
usage["requests"][cur_model] = \
|
||||
usage["requests"].get(cur_model, 0) + 1
|
||||
usage["tokens"][cur_model] = \
|
||||
usage["tokens"].get(cur_model, 0) + max(delta, 0)
|
||||
d = usage["daily"].setdefault(day, {})
|
||||
d[cur_model] = d.get(cur_model, 0) + max(delta, 0)
|
||||
# 只留 14 天
|
||||
keep = (now - timedelta(days=14)).strftime("%Y-%m-%d")
|
||||
usage["daily"] = {k: v for k, v in usage["daily"].items() if k >= keep}
|
||||
usage["meta"] = {"updated_at": now.isoformat(timespec="seconds"),
|
||||
"note": "token 为本地增量估算,非计费 Credits"}
|
||||
tmp = STATE_FILE + ".tmp"
|
||||
with open(tmp, "w") as f:
|
||||
json.dump(usage, f, ensure_ascii=False, indent=1)
|
||||
os.replace(tmp, STATE_FILE)
|
||||
with open(OFFSETS_FILE, "w") as f:
|
||||
json.dump(offsets, f)
|
||||
return usage
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
u = scan()
|
||||
print(json.dumps({"requests": u["requests"],
|
||||
"meta": u["meta"]}, ensure_ascii=False, indent=1))
|
||||
Loading…
Reference in a new issue