Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Sistema inteligente de catalogación de libros

Sistema de catalogación de libros (PDF/EPUB) con ingesta automática en Apache NiFi, identificación bibliográfica escalonada (1º se prueba mediante metadatos embebidos, 2º Open Library API y 3º LLM), indexación GraphRAG en Neo4j orquestada con Airflow, y consulta en lenguaje natural desde Claude Desktop vía servidor MCP propio.

Arquitectura del sistema

Resumen

El sistema integra seis tecnologías orquestadas mediante Docker Compose:

  • Apache NiFi 2.4 — ingestión, hash SHA-256, deduplicación y clasificación automática de ficheros (14 procesadores, 4 fases)
  • PostgreSQL 16 — catálogo estructurado (books, files, processing_log)
  • Pipeline de identificación bibliográfica escalonada — regex → metadatos embebidos → ISBN → Open Library API → LLM (Groq)
  • Neo4j 5.26 con índice vectorial — GraphRAG (búsqueda híbrida vector + grafo)
  • Apache Airflow 2.9 — orquestación batch de la indexación GraphRAG
  • Servidor MCP (FastMCP) — 5 herramientas expuestas a Claude Desktop

El resultado es un sistema capaz de llevar libros técnicos desde su formato original hasta ser consultables en lenguaje natural, con trazabilidad completa de cada etapa del proceso.

Arquitectura del sistema

Capa Componente Responsabilidad
Ingesta Apache NiFi 2.4 Detección, hash, deduplicación y clasificación de ficheros
Almacenamiento PostgreSQL 16 Catálogo estructurado: books, files, processing_log
Identificación Scripts Python (1-5) Identificación bibliográfica escalonada
Grafo Neo4j 5.26 Nodos Book/Chunk/Concept/Author/Topic con índice vectorial coseno 768D
Orquestación Apache Airflow 2.9 DAG batch de indexación GraphRAG
Embeddings Ollama + nomic-embed-text Vectorización de chunks (768 dimensiones)
API MCP FastMCP Exposición de 5 herramientas para Claude Desktop
LLM Groq (llama-3.3-70b-versatile) Identificación (último recurso) y extracción de conceptos

Flujo de datos

  1. Fichero depositado en data/input
  2. NiFi calcula SHA-256 y detecta duplicados contra PostgreSQL
  3. Clasificación por extensión: epub/mobi → texto, pdf → análisis OCR, otros → rechazado
  4. Inserción en tabla files con status='pending'
  5. Scripts de identificación ejecutados en orden de coste ascendente
  6. Resultado persistido en books con metadata_src y confidence
  7. Fichero renombrado y movido a data/processed/{inicial}/{autor}/fichero.ext
  8. DAG de Airflow indexa libros pendientes en Neo4j (chunking + embeddings + conceptos)
  9. Servidor MCP expone las 5 herramientas a Claude Desktop

Componentes Docker

Todos los contenedores llevan el sufijo _CL para evitar conflictos con otros contenedores Docker que puedas tener corriendo. Se comunican entre sí usando el container_name como hostname — ya configurado en docker-compose.yml.

Contenedor Imagen Puerto Función
postgres_CL postgres:16-alpine 5432 Base de datos relacional (bookcat + airflow_meta)
nifi_CL apache/nifi (custom) 8443 Ingesta y clasificación de ficheros
neo4j_CL neo4j:5.26-community 7474 / 7687 Grafo de conocimiento con índice vectorial
ollama_CL ollama/ollama 11434 Embeddings locales (nomic-embed-text)
airflow_CL apache/airflow (custom) 8080 Orquestación del DAG de indexación
mcp-server_CL custom FastMCP 3001 Servidor MCP (modo SSE) para pruebas

Arranque rápido

# 1. Levantar todos los servicios
docker compose up -d --build

# 2. Descargar el modelo de embeddings en Ollama (obligatorio)
docker exec ollama_CL ollama pull nomic-embed-text

# 3. Configurar la API key de Groq (identificación LLM + extracción de conceptos)
export GROQ_API_KEY="tu-api-key-de-groq"

# 4. Reiniciar para que los servicios lean la variable
docker compose up -d

# 5. Verificar accesos
#    PostgreSQL:  psql -h localhost -U catalog -d bookcat
#    NiFi:        https://localhost:8443/nifi  (admin / admin1234admin)
#    Neo4j:       http://localhost:7474        (neo4j / neo4j1234)
#    Ollama:      curl http://localhost:11434/api/tags
#    Airflow:     http://localhost:8080        (admin / admin)

