59 lines
2.8 KiB
Python
59 lines
2.8 KiB
Python
"""Consumi: token e costi per giorno e per motore, dal registro data/consumi.jsonl scritto a ogni risposta."""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
from collections import defaultdict
|
|
from datetime import datetime, timedelta
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
from avatar.settings import DATA_DIR # noqa: E402
|
|
|
|
LOG = DATA_DIR / "consumi.jsonl"
|
|
|
|
|
|
def _n(x: int) -> str:
|
|
return f"{x:,}".replace(",", ".")
|
|
|
|
|
|
def riepilogo(giorni: int = 7) -> str:
|
|
since = (datetime.now() - timedelta(days=giorni - 1)).strftime("%Y-%m-%d")
|
|
try:
|
|
rows = [json.loads(l) for l in LOG.read_text(encoding="utf-8").splitlines() if l.strip()]
|
|
except FileNotFoundError:
|
|
rows = []
|
|
rows = [r for r in rows if r["ts"][:10] >= since]
|
|
if not rows:
|
|
return f"Nessun consumo registrato negli ultimi {giorni} giorni (il conteggio parte da oggi)."
|
|
per_m = defaultdict(lambda: [0, 0, 0, 0.0, False]); per_g = defaultdict(lambda: [0, 0.0])
|
|
for r in rows:
|
|
m = per_m[r["motore"]]; m[0] += 1; m[1] += r["input"]; m[2] += r["output"]; m[3] += r["costo"]; m[4] = m[4] or r.get("abbonamento", False)
|
|
g = per_g[r["ts"][:10]]; g[0] += r["input"] + r["output"]; g[1] += 0 if r.get("abbonamento") else r["costo"]
|
|
out = [f"Consumi ultimi {giorni} giorni:"]
|
|
for mot, (n, i, o, c, abb) in sorted(per_m.items(), key=lambda kv: -(kv[1][1] + kv[1][2])):
|
|
costo = "gratis (locale)" if mot.startswith("locale") else (f"≈ ${c:.2f} equivalente API, incluso nell'abbonamento" if abb else f"≈ ${c:.2f}")
|
|
out.append(f"- {mot}: {n} risposte, {_n(i)} token in ingresso, {_n(o)} in uscita, {costo}")
|
|
out.append("Per giorno: " + "; ".join(f"{g[8:10]}/{g[5:7]} {_n(t)} token" + (f" (${c:.2f})" if c else "") for g, (t, c) in sorted(per_g.items())))
|
|
return "\n".join(out)
|
|
|
|
|
|
def t_riepilogo(params: dict, ctx: dict) -> str:
|
|
return riepilogo(max(1, min(int(params.get("giorni") or 7), 90)))
|
|
|
|
|
|
TOOLS = [
|
|
{"name": "consumi_riepilogo", "description": "Token e costi delle risposte di LuZa per motore (locale, Claude Code, Claude API) e per giorno, negli ultimi N giorni (default 7). Per 'quanto ho speso?', 'quanti token ho usato?'.",
|
|
"parameters": {"type": "object", "properties": {"giorni": {"type": "integer"}}}, "run": t_riepilogo},
|
|
]
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import tempfile
|
|
LOG = Path(tempfile.mkdtemp()) / "c.jsonl"
|
|
now = datetime.now().strftime("%Y-%m-%d %H:%M")
|
|
LOG.write_text("\n".join(json.dumps(r) for r in [
|
|
{"ts": now, "motore": "locale (gemma)", "input": 100, "output": 50, "costo": 0, "abbonamento": False},
|
|
{"ts": now, "motore": "claude api (x)", "input": 1000, "output": 200, "costo": 0.01, "abbonamento": False}]) + "\n")
|
|
out = riepilogo(7); assert "gratis (locale)" in out and "$0.01" in out, out; print(out)
|