Dominio activo: este proyecto, la parte de la vicualizacion de noticias, funciona en trh.com.ar.
Pipeline para extraer noticias, agruparlas por similitud, asistir la revisión editorial en un panel web y publicar artículos con IA en WordPress.
Guía para operadores y editores. Si vas a desarrollar o mantener el código, empezá por
docs/repo-layout.md.
Recoge noticias de distintos sitios, detecta cuáles hablan del mismo tema, les saca palabras clave, presenta esos grupos en un panel para que un editor elija y, desde ahí, genera un artículo unificado con IA y lo publica en WordPress.
Este es el camino que recorre una noticia desde que aparece en un sitio fuente hasta que se convierte en un artículo publicado.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Sitios web │────▶│ Crawlers │────▶│ noticias_ │
│ de fuentes │ │ (uno por │ │ historico │
│ │ │ fuente) │ │ (tabla DB) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ clusters_ │◀────│ Clustering │◀────│ Embeddings │
│ editoriales │ │ (similitud) │ │ (vectoriza) │
│ (tabla DB) │ │ │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Keywords / │────▶│ Panel web │────▶│ Artículo con │
│ entidades │ │ (app.py) │ │ IA │
│ │ │ │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ WordPress │
│ (publicación) │
└─────────────────┘
- Crawlers (
crawler/sites/*_crawler.py) — Entran a cada sitio fuente, extraen títulos, texto, fecha, imagen y guardan todo ennoticias_historico. - Embeddings (
pipeline/embedding_archivo.py) — Convierte el contenido de cada noticia en un vector numérico y lo guarda en una columnapgvector. - Clustering (
pipeline/cluster_noticias.py) — Compara vectores y agrupa noticias que tratan el mismo tema en un solo registro declusters_editoriales. - Keywords y entidades (
pipeline/extraer_keywords_ner.py) — Detecta personas, organizaciones, lugares y frases clave del grupo. - Selección (
pipeline/seleccionar_publicables.py) — Decide qué clusters son candidatos a publicar según reglas de ventana de tiempo y penalización. - Panel editorial (
app.py) — El editor revisa, elige, edita y aprueba. - Generación con IA (
trh/publication/publicador.py) — Escribe un artículo unificado con título, resumen, cuerpo y categoría. - Publicación (
trh/publication/publicapress.py) — Sube el artículo, imágenes y categoría a WordPress.
Para ver el detalle del orquestador que une las primeras etapas, leé
docs/proceso.md.
Un cluster pasa por estos estados a medida que avanza el flujo:
┌─────────────┐
│ NUEVO │ (creado por cluster_noticias.py)
└──────┬──────┘
│
▼
┌─────────────┐
│ PENDIENTE │ (listo para revisión editorial)
└──────┬──────┘
│
┌──────┴──────┐
│ │
▼ ▼
┌─────────┐ ┌─────────────┐
│GENERADO │ │ RECHAZADO │
│ (IA) │ │ (descartado)│
└────┬────┘ └─────────────┘
│
▼
┌─────────────┐
│ PUBLICADO │ (ya en WordPress)
└─────────────┘
- NUEVO: recién creado por el clustering.
- PENDIENTE: candidato a revisión. El editor lo ve en el panel.
- GENERADO: se generó un borrador con IA. El editor puede editar y publicar.
- RECHAZADO: el editor decidió descartarlo.
- PUBLICADO: ya fue enviado a WordPress.
La forma oficial de instalar es con el script remoto:
curl -fsSL https://raw.githubusercontent.com/Clowraider/trh/main/install.sh | shPara ver qué haría sin tocar nada:
curl -fsSL https://raw.githubusercontent.com/Clowraider/trh/main/install.sh | sh -s -- --dry-runAntes de correr el instalador:
- PostgreSQL con
pgvector. Sin esta extensión no funciona la similitud ni el clustering. - Usuario normal, no root. El script usa
sudosolo cuando necesita paquetes del sistema. - API key de un proveedor compatible con OpenAI (OpenAI, DeepSeek, etc.) con saldo disponible.
- WordPress con URL, usuario y Application Password lista.
- Modelo de embeddings local y estable. Preferentemente un modelo local, guardado como artefacto crítico: si cambia el modelo, cambian los vectores y se pierde consistencia histórica.
python3.11 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python -m spacy download es_core_news_md
cp .env.example .env
# editar .env con tus credenciales
./scripts/check_env.sh
./scripts/init_db.sh
python3 app.pyPanel: http://localhost:5000/
El pipeline principal se ejecuta con:
python3 proceso.pyproceso.py hace:
- Crawlers en paralelo: descubre y ejecuta automáticamente todos los archivos
crawler/sites/*_crawler.py. Ahí es donde cada instalación agrega sus propios extractores; no van al repo base. - Como ejemplo y punto de partida se incluye
crawler/sites/plantilla_crawler.py. Copialo, renombralo y adaptalo a tu sitio. - Luego, secuencial:
pipeline/embedding_archivo.pypipeline/cluster_noticias.pypipeline/extraer_keywords_ner.py
Además gestiona locks para que no se pisen dos ejecuciones, y permite encolar una sola corrida más.
Ver detalle completo:
docs/proceso.md
python3 app.pyDesde el panel el editor puede:
- Ver clusters pendientes.
- Revisar noticias fuente.
- Generar un borrador con IA.
- Editar título, resumen, cuerpo y categoría.
- Seleccionar fotos principal y secundarias.
- Guardar cambios.
- Publicar en WordPress.
Ejecutar el pipeline cada pocas horas, según la frecuencia de publicación de tus fuentes:
0 7,10,13,16,19,22 * * * cd /ruta/TRH && /ruta/TRH/.venv/bin/python3 proceso.py >> /ruta/TRH/logs/proceso.log 2>&1Evitá frecuencias agresivas para no saturar sitios pequeños.
| Carpeta / archivo | Qué contiene |
|---|---|
app.py |
Panel web Flask. |
proceso.py |
Orquestador del pipeline de crawlers → embeddings → clusters → keywords. |
crawler/sites/ |
Un archivo por cada sitio fuente. Acá se agregan nuevos medios. |
pipeline/ |
Procesamiento de datos: embeddings, clustering, keywords, selección. |
trh/publication/ |
Generación de artículos con IA y publicación en WordPress. |
trh/editorial/ |
Control editorial y selección asistida por IA. |
prompts/ |
Prompts y reglas que usa la IA. |
templates/ |
Pantallas del panel. |
scripts/ |
Utilidades de entorno, inicialización y wrappers. |
deploy/ |
Ejemplos de systemd y nginx. |
docs/ |
Documentación del sistema. |
docs/proceso.md— Cómo funciona el pipeline principal (proceso.py).docs/repo-layout.md— Cómo está organizado el código (para desarrolladores).
Próximos documentos planificados:
docs/cluster_noticias.md— Cómo agrupa noticias.docs/embedding_archivo.md— Cómo se generan los embeddings.docs/extraer_keywords_ner.md— Cómo se extraen keywords y entidades.docs/seleccionar_publicables.md— Cómo se eligen los clusters publicables.docs/panel.md— Flujo del panel editorial.docs/publicacion.md— Cómo se genera y publica un artículo.
Antes de cambios sensibles, corré:
python -m pytest -qProgramar proceso.py en horarios definidos según la frecuencia de tus fuentes.
Ejemplo base en deploy/trh-panel.service.
Recomendado para exponer el panel en 80/443 mientras app.py escucha en localhost.
Archivos listos para copiar en deploy/:
deploy/trh-panel.servicedeploy/nginx-trh.confdeploy/README.md
- Verificar que
pgvectoresté instalado en PostgreSQL. - Reejecutar
./scripts/init_db.sh.
- Ejecutar
./scripts/check_env.sh. - Confirmar
.envcompleto (DB, proveedor compatible con OpenAI, WordPress).
- Revisar
logs/proceso.log. - Verificar que no haya un lock viejo atascado (
scripts/limpia locks si se ejecuta correctamente, pero un corte abrupto puede dejar uno). En ese caso, ver los archivos de lock en/tmpo donde esté configurado.
- No aumentar la frecuencia de
proceso.pysin necesidad. - Mantener horarios razonables y monitorear tiempos/respuestas.
- Verificar
WP_URL,WP_USERNAMEyWP_APP_PASSWORD. - Confirmar que el usuario de WordPress tenga permisos para crear posts y categorías.
- Revisar logs del panel para ver el error exacto de la API REST.
- Estado actual del proyecto: v1.1.0