evolutia 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- evolutia/__init__.py +5 -0
- evolutia/complexity_validator.py +179 -0
- evolutia/config_manager.py +208 -0
- evolutia/evolutia_engine.py +284 -0
- evolutia/exam_generator.py +328 -0
- evolutia/exercise_analyzer.py +256 -0
- evolutia/llm_providers.py +217 -0
- evolutia/material_extractor.py +237 -0
- evolutia/rag/__init__.py +6 -0
- evolutia/rag/consistency_validator.py +200 -0
- evolutia/rag/context_enricher.py +285 -0
- evolutia/rag/enhanced_variation_generator.py +349 -0
- evolutia/rag/rag_indexer.py +424 -0
- evolutia/rag/rag_manager.py +221 -0
- evolutia/rag/rag_retriever.py +366 -0
- evolutia/utils/__init__.py +4 -0
- evolutia/utils/json_parser.py +69 -0
- evolutia/utils/markdown_parser.py +160 -0
- evolutia/utils/math_extractor.py +144 -0
- evolutia/variation_generator.py +97 -0
- evolutia-0.1.0.dist-info/METADATA +723 -0
- evolutia-0.1.0.dist-info/RECORD +27 -0
- evolutia-0.1.0.dist-info/WHEEL +5 -0
- evolutia-0.1.0.dist-info/entry_points.txt +2 -0
- evolutia-0.1.0.dist-info/licenses/LICENSE +201 -0
- evolutia-0.1.0.dist-info/top_level.txt +2 -0
- evolutia_cli.py +160 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utilidades para extraer y analizar expresiones matemáticas de archivos Markdown.
|
|
3
|
+
"""
|
|
4
|
+
import re
|
|
5
|
+
from typing import List, Dict, Set
|
|
6
|
+
|
|
7
|
+
# Patrones comunes para variables
|
|
8
|
+
# Variables latinas: \vec{A}, A, \mathbf{B}, etc.
|
|
9
|
+
LATIN_PATTERN = re.compile(r'\\vec\{([A-Za-z])\}|\\mathbf\{([A-Za-z])\}|\\hat\{([A-Za-z])\}|([A-Za-z])(?![a-z])')
|
|
10
|
+
|
|
11
|
+
# Letras griegas: \alpha, \beta, \theta, etc.
|
|
12
|
+
GREEK_PATTERN = re.compile(r'\\(alpha|beta|gamma|delta|epsilon|theta|phi|rho|omega|sigma|lambda|mu|nu|pi|tau)')
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def extract_math_expressions(content: str) -> List[str]:
|
|
16
|
+
r"""
|
|
17
|
+
Extrae todas las expresiones matemáticas del contenido.
|
|
18
|
+
|
|
19
|
+
Busca expresiones en formato LaTeX:
|
|
20
|
+
- Inline: $...$ o \(...\)
|
|
21
|
+
- Display: $$...$$ o \[...\]
|
|
22
|
+
- Math blocks: :::{math} ... :::
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
content: Contenido Markdown
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
Lista de expresiones matemáticas encontradas
|
|
29
|
+
"""
|
|
30
|
+
expressions = []
|
|
31
|
+
|
|
32
|
+
# 1. Bloques math de MyST: :::{math} ... :::
|
|
33
|
+
# Se procesan primero y se eliminan del contenido para evitar duplicados si contienen $ o $$
|
|
34
|
+
math_block_pattern = r':::\{math\}\s*(.*?)\s*:::'
|
|
35
|
+
for match in re.finditer(math_block_pattern, content, re.DOTALL):
|
|
36
|
+
expr = match.group(1).strip()
|
|
37
|
+
if expr:
|
|
38
|
+
expressions.append(expr)
|
|
39
|
+
content = re.sub(math_block_pattern, '', content, flags=re.DOTALL)
|
|
40
|
+
|
|
41
|
+
# 2. Expresiones display: $$...$$ o \[...\]
|
|
42
|
+
display_pattern = r'\$\$([^$]+)\$\$|\\\[([^\]]+)\\\]'
|
|
43
|
+
for match in re.finditer(display_pattern, content, re.DOTALL):
|
|
44
|
+
expr = match.group(1) or match.group(2)
|
|
45
|
+
if expr:
|
|
46
|
+
expressions.append(expr.strip())
|
|
47
|
+
content = re.sub(display_pattern, '', content, flags=re.DOTALL)
|
|
48
|
+
|
|
49
|
+
# 3. Expresiones inline: $...$ o \(...\)
|
|
50
|
+
inline_pattern = r'\$([^$]+)\$|\\\(([^\)]+)\\\)'
|
|
51
|
+
for match in re.finditer(inline_pattern, content):
|
|
52
|
+
expr = match.group(1) or match.group(2)
|
|
53
|
+
if expr:
|
|
54
|
+
expressions.append(expr.strip())
|
|
55
|
+
|
|
56
|
+
return expressions
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def extract_variables(math_expressions: List[str]) -> Set[str]:
|
|
60
|
+
"""
|
|
61
|
+
Extrae variables de expresiones matemáticas.
|
|
62
|
+
|
|
63
|
+
Identifica letras griegas, variables latinas, y símbolos comunes.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
math_expressions: Lista de expresiones matemáticas
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
Conjunto de variables identificadas
|
|
70
|
+
"""
|
|
71
|
+
variables = set()
|
|
72
|
+
|
|
73
|
+
for expr in math_expressions:
|
|
74
|
+
# Buscar variables latinas
|
|
75
|
+
for match in LATIN_PATTERN.finditer(expr):
|
|
76
|
+
var = match.group(1) or match.group(2) or match.group(3) or match.group(4)
|
|
77
|
+
if var and var.isalpha():
|
|
78
|
+
variables.add(var)
|
|
79
|
+
|
|
80
|
+
# Buscar letras griegas
|
|
81
|
+
for match in GREEK_PATTERN.finditer(expr):
|
|
82
|
+
variables.add(match.group(1))
|
|
83
|
+
|
|
84
|
+
return variables
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def count_math_operations(expression: str) -> Dict[str, int]:
|
|
88
|
+
"""
|
|
89
|
+
Cuenta operaciones matemáticas en una expresión.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
expression: Expresión matemática
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
Diccionario con conteo de operaciones
|
|
96
|
+
"""
|
|
97
|
+
operations = {
|
|
98
|
+
'integrals': len(re.findall(r'\\int|\\oint', expression)),
|
|
99
|
+
'derivatives': len(re.findall(r'\\partial|\\nabla|\\frac\{d', expression)),
|
|
100
|
+
'sums': len(re.findall(r'\\sum|\\prod', expression)),
|
|
101
|
+
'vectors': len(re.findall(r'\\vec|\\mathbf', expression)),
|
|
102
|
+
'matrices': len(re.findall(r'\\begin\{matrix\}|\\begin\{pmatrix\}|\\begin\{bmatrix\}', expression)),
|
|
103
|
+
'functions': len(re.findall(r'\\sin|\\cos|\\tan|\\exp|\\log|\\ln', expression)),
|
|
104
|
+
}
|
|
105
|
+
return operations
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def estimate_complexity(expressions: List[str]) -> float:
|
|
109
|
+
"""
|
|
110
|
+
Estima la complejidad matemática de un conjunto de expresiones.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
expressions: Lista de expresiones matemáticas
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
Puntuación de complejidad (mayor = más complejo)
|
|
117
|
+
"""
|
|
118
|
+
if not expressions:
|
|
119
|
+
return 0.0
|
|
120
|
+
|
|
121
|
+
total_complexity = 0.0
|
|
122
|
+
|
|
123
|
+
for expr in expressions:
|
|
124
|
+
# Longitud de la expresión
|
|
125
|
+
total_complexity += len(expr) * 0.01
|
|
126
|
+
|
|
127
|
+
# Operaciones complejas
|
|
128
|
+
ops = count_math_operations(expr)
|
|
129
|
+
total_complexity += ops['integrals'] * 2.0
|
|
130
|
+
total_complexity += ops['derivatives'] * 1.5
|
|
131
|
+
total_complexity += ops['sums'] * 1.5
|
|
132
|
+
total_complexity += ops['vectors'] * 1.0
|
|
133
|
+
total_complexity += ops['matrices'] * 2.5
|
|
134
|
+
total_complexity += ops['functions'] * 0.5
|
|
135
|
+
|
|
136
|
+
# Número de variables
|
|
137
|
+
vars_count = len(extract_variables([expr]))
|
|
138
|
+
total_complexity += vars_count * 0.3
|
|
139
|
+
|
|
140
|
+
# Bloques align (ecuaciones múltiples)
|
|
141
|
+
if '\\begin{align' in expr or '\\begin{aligned' in expr:
|
|
142
|
+
total_complexity += 2.0
|
|
143
|
+
|
|
144
|
+
return total_complexity
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Generador de variaciones de ejercicios con mayor complejidad.
|
|
3
|
+
Utiliza APIs de IA para generar variaciones inteligentes.
|
|
4
|
+
"""
|
|
5
|
+
import os
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Dict, Optional
|
|
8
|
+
from dotenv import load_dotenv
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
# Imports for new Provider system
|
|
12
|
+
from .llm_providers import get_provider
|
|
13
|
+
from .utils.json_parser import extract_and_parse_json
|
|
14
|
+
|
|
15
|
+
# Cargar variables de entorno explícitamente desde el directorio del script
|
|
16
|
+
env_path = Path(__file__).parent / '.env'
|
|
17
|
+
load_dotenv(dotenv_path=env_path)
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class VariationGenerator:
|
|
24
|
+
"""Genera variaciones de ejercicios con mayor complejidad."""
|
|
25
|
+
|
|
26
|
+
def __init__(self, api_provider: str = "openai"):
|
|
27
|
+
"""
|
|
28
|
+
Inicializa el generador.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
api_provider: Proveedor de API ('openai', 'anthropic', 'gemini' o 'local')
|
|
32
|
+
"""
|
|
33
|
+
self.api_provider = api_provider
|
|
34
|
+
self.base_url = None # For local overrides
|
|
35
|
+
self.local_model = None # For local overrides
|
|
36
|
+
self.model_name = None # For overrides
|
|
37
|
+
|
|
38
|
+
self._provider_instance = None
|
|
39
|
+
|
|
40
|
+
def _get_provider(self):
|
|
41
|
+
"""Lazy loader para el proveedor, permitiendo configuración tardía de props."""
|
|
42
|
+
if self._provider_instance:
|
|
43
|
+
return self._provider_instance
|
|
44
|
+
|
|
45
|
+
kwargs = {}
|
|
46
|
+
if self.model_name:
|
|
47
|
+
kwargs['model_name'] = self.model_name
|
|
48
|
+
elif self.local_model and self.api_provider == 'local':
|
|
49
|
+
kwargs['model_name'] = self.local_model
|
|
50
|
+
|
|
51
|
+
if self.base_url and self.api_provider == 'local':
|
|
52
|
+
kwargs['base_url'] = self.base_url
|
|
53
|
+
|
|
54
|
+
try:
|
|
55
|
+
self._provider_instance = get_provider(self.api_provider, **kwargs)
|
|
56
|
+
except ValueError as e:
|
|
57
|
+
logger.error(f"Error inicializando proveedor: {e}")
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
return self._provider_instance
|
|
61
|
+
|
|
62
|
+
def generate_variation_with_solution(self, exercise: Dict, analysis: Dict) -> Optional[Dict]:
|
|
63
|
+
"""
|
|
64
|
+
Genera una variación con su solución.
|
|
65
|
+
"""
|
|
66
|
+
# Primero generar el ejercicio
|
|
67
|
+
variation = self.generate_variation(exercise, analysis)
|
|
68
|
+
|
|
69
|
+
if not variation:
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
provider = self._get_provider()
|
|
73
|
+
if not provider: return None
|
|
74
|
+
|
|
75
|
+
# Luego generar la solución
|
|
76
|
+
solution_prompt = f"""Eres un experto en métodos matemáticos para física e ingeniería. Resuelve el siguiente ejercicio paso a paso, mostrando todos los cálculos y procedimientos.
|
|
77
|
+
|
|
78
|
+
EJERCICIO:
|
|
79
|
+
{variation['variation_content']}
|
|
80
|
+
|
|
81
|
+
INSTRUCCIONES:
|
|
82
|
+
1. Resuelve el ejercicio de forma completa y detallada
|
|
83
|
+
2. Muestra todos los pasos intermedios
|
|
84
|
+
3. Usa notación matemática LaTeX correcta
|
|
85
|
+
4. Explica el razonamiento cuando sea necesario
|
|
86
|
+
5. Usa bloques :::{{math}} para ecuaciones display y $...$ para inline
|
|
87
|
+
6. Escribe en español
|
|
88
|
+
|
|
89
|
+
GENERA LA SOLUCIÓN COMPLETA:"""
|
|
90
|
+
|
|
91
|
+
solution_content = provider.generate_content(solution_prompt)
|
|
92
|
+
|
|
93
|
+
if solution_content:
|
|
94
|
+
variation['variation_solution'] = solution_content
|
|
95
|
+
|
|
96
|
+
return variation
|
|
97
|
+
|