Nota sobre el LLM: el diseño original del proyecto pedía usar la API de Claude para identificación y extracción de conceptos. Durante el desarrollo se migró a Groq (llama-3.3-70b-versatile) por su capa gratuita más generosa. docker-compose.yml sigue reservando GEMINI_API_KEY, ANTHROPIC_API_KEY y OPENAI_API_KEY como variables de entorno para una futura extensión multi-proveedor, pero ningún script las usa actualmente — la única variable que el código necesita es GROQ_API_KEY. Sin ella, el sistema sigue funcionando pero sin identificación por LLM ni extracción de conceptos (ambas son el último eslabón de sus respectivos pipelines).

Modelo de datos

PostgreSQL

  • books — id, title, authors, isbn, year, publisher, language, summary, main_topic, subtopics, tags, metadata_src, confidence, graphrag_indexed
  • files — id, book_id, file_hash, file_size, extension, original_name, stored_path, status
  • processing_log — id, file_id, stage, message, result, created_at

Índice único sobre file_hash para deduplicación eficiente.

Neo4j — modelo de grafo

Grafo en Neo4j Browser Grafo en Neo4j Browser

Nodo Propiedades Descripción
Book pg_id, title, authors, isbn, year, publisher Espejo del libro en PostgreSQL
Chunk id, text, position, page, embedding[768] Fragmento de 750 tokens con vector coseno
Concept name, description, domain Entidad extraída por LLM
Author name Autor del libro
Topic name Tema principal

Relaciones: Book -[HAS_CHUNK]-> Chunk, Chunk -[MENTIONS]-> Concept, Book -[WRITTEN_BY]-> Author, Book -[ABOUT]-> Topic/Concept.

Índice vectorial chunk_embeddings (768 dimensiones, similaridad coseno).

Ingesta y pipeline de identificación bibliográfica

Flujo NiFi El flujo de NiFi (docs/NiFi-flow.json) implementa 4 fases: A ingesta y hash, B deduplicación, C clasificación por formato, D registro e identificación.

La identificación bibliográfica se resuelve en cascada, deteniéndose en cuanto la confianza es suficiente:

Script Método Confianza Activación
identify_filename.py Regex sobre nombre del fichero 0.1 – 0.7 Siempre
identify_metadata.py PyPDF2 / ebooklib (metadatos embebidos) 0.5 – 0.8 Si confianza < 0.8
identify_isbn.py Regex ISBN-10/13 con validación de dígito de control 0.9 Siempre (extrae ISBN)
identify_openlibrary.py API Open Library por ISBN o título+autor 0.75 – 0.95 Si hay ISBN o confianza < 0.9
identify_llm.py Groq llama-3.3-70b (fallback) 0.6 – 0.8 Si confianza < 0.5

Organización física resultante: data/processed/{inicial}/{autor_normalizado}/{Autor - Título - Año - Editorial.ext}

GraphRAG con Neo4j y Airflow

DAG de indexación GraphRAG en Airflow

El DAG graphrag_indexing procesa hasta 10 libros pendientes por ejecución (schedule_interval="0 2 * * *"). Para cada libro:

  1. extract_text.py — extrae texto por páginas (PyPDF2 / ebooklib)
  2. chunk_text.py — divide en chunks de 750 tokens con solapamiento de 100
  3. generate_embeddings.py — genera embeddings 768D con nomic-embed-text vía Ollama
  4. insert_neo4j.py — crea nodos Book, Chunk, Author, Topic y relaciones
  5. extract_concepts.py — extrae conceptos con Groq, muestreando cada 5 chunks

Airflow — vista de tareas Airflow — logs de ejecución

Servidor MCP y Claude Desktop

El servidor MCP (scripts/mcp/server.py), implementado con FastMCP, expone 5 herramientas:

Tool Backend Descripción
search_books PostgreSQL ILIKE Búsqueda por texto libre con filtros opcionales (tema, autor, idioma, año)
book_detail PostgreSQL JOIN Ficha completa del libro con ruta física del fichero
ask_content Neo4j vector + grafo Embedding de la pregunta → búsqueda vectorial → traversal de conceptos
find_concepts Neo4j traversal Búsqueda por nombre de concepto con libros y fragmentos asociados
compare_books Neo4j vector filtrado Búsqueda vectorial por libro con similaridad coseno directa

Modos de ejecución: SSE (puerto 3001, Docker) para pruebas y stdio (venv local) para Claude Desktop.

