# retoor <retoor@molodetz.nl>
from .core import datetime, db, get_table, timezone
def _add_usage(usage_table: str, user_uid: str, totals: dict) -> None:
if not user_uid or int(totals.get("calls") or 0) <= 0 or usage_table not in db.tables:
return
with db:
db.query(
f"INSERT INTO {usage_table} "
"(user_uid, calls, prompt_tokens, completion_tokens, total_tokens, cost_usd, "
"upstream_latency_ms, total_latency_ms, updated_at) "
"VALUES (:user_uid, :calls, :prompt, :completion, :total, :cost, :ulat, :tlat, :now) "
"ON CONFLICT(user_uid) DO UPDATE SET "
"calls = calls + excluded.calls, "
"prompt_tokens = prompt_tokens + excluded.prompt_tokens, "
"completion_tokens = completion_tokens + excluded.completion_tokens, "
"total_tokens = total_tokens + excluded.total_tokens, "
"cost_usd = cost_usd + excluded.cost_usd, "
"upstream_latency_ms = upstream_latency_ms + excluded.upstream_latency_ms, "
"total_latency_ms = total_latency_ms + excluded.total_latency_ms, "
"updated_at = excluded.updated_at",
user_uid=user_uid,
calls=int(totals.get("calls") or 0),
prompt=int(totals.get("prompt_tokens") or 0),
completion=int(totals.get("completion_tokens") or 0),
total=int(totals.get("total_tokens") or 0),
cost=float(totals.get("cost_usd") or 0.0),
ulat=float(totals.get("upstream_latency_ms") or 0.0),
tlat=float(totals.get("total_latency_ms") or 0.0),
now=datetime.now(timezone.utc).isoformat(),
)
def _get_usage(usage_table: str, user_uid: str) -> dict:
empty = {
"calls": 0,
"prompt_tokens": 0,
"completion_tokens": 0,
"total_tokens": 0,
"cost_usd": 0.0,
"upstream_latency_ms": 0.0,
"total_latency_ms": 0.0,
"avg_tokens": 0.0,
"avg_upstream_latency_ms": 0.0,
"avg_total_latency_ms": 0.0,
"avg_tokens_per_second": 0.0,
"avg_cost_usd": 0.0,
"updated_at": None,
}
if not user_uid or usage_table not in db.tables:
return empty
row = get_table(usage_table).find_one(user_uid=user_uid)
if not row:
return empty
calls = int(row.get("calls") or 0)
completion = int(row.get("completion_tokens") or 0)
total_tokens = int(row.get("total_tokens") or 0)
cost = float(row.get("cost_usd") or 0.0)
upstream_ms = float(row.get("upstream_latency_ms") or 0.0)
total_ms = float(row.get("total_latency_ms") or 0.0)
return {
"calls": calls,
"prompt_tokens": int(row.get("prompt_tokens") or 0),
"completion_tokens": completion,
"total_tokens": total_tokens,
"cost_usd": cost,
"upstream_latency_ms": upstream_ms,
"total_latency_ms": total_ms,
"avg_tokens": round(total_tokens / calls, 1) if calls else 0.0,
"avg_upstream_latency_ms": round(upstream_ms / calls, 1) if calls else 0.0,
"avg_total_latency_ms": round(total_ms / calls, 1) if calls else 0.0,
"avg_tokens_per_second": round(completion / (upstream_ms / 1000.0), 1)
if upstream_ms > 0
else 0.0,
"avg_cost_usd": (cost / calls) if calls else 0.0,
"updated_at": row.get("updated_at"),
}
def add_correction_usage(user_uid: str, totals: dict) -> None:
_add_usage("correction_usage", user_uid, totals)
def get_correction_usage(user_uid: str) -> dict:
return _get_usage("correction_usage", user_uid)
def add_modifier_usage(user_uid: str, totals: dict) -> None:
_add_usage("modifier_usage", user_uid, totals)
def get_modifier_usage(user_uid: str) -> dict:
return _get_usage("modifier_usage", user_uid)
NEWS_USAGE_KEY = "news"
def add_news_usage(totals: dict) -> None:
_add_usage("news_usage", NEWS_USAGE_KEY, totals)
def get_news_usage() -> dict:
return _get_usage("news_usage", NEWS_USAGE_KEY)
ISSUE_USAGE_KEY = "issues"
def add_issue_usage(totals: dict) -> None:
_add_usage("issue_usage", ISSUE_USAGE_KEY, totals)
def get_issue_usage() -> dict:
return _get_usage("issue_usage", ISSUE_USAGE_KEY)
SEO_USAGE_KEY = "seo_meta"
def add_seo_usage(totals: dict) -> None:
_add_usage("seo_usage", SEO_USAGE_KEY, totals)
def get_seo_usage() -> dict:
return _get_usage("seo_usage", SEO_USAGE_KEY)