- Move BACK_BACK/ → POCS/BACK_BACK/ (image pipeline scripts) - Move VISUALIZACION/ → POCS/VISUALIZACION/ (demos + static assets) - No path changes needed: ../VISUALIZACION/public still resolves correctly from POCS/BACK_BACK/FLUJOS_APP_PRUEBAS.js - Add FLUJOS_DATOS/DOCS/extraer_info_bbdd.txt (DB state snapshot + commands) FLUJOS/ and FLUJOS_DATOS/ untouched (production). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
268 lines
11 KiB
Python
268 lines
11 KiB
Python
"""
|
|
pipeline_pruebas.py
|
|
-------------------
|
|
Pipeline de prueba end-to-end para análisis de imágenes.
|
|
|
|
Flujo:
|
|
1. Carga imágenes desde una carpeta (por defecto: las imágenes del proyecto)
|
|
2. Analiza cada imagen con el VLM via ollama → keywords + metadata
|
|
3. Guarda resultados en JSON local (output/)
|
|
4. Compara keywords de imágenes con documentos de texto (noticias/wiki/torrents)
|
|
- Si MongoDB disponible: lee corpus real
|
|
- Si no: usa corpus de prueba hardcodeado
|
|
5. Guarda comparaciones en JSON local
|
|
6. Opcional: sube todo a MongoDB
|
|
|
|
Ejecutar:
|
|
python pipeline_pruebas.py
|
|
python pipeline_pruebas.py --carpeta /ruta/a/imagenes --modelo qwen2-vl:7b
|
|
python pipeline_pruebas.py --solo-json # sin MongoDB
|
|
python pipeline_pruebas.py --tema "clima" # filtra corpus por tema
|
|
|
|
Requisitos previos:
|
|
pip install -r requirements_imagenes.txt
|
|
ollama pull qwen2-vl:7b (o el modelo que prefieras)
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import sys
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
# Añadir el directorio padre al path para importar desde BACK_BACK
|
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
|
|
from image_analyzer import ImageAnalyzer
|
|
from image_comparator import ImageComparator
|
|
from mongo_helper import MongoHelper
|
|
|
|
# ── Configuración por defecto ──────────────────────────────────────────────────
|
|
|
|
DEFAULT_IMAGES_FOLDER = str(
|
|
Path(__file__).parent.parent.parent / "VISUALIZACION" / "public" / "images"
|
|
)
|
|
DEFAULT_MODEL = os.getenv("VISION_MODEL", "qwen2-vl:7b")
|
|
OUTPUT_DIR = Path(__file__).parent / "output"
|
|
|
|
# ── Corpus de prueba (cuando no hay MongoDB) ───────────────────────────────────
|
|
|
|
CORPUS_PRUEBA = [
|
|
{
|
|
"archivo": "noticia_clima_001.txt",
|
|
"tema": "cambio climático",
|
|
"subtema": "emisiones co2",
|
|
"texto": "Las emisiones de dióxido de carbono alcanzan niveles récord. Los países industrializados deben reducir su huella de carbono para frenar el calentamiento global. La crisis climática afecta a millones de personas.",
|
|
"source_type": "noticias",
|
|
},
|
|
{
|
|
"archivo": "wiki_energia_renovable.txt",
|
|
"tema": "energía renovable",
|
|
"subtema": "energía solar",
|
|
"texto": "La energía solar fotovoltaica ha experimentado un crecimiento exponencial. Los paneles solares reducen la dependencia de combustibles fósiles y disminuyen las emisiones de gases de efecto invernadero.",
|
|
"source_type": "wikipedia",
|
|
},
|
|
{
|
|
"archivo": "noticia_tecnologia_001.txt",
|
|
"tema": "tecnología",
|
|
"subtema": "inteligencia artificial",
|
|
"texto": "Los modelos de lenguaje de gran tamaño están transformando la industria tecnológica. Empresas como Google, Meta y OpenAI compiten por el liderazgo en inteligencia artificial generativa.",
|
|
"source_type": "noticias",
|
|
},
|
|
{
|
|
"archivo": "wiki_desinformacion.txt",
|
|
"tema": "desinformación",
|
|
"subtema": "redes sociales",
|
|
"texto": "La desinformación en redes sociales representa una amenaza para la democracia. Las fake news se propagan más rápido que las noticias verificadas. Los algoritmos de plataformas como Twitter y Facebook amplifican contenido polarizante.",
|
|
"source_type": "wikipedia",
|
|
},
|
|
{
|
|
"archivo": "noticia_geopolitica_001.txt",
|
|
"tema": "geopolítica",
|
|
"subtema": "conflictos internacionales",
|
|
"texto": "Las tensiones geopolíticas entre potencias mundiales aumentan la incertidumbre global. Los conflictos armados desplazan millones de personas y generan crisis humanitarias sin precedentes.",
|
|
"source_type": "noticias",
|
|
},
|
|
{
|
|
"archivo": "wiki_privacidad_datos.txt",
|
|
"tema": "privacidad",
|
|
"subtema": "datos personales",
|
|
"texto": "La privacidad de los datos personales es un derecho fundamental en la era digital. El RGPD europeo establece normas estrictas sobre el tratamiento de datos. La vigilancia masiva por parte de gobiernos y corporaciones amenaza las libertades individuales.",
|
|
"source_type": "wikipedia",
|
|
},
|
|
{
|
|
"archivo": "torrent_documental_medioambiente.txt",
|
|
"tema": "medioambiente",
|
|
"subtema": "biodiversidad",
|
|
"texto": "Documental sobre la pérdida de biodiversidad y el impacto de la actividad humana en los ecosistemas. La deforestación, la contaminación y el cambio climático amenazan la supervivencia de miles de especies.",
|
|
"source_type": "torrents",
|
|
},
|
|
{
|
|
"archivo": "noticia_corporaciones_001.txt",
|
|
"tema": "corporaciones",
|
|
"subtema": "paraísos fiscales",
|
|
"texto": "Las grandes corporaciones utilizan paraísos fiscales para eludir el pago de impuestos. El lobbying corporativo influye decisivamente en las políticas gubernamentales. La concentración de poder económico en pocas empresas amenaza la competencia.",
|
|
"source_type": "noticias",
|
|
},
|
|
]
|
|
|
|
|
|
# ── Pipeline principal ─────────────────────────────────────────────────────────
|
|
|
|
def run_pipeline(
|
|
images_folder: str,
|
|
model: str,
|
|
tema_filtro: str,
|
|
solo_json: bool,
|
|
threshold: float,
|
|
contexto: str,
|
|
):
|
|
OUTPUT_DIR.mkdir(exist_ok=True)
|
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
|
|
print("\n" + "="*60)
|
|
print(" FLUJOS — Pipeline de Imágenes (PRUEBAS)")
|
|
print("="*60)
|
|
print(f" Carpeta: {images_folder}")
|
|
print(f" Modelo: {model}")
|
|
print(f" Umbral: {threshold}%")
|
|
print(f" Solo JSON: {solo_json}")
|
|
print("="*60 + "\n")
|
|
|
|
# ── PASO 1: Analizar imágenes ──────────────────────────────────────────────
|
|
print("[ PASO 1 ] Análisis de imágenes con VLM")
|
|
print("-"*40)
|
|
|
|
analyzer = ImageAnalyzer(model=model)
|
|
image_docs = analyzer.analyze_folder(images_folder, extra_context=contexto)
|
|
|
|
if not image_docs:
|
|
print(" ⚠ No se analizaron imágenes. Comprueba que ollama está corriendo.")
|
|
print(f" ollama serve → ollama pull {model}")
|
|
return
|
|
|
|
# Guardar resultados de análisis
|
|
json_imagenes = OUTPUT_DIR / f"imagenes_{timestamp}.json"
|
|
ImageAnalyzer.save_json(image_docs, str(json_imagenes))
|
|
|
|
# ── PASO 2: Cargar corpus de texto para comparar ───────────────────────────
|
|
print("\n[ PASO 2 ] Cargando corpus de texto")
|
|
print("-"*40)
|
|
|
|
mongo = MongoHelper()
|
|
text_docs = []
|
|
|
|
if not solo_json and mongo.is_available():
|
|
print(" MongoDB disponible — cargando corpus real")
|
|
text_docs = mongo.get_all_text_docs(tema=tema_filtro, limit_per_collection=300)
|
|
else:
|
|
if not solo_json:
|
|
print(" ⚠ MongoDB no disponible — usando corpus de prueba hardcodeado")
|
|
else:
|
|
print(" Modo solo-json — usando corpus de prueba hardcodeado")
|
|
text_docs = CORPUS_PRUEBA
|
|
|
|
print(f" Total documentos de texto: {len(text_docs)}")
|
|
|
|
# ── PASO 3: Comparar imágenes vs corpus ───────────────────────────────────
|
|
print("\n[ PASO 3 ] Comparando keywords de imágenes vs corpus")
|
|
print("-"*40)
|
|
|
|
comparador = ImageComparator(threshold=threshold)
|
|
valid_image_docs = [d for d in image_docs if "error" not in d]
|
|
comparaciones = comparador.compare_batch(valid_image_docs, text_docs)
|
|
|
|
stats = comparador.stats(comparaciones)
|
|
print(f" Comparaciones generadas: {stats.get('total', 0)}")
|
|
print(f" Similitud media: {stats.get('media', 0)}%")
|
|
print(f" Similitud máxima: {stats.get('max', 0)}%")
|
|
print(f" Con > 50%: {stats.get('sobre_50', 0)}")
|
|
print(f" Con > 70%: {stats.get('sobre_70', 0)}")
|
|
|
|
# Guardar comparaciones
|
|
json_comparaciones = OUTPUT_DIR / f"comparaciones_{timestamp}.json"
|
|
with open(json_comparaciones, "w", encoding="utf-8") as f:
|
|
json.dump(comparaciones, f, ensure_ascii=False, indent=2)
|
|
print(f"\n Guardado: {json_comparaciones}")
|
|
|
|
# Mostrar top 10
|
|
if comparaciones:
|
|
print("\n Top 10 similitudes:")
|
|
for c in comparador.top_n(comparaciones, 10):
|
|
print(f" {c['porcentaje_similitud']:5.1f}% {c['noticia1']} ↔ {c['noticia2']}")
|
|
|
|
# ── PASO 4: Subir a MongoDB (opcional) ────────────────────────────────────
|
|
if not solo_json and mongo.is_available():
|
|
print("\n[ PASO 4 ] Subiendo a MongoDB")
|
|
print("-"*40)
|
|
|
|
mongo.upsert_imagenes(valid_image_docs)
|
|
mongo.insert_comparaciones(comparaciones)
|
|
mongo.disconnect()
|
|
|
|
print("\n ✓ Datos guardados en MongoDB")
|
|
print(f" Colección 'imagenes': {len(valid_image_docs)} documentos")
|
|
print(f" Colección 'comparaciones': {len(comparaciones)} documentos")
|
|
else:
|
|
print("\n[ PASO 4 ] Skipped (solo-json o MongoDB no disponible)")
|
|
|
|
# ── Resumen final ──────────────────────────────────────────────────────────
|
|
print("\n" + "="*60)
|
|
print(" COMPLETADO")
|
|
print(f" Imágenes analizadas: {len(valid_image_docs)}")
|
|
print(f" Comparaciones: {len(comparaciones)}")
|
|
print(f" Output JSON:")
|
|
print(f" {json_imagenes}")
|
|
print(f" {json_comparaciones}")
|
|
print("="*60 + "\n")
|
|
|
|
|
|
# ── CLI ────────────────────────────────────────────────────────────────────────
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser(
|
|
description="Pipeline de prueba: imágenes → keywords → comparaciones"
|
|
)
|
|
parser.add_argument(
|
|
"--carpeta",
|
|
default=DEFAULT_IMAGES_FOLDER,
|
|
help=f"Carpeta con imágenes (default: {DEFAULT_IMAGES_FOLDER})"
|
|
)
|
|
parser.add_argument(
|
|
"--modelo",
|
|
default=DEFAULT_MODEL,
|
|
help=f"Modelo ollama a usar (default: {DEFAULT_MODEL})"
|
|
)
|
|
parser.add_argument(
|
|
"--tema",
|
|
default=None,
|
|
help="Filtrar corpus MongoDB por tema (ej: 'clima', 'tecnología')"
|
|
)
|
|
parser.add_argument(
|
|
"--umbral",
|
|
type=float,
|
|
default=5.0,
|
|
help="Porcentaje mínimo de similitud para guardar comparación (default: 5.0)"
|
|
)
|
|
parser.add_argument(
|
|
"--contexto",
|
|
default="",
|
|
help="Contexto adicional para el prompt de análisis (ej: 'imágenes de noticias políticas')"
|
|
)
|
|
parser.add_argument(
|
|
"--solo-json",
|
|
action="store_true",
|
|
help="No conectar a MongoDB, solo guardar JSONs locales"
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
run_pipeline(
|
|
images_folder=args.carpeta,
|
|
model=args.modelo,
|
|
tema_filtro=args.tema,
|
|
solo_json=args.solo_json,
|
|
threshold=args.umbral,
|
|
contexto=args.contexto,
|
|
)
|