cd scripts/mcp
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
# Copiar config/claude_desktop_config.example.json al directorio de Claude Desktop
# Ajustar rutas y reiniciar Claude Desktop

Demostración de las 5 herramientas conectadas a Claude Desktop:

Demo del servidor MCP en Claude Desktop

Vídeo completo (mejor calidad): docs/Claude_desktop_MCP_test.mp4

Métricas de la ejecución de referencia

Cifras de una ejecución de validación con un catálogo de prueba de 10 libros (no un despliegue en producción):

Métrica Valor
Libros catalogados / ficheros procesados 10 / 10
Identificados vía openlibrary_isbn 7 (70%)
Identificados vía metadatos embebidos 2 (20%)
Identificados vía LLM 1 (10%)
Libros indexados en Neo4j (graphrag_indexed=true) 10 (100%)
Nodos Chunk / Concept / Author en Neo4j 2280 / 557 / 9
Relaciones HAS_CHUNK / MENTIONS / ABOUT 2280 / 686 / 573

Tiempos de respuesta del servidor MCP: search_books y book_detail < 100ms; find_concepts < 500ms; ask_content 1-3s; compare_books 2-5s.

Estado del proyecto y mejoras futuras

Deuda técnica conocida:

  • El campo language se detecta de forma inconsistente para libros en inglés (Open Library no siempre lo devuelve)
  • main_topic y subtopics quedan vacíos cuando no se alcanza el umbral de confianza necesario para invocar al LLM
  • El directorio temporal /tmp/graphrag_N no se limpia automáticamente tras la indexación

Próximos pasos (corto/medio/largo plazo):

  • Migrar identify_llm.py de Groq a la API de Claude (requisito original del proyecto)
  • Reindexación incremental en Neo4j (hoy requiere borrar y reindexar)
  • Autenticación en el servidor MCP para entornos multiusuario
  • Tool list_books y paginación en search_books
  • Chunking con detección de capítulos/secciones para mejorar el linaje de ask_content

Estructura del proyecto

proyecto/
├── docker-compose.yml
├── README.md
├── dockerfiles/
│   ├── nifi/Dockerfile + requirements.txt
│   └── airflow/Dockerfile + requirements.txt
├── sql/init.sql
├── scripts/
│   ├── identify_*.py           # Pipeline de identificación bibliográfica (1-5)
│   ├── move_to_processed.py
│   ├── nifi/                   # Scripts Python invocados desde NiFi
│   ├── graphrag/                # Indexación GraphRAG (Airflow)
│   └── mcp/                     # Servidor MCP (server.py + Dockerfile)
├── airflow/dags/dag_graphrag.py
├── data/                        # input/ pending_ocr/ processed/ rejected/
├── config/                      # claude_desktop_config.example.json
└── docs/                        # diagramas, capturas y demo del MCP

Requisitos de hardware

  • Mínimo: 8 GB RAM, 4 cores, 20 GB disco
  • Recomendado: 16 GB RAM, SSD
  • GPU: no necesaria — el único modelo local (nomic-embed-text para embeddings) va bien en CPU; la identificación/extracción de conceptos usa la API de Groq

Credenciales (entorno local de desarrollo)

Todas las credenciales están fijadas en docker-compose.yml y sql/init.sql para simplificar el arranque en local. No se usan fuera de este entorno de desarrollo.

Servicio Usuario Contraseña
PostgreSQL catalog catalog1234
NiFi admin admin1234admin
Neo4j neo4j neo4j1234
Airflow admin admin

Inicialización de la base de datos

El fichero sql/init.sql se ejecuta automáticamente en el primer arranque de PostgreSQL. La imagen oficial detecta que el volumen pg_data está vacío y ejecuta todos los .sql de /docker-entrypoint-initdb.d/ (donde está montada la carpeta sql/).

En arranques posteriores, PostgreSQL ignora ese directorio. Si modificas init.sql después del primer arranque, tienes dos opciones:

  • Ejecutar los cambios manualmente: psql -h localhost -U catalog -d bookcat -f sql/init.sql
  • Borrar el volumen y reiniciar desde cero: docker compose down -v && docker compose up -d

Basado en un trabajo de Antonio Javier Calvo Torrejón.

About

Sistema de catalogación de libros con ingesta a través de Apache NiFi, identificación bibliográfica escalonada, indexación GraphRAG en Neo4j orquestada con Airflow, y consultas en lenguaje natural desde Claude Desktop vía servidor MCP propio.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages