código completo FLUJOS — snapshot limpio sin datos scrapeados
Incluye: backend Node.js/Express, visualización 3D (Three.js/3d-force-graph), scrapers Wikipedia/noticias/imágenes, analizador Qwen3-VL, pipeline maestro con systemd timer, fixes de seguridad (NoSQL injection, XSS, ReDoS, port binding) y documentación técnica completa en docs/. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
013fe673f3
commit
83f67b76b4
190 changed files with 193337 additions and 2 deletions
271
docs/SCRAPER_IMAGENES_QWEN.md
Normal file
271
docs/SCRAPER_IMAGENES_QWEN.md
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
# Scraper de Imágenes + Analizador Qwen3-VL — Contexto técnico FLUJOS
|
||||
**Fecha:** 2026-04-21
|
||||
**Directorio:** `FLUJOS_DATOS/IMAGENES/`
|
||||
**Entorno:** `FLUJOS_DATOS/myenv/` (Python 3.11, venv)
|
||||
|
||||
---
|
||||
|
||||
## Componentes del módulo
|
||||
|
||||
```
|
||||
FLUJOS_DATOS/IMAGENES/
|
||||
├── wikipedia_image_scraper.py # Descarga imágenes de Wikipedia por tema
|
||||
├── image_analyzer.py # Analiza imágenes con Qwen3-VL-8B
|
||||
├── image_comparator.py # Compara imágenes (similaridad visual)
|
||||
├── mongo_helper.py # Utilidades MongoDB para este módulo
|
||||
├── pipeline_imagenes.py # Orquestador del módulo (flags CLI)
|
||||
├── requirements_imagenes.txt # Dependencias del módulo
|
||||
├── model_cache/ # Modelo Qwen descargado (~16 GB) — en .gitignore
|
||||
└── output/
|
||||
└── wiki_images/ # Imágenes descargadas — en .gitignore
|
||||
├── cambio_climático/
|
||||
├── geopolítica_conflictos/
|
||||
├── seguridad_internacional_espionaje/
|
||||
└── ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Parte 1: wikipedia_image_scraper.py
|
||||
|
||||
### Qué hace
|
||||
|
||||
Descarga imágenes de Wikipedia por tema usando la **Wikimedia REST API**. Para cada tema de FLUJOS busca artículos relacionados, extrae las imágenes de cada artículo y las descarga filtrando iconos/logos pequeños.
|
||||
|
||||
### Temas de FLUJOS que se scrapean (`TEMAS_FLUJOS`)
|
||||
|
||||
```python
|
||||
TEMAS_FLUJOS = [
|
||||
"cambio climático",
|
||||
"geopolítica conflictos",
|
||||
"seguridad internacional espionaje",
|
||||
"libertad de prensa periodismo",
|
||||
"corporaciones poder económico",
|
||||
"populismo extremismo",
|
||||
"desinformación redes sociales",
|
||||
"privacidad vigilancia masiva",
|
||||
"biodiversidad medioambiente",
|
||||
"inteligencia artificial tecnología",
|
||||
]
|
||||
```
|
||||
|
||||
### Filtros de calidad (imágenes que se descartan)
|
||||
|
||||
```python
|
||||
MIN_WIDTH = 200 # pixels
|
||||
MIN_HEIGHT = 200 # pixels
|
||||
MIN_BYTES = 20_000 # 20 KB mínimo
|
||||
|
||||
SKIP_PATTERNS = [
|
||||
"flag_", "Flag_", "icon", "Icon", "logo", "Logo",
|
||||
"symbol", "Symbol", "coat_of_arms", "commons-logo",
|
||||
"wiki", "Wiki", "question_mark", "edit-", "nuvola",
|
||||
"Nuvola", "pictogram", "OOjs", "Ambox", "Portal-", "Disambig",
|
||||
]
|
||||
|
||||
VALID_EXTENSIONS = {".jpg", ".jpeg", ".png", ".webp"}
|
||||
```
|
||||
|
||||
### Flujo interno
|
||||
|
||||
```
|
||||
buscar_articulos(tema, lang='es')
|
||||
└── GET https://es.wikipedia.org/w/api.php?action=query&list=search&srsearch={tema}
|
||||
└── para cada artículo:
|
||||
get_article_images(titulo)
|
||||
└── GET https://es.wikipedia.org/w/api.php?action=query&prop=images
|
||||
└── para cada imagen:
|
||||
get_image_info(filename) → Wikimedia API
|
||||
└── descarga si pasa filtros
|
||||
└── guarda en output/wiki_images/{tema_slug}/
|
||||
└── upsert en MongoDB imagenes_wiki
|
||||
```
|
||||
|
||||
### Deduplicación
|
||||
|
||||
Upsert por `archivo` (nombre del fichero) en MongoDB `imagenes_wiki`. Si el fichero ya existe en disco, se salta la descarga.
|
||||
|
||||
### Uso CLI
|
||||
|
||||
```bash
|
||||
# Scrape de todos los temas FLUJOS, max 20 imgs/tema, con MongoDB
|
||||
python wikipedia_image_scraper.py --flujos --max 20 --mongo
|
||||
|
||||
# Scrape de un tema concreto
|
||||
python wikipedia_image_scraper.py --tema "cambio climático" --max 30 --mongo
|
||||
|
||||
# Con idioma inglés
|
||||
python wikipedia_image_scraper.py --tema "climate change" --lang en --max 40
|
||||
```
|
||||
|
||||
### Documento MongoDB generado (colección `imagenes_wiki`)
|
||||
|
||||
```json
|
||||
{
|
||||
"archivo": "cambio_climático_003.jpg",
|
||||
"image_path": "/var/www/theflows.net/flujos/FLUJOS_DATOS/IMAGENES/output/wiki_images/cambio_climático/cambio_climático_003.jpg",
|
||||
"image_url": "https://upload.wikimedia.org/wikipedia/commons/...",
|
||||
"tema": "cambio climático",
|
||||
"subtema": "derretimiento glaciar ártico",
|
||||
"descripcion_wiki": "Glaciar en retroceso en el Ártico, 2019",
|
||||
"articulo_titulo": "Cambio climático en el Ártico",
|
||||
"fecha": ISODate("2026-04-21")
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Parte 2: image_analyzer.py (Qwen3-VL-8B)
|
||||
|
||||
### Modelo usado
|
||||
|
||||
**Qwen/Qwen2.5-VL-7B-Instruct** (HuggingFace)
|
||||
- Tamaño: ~16 GB en disco (bfloat16)
|
||||
- Inferencia: CPU (sin GPU disponible actualmente)
|
||||
- RAM necesaria: ~16–18 GB para el modelo + ~2 GB por batch de 4 imágenes
|
||||
- Cache local: `IMAGENES/model_cache/`
|
||||
|
||||
> El servidor tiene 64 GB RAM, por lo que cabe sin problema. En GPU (A100/RTX 3090+) sería 10–50x más rápido.
|
||||
|
||||
### Carga del modelo
|
||||
|
||||
```python
|
||||
from transformers import Qwen2_5_VLForConditionalGeneration, AutoProcessor
|
||||
import torch
|
||||
|
||||
model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
|
||||
"Qwen/Qwen2.5-VL-7B-Instruct",
|
||||
torch_dtype=torch.bfloat16, # mitad de RAM vs float32
|
||||
device_map="cpu",
|
||||
cache_dir=str(IMAGENES_DIR / "model_cache"),
|
||||
)
|
||||
processor = AutoProcessor.from_pretrained(
|
||||
"Qwen/Qwen2.5-VL-7B-Instruct",
|
||||
cache_dir=str(IMAGENES_DIR / "model_cache"),
|
||||
)
|
||||
```
|
||||
|
||||
### Prompt de análisis
|
||||
|
||||
```python
|
||||
PROMPT = """Analiza esta imagen y proporciona:
|
||||
1. Una descripción concisa del contenido principal (máx. 2 frases).
|
||||
2. El tema principal (elige uno): cambio climático, conflicto armado, economía, política, tecnología, sociedad, otro.
|
||||
3. Lista de 3-5 palabras clave relevantes.
|
||||
|
||||
Formato de respuesta:
|
||||
DESCRIPCIÓN: [descripción]
|
||||
TEMA: [tema]
|
||||
PALABRAS CLAVE: [kw1, kw2, kw3]"""
|
||||
```
|
||||
|
||||
### Procesamiento por batch
|
||||
|
||||
```python
|
||||
def analyze_batch(image_paths: list[Path]) -> list[dict]:
|
||||
"""Procesa hasta 4 imágenes por llamada al modelo."""
|
||||
```
|
||||
|
||||
`batch_size=4` por defecto. Cada batch ocupa ~2 GB RAM adicionales.
|
||||
|
||||
### Resume automático
|
||||
|
||||
Antes de analizar, verifica qué imágenes ya están en MongoDB `imagenes`:
|
||||
|
||||
```python
|
||||
def get_already_analyzed() -> set[str]:
|
||||
"""Devuelve set de nombres de archivo ya en la colección imagenes."""
|
||||
return {doc['archivo'] for doc in db['imagenes'].find({}, {'archivo': 1})}
|
||||
```
|
||||
|
||||
Solo procesa imágenes no presentes en la BD.
|
||||
|
||||
### Priorización de imágenes
|
||||
|
||||
```python
|
||||
def get_known_article_titles() -> set[str]:
|
||||
"""Títulos de artículos presentes en wikipedia/noticias."""
|
||||
# Prioriza imágenes cuyo tema coincide con artículos existentes
|
||||
```
|
||||
|
||||
Las imágenes de temas con más documentos de texto en la BD se procesan primero, para maximizar la probabilidad de que los nodos imagen queden conectados por comparaciones.
|
||||
|
||||
### Documento MongoDB generado (colección `imagenes`)
|
||||
|
||||
```json
|
||||
{
|
||||
"archivo": "cambio_climático_003.jpg",
|
||||
"image_path": "/var/www/.../output/wiki_images/cambio_climático/cambio_climático_003.jpg",
|
||||
"tema": "cambio climático",
|
||||
"subtema": "calentamiento global",
|
||||
"texto": "Imagen satelital del retroceso del glaciar ártico entre 1990 y 2023. Se observa una reducción significativa de la capa de hielo.",
|
||||
"keywords": ["glaciar", "ártico", "deshielo", "calentamiento", "satélite"],
|
||||
"fecha": ISODate("2026-04-21")
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Parte 3: pipeline_imagenes.py (orquestador)
|
||||
|
||||
### Flags CLI
|
||||
|
||||
```bash
|
||||
python pipeline_imagenes.py --scrape # solo scraping de imágenes
|
||||
python pipeline_imagenes.py --analizar # solo análisis Qwen
|
||||
python pipeline_imagenes.py --mongo # escribe resultados en MongoDB
|
||||
python pipeline_imagenes.py --solo-json # escribe JSON local en vez de Mongo
|
||||
python pipeline_imagenes.py --analizar --carpeta /ruta/custom --mongo
|
||||
```
|
||||
|
||||
### Integración en el pipeline maestro
|
||||
|
||||
El `pipeline_maestro.py` lo llama así:
|
||||
|
||||
**Fase 1 (scraping):**
|
||||
```bash
|
||||
python wikipedia_image_scraper.py --flujos --max 20 --mongo
|
||||
```
|
||||
|
||||
**Fase 2 (análisis):**
|
||||
```bash
|
||||
python pipeline_imagenes.py --analizar \
|
||||
--carpeta FLUJOS_DATOS/IMAGENES/output/wiki_images \
|
||||
--mongo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dependencias Python (requirements_imagenes.txt)
|
||||
|
||||
```
|
||||
transformers>=4.45
|
||||
torch>=2.1
|
||||
qwen-vl-utils
|
||||
Pillow
|
||||
requests
|
||||
pymongo
|
||||
scikit-learn
|
||||
python-dotenv
|
||||
```
|
||||
|
||||
Instalación en el venv:
|
||||
```bash
|
||||
/var/www/theflows.net/flujos/FLUJOS_DATOS/myenv/bin/python3 -m pip install -r requirements_imagenes.txt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Estado actual (2026-04-21)
|
||||
|
||||
- Imágenes en disco: ~155 imágenes en `output/wiki_images/` (10 temas × ~15 imgs)
|
||||
- Imágenes en `imagenes_wiki` (MongoDB): ~150 docs
|
||||
- Imágenes analizadas con Qwen en `imagenes` (MongoDB): proceso en curso / pendiente de primera ejecución completa
|
||||
- El modelo Qwen se descarga automáticamente la primera vez que se llama (~16 GB, puede tardar 30–60 min)
|
||||
|
||||
## Pendiente / mejoras futuras
|
||||
|
||||
- Conectar nodos imagen a la colección `comparaciones` (requiere embeddings de imagen o comparación texto-descripción)
|
||||
- Activar GPU cuando esté disponible (cambiar `device_map="cpu"` → `"cuda"`)
|
||||
- Aumentar `--max` a 50+ imágenes por tema una vez el análisis esté validado
|
||||
- Añadir soporte para imágenes de noticias (no solo Wikipedia)
|
||||
Loading…
Add table
Add a link
Reference in a new issue