#1 batch scoring (processor):
- _score_quality_batch puntúa hasta 25 chunks por llamada a Claude en vez
de una por chunk (una fuente de 19 chunks pasaba de 19 llamadas a 1)
- parser robusto (último número por línea, padding neutro si faltan)
- fallback por-chunk con Ollama si el batch falla
#2 fuentes opcionales (config + scraper):
- ENABLE_YOUTUBE / ENABLE_REDDIT, default False: la IP del homelab está
bloqueada por Reddit (403) y YouTube (transcripts vacíos), eran peso muerto
- se saltan también las URLs de yt/reddit descubiertas dentro de webs, sin
gastar petición de red
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
simple_chunk:
- parte por \n+ (no solo \n\n): Wikipedia/trafilatura usan \n simple, lo
que colapsaba cada fuente en un único chunk gigante
- subdivide párrafos que superan chunk_size
- el overlap arrastra un tail de N palabras en vez del párrafo completo
(evita chunks inflados a ~2x cuando los párrafos son grandes)
processor: embedding sobre el chunk completo (antes truncaba a 1000 chars,
el vector solo representaba el principio del chunk → ranking RAG pobre)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
processor.py: split _score_quality into _score_with_claude and
_score_with_ollama; if ANTHROPIC_API_KEY is set, use Claude Haiku
(claude-haiku-4-5) with max_tokens=10 for fast, accurate 0-10
relevance scoring; falls back to Ollama on any error
requirements.txt: add anthropic>=0.40.0
k8s: ANTHROPIC_API_KEY added to researchowl-secrets and mounted in
deployment; QUALITY_THRESHOLD restored to 0.4 (Claude scoring
is accurate enough to use the threshold)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
database.py: enable PRAGMA journal_mode=WAL + synchronous=NORMAL so
/status reads from concurrent connections see committed data without
blocking behind the scraper's writes; add 'skipped' to get_session_stats
bot.py: show skipped count in fmt_progress and cmd_status; use 'or 0'
to guard against NULL from SUM(); label active research in /status
processor.py: raise generate() temperature default to 0.7 + add
repeat_penalty=1.15/repeat_last_n=128 to Ollama options to stop
qwen2.5:3b from looping; scoring prompt keeps temperature=0.1
generator.py: rewrite all prompts with explicit "NEVER repeat"
constraints and distinct-content rules per section; podcast prompt
now asks for spoken-word style (no formal headers); reduce thread
to 12-18 tweets (was 15-25) to fit model context; pass temperature=0.7
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
processor.py: simplify _score_quality prompt to single axis —
"how relevant is this text to topic X?" — instead of averaging
relevance + density + credibility, which let off-topic but
well-written content pass through
exhaustive.py: pre-compute topic keywords (stopword-filtered) at
scraper init; filter child URLs (discovered during crawl, depth>0)
to only add ones whose URL path or title contains a topic keyword;
seed URLs (depth=0, from DDG/Wikipedia/Reddit) are always included
since those searches are already topic-scoped
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- bot.py: add cmd_process handler to manually trigger chunk processing
on the last session; register CommandHandler("process")
- processor.py: log exceptions from asyncio.gather instead of silently
dropping them; add per-chunk quality score debug logging; warn when
all chunks filtered by quality threshold with actionable hint;
raise fallback score to 0.6 so Ollama failures don't filter chunks
- exhaustive.py: replace bot User-Agent with full browser UA + headers
for REDDIT_HEADERS; downgrade Reddit 403 from warning to info since
server IPs are routinely blocked; use content_type=None on json()
to avoid aiohttp content-type mismatch errors
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>