Initial clean commit
This commit is contained in:
commit
6784d81c2c
141 changed files with 25219 additions and 0 deletions
391
docs/FEED_DISCOVERY.md
Normal file
391
docs/FEED_DISCOVERY.md
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
# Sistema de Descubrimiento y Gestión de Feeds RSS
|
||||
|
||||
Este documento describe el sistema mejorado de descubrimiento automático y gestión de feeds RSS implementado en RSS2.
|
||||
|
||||
## 📋 Visión General
|
||||
|
||||
El sistema ahora incluye dos mecanismos para gestionar feeds RSS:
|
||||
|
||||
1. **Gestión Manual Mejorada**: Interfaz web para descubrir y añadir feeds desde cualquier URL
|
||||
2. **Worker Automático**: Proceso en segundo plano que descubre feeds desde URLs almacenadas
|
||||
|
||||
## 🎯 Componentes del Sistema
|
||||
|
||||
### 1. Utilidad de Descubrimiento (`utils/feed_discovery.py`)
|
||||
|
||||
Módulo Python que proporciona funciones para:
|
||||
|
||||
- **`discover_feeds(url)`**: Descubre automáticamente todos los feeds RSS/Atom desde una URL
|
||||
- **`validate_feed(feed_url)`**: Valida un feed y extrae su información básica
|
||||
- **`get_feed_metadata(feed_url)`**: Obtiene metadatos detallados de un feed
|
||||
|
||||
```python
|
||||
from utils.feed_discovery import discover_feeds
|
||||
|
||||
# Descubrir feeds desde una URL
|
||||
feeds = discover_feeds('https://elpais.com')
|
||||
# Retorna: [{'url': '...', 'title': '...', 'valid': True, ...}, ...]
|
||||
```
|
||||
|
||||
### 2. Router de Feeds Mejorado (`routers/feeds.py`)
|
||||
|
||||
Nuevos endpoints añadidos:
|
||||
|
||||
#### Interfaz Web
|
||||
- **`GET/POST /feeds/discover`**: Interfaz para descubrir feeds desde una URL
|
||||
- Muestra todos los feeds encontrados
|
||||
- Permite seleccionar cuáles añadir
|
||||
- Aplica configuración global (categoría, país, idioma)
|
||||
|
||||
- **`POST /feeds/discover_and_add`**: Añade múltiples feeds seleccionados
|
||||
- Extrae automáticamente título y descripción
|
||||
- Evita duplicados
|
||||
- Muestra estadísticas de feeds añadidos
|
||||
|
||||
#### API JSON
|
||||
- **`POST /feeds/api/discover`**: API para descubrir feeds
|
||||
```json
|
||||
{
|
||||
"url": "https://example.com"
|
||||
}
|
||||
```
|
||||
Retorna:
|
||||
```json
|
||||
{
|
||||
"feeds": [...],
|
||||
"count": 5
|
||||
}
|
||||
```
|
||||
|
||||
- **`POST /feeds/api/validate`**: API para validar un feed específico
|
||||
```json
|
||||
{
|
||||
"url": "https://example.com/rss"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Worker de Descubrimiento (`workers/url_discovery_worker.py`)
|
||||
|
||||
Worker automático que:
|
||||
|
||||
1. **Procesa URLs de la tabla `fuentes_url`**
|
||||
- Prioriza URLs nunca procesadas
|
||||
- Reintenta URLs con errores
|
||||
- Actualiza URLs antiguas
|
||||
|
||||
2. **Descubre y Crea Feeds Automáticamente**
|
||||
- Encuentra todos los feeds RSS en cada URL
|
||||
- Valida cada feed encontrado
|
||||
- Crea entradas en la tabla `feeds`
|
||||
- Evita duplicados
|
||||
|
||||
3. **Gestión de Estado**
|
||||
- Actualiza `last_check`, `last_status`, `status_message`
|
||||
- Maneja errores gracefully
|
||||
- Registra estadísticas detalladas
|
||||
|
||||
#### Configuración del Worker
|
||||
|
||||
Variables de entorno:
|
||||
|
||||
```bash
|
||||
# Intervalo de ejecución (minutos)
|
||||
URL_DISCOVERY_INTERVAL_MIN=15
|
||||
|
||||
# Número de URLs a procesar por ciclo
|
||||
URL_DISCOVERY_BATCH_SIZE=10
|
||||
|
||||
# Máximo de feeds a crear por URL
|
||||
MAX_FEEDS_PER_URL=5
|
||||
```
|
||||
|
||||
#### Estados de URLs en `fuentes_url`
|
||||
|
||||
| Estado | Descripción |
|
||||
|--------|-------------|
|
||||
| `success` | Feeds creados exitosamente |
|
||||
| `existing` | Feeds encontrados pero ya existían |
|
||||
| `no_feeds` | No se encontraron feeds RSS |
|
||||
| `no_valid_feeds` | Se encontraron feeds pero ninguno válido |
|
||||
| `error` | Error al procesar la URL |
|
||||
|
||||
## 🚀 Uso del Sistema
|
||||
|
||||
### Método 1: Interfaz Web Manual
|
||||
|
||||
1. **Navega a `/feeds/discover`**
|
||||
2. **Ingresa una URL** (ej: `https://elpais.com`)
|
||||
3. **Haz clic en "Buscar Feeds"**
|
||||
4. El sistema mostrará todos los feeds encontrados con:
|
||||
- Estado de validación
|
||||
- Título y descripción
|
||||
- Número de entradas
|
||||
- Tipo de feed (RSS/Atom)
|
||||
5. **Configura opciones globales**:
|
||||
- Categoría
|
||||
- País
|
||||
- Idioma
|
||||
6. **Selecciona los feeds deseados** y haz clic en "Añadir Feeds Seleccionados"
|
||||
|
||||
### Método 2: Worker Automático
|
||||
|
||||
1. **Añade URLs a la tabla `fuentes_url`**:
|
||||
```sql
|
||||
INSERT INTO fuentes_url (nombre, url, categoria_id, pais_id, idioma, active)
|
||||
VALUES ('El País', 'https://elpais.com', 1, 1, 'es', TRUE);
|
||||
```
|
||||
|
||||
2. **El worker procesará automáticamente**:
|
||||
- Cada 15 minutos (configurable)
|
||||
- Descubrirá todos los feeds
|
||||
- Creará entradas en `feeds`
|
||||
- Actualizará el estado
|
||||
|
||||
3. **Monitorea el progreso**:
|
||||
```sql
|
||||
SELECT nombre, url, last_check, last_status, status_message
|
||||
FROM fuentes_url
|
||||
ORDER BY last_check DESC;
|
||||
```
|
||||
|
||||
### Método 3: Interfaz de URLs (Existente)
|
||||
|
||||
Usa la interfaz web existente en `/urls/add_source` para añadir URLs que serán procesadas por el worker.
|
||||
|
||||
## 🔄 Flujo de Trabajo Completo
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ Usuario añade │
|
||||
│ URL del sitio │
|
||||
└────────┬────────┘
|
||||
│
|
||||
v
|
||||
┌─────────────────────────┐
|
||||
│ URL guardada en │
|
||||
│ tabla fuentes_url │
|
||||
└────────┬────────────────┘
|
||||
│
|
||||
v
|
||||
┌─────────────────────────┐
|
||||
│ Worker ejecuta cada │
|
||||
│ 15 minutos │
|
||||
└────────┬────────────────┘
|
||||
│
|
||||
v
|
||||
┌─────────────────────────┐
|
||||
│ Descubre feeds RSS │
|
||||
│ usando feedfinder2 │
|
||||
└────────┬────────────────┘
|
||||
│
|
||||
v
|
||||
┌─────────────────────────┐
|
||||
│ Valida cada feed │
|
||||
│ encontrado │
|
||||
└────────┬────────────────┘
|
||||
│
|
||||
v
|
||||
┌─────────────────────────┐
|
||||
│ Crea entradas en │
|
||||
│ tabla feeds │
|
||||
└────────┬────────────────┘
|
||||
│
|
||||
v
|
||||
┌─────────────────────────┐
|
||||
│ Ingestor Go procesa │
|
||||
│ feeds cada 15 minutos │
|
||||
└────────┬────────────────┘
|
||||
│
|
||||
v
|
||||
┌─────────────────────────┐
|
||||
│ Noticias descargadas │
|
||||
│ y procesadas │
|
||||
└─────────────────────────┘
|
||||
```
|
||||
|
||||
## 📊 Tablas de Base de Datos
|
||||
|
||||
### `fuentes_url`
|
||||
Almacena URLs de sitios web para descubrimiento automático:
|
||||
|
||||
```sql
|
||||
CREATE TABLE fuentes_url (
|
||||
id SERIAL PRIMARY KEY,
|
||||
nombre VARCHAR(255) NOT NULL,
|
||||
url TEXT NOT NULL UNIQUE,
|
||||
categoria_id INTEGER REFERENCES categorias(id),
|
||||
pais_id INTEGER REFERENCES paises(id),
|
||||
idioma CHAR(2) DEFAULT 'es',
|
||||
last_check TIMESTAMP,
|
||||
last_status VARCHAR(50),
|
||||
status_message TEXT,
|
||||
last_http_code INTEGER,
|
||||
active BOOLEAN DEFAULT TRUE
|
||||
);
|
||||
```
|
||||
|
||||
### `feeds`
|
||||
Almacena feeds RSS descubiertos y validados:
|
||||
|
||||
```sql
|
||||
CREATE TABLE feeds (
|
||||
id SERIAL PRIMARY KEY,
|
||||
nombre VARCHAR(255),
|
||||
descripcion TEXT,
|
||||
url TEXT NOT NULL UNIQUE,
|
||||
categoria_id INTEGER REFERENCES categorias(id),
|
||||
pais_id INTEGER REFERENCES paises(id),
|
||||
idioma CHAR(2),
|
||||
activo BOOLEAN DEFAULT TRUE,
|
||||
fallos INTEGER DEFAULT 0,
|
||||
last_etag TEXT,
|
||||
last_modified TEXT,
|
||||
last_error TEXT
|
||||
);
|
||||
```
|
||||
|
||||
## ⚙️ Configuración del Sistema
|
||||
|
||||
### Variables de Entorno
|
||||
|
||||
Añade al archivo `.env`:
|
||||
|
||||
```bash
|
||||
# RSS Ingestor
|
||||
RSS_POKE_INTERVAL_MIN=15 # Intervalo de ingesta (minutos)
|
||||
RSS_MAX_FAILURES=10 # Fallos máximos antes de desactivar feed
|
||||
RSS_FEED_TIMEOUT=60 # Timeout para descargar feeds (segundos)
|
||||
|
||||
# URL Discovery Worker
|
||||
URL_DISCOVERY_INTERVAL_MIN=15 # Intervalo de descubrimiento (minutos)
|
||||
URL_DISCOVERY_BATCH_SIZE=10 # URLs a procesar por ciclo
|
||||
MAX_FEEDS_PER_URL=5 # Máximo de feeds por URL
|
||||
```
|
||||
|
||||
### Docker Compose
|
||||
|
||||
El worker ya está configurado en `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
url-discovery-worker:
|
||||
build: .
|
||||
container_name: rss2_url_discovery
|
||||
command: bash -lc "python -m workers.url_discovery_worker"
|
||||
environment:
|
||||
DB_HOST: db
|
||||
URL_DISCOVERY_INTERVAL_MIN: 15
|
||||
URL_DISCOVERY_BATCH_SIZE: 10
|
||||
MAX_FEEDS_PER_URL: 5
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
## 🔧 Comandos Útiles
|
||||
|
||||
### Ver logs del worker de descubrimiento
|
||||
```bash
|
||||
docker logs -f rss2_url_discovery
|
||||
```
|
||||
|
||||
### Reiniciar el worker
|
||||
```bash
|
||||
docker restart rss2_url_discovery
|
||||
```
|
||||
|
||||
### Ejecutar manualmente el worker (testing)
|
||||
```bash
|
||||
docker exec -it rss2_url_discovery python -m workers.url_discovery_worker
|
||||
```
|
||||
|
||||
### Ver estadísticas de descubrimiento
|
||||
```sql
|
||||
-- URLs procesadas recientemente
|
||||
SELECT nombre, url, last_check, last_status, status_message
|
||||
FROM fuentes_url
|
||||
WHERE last_check > NOW() - INTERVAL '1 day'
|
||||
ORDER BY last_check DESC;
|
||||
|
||||
-- Feeds creados recientemente
|
||||
SELECT nombre, url, fecha_creacion
|
||||
FROM feeds
|
||||
WHERE fecha_creacion > NOW() - INTERVAL '1 day'
|
||||
ORDER BY fecha_creacion DESC;
|
||||
```
|
||||
|
||||
## 🛠️ Troubleshooting
|
||||
|
||||
### El worker no encuentra feeds
|
||||
|
||||
1. Verifica que la URL sea accesible:
|
||||
```bash
|
||||
curl -I https://example.com
|
||||
```
|
||||
|
||||
2. Verifica los logs del worker:
|
||||
```bash
|
||||
docker logs rss2_url_discovery
|
||||
```
|
||||
|
||||
3. Prueba manualmente el descubrimiento:
|
||||
```python
|
||||
from utils.feed_discovery import discover_feeds
|
||||
feeds = discover_feeds('https://example.com')
|
||||
print(feeds)
|
||||
```
|
||||
|
||||
### Feeds duplicados
|
||||
|
||||
El sistema previene duplicados usando `ON CONFLICT (url) DO NOTHING`. Si un feed ya existe, simplemente se omite.
|
||||
|
||||
### Worker consume muchos recursos
|
||||
|
||||
Ajusta las configuraciones:
|
||||
|
||||
```bash
|
||||
# Reduce el batch size
|
||||
URL_DISCOVERY_BATCH_SIZE=5
|
||||
|
||||
# Aumenta el intervalo
|
||||
URL_DISCOVERY_INTERVAL_MIN=30
|
||||
|
||||
# Reduce feeds por URL
|
||||
MAX_FEEDS_PER_URL=3
|
||||
```
|
||||
|
||||
## 📝 Mejores Prácticas
|
||||
|
||||
1. **Añade URLs de sitios, no feeds directos**
|
||||
- ✅ `https://elpais.com`
|
||||
- ❌ `https://elpais.com/rss/feed.xml`
|
||||
|
||||
2. **Configura categoría y país correctamente**
|
||||
- Facilita la organización
|
||||
- Mejora la experiencia del usuario
|
||||
|
||||
3. **Monitorea el estado de las URLs**
|
||||
- Revisa periódicamente `fuentes_url`
|
||||
- Desactiva URLs que fallan consistentemente
|
||||
|
||||
4. **Limita el número de feeds por URL**
|
||||
- Evita sobrecarga de feeds similares
|
||||
- Mantén `MAX_FEEDS_PER_URL` entre 3-5
|
||||
|
||||
## 🎉 Ventajas del Sistema
|
||||
|
||||
✅ **Automatización completa**: Solo añade URLs, el sistema hace el resto
|
||||
✅ **Descubrimiento inteligente**: Encuentra todos los feeds disponibles
|
||||
✅ **Validación automática**: Solo crea feeds válidos y funcionales
|
||||
✅ **Sin duplicados**: Gestión inteligente de feeds existentes
|
||||
✅ **Escalable**: Procesa múltiples URLs en lotes
|
||||
✅ **Resiliente**: Manejo robusto de errores y reintentos
|
||||
✅ **Monitoreable**: Logs detallados y estados claros
|
||||
|
||||
## 📚 Referencias
|
||||
|
||||
- **feedfinder2**: https://github.com/dfm/feedfinder2
|
||||
- **feedparser**: https://feedparser.readthedocs.io/
|
||||
- **Tabla fuentes_url**: `/init-db/01.schema.sql`
|
||||
- **Worker**: `/workers/url_discovery_worker.py`
|
||||
- **Utilidades**: `/utils/feed_discovery.py`
|
||||
223
docs/PARRILLAS_VIDEOS.md
Normal file
223
docs/PARRILLAS_VIDEOS.md
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
# 🎬 Sistema de Parrillas de Videos Automatizados
|
||||
|
||||
## 📋 Descripción
|
||||
|
||||
Este sistema permite generar videos automáticos de noticias filtradas según diferentes criterios:
|
||||
- **Por País**: Noticias de Bulgaria, España, Estados Unidos, etc.
|
||||
- **Por Categoría**: Ciencia, Tecnología, Deport, Política, etc.
|
||||
- **Por Entidad**: Personas u organizaciones específicas (ej: "Donald Trump", "OpenAI")
|
||||
- **Por Continente**: Europa, Asia, América, etc.
|
||||
|
||||
## 🎯 Características
|
||||
|
||||
### ✅ Sistema Implementado
|
||||
|
||||
1. **Base de Datos**
|
||||
- Tabla `video_parrillas`: Configuraciones de parrillas
|
||||
- Tabla `video_generados`: Registro de videos creados
|
||||
- Tabla `video_noticias`: Relación entre videos y noticias
|
||||
|
||||
2. **API REST**
|
||||
- `GET /parrillas/` - Listado de parrillas
|
||||
- `GET /parrillas/<id>` - Detalle de parrilla
|
||||
- `POST /parrillas/nueva` - Crear parrilla
|
||||
- `GET /parrillas/api/<id>/preview` - Preview de noticias
|
||||
- `POST /parrillas/api/<id>/generar` - Generar video
|
||||
- `POST /parrillas/api/<id>/toggle` - Activar/desactivar
|
||||
- `DELETE /parrillas/api/<id>` - Eliminar parrilla
|
||||
|
||||
3. **Generador de Videos**
|
||||
- Script: `generar_videos_noticias.py`
|
||||
- Integración con AllTalk TTS
|
||||
- Generación automática de subtítulos SRT
|
||||
- Soporte para múltiples idiomas
|
||||
|
||||
## 🚀 Uso Rápido
|
||||
|
||||
### 1. Crear una Parrilla
|
||||
|
||||
```bash
|
||||
# Acceder a la interfaz web
|
||||
http://localhost:8001/parrillas/
|
||||
|
||||
# O usar SQL directo
|
||||
docker-compose exec -T db psql -U rss -d rss -c "
|
||||
INSERT INTO video_parrillas (nombre, descripcion, tipo_filtro, pais_id, max_noticias, frecuencia, activo)
|
||||
VALUES ('Noticias de Bulgaria', 'Resumen diario de noticias de Bulgaria', 'pais',
|
||||
(SELECT id FROM paises WHERE nombre = 'Bulgaria'), 5, 'daily', true);
|
||||
"
|
||||
```
|
||||
|
||||
### 2. Generar Video Manualmente
|
||||
|
||||
```bash
|
||||
# Generar video para parrilla con ID 1
|
||||
docker-compose exec web python generar_videos_noticias.py 1
|
||||
```
|
||||
|
||||
### 3. Generación Automática (Diaria)
|
||||
|
||||
```bash
|
||||
# Procesar todas las parrillas activas con frecuencia 'daily'
|
||||
docker-compose exec web python generar_videos_noticias.py
|
||||
```
|
||||
|
||||
## 📝 Ejemplos de Parrillas
|
||||
|
||||
### Ejemplo 1: Noticias de Ciencia en Europa
|
||||
|
||||
```sql
|
||||
INSERT INTO video_parrillas (
|
||||
nombre, descripcion, tipo_filtro,
|
||||
categoria_id, continente_id,
|
||||
max_noticias, duracion_maxima, idioma_voz,
|
||||
frecuencia, activo
|
||||
) VALUES (
|
||||
'Ciencia en Europa',
|
||||
'Las últimas noticias científicas de Europa',
|
||||
'categoria',
|
||||
(SELECT id FROM categorias WHERE nombre ILIKE '%ciencia%'),
|
||||
(SELECT id FROM continentes WHERE nombre = 'Europa'),
|
||||
7, 300, 'es',
|
||||
'daily', true
|
||||
);
|
||||
```
|
||||
|
||||
### Ejemplo 2: Noticias sobre una Persona
|
||||
|
||||
```sql
|
||||
INSERT INTO video_parrillas (
|
||||
nombre, descripcion, tipo_filtro,
|
||||
entidad_nombre, entidad_tipo,
|
||||
max_noticias, idioma_voz,
|
||||
frecuencia, activo
|
||||
) VALUES (
|
||||
'Donald Trump en las Noticias',
|
||||
'Todas las menciones de Donald Trump',
|
||||
'entidad',
|
||||
'Donald Trump', 'persona',
|
||||
10, 'es',
|
||||
'daily', true
|
||||
);
|
||||
```
|
||||
|
||||
### Ejemplo 3: Noticias de Tecnología
|
||||
|
||||
```sql
|
||||
INSERT INTO video_parrillas (
|
||||
nombre, descripcion, tipo_filtro,
|
||||
categoria_id,
|
||||
max_noticias, idioma_voz,
|
||||
include_subtitles, template,
|
||||
frecuencia, activo
|
||||
) VALUES (
|
||||
'Tech News Daily',
|
||||
'Resumen diario de tecnología',
|
||||
'categoria',
|
||||
(SELECT id FROM categorias WHERE nombre ILIKE '%tecnolog%'),
|
||||
8, 'es',
|
||||
true, 'modern',
|
||||
'daily', true
|
||||
);
|
||||
```
|
||||
|
||||
## 🔧 Configuración Avanzada
|
||||
|
||||
### Opciones de Parrilla
|
||||
|
||||
| Campo | Tipo | Descripción |
|
||||
|-------|------|-------------|
|
||||
| `nombre` | string | Nombre único de la parrilla |
|
||||
| `descripcion` | text | Descripción detallada |
|
||||
| `tipo_filtro` | enum | 'pais', 'categoria', 'entidad', 'continente', 'custom' |
|
||||
| `pais_id` | int | ID del país (si tipo_filtro='pais') |
|
||||
| `categoria_id` | int | ID de categoría |
|
||||
| `continente_id` | int | ID de continente |
|
||||
| `entidad_nombre` | string | Nombre de persona/organización |
|
||||
| `entidad_tipo` | string | 'persona' o 'organizacion' |
|
||||
| `max_noticias` | int | Máximo de noticias por video (default: 5) |
|
||||
| `duracion_maxima` | int | Duración máxima en segundos (default: 180) |
|
||||
| `idioma_voz` | string | Idioma del TTS ('es', 'en', etc.) |
|
||||
| `template` | string | 'standard', 'modern', 'minimal' |
|
||||
| `include_images` | bool | Incluir imágenes en el video |
|
||||
| `include_subtitles` | bool | Generar subtítulos SRT |
|
||||
| `frecuencia` | string | 'daily', 'weekly', 'manual' |
|
||||
|
||||
### Configuración de AllTalk
|
||||
|
||||
El sistema utiliza AllTalk para generar la narración con voz. Configurar en docker-compose.yml:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
ALLTALK_URL: http://alltalk:7851
|
||||
```
|
||||
|
||||
## 📊 Estructura de Archivos Generados
|
||||
|
||||
```
|
||||
data/
|
||||
videos/
|
||||
<video_id>/
|
||||
script.txt # Libreto completo del video
|
||||
audio.wav # Audio generado con TTS
|
||||
subtitles.srt # Subtítulos (si enabled)
|
||||
metadata.json # Metadata del video
|
||||
```
|
||||
|
||||
## 🔄 Workflow de Generación
|
||||
|
||||
1. **Consulta de Noticias**: Filtra noticias según criterios de la parrilla
|
||||
2. **Construcción de Script**: Genera libreto narrativo
|
||||
3. **Síntesis de Voz**: Envía texto a AllTalk TTS
|
||||
4. **Generación de Subtítulos**: Crea archivo SRT con timestamps
|
||||
5. **Registro en BD**: Guarda paths y metadata en `video_generados`
|
||||
6. **Relación de Noticias**: Vincula noticias incluidas en `video_noticias`
|
||||
|
||||
## 🎨 Próximas Mejoras
|
||||
|
||||
- [ ] Integración con generador de videos (combinar audio + imágenes)
|
||||
- [ ] Templates visuales personalizados
|
||||
- [ ] Transiciones entre noticias
|
||||
- [ ] Música de fondo
|
||||
- [ ] Logo/branding personalizado
|
||||
- [ ] Exportación directa a YouTube/TikTok
|
||||
- [ ] Programación automática con cron
|
||||
- [ ] Dashboard de analíticas de videos
|
||||
- [ ] Sistema de thumbnails automáticos
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Error: "No hay noticias disponibles"
|
||||
- Verificar que existan noticias traducidas (`traducciones.status = 'done'`)
|
||||
- Ajustar filtros de la parrilla
|
||||
- Verificar rango de fechas (por defecto últimas 24h)
|
||||
|
||||
### Error en AllTalk TTS
|
||||
- Verificar que el servicio AllTalk esté corriendo
|
||||
- Revisar URL en variable de entorno `ALLTALK_URL`
|
||||
- Comprobar logs: `docker-compose logs alltalk`
|
||||
|
||||
### Video no se genera
|
||||
- Revisar estado en tabla `video_generados`
|
||||
- Ver columna `error_message` si `status = 'error'`
|
||||
- Verificar permisos en directorio `/app/data/videos`
|
||||
|
||||
## 📞 Soporte
|
||||
|
||||
Para problemas o sugerencias, revisar los logs:
|
||||
|
||||
```bash
|
||||
# Logs del generador
|
||||
docker-compose exec web python generar_videos_noticias.py <id> 2>&1 | tee video_generation.log
|
||||
|
||||
# Ver videos en cola
|
||||
docker-compose exec -T db psql -U rss -d rss -c "
|
||||
SELECT id, parrilla_id, titulo, status, fecha_generacion
|
||||
FROM video_generados
|
||||
ORDER BY fecha_generacion DESC LIMIT 10;
|
||||
"
|
||||
```
|
||||
|
||||
## 📄 Licencia
|
||||
|
||||
Este módulo es parte del sistema RSS2 News Aggregator.
|
||||
426
docs/PROCESO_COMPLETO_FEEDS.md
Normal file
426
docs/PROCESO_COMPLETO_FEEDS.md
Normal file
|
|
@ -0,0 +1,426 @@
|
|||
# 📖 PROCESO COMPLETO: Descubrimiento y Gestión de Feeds RSS
|
||||
|
||||
## 🎯 Problema Resuelto
|
||||
|
||||
**Pregunta:** ¿Cómo asigno país y categoría a los feeds descubiertos automáticamente?
|
||||
|
||||
**Respuesta:** El sistema ahora usa un flujo inteligente de 3 niveles:
|
||||
|
||||
1. **Auto-aprobación** (feeds con categoría/país)
|
||||
2. **Revisión manual** (feeds sin metadata completa)
|
||||
3. **Análisis automático** (sugerencias inteligentes)
|
||||
|
||||
---
|
||||
|
||||
## 🔄 FLUJO COMPLETO DEL SISTEMA
|
||||
|
||||
### Paso 1: Añadir URL Fuente
|
||||
|
||||
Tienes 2 opciones para añadir URLs:
|
||||
|
||||
#### Opción A: Con Categoría y País (AUTO-APROBACIÓN)
|
||||
```sql
|
||||
INSERT INTO fuentes_url (nombre, url, categoria_id, pais_id, idioma, active)
|
||||
VALUES ('El País', 'https://elpais.com', 1, 44, 'es', TRUE);
|
||||
-- ^ ^
|
||||
-- categoria_id pais_id
|
||||
```
|
||||
|
||||
✅ **Resultado**: Feeds se crean **AUTOMÁTICAMENTE** y se activan
|
||||
- Worker descubre feeds
|
||||
- Hereda categoría (1) y país (44) del padre
|
||||
- Crea feeds en tabla `feeds` directam ente
|
||||
- Ingestor empieza a descargar noticias
|
||||
|
||||
#### Opción B: Sin Categoría o País (REQUIERE REVISIÓN)
|
||||
```sql
|
||||
INSERT INTO fuentes_url (nombre, url, active)
|
||||
VALUES ('BBC News', 'https://www.bbc.com/news', TRUE);
|
||||
-- Sin categoria_id ni pais_id
|
||||
```
|
||||
|
||||
⚠️ **Resultado**: Feeds van a **REVISIÓN MANUAL**
|
||||
- Worker descubre feeds
|
||||
- Analiza automáticamente:
|
||||
- Detecta país desde dominio (.com → Reino Unido)
|
||||
- Detecta idioma (en)
|
||||
- Sugiere categoría ("Internacional")
|
||||
- Crea feeds en tabla `feeds_pending`
|
||||
- **ESPERA APROBACIÓN MANUAL** antes de activar
|
||||
|
||||
---
|
||||
|
||||
### Paso 2: Worker Descubre Feeds (cada 15 min)
|
||||
|
||||
El worker `url_discovery_worker` ejecuta automaticamente:
|
||||
|
||||
```
|
||||
1. Lee fuentes_url activas
|
||||
2. Para cada URL:
|
||||
a. Descubre todos los feeds RSS
|
||||
b. Valida cada feed
|
||||
c. Analiza metadata:
|
||||
- Idioma del feed
|
||||
- País (desde dominio: .es, .uk, .fr, etc.)
|
||||
- Categoría sugerida (keywords en título/descripción)
|
||||
|
||||
d. DECIDE EL FLUJO:
|
||||
|
||||
┌─────────────────────────────────────┐
|
||||
│ ¿Parent tiene categoria_id Y pais_id? │
|
||||
└──────────┬──────────────────────────┘
|
||||
│
|
||||
┌────────┴────────┐
|
||||
│ SÍ │ NO
|
||||
▼ ▼
|
||||
┌──────────────┐ ┌─────────────────┐
|
||||
│ AUTO-APROBAR │ │ REQUIERE REVISIÓN│
|
||||
└───────┬──────┘ └─────────┬───────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
tabla: feeds tabla: feeds_pending
|
||||
activo: TRUE reviewed: FALSE
|
||||
✅ Listo para ⏳ Espera aprobación
|
||||
ingestor
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Paso 3A: Feeds AUTO-APROBADOS
|
||||
|
||||
Si la URL padre tiene `categoria_id` y `pais_id`:
|
||||
|
||||
```sql
|
||||
-- Ejemplo: URL con metadata completa
|
||||
fuentes_url:
|
||||
id=1, url='https://elpais.com',
|
||||
categoria_id=1 (Noticias),
|
||||
pais_id=44 (España)
|
||||
|
||||
↓ Worker descubre 3 feeds:
|
||||
- https://elpais.com/rss/portada.xml
|
||||
- https://elpais.com/rss/internacional.xml
|
||||
- https://elpais.com/rss/deportes.xml
|
||||
|
||||
↓ Se crean DIRECTAMENTE en tabla feeds:
|
||||
INSERT INTO feeds (nombre, url, categoria_id, pais_id, activo)
|
||||
VALUES
|
||||
('El País - Portada', 'https://elpais.com/rss/portada.xml', 1, 44, TRUE),
|
||||
('El País - Internacional', 'https://elpais.com/rss/internacional.xml', 1, 44, TRUE),
|
||||
('El País - Deportes', 'https://elpais.com/rss/deportes.xml', 1, 44, TRUE);
|
||||
|
||||
✅ Feeds están ACTIVOS inmediatamente
|
||||
✅ Ingestor Go los procesa en siguiente ciclo (15 min)
|
||||
✅ Noticias empiezan a llegar
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Paso 3B: Feeds PENDIENTES (requieren revisión)
|
||||
|
||||
Si la URL padre NO tiene `categoria_id` o `pais_id`:
|
||||
|
||||
```sql
|
||||
-- Ejemplo: URL sin metadata
|
||||
fuentes_url:
|
||||
id=2, url='https://www.bbc.com/news',
|
||||
categoria_id=NULL,
|
||||
pais_id=NULL
|
||||
|
||||
↓ Worker descubre 2 feeds y ANALIZA automáticamente:
|
||||
|
||||
Feed 1: https://www.bbc.com/news/world/rss.xml
|
||||
- Título: "BBC News - World"
|
||||
- Idioma detectado: 'en'
|
||||
- País detectado: 'Reino Unido' (desde .com + idioma inglés)
|
||||
- Categoría sugerida: 'Internacional' (keyword "world")
|
||||
|
||||
Feed 2: https://www.bbc.com/sport/rss.xml
|
||||
- Título: "BBC Sport"
|
||||
- Idioma detectado: 'en'
|
||||
- País detectado: 'Reino Unido'
|
||||
- Categoría sugerida: 'Deportes' (keyword "sport")
|
||||
|
||||
↓ Se crean en tabla feeds_pending:
|
||||
INSERT INTO feeds_pending (
|
||||
fuente_url_id, feed_url, feed_title,
|
||||
feed_language, detected_country_id, suggested_categoria_id,
|
||||
reviewed, approved, notes
|
||||
) VALUES (
|
||||
2,
|
||||
'https://www.bbc.com/news/world/rss.xml',
|
||||
'BBC News - World',
|
||||
'en',
|
||||
74, -- Reino Unido (ID detectado)
|
||||
2, -- Internacional (ID sugerido)
|
||||
FALSE, FALSE,
|
||||
'Country from domain: Reino Un ido | Suggested category: Internacional (confidence: 85%)'
|
||||
);
|
||||
|
||||
⏳ Feeds están PENDIENTES
|
||||
⏳ NO están activos aún
|
||||
⏳ Requieren revisión manual en /feeds/pending
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Tabla Comparativa
|
||||
|
||||
| Aspecto | Auto-Aprobación | Revisión Manual |
|
||||
|---------|----------------|-----------------|
|
||||
| **Requisito** | URL padre con `categoria_id` Y `pais_id` | URL padre sin uno o ambos |
|
||||
| **Tabla destino** | `feeds` (directa) | `feeds_pending` (temporal) |
|
||||
| **Estado inicial** | `activo = TRUE` | `reviewed = FALSE, approved = FALSE` |
|
||||
| **Análisis automático** | Hereda valores del padre | Detecta país, sugiere categoría |
|
||||
| **Intervención manual** | ❌ No necesaria | ✅ Requerida |
|
||||
| **Tiempo hasta activación** | Inmediato | Después de aprobación |
|
||||
| **Ingestor procesa** | Sí (próximo ciclo) | No (hasta aprobar) |
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Interfaces de Gestión
|
||||
|
||||
### 1. Añadir URL con Metadata (Auto-aprobación)
|
||||
|
||||
**Ruta:** `/urls/add_source`
|
||||
|
||||
```
|
||||
Formulario:
|
||||
┌─────────────────────────────────────┐
|
||||
│ Nombre: El País │
|
||||
│ URL: https://elpais.com │
|
||||
│ Categoría: [Noticias ▼] ← IMPORTANTE
|
||||
│ País: [España ▼] ← IMPORTANTE
|
||||
│ Idioma: es │
|
||||
│ │
|
||||
│ [Añadir Fuente] │
|
||||
└─────────────────────────────────────┘
|
||||
|
||||
Resultado: Feeds se crearán AUTOMÁTICAMENTE
|
||||
```
|
||||
|
||||
### 2. Revisar Feeds Pendientes (Nueva interfaz)
|
||||
|
||||
**Ruta:** `/feeds/pending` (próximamente)
|
||||
|
||||
```
|
||||
Feeds Pendientes de Revisión
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
Feed: BBC News - World
|
||||
URL: https://www.bbc.com/news/world/rss.xml
|
||||
Fuente: BBC News (https://www.bbc.com/news)
|
||||
|
||||
Análisis Automático:
|
||||
├─ Idioma: English (en)
|
||||
├─ País detectado: Reino Unido (.com domain + language)
|
||||
└─ Categoría sugerida: Internacional (85% confianza)
|
||||
Keywords: "world", "international", "global"
|
||||
|
||||
┌─────────────────────────────────────┐
|
||||
│ Categoría: [Internacional ▼] │ ← Pre-seleccionada
|
||||
│ País: [Reino Unido ▼] │ ← Pre-seleccionado
|
||||
│ Idioma: [en] │ ← Auto-detectado
|
||||
│ │
|
||||
│ [✓ Aprobar Feed] [✗ Rechazar] │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3. Descubrir Feeds Manualmente
|
||||
|
||||
**Ruta:** `/feeds/discover`
|
||||
|
||||
```
|
||||
Perfecto para cuando quieres control total:
|
||||
1. Ingresar URL
|
||||
2. Ver todos los feeds encontrados
|
||||
3. Seleccionar cuáles añadir
|
||||
4. Asignar categoría/país globalmente
|
||||
5. Feeds se crean directamente (no van a pending)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 RECOMENDACIONES DE USO
|
||||
|
||||
### Estrategia 1: Auto-aprobación Total
|
||||
**Para fuentes conocidas y confiables:**
|
||||
|
||||
```sql
|
||||
-- Añadir fuentes con metadata completa
|
||||
INSERT INTO fuentes_url (nombre, url, categoria_id, pais_id, idioma) VALUES
|
||||
('El País', 'https://elpais.com', 1, 44, 'es'),
|
||||
('Le Monde', 'https://lemonde.fr', 1, 60, 'fr'),
|
||||
('The Guardian', 'https://theguardian.com', 1, 74, 'en');
|
||||
|
||||
-- Worker creará feeds automáticamente
|
||||
-- Sin intervención manual necesaria
|
||||
```
|
||||
|
||||
### Estrategia 2: Revisión Manual
|
||||
**Para fuentes nuevas o desconocidas:**
|
||||
|
||||
```sql
|
||||
-- Añadir sin metadata
|
||||
INSERT INTO fuentes_url (nombre, url) VALUES
|
||||
('Sitio Desconocido', 'https://ejemplo.com');
|
||||
|
||||
-- Worker crea feeds en feeds_pending
|
||||
-- Revisar en /feeds/pending
|
||||
-- Aprobar/rechazar manualmente
|
||||
```
|
||||
|
||||
### Estrategia 3: Híbrida (Recomendada)
|
||||
**Combinar ambas:**
|
||||
|
||||
- URLs conocidas → Con categoría/país
|
||||
- URLs nuevas → Sin metadata (revisión)
|
||||
- Usar análisis automático como guía
|
||||
- Ajustar manualmente si es necesario
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Análisis Automático Explicado
|
||||
|
||||
### Detección de País
|
||||
|
||||
```python
|
||||
# 1. Desde dominio (TLD)
|
||||
.es → España
|
||||
.uk, .co.uk → Reino Unido
|
||||
.fr → Francia
|
||||
.de → Alemania
|
||||
.mx → México
|
||||
.ar → Argentina
|
||||
|
||||
# 2. Desde idioma (si no hay dominio claro)
|
||||
es → España (país principal)
|
||||
en → Reino Unido
|
||||
fr → Francia
|
||||
pt → Portugal
|
||||
|
||||
# 3. Desde subdominios
|
||||
es.example.com → España
|
||||
uk.example.com → Reino Unido
|
||||
```
|
||||
|
||||
### Sugerencia de Categoría
|
||||
|
||||
```python
|
||||
# Análisis de keywords en título + descripción
|
||||
|
||||
Keywords encontrados → Categoría sugerida (% confianza)
|
||||
|
||||
"política", "gobierno", "elecciones" → Política (75%)
|
||||
"economía", "bolsa", "mercado" → Economía (82%)
|
||||
"tecnología", "software", "digital" → Tecnología (90%)
|
||||
"deportes", "fútbol", "liga" → Deportes (95%)
|
||||
"internacional", "mundo", "global" → Internacional (70%)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Ejemplos Completos
|
||||
|
||||
### Ejemplo 1: Periódico Español (Auto-aprobación)
|
||||
|
||||
```sql
|
||||
-- 1. Añadir fuente con metadata
|
||||
INSERT INTO fuentes_url (nombre, url, categoria_id, pais_id, idioma)
|
||||
VALUES ('El Mundo', 'https://elmundo.es', 1, 44, 'es');
|
||||
|
||||
-- 2. Worker ejecuta (15 min después):
|
||||
-- - Descubre: elmundo.es/rss/portada.xml
|
||||
-- - Descubre: elmundo.es/rss/deportes.xml
|
||||
-- - Hereda: categoria_id=1, pais_id=44
|
||||
-- - Crea en feeds directamente
|
||||
|
||||
-- 3. Resultado en tabla feeds:
|
||||
SELECT id, nombre, url, categoria_id, pais_id, activo
|
||||
FROM feeds
|
||||
WHERE fuente_nombre LIKE '%El Mundo%';
|
||||
|
||||
-- id | nombre | url | cat | pais | activo
|
||||
-- 1 | El Mundo - Portada | elmundo.es/rss/portada.xml | 1 | 44 | TRUE
|
||||
-- 2 | El Mundo - Deportes | elmundo.es/rss/deportes.xml | 1 | 44 | TRUE
|
||||
|
||||
-- ✅ Feeds activos, ingestor procesando
|
||||
```
|
||||
|
||||
### Ejemplo 2: Sitio Internacional (Revisión Manual)
|
||||
|
||||
```sql
|
||||
-- 1. Añadir fuente SIN metadata
|
||||
INSERT INTO fuentes_url (nombre, url)
|
||||
VALUES ('Reuters', 'https://www.reuters.com');
|
||||
|
||||
-- 2. Worker ejecuta (15 min después):
|
||||
-- - Descubre: reuters.com/rssfeed/worldNews
|
||||
-- - Analiza: idioma=en, país=Reino Unido (dominio+idioma)
|
||||
-- - Sugiere: categoría=Internacional (keyword "world")
|
||||
-- - Crea en feeds_pending
|
||||
|
||||
-- 3. Resultado en tabla feeds_pending:
|
||||
SELECT feed_title, detected_country_id, suggested_categoria_id, notes
|
||||
FROM feeds_pending
|
||||
WHERE fuente_url_id = 3;
|
||||
|
||||
-- feed_title | detected_country_id | suggested_cat | notes
|
||||
-- Reuters World News | 74 (Reino Unido) | 2 (Int.) | "Country from domain..."
|
||||
|
||||
-- ⏳ Requiere aprobación en /feeds/pending
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ CHECKLIST: Añadir Nueva Fuente
|
||||
|
||||
**Para auto-aprobación (recomendado si sabes país/categoría):**
|
||||
|
||||
- [ ] Ir a `/urls/add_source`
|
||||
- [ ] Ingresar nombre descriptivo
|
||||
- [ ] Ingresar URL del sitio (NO del feed RSS)
|
||||
- [ ] **IMPORTANTE:** Seleccionar categoría
|
||||
- [ ] **IMPORTANTE:** Seleccionar país
|
||||
- [ ] Ingresar idioma (opcional, se detecta)
|
||||
- [ ] Guardar
|
||||
- [ ] Esperar 15 minutos (máximo)
|
||||
- [ ] Ver feeds en `/feeds/` (activos automáticamente)
|
||||
|
||||
**Para revisión manual (si no estás seguro):**
|
||||
|
||||
- [ ] Ir a `/urls/add_source`
|
||||
- [ ] Ingresar nombre y URL
|
||||
- [ ] Dejar categoría/país vacíos
|
||||
- [ ] Guardar
|
||||
- [ ] Esperar 15 minutos
|
||||
- [ ] Ir a `/feeds/pending`
|
||||
- [ ] Revisar sugerencias automáticas
|
||||
- [ ] Ajustar categoría/país si necesario
|
||||
- [ ] Aprobar feeds
|
||||
- [ ] Feeds se activan inmediatamente
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Resumen Ejecutivo
|
||||
|
||||
**3 Niveles de Automatización:**
|
||||
|
||||
| Nivel | Descripción | Cuándo Usar |
|
||||
|-------|-------------|-------------|
|
||||
| **Nivel 1: Totalmente Manual** | Descubrir en `/feeds/discover` | Control total, pocas URLs |
|
||||
| **Nivel 2: Auto-aprobación** | URL con cat/país → feeds activos | URLs confiables, muchas fuentes |
|
||||
| **Nivel 3: Revisión Asistida** | URL sin cat/país → análisis → aprobar | URLs nuevas, verificación |
|
||||
|
||||
**Flujo Recomendado:**
|
||||
1. Añade URL con categoría/país si la conoces
|
||||
2. Si no, déjalo vacío y revisa sugerencias automáticas
|
||||
3. Worker descubre y analiza todo automáticamente
|
||||
4. Tú solo apruebas/ajustas lo necesario
|
||||
|
||||
**Resultado:** Gestión eficiente de cientos de fuentes RSS con mínima intervención manual.
|
||||
|
||||
---
|
||||
|
||||
**📅 Fecha de última actualización:** 2026-01-07
|
||||
**📌 Versión del sistema:** 2.0 - Análisis Inteligente de Feeds
|
||||
Loading…
Add table
Add a link
Reference in a new issue