|
# 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)
|