File size: 7,096 Bytes
f729bac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4cc8f6d
f729bac
4cc8f6d
f729bac
 
 
 
 
7d90935
 
 
85e8be9
f729bac
 
 
 
7d90935
 
 
 
 
f729bac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
"""
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]