""" MIT License Autor: Fernando Lafuente Proyecto: Ejercicio opcional NLP - Chunking y Recuperación Descripción: Configuración centralizada de parámetros del sistema Este módulo centraliza todos los parámetros configurables del sistema de chunking y recuperación semántica. Permite modificar el comportamiento sin tocar el código principal, siguiendo principios de arquitectura limpia. """ import os from pathlib import Path from dotenv import load_dotenv # Cargar variables de entorno desde archivo .env load_dotenv() # ============================================================================= # CONFIGURACIÓN DE RUTAS Y ARCHIVOS # ============================================================================= # Directorio raíz del proyecto PROJECT_ROOT = Path(__file__).parent.absolute() # Directorio donde se almacenan los archivos PDF PDF_DIRECTORY = PROJECT_ROOT / "data" / "pdf" # Crear directorio si no existe PDF_DIRECTORY.mkdir(parents=True, exist_ok=True) # ============================================================================= # CONFIGURACIÓN DE OPENAI EMBEDDINGS # ============================================================================= # Clave de API de OpenAI (debe configurarse como variable de entorno) # Ejecutar: export OPENAI_API_KEY="tu_clave_aqui" OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") # Modelo de embeddings de OpenAI a utilizar # Opciones: "text-embedding-3-small", "text-embedding-3-large", "text-embedding-ada-002" OPENAI_EMBEDDING_MODEL = "text-embedding-3-large" # Más económico y eficiente # Dimensionalidad de los embeddings de OpenAI (text-embedding-3-large) EMBEDDING_DIMENSION = 3072 EMBEDDING_DIMENSIONS = 3072 # Alias for compatibility # ============================================================================= # CONFIGURACIÓN DE QDRANT # ============================================================================= # URL de conexión a Qdrant (leer de entorno si existe) # Prioriza variables de entorno definidas en .env o en el entorno de ejecución QDRANT_URL = os.getenv("QDRANT_URL", "https://4f31fdeb-269a-4aaf-bb34-f93214bf332f.europe-west3-0.gcp.cloud.qdrant.io:6333") QDRANT_API_KEY = os.getenv("QDRANT_API_KEY", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3MiOiJtIn0.E5XdnXbENZYRKHwhgVXYvZE3VtbWQc91Jbdr85aNenc") # Nombre de la colección donde se almacenan los vectores QDRANT_COLLECTION_NAME = "chunks_collection" # Política de inserción al procesar documentos: # True = reemplazar colección del método (limpiar y reinsertar) # False = anexar (append) a la colección existente REPLACE_COLLECTION_ON_PROCESS = bool(int(os.getenv("REPLACE_COLLECTION_ON_PROCESS", "1"))) # ============================================================================= # CONFIGURACIÓN DE CHUNKING # ============================================================================= # Método de chunking a utilizar # Opciones: "fixed", "sentence", "adaptive" CHUNKING_METHOD = "adaptive" # Parámetros para chunking fijo FIXED_CHUNK_SIZE = 500 # caracteres por chunk FIXED_CHUNK_OVERLAP = 50 # caracteres de solapamiento # Parámetros para chunking por oraciones SENTENCE_MIN_LENGTH = 50 # longitud mínima de oración en caracteres SENTENCE_MAX_CHUNK_SIZE = 800 # tamaño máximo de chunk en caracteres # Parámetros para chunking adaptativo ADAPTIVE_SIMILARITY_THRESHOLD = 0.7 # umbral de similitud coseno (0-1) ADAPTIVE_MIN_CHUNK_SIZE = 100 # tamaño mínimo de chunk en caracteres ADAPTIVE_MAX_CHUNK_SIZE = 1000 # tamaño máximo de chunk en caracteres # Lista de métodos de chunking soportados por el sistema CHUNKING_METHODS = ["fixed", "sentence", "adaptive"] # ============================================================================= # CONFIGURACIÓN DE BÚSQUEDA Y RETRIEVAL # ============================================================================= # Número de chunks más relevantes a retornar TOP_K_RESULTS = 10 # Puntuación mínima de similitud para considerar un resultado relevante MIN_SIMILARITY_SCORE = 0.5 # ============================================================================= # CONFIGURACIÓN DE LOGGING # ============================================================================= # Nivel de logging # Opciones: "DEBUG", "INFO", "WARNING", "ERROR" LOG_LEVEL = "DEBUG" # Formato de los mensajes de log LOG_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" # ============================================================================= # CONFIGURACIÓN DE PROCESAMIENTO DE TEXTO # ============================================================================= # Caracteres a eliminar durante la limpieza de texto CHARS_TO_REMOVE = ["\n\n", "\t", "\r"] # Caracteres a reemplazar por espacios CHARS_TO_REPLACE = {"\n": " ", " ": " "} # Longitud mínima de texto válido después de limpieza MIN_TEXT_LENGTH = 10 # ============================================================================= # VALIDACIÓN DE CONFIGURACIÓN # ============================================================================= def validate_settings(): """ Valida que la configuración sea correcta antes de ejecutar el sistema. Raises: ValueError: Si algún parámetro es inválido FileNotFoundError: Si no se encuentra el directorio de PDFs """ # Validar que existe el directorio de PDFs if not PDF_DIRECTORY.exists(): raise FileNotFoundError(f"Directorio de PDFs no encontrado: {PDF_DIRECTORY}") # Validar que hay al menos un PDF en el directorio pdf_files = list(PDF_DIRECTORY.glob("*.pdf")) if not pdf_files: raise FileNotFoundError(f"No se encontraron archivos PDF en: {PDF_DIRECTORY}") # Validar clave de API de OpenAI if not OPENAI_API_KEY: raise ValueError("Variable de entorno OPENAI_API_KEY no configurada") # Validar método de chunking valid_methods = ["fixed", "sentence", "adaptive"] if CHUNKING_METHOD not in valid_methods: raise ValueError(f"Método de chunking inválido: {CHUNKING_METHOD}. " f"Opciones válidas: {valid_methods}") # Validar parámetros numéricos if TOP_K_RESULTS <= 0: raise ValueError("TOP_K_RESULTS debe ser mayor que 0") if MIN_SIMILARITY_SCORE < 0 or MIN_SIMILARITY_SCORE > 1: raise ValueError("MIN_SIMILARITY_SCORE debe estar entre 0 y 1") # Validar umbrales de chunking adaptativo if ADAPTIVE_SIMILARITY_THRESHOLD < 0 or ADAPTIVE_SIMILARITY_THRESHOLD > 1: raise ValueError("ADAPTIVE_SIMILARITY_THRESHOLD debe estar entre 0 y 1") def get_pdf_file(): """ Obtiene el primer archivo PDF encontrado en el directorio configurado. Returns: Path: Ruta al archivo PDF Raises: FileNotFoundError: Si no se encuentra ningún PDF """ pdf_files = list(PDF_DIRECTORY.glob("*.pdf")) if not pdf_files: raise FileNotFoundError(f"No se encontraron archivos PDF en: {PDF_DIRECTORY}") # Retorna el primer PDF encontrado return pdf_files[0]