fix: correcciones de scraping/DB y mejoras de robustez
Sección crítica: - is_blacklisted: match por dominio/subdominio exacto (antes "x.com" como substring bloqueaba netflix.com, phoenix.com, etc.) - normalize_url: conserva el query string (rompía YouTube watch?v= y URLs con ?id=); solo borra el fragment - get_db: PRAGMA busy_timeout=5000 para evitar "database is locked" en /compare y watches solapados - OllamaClient.embed: usa OLLAMA_EMBED_MODEL en vez del modelo de chat - log_api_call: coste por modelo (opus/sonnet/haiku) en vez de Haiku fijo Mejoras: - src/llm.py: cliente Anthropic compartido y cacheado (antes se instanciaba uno por cada llamada/chunk) - SEARXNG_URL configurable via env - get_running_loop() en vez de get_event_loop() (deprecado) - soup.title.get_text() robusto ante <title> con tags anidados - limpieza: import muerto, total_words duplicado, w_id no usado Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
fd9aaa193b
commit
bf275b7f82
+22
-3
@@ -123,6 +123,10 @@ async def get_db() -> aiosqlite.Connection:
|
||||
db.row_factory = aiosqlite.Row
|
||||
await db.execute("PRAGMA journal_mode=WAL")
|
||||
await db.execute("PRAGMA synchronous=NORMAL")
|
||||
# Espera hasta 5s si otra conexión tiene el lock de escritura (scheduler
|
||||
# solapado con research activa, o las 2 sesiones de /compare) en vez de
|
||||
# fallar al instante con "database is locked".
|
||||
await db.execute("PRAGMA busy_timeout=5000")
|
||||
await db.executescript(SCHEMA)
|
||||
await db.commit()
|
||||
return db
|
||||
@@ -341,11 +345,26 @@ class ResearchDB:
|
||||
|
||||
# --- API Usage ---
|
||||
|
||||
# Precios Claude en USD por 1M de tokens (input, output).
|
||||
# Se busca por substring del id del modelo; fallback a Haiku.
|
||||
_MODEL_PRICING = {
|
||||
"opus": (15.00, 75.00),
|
||||
"sonnet": (3.00, 15.00),
|
||||
"haiku": (0.80, 4.00),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def _price_for_model(cls, model: str) -> tuple[float, float]:
|
||||
m = (model or "").lower()
|
||||
for key, price in cls._MODEL_PRICING.items():
|
||||
if key in m:
|
||||
return price
|
||||
return cls._MODEL_PRICING["haiku"]
|
||||
|
||||
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
|
||||
in_price, out_price = self._price_for_model(model)
|
||||
cost = (input_tokens * in_price + output_tokens * out_price) / 1_000_000
|
||||
await self.db.execute(
|
||||
"""INSERT INTO api_usage
|
||||
(session_id, call_type, model, input_tokens, output_tokens, cost_usd, created_at)
|
||||
|
||||
Reference in New Issue
Block a user