feat: trackeo de coste por llamada Claude — tabla api_usage + /costs
Build & Deploy ResearchOwl / build-and-push (push) Successful in 6s
Build & Deploy ResearchOwl / build-and-push (push) Successful in 6s
This commit is contained in:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user