textmachine/eval/promptlang/spend.py

91 lines
4 KiB
Python
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
"""$0 сводка расхода сессии ДВУМЯ независимыми путями.
Путь 1 — то, что каждый харнесс записал сам (`cost_usd` в своих артефактах).
Путь 2 — пере-счёт из СЫРОГО `usage` по прайсу `models.yaml` (кэш-токены по своей ставке).
Расхождение двух путей и есть проверка: одинаковые числа, полученные одним способом, — не проверка.
"""
from __future__ import annotations
import json
import sqlite3
from pathlib import Path
import yaml
REPO = Path("/home/ubuntu/projects/textmachine")
PL = Path.home() / "books" / "gu-zhenren" / "promptlang"
CUTOFF = "2026-07-31 18:40" # первая трата сессии
prices = yaml.safe_load((REPO / "backend/configs/models.yaml").read_text(encoding="utf-8"))["models"]
def px(model: str) -> tuple[float, float, float]:
p = prices[model]["price"]
return p["input_per_m"], p["output_per_m"], p.get("cached_per_m", 0.0)
rows = []
# — движковые прогоны (задача A арм en; задача B арм a0 в боевой форме до стоп-гейта)
for proj in ("A-ru", "A-en", "B-a0", "B-a1", "B-a2"):
db = PL / proj / "db.sqlite"
if not db.exists():
continue
con = sqlite3.connect(db)
for r in con.execute("select model_actual, prompt_tokens, cached_tokens, completion_tokens,"
" cost_usd from request_log where ts > ?", (CUTOFF,)):
m, pt, cch, ct, self_cost = r
if not m:
continue
pin, pout, pcached = px(m)
recomputed = (pt - cch) / 1e6 * pin + cch / 1e6 * pcached + ct / 1e6 * pout
rows.append(("движок " + proj, self_cost, recomputed))
con.close()
# — сырые пробы провода и армы
for d, label in ((PL / "wire", "wire-пробы"), (PL / "armsraw", "армы задачи B/A")):
for f in sorted(d.glob("*.json")):
if f.name == "fragments.json":
continue
j = json.loads(f.read_text(encoding="utf-8"))
if "error" in j:
continue
pin, pout, pcached = px("deepseek-v4-flash")
pt, cch, ct = j.get("prompt_tokens", 0), j.get("cached_tokens", 0), j.get("completion_tokens", 0)
recomputed = (pt - cch) / 1e6 * pin + cch / 1e6 * pcached + ct / 1e6 * pout
rows.append((label, j.get("cost_usd", 0.0), recomputed))
# — судьи (свои леджеры, свои модели; в judge_p4 их ДВА, маршрутизация по семейству пары)
for sub, label in (("judge", "судья армов"), ("judge_p4", "судья пар P4")):
led = PL / sub / "ledger.jsonl"
if not led.exists():
continue
for ln in led.read_text().splitlines():
j = json.loads(ln)
if "error" in j:
continue
model = j.get("judge", "grok-4.3")
pin, pout, _ = px(model)
billed = j.get("out_billed")
if billed is None: # judge_p4: reasoning у deepseek subset, у xai additive
ct, rt = j.get("completion_tok", 0), j.get("reasoning_tok", 0)
billed = ct + rt if model.startswith("grok") and rt > ct else ct
recomputed = j.get("prompt_tok", 0) / 1e6 * pin + billed / 1e6 * pout
rows.append((f"{label} {model}", j.get("cost_usd", 0.0), recomputed))
agg: dict[str, list[float]] = {}
for label, a, b in rows:
v = agg.setdefault(label, [0.0, 0.0, 0])
v[0] += a
v[1] += b
v[2] += 1
print(f"{'источник':<22}{'вызовов':>9}{'путь 1 ($)':>13}{'путь 2 ($)':>13}{'Δ':>12}")
t1 = t2 = 0.0
for label, (a, b, n) in sorted(agg.items()):
print(f"{label:<22}{n:>9}{a:>13.6f}{b:>13.6f}{a-b:>12.2e}")
t1 += a
t2 += b
print(f"{'ИТОГО':<22}{sum(v[2] for v in agg.values()):>9}{t1:>13.6f}{t2:>13.6f}{t1-t2:>12.2e}")
print(f"\nпотолок сессии $0.15 · использовано {t1/0.15*100:.1f}% · остаток ${0.15-t1:.6f}")