Handoff: sentimiento + pulso para el boletín

2026-09-06 noche · sesión siguiente: 2026-09-07 Detalle técnico completo: 2026-09-06-fuentes-sentimiento-libres.md

Estado del sistema (todo verificado en vivo hoy)

feed.py ──> feed.json (X vía RSSHub, YT, hermanas, + fast.ai NUEVO)
sentimiento.py ──> data/corpus/*.jsonl + reporte/sentimiento.json
pulso.py ──> reporte/pulso.json|html ──┐
reporte.py / mailing.py <──────────────┘ bloque "Pulso social" si e["pulso"] existe

Búsquedas sociales por nube (cierre del loop): temas_desde_nube() en sentimiento.py deriva los terminos de busqueda del propio material — propios en etiquetas triage primero, luego emergentes y nube filtrada (stoplist + nombres de fuentes excluidos). Hoy resolvió: Chiapas, Maternidad, México, Oaxaca → mastodon/newsapi/gnews/bluesky los usan automaticamente. --temas X Y sigue para forzar a mano. (Algo de basura residual: vigilar al crecer candidatas/; el filtro mejora solo con volumen.)

Fuentes activas sin ninguna credencial: reddit .rss (estrangulado), bluesky actor-feeds + hilos anónimos (respuestas reales), mastodon hashtags (mastodon.social/hachyderm), Google News RSS, NewsAPI (key en .env.local), prensa propia (feed.json), YouTube comentarios (--yt, el corpus ES de replies con más volumen).

Clasificador: robertuito local CPU — validado (NEG “traidor” 0.94). Backend de texto: Ollama gemma4 default (Gemini prepay agotado — no bloquea nada). Portadas apuntadas a Vertex/ADC, sin probar aún.

X: solo a petición expresa — pulso.py --x usa twitterapi.io (key en .env.local, funciona, ~$0.01/edición; endpoint user/tweets está muerto, advanced_search + by_ids vivos). RSSHub actual solo para display.

Servidor ligero (madrugada 06→07 sep)

  • reporte/ 6.9MB→1.8MB: 3 PNGs portada borrados (los .url de Cloudinary ya mandan; /e/{fecha}.png ahora REDIRIGE al sidecar en vez de 404 — fix de orden de rutas, bug latente).
  • .vercelignore: .venv, monitoreo, worker, candidatas, scripts, data, _emls_consulta, briefes, requirements-local, *.png no viajan al deploy.
  • humo con TestClient: /, /hn, /hn/tech, /feed, /analisis, /ediciones 200; /api/cron 200 degradado (RSSHub abajo en ese momento, merge de feed.json preservó historial). Cron NO revienta sin nada externo.
  • PENDIENTE Vercel (manual, 2 min): vercel env rm GEMINI_API_KEY/GCP_*; poner LLM_BACKEND=gateway + AI_GATEWAY_API_KEY o borrarla (el codigo ya degrada a cache con RuntimeError capturado, pero el mensaje limpio salva el terna nocturna: mover /api/proponer a launchd local si no hay gateway).
  • pendiente local: el contenedor rsshub-surtido estaba abajo al humo — el paso 1 de actualizar_hn.sh lo levanta solo.

Pendientes de mañana (priorizados)

  1. Carburante del loop: meter ingest.py --limit 3 en la noche (o al menos 3x/semana) — sin candidatas frescas el resolucioner degrada a hashtags del feed; con ellas devuelve propios editoriales (Chiapas, Oaxaca). Ventanas actuales: triage 14d, corpus 7d.

  2. Primer actualizar_hn.sh completo → valida pulso en el flujo diario

    • fast.ai entrando al hn-tech traducido.
  3. Talkwalker Alerts (30 s, tu correo): crear "Sheinbaum", "Culiacán", "elecciones judiciales" → copiar URLs RSS a TALKWALKER_RSS= en .env.local. Cubre conversaciones X sin tocar X.

  4. Cuenta Bluesky gratis + app password → BSKY_IDENTIFIER/ BSKY_APP_PASSWORD: desbloquea búsqueda por tema (hoy 403 anónimo) y alimenta hilos de respuestas de periodistas MX.

  5. Editar preview y considerar envío: reporte/2026-09-06-preview.{json,html} — sección TECNOLOGÍA·CHINA con titulares ES + Pulso social. Si nada de esto a edición real, --edicion lo inyecta. Revisar manualmente los titulares ZH→ES que generó gemma4.

  6. Portada vertex: primera corrida de imagen.py confirma el ADC (fallback si falla: IMAGEN_PROVEEDOR=nanobanana o recargar gemini).

  7. (Opcional) reddit.com/r/mexico: ya NO hay apps self-serve — no perder tiempo ahí; el reemplazo son hilos bluesky + yt comments.

Comandos de bolsillo

.venv/bin/python sentimiento.py --limite 20              # corpus + resumen
.venv/bin/python sentimiento.py --yt <url_video> --temas Sheinbaum
.venv/bin/python pulso.py --html                         # pulso social
.venv/bin/python pulso.py --x                            # SOLO a petición (twitterapi)
.venv/bin/python pulso.py --edicion reporte/FECHA.json   # inyectar al boletín

Números de hoy (referencia de calibración)

  • Corpus multifuente: Culiacán −0.56 · judiciales −0.58 · Sheinbaum −0.36
  • Prensa propia −0.13 vs cobertura nacional −0.6 → el contraste es el dato editorial
  • Pulso social 61 muestras: −0.20 · modo X 60 posts: −0.18

Trampas conocidas (no repetir debugging)

  • yt comments: videos recién subidos dan 0; usa videos de días atrás. player_client=tv falla; default funciona.
  • newsapi: siempre q="término"&language=es (sin quotes = basura turca); top-headlines?country=mx = 0.
  • Bluesky searchPosts anon 403 (buscó headers de origen; es duro); getAuthorFeed/getPostThread anon 200.
  • twitterapi: user/tweets minte con “suspended”; advanced_search desde ya.
  • reddit .rss y .json viven de su humor: retry x2 con sleep 8s ya incluido.