feat: trackeo de coste por llamada Claude — tabla api_usage + /costs
Build & Deploy ResearchOwl / build-and-push (push) Successful in 6s

This commit is contained in:
ChemaVX
2026-05-03 20:06:06 +00:00
parent 65917518ce
commit b33ae202b8
4 changed files with 129 additions and 8 deletions
+48
View File
@@ -88,6 +88,17 @@ CREATE INDEX IF NOT EXISTS idx_sources_session ON sources(session_id);
CREATE INDEX IF NOT EXISTS idx_chunks_session ON chunks(session_id);
CREATE INDEX IF NOT EXISTS idx_chunks_quality ON chunks(session_id, quality_score DESC);
CREATE INDEX IF NOT EXISTS idx_source_contents ON source_contents(source_id);
CREATE TABLE IF NOT EXISTS api_usage (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id INTEGER REFERENCES research_sessions(id),
call_type TEXT NOT NULL,
model TEXT NOT NULL,
input_tokens INTEGER NOT NULL,
output_tokens INTEGER NOT NULL,
cost_usd REAL NOT NULL,
created_at REAL NOT NULL
);
"""
@@ -271,6 +282,43 @@ class ResearchDB:
rows = await cursor.fetchall()
return [dict(r) for r in rows]
# --- API Usage ---
async def log_api_call(self, session_id, call_type: str, model: str,
input_tokens: int, output_tokens: int):
# Precios Claude Haiku (claude-haiku-4-5):
# input: $0.80 / 1M tokens output: $4.00 / 1M tokens
cost = (input_tokens * 0.80 + output_tokens * 4.00) / 1_000_000
await self.db.execute(
"""INSERT INTO api_usage
(session_id, call_type, model, input_tokens, output_tokens, cost_usd, created_at)
VALUES (?,?,?,?,?,?,?)""",
(session_id, call_type, model, input_tokens, output_tokens, cost, time.time())
)
await self.db.commit()
async def get_usage_stats(self, session_id: int) -> list[dict]:
cursor = await self.db.execute(
"""SELECT call_type,
COUNT(*) as calls,
SUM(input_tokens + output_tokens) as total_tokens,
SUM(cost_usd) as total_cost
FROM api_usage WHERE session_id = ?
GROUP BY call_type""",
(session_id,)
)
rows = await cursor.fetchall()
return [dict(r) for r in rows]
async def get_total_usage_stats(self) -> dict:
cursor = await self.db.execute(
"""SELECT COUNT(DISTINCT session_id) as sessions,
SUM(cost_usd) as total_cost
FROM api_usage"""
)
row = await cursor.fetchone()
return dict(row) if row else {"sessions": 0, "total_cost": 0}
# --- Maintenance ---
async def purge_old_sessions(self, max_age_days: int = 30) -> dict: