Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -58,7 +58,7 @@ def extraer_texto(pdf_path: str) -> str:
|
|
| 58 |
def split_secciones(texto: str) -> (str, str):
|
| 59 |
"""
|
| 60 |
Separa el texto en dos partes: la secci贸n 'Preguntas' y la secci贸n 'RESPUESTAS'.
|
| 61 |
-
Busca las palabras 'Preguntas' y 'RESPUESTAS' ignorando espacios al inicio
|
| 62 |
"""
|
| 63 |
match_preg = re.search(r'(?im)^\s*preguntas', texto)
|
| 64 |
match_resp = re.search(r'(?im)^\s*respuestas', texto)
|
|
@@ -66,8 +66,8 @@ def split_secciones(texto: str) -> (str, str):
|
|
| 66 |
if not match_preg or not match_resp:
|
| 67 |
return (texto, "")
|
| 68 |
|
| 69 |
-
start_preg = match_preg.end() #
|
| 70 |
-
start_resp = match_resp.start() #
|
| 71 |
|
| 72 |
texto_preguntas = texto[start_preg:start_resp].strip()
|
| 73 |
texto_respuestas = texto[match_resp.end():].strip()
|
|
@@ -79,26 +79,29 @@ def parsear_enumeraciones(texto: str) -> dict:
|
|
| 79 |
separa cada n煤mero y su contenido.
|
| 80 |
Retorna un dict: {"Pregunta 1": "contenido", "Pregunta 2": "contenido", ...}.
|
| 81 |
Este patr贸n es flexible y tolera espacios al inicio y formatos creativos.
|
|
|
|
| 82 |
"""
|
| 83 |
-
#
|
| 84 |
-
# un punto o gui贸n y opcionalmente otro n煤mero
|
| 85 |
bloques = re.split(r'(?=^\s*\d+[\.\-]\s*(?:\d+[\.\-])?\s*)', texto, flags=re.MULTILINE)
|
| 86 |
resultado = {}
|
| 87 |
for bloque in bloques:
|
| 88 |
bloque = bloque.strip()
|
| 89 |
if not bloque:
|
| 90 |
continue
|
| 91 |
-
#
|
| 92 |
match = re.match(r'^\s*(\d+)[\.\-]\s*(?:\d+[\.\-])?\s*(.*)', bloque)
|
| 93 |
if match:
|
| 94 |
numero = match.group(1)
|
| 95 |
contenido = match.group(2)
|
| 96 |
-
# Si
|
| 97 |
lineas = bloque.split("\n")
|
| 98 |
if len(lineas) > 1:
|
| 99 |
contenido_completo = " ".join([linea.strip() for linea in lineas[1:]])
|
| 100 |
if contenido_completo:
|
| 101 |
-
contenido
|
|
|
|
|
|
|
| 102 |
resultado[f"Pregunta {numero}"] = contenido.strip()
|
| 103 |
return resultado
|
| 104 |
|
|
@@ -165,7 +168,7 @@ def revisar_examen(json_cred, pdf_docente, pdf_alumno):
|
|
| 165 |
1. Configura credenciales.
|
| 166 |
2. Extrae y parsea el contenido de los PDFs.
|
| 167 |
3. Separa las secciones 'Preguntas' y 'RESPUESTAS'.
|
| 168 |
-
4. Parsea las enumeraciones de cada secci贸n (
|
| 169 |
5. Compara las respuestas del alumno con las correctas.
|
| 170 |
6. Llama a un LLM para generar un resumen final con retroalimentaci贸n.
|
| 171 |
"""
|
|
@@ -191,7 +194,7 @@ def revisar_examen(json_cred, pdf_docente, pdf_alumno):
|
|
| 191 |
yield "Parseando enumeraciones (docente)..."
|
| 192 |
dict_preg_doc = parsear_enumeraciones(preguntas_doc)
|
| 193 |
dict_resp_doc = parsear_enumeraciones(respuestas_doc)
|
| 194 |
-
# Unir las respuestas del docente
|
| 195 |
dict_docente = {}
|
| 196 |
for key in dict_preg_doc:
|
| 197 |
dict_docente[key] = dict_resp_doc.get(key, "")
|
|
|
|
| 58 |
def split_secciones(texto: str) -> (str, str):
|
| 59 |
"""
|
| 60 |
Separa el texto en dos partes: la secci贸n 'Preguntas' y la secci贸n 'RESPUESTAS'.
|
| 61 |
+
Busca las palabras 'Preguntas' y 'RESPUESTAS' ignorando may煤sculas y espacios al inicio.
|
| 62 |
"""
|
| 63 |
match_preg = re.search(r'(?im)^\s*preguntas', texto)
|
| 64 |
match_resp = re.search(r'(?im)^\s*respuestas', texto)
|
|
|
|
| 66 |
if not match_preg or not match_resp:
|
| 67 |
return (texto, "")
|
| 68 |
|
| 69 |
+
start_preg = match_preg.end() # Fin de "Preguntas"
|
| 70 |
+
start_resp = match_resp.start() # Inicio de "RESPUESTAS"
|
| 71 |
|
| 72 |
texto_preguntas = texto[start_preg:start_resp].strip()
|
| 73 |
texto_respuestas = texto[match_resp.end():].strip()
|
|
|
|
| 79 |
separa cada n煤mero y su contenido.
|
| 80 |
Retorna un dict: {"Pregunta 1": "contenido", "Pregunta 2": "contenido", ...}.
|
| 81 |
Este patr贸n es flexible y tolera espacios al inicio y formatos creativos.
|
| 82 |
+
Adem谩s, elimina duplicados al inicio de la respuesta (por ejemplo, "Durante Durante ...").
|
| 83 |
"""
|
| 84 |
+
# Se utiliza un lookahead para dividir cada bloque cuando se encuentre una l铆nea que empiece con un n煤mero,
|
| 85 |
+
# un punto o gui贸n y, opcionalmente, otro n煤mero con punto o gui贸n.
|
| 86 |
bloques = re.split(r'(?=^\s*\d+[\.\-]\s*(?:\d+[\.\-])?\s*)', texto, flags=re.MULTILINE)
|
| 87 |
resultado = {}
|
| 88 |
for bloque in bloques:
|
| 89 |
bloque = bloque.strip()
|
| 90 |
if not bloque:
|
| 91 |
continue
|
| 92 |
+
# Extraemos el n煤mero de la pregunta y el contenido.
|
| 93 |
match = re.match(r'^\s*(\d+)[\.\-]\s*(?:\d+[\.\-])?\s*(.*)', bloque)
|
| 94 |
if match:
|
| 95 |
numero = match.group(1)
|
| 96 |
contenido = match.group(2)
|
| 97 |
+
# Si hay m煤ltiples l铆neas, unimos las l铆neas adicionales.
|
| 98 |
lineas = bloque.split("\n")
|
| 99 |
if len(lineas) > 1:
|
| 100 |
contenido_completo = " ".join([linea.strip() for linea in lineas[1:]])
|
| 101 |
if contenido_completo:
|
| 102 |
+
contenido = contenido + " " + contenido_completo
|
| 103 |
+
# Eliminar duplicados al inicio (por ejemplo, "Durante Durante ..." se convierte en "Durante ...")
|
| 104 |
+
contenido = re.sub(r'^(\S+)(\s+\1)+\s+', r'\1 ', contenido)
|
| 105 |
resultado[f"Pregunta {numero}"] = contenido.strip()
|
| 106 |
return resultado
|
| 107 |
|
|
|
|
| 168 |
1. Configura credenciales.
|
| 169 |
2. Extrae y parsea el contenido de los PDFs.
|
| 170 |
3. Separa las secciones 'Preguntas' y 'RESPUESTAS'.
|
| 171 |
+
4. Parsea las enumeraciones de cada secci贸n (soportando formatos creativos).
|
| 172 |
5. Compara las respuestas del alumno con las correctas.
|
| 173 |
6. Llama a un LLM para generar un resumen final con retroalimentaci贸n.
|
| 174 |
"""
|
|
|
|
| 194 |
yield "Parseando enumeraciones (docente)..."
|
| 195 |
dict_preg_doc = parsear_enumeraciones(preguntas_doc)
|
| 196 |
dict_resp_doc = parsear_enumeraciones(respuestas_doc)
|
| 197 |
+
# Unir las respuestas correctas del docente
|
| 198 |
dict_docente = {}
|
| 199 |
for key in dict_preg_doc:
|
| 200 |
dict_docente[key] = dict_resp_doc.get(key, "")
|