39 lines
1.8 KiB
Python
39 lines
1.8 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import json
|
|
|
|
from sqlalchemy import text
|
|
|
|
from app.models.base import async_session
|
|
from app.services.credit.utils import utc_now
|
|
|
|
|
|
async def amain() -> int:
|
|
async with async_session() as db:
|
|
rows = (await db.execute(text("""
|
|
SELECT e.id, e.total_call_count, e.successful_call_count, e.failed_call_count,
|
|
e.total_input_tokens, e.total_output_tokens, e.total_tokens,
|
|
COUNT(a.id) AS actual_calls,
|
|
COALESCE(SUM(CASE WHEN a.status = 'succeeded' THEN 1 ELSE 0 END), 0) AS actual_success,
|
|
COALESCE(SUM(CASE WHEN a.status IN ('failed','timeout','unknown') THEN 1 ELSE 0 END), 0) AS actual_failed,
|
|
COALESCE(SUM(a.input_tokens), 0) AS actual_input,
|
|
COALESCE(SUM(a.output_tokens), 0) AS actual_output,
|
|
COALESCE(SUM(a.total_tokens), 0) AS actual_total
|
|
FROM llm_billing_executions e
|
|
LEFT JOIN llm_call_attempts a ON a.billing_execution_id = e.id
|
|
GROUP BY e.id
|
|
HAVING e.total_call_count <> COUNT(a.id)
|
|
OR e.successful_call_count <> COALESCE(SUM(CASE WHEN a.status = 'succeeded' THEN 1 ELSE 0 END), 0)
|
|
OR e.failed_call_count <> COALESCE(SUM(CASE WHEN a.status IN ('failed','timeout','unknown') THEN 1 ELSE 0 END), 0)
|
|
OR e.total_tokens <> COALESCE(SUM(a.total_tokens), 0)
|
|
ORDER BY e.id
|
|
LIMIT 1000
|
|
"""))).mappings().all()
|
|
print(json.dumps({"checked_at": utc_now().isoformat(), "mismatch_count": len(rows), "items": [dict(r) for r in rows]}, ensure_ascii=False, indent=2, default=str))
|
|
return 0 if not rows else 2
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(asyncio.run(amain()))
|