
Proyecto IA Monterroso (XIX): httrack se cayó a mitad, pero el Moodle de Computación y Robótica ya está en el RAG
Esta entrada tiene un fallo real de por medio, contado tal cual pasó, y un resultado que compensa el disgusto.
El fallo
Para tener más material de cara al “modo repaso” (aparcado en la entrada anterior por falta de apuntes suficientes de Computación y Robótica en 1º de ESO), se lanzó una copia con httrack del curso real en el Moodle de la Junta de Andalucía, con sesión de profesor. A mitad de la descarga, httrack se cayó con un error de memoria:
memory allocation failed (1048576 bytes)!
"memory allocation failed" failed at c:\dev\httrack\src\htsarrays.h:46
Caught signal 22
Sin más detalle que ese: el proceso murió. El curso es grande y, aparentemente, httrack no aguantó acumular en memoria todo lo que iba encontrando. Queda anotado como límite real de la herramienta para cursos de este tamaño, no como un capricho — si se repite el intento, habrá que acotar más el alcance de la descarga en vez de lanzarla contra el curso entero.
Qué se pudo salvar
Antes de morir, httrack había terminado de escribir 84 páginas de mod/page (las páginas de contenido, escritas por el profesor). El resto de archivos quedaron a medio escribir (.tmp) y se descartaron sin abrirlos. Y, como en toda esta operación, hubo una regla que no se tocó en ningún momento: mod/assign, mod/forum, mod/quiz y las páginas de administración del curso ni se abrieron ni se van a abrir. Eso no ha cambiado por el hecho de que la descarga fallara.
La limpieza: cada página traía todo el menú del curso pegado
El primer intento de extracción, tal cual, sacaba unos 3 MB de texto de 84 páginas — una barbaridad para lo que en realidad hay que decir. El motivo: en el tema de Moodle del centro, el índice completo del curso (decenas de actividades, muchas repetidas varias veces) va dentro de la misma región de “contenido principal” de la página, no en un menú aparte. Al extraer el contenido principal sin más, se llevaba también el índice entero del curso, repetido.
La solución fue cortar cada página justo donde Moodle marca el final del contenido propio:
python
def solo_contenido_real(texto):
"""Corta en la primera aparición de 'Última modificación:' (fin del
contenido propio de la página en Moodle; lo que viene después es
navegación/índice del curso, no contenido)."""
idx = texto.find("Última modificación:")
if idx != -1:
return texto[:idx].strip()
for marcador in ["Actividad previa", "Ir a...", "Siguiente actividad"]:
idx = texto.find(marcador)
if idx != -1:
return texto[:idx].strip()
return texto.strip()
Con ese corte, el texto bajó de 3 MB a menos de 400 KB. Aun así, 7 de las 84 páginas resultaron ser solo el panel de administración de Moodle sin nada de contenido propio (empiezan literalmente por “Agregar un bloque”) — se descartaron también. Quedaron 77 páginas con contenido real.
Revisión de privacidad
Con las 77 páginas ya fusionadas en un solo texto, se revisó una muestra amplia buscando cualquier dato de alumnado: nombres reales, correos, notas, DNI. No apareció nada. Lo que sí aparece con esas palabras es contenido pedagógico genérico — un ejercicio sobre proteger tu identidad digital que usa “DNI” como metáfora, una tarea que pide comprobar el propio perfil de Moodle — no datos reales de nadie. El contenido en sí es la narrativa de “El Lince de la Noche” y los “Centuriones de la Verdad” aplicada a Scratch, micro:bit, IA y ciberseguridad: material didáctico de calidad, no un volcado de datos personales.
Un pequeño hueco de arquitectura que hizo falta cerrar
El RAG solo sabía leer PDF, .docx y .odt. El texto ya limpio de Moodle es un simple .txt, así que hizo falta añadir un formato más — otra vez, sin tocar nada del resto de rag.py:
python
EXTENSIONES_ADMITIDAS = (".pdf", ".docx", ".odt", ".txt")
def _extraer_paginas_txt(ruta):
"""Texto plano ya extraído por otro proceso (por ejemplo, páginas de
Moodle ya limpiadas de menús/navegación antes de llegar aquí). Sin
concepto de página, igual que .docx/.odt."""
with open(ruta, "r", encoding="utf-8", errors="replace") as f:
return [(f.read(), None)]
El archivo fusionado se copió directamente dentro de documentosmonterroso/cyr1eso/, la misma carpeta donde ya estaban los apuntes propios en .odt y .docx — no se ha creado un corpus nuevo, se ha ampliado el que ya existía.
Cómo se comprobó
Revisión manual de una muestra amplia del texto fusionado (no las 77 páginas una por una, pero sí una porción representativa grande), buscando expresamente datos de alumnado. rag.py compila sin errores tras el cambio. Queda pendiente el reinicio real de la API para que el corpus “cyr1eso” se reindexe con este contenido añadido.
Instalación
rag.py actualizado (soporte de .txt). main.py no se ha tocado esta vez. El archivo de texto ya está copiado dentro de documentosmonterroso/cyr1eso/. Solo falta reiniciar la API para que el índice BM25 de ese corpus se reconstruya incluyéndolo.
Cómo comprobarlo
Seleccionar el corpus “Computación y Robótica 1º ESO (piloto)” y preguntar algo específico de las páginas nuevas — por ejemplo, sobre el “Bucle del Tiempo del Doctor Mente” o sobre sensores de la micro:bit y los Centuriones de la Verdad. La respuesta debería citar cyr1eso_moodle_pages.txt como fuente.
Qué queda pendiente
Del curso completo solo se ha recuperado la parte que terminó de descargarse antes del fallo de memoria — si se quiere el resto, habrá que repetir la descarga acotando el alcance, no repetirla igual esperando que no vuelva a caerse. mod/resource y mod/folder (los archivos que José Luis subió directamente a Moodle) se han dejado sin tocar esta vez; podrían ser una fuente de contenido tan buena o mejor que las páginas, pendiente de una decisión aparte. Y, ya con el contenido útil copiado a salvo dentro del RAG, la carpeta original de la descarga de httrack en el ordenador no hace falta conservarla — se puede borrar.




