DemoProfeIA / app.py
cesar's picture
Update app.py
1b22788 verified
raw
history blame
4.98 kB
import gradio as gr
import PyPDF2
import os
import json
import vertexai
from vertexai.generative_models import GenerativeModel, Part, SafetySetting
# Configuración global
generation_config = {
"max_output_tokens": 4096,
"temperature": 0,
"top_p": 0.8,
}
safety_settings = [
SafetySetting(
category=SafetySetting.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
threshold=SafetySetting.HarmBlockThreshold.OFF
),
SafetySetting(
category=SafetySetting.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold=SafetySetting.HarmBlockThreshold.OFF
),
SafetySetting(
category=SafetySetting.HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
threshold=SafetySetting.HarmBlockThreshold.OFF
),
SafetySetting(
category=SafetySetting.HarmCategory.HARM_CATEGORY_HARASSMENT,
threshold=SafetySetting.HarmBlockThreshold.OFF
),
]
def configurar_credenciales(json_path: str):
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = json_path
def extraer_texto(pdf_path: str) -> str:
texto_total = ""
with open(pdf_path, "rb") as f:
lector = PyPDF2.PdfReader(f)
for page in lector.pages:
texto_total += page.extract_text() or ""
return texto_total
def parsear_con_llm(texto_pdf: str, model: GenerativeModel) -> dict:
# Instrucciones para parsear:
prompt = f"""
Eres un parser de texto.
A continuación tienes el contenido de un PDF con un examen (o respuestas).
Debes extraer todas las preguntas y sus respuestas.
Considera que las palabras podrían estar en mayúsculas, minúsculas o plural
(por ejemplo 'Pregunta', 'PREGUNTA', 'Preguntas', 'RESPUESTA', 'RESPUESTAS', etc.).
Devuélvelas en formato JSON puro, sin explicación adicional.
Usa este formato de salida:
{{
"Pregunta 1": "Texto de la respuesta",
"Pregunta 2": "Texto de la respuesta"
}}
Si hay preguntas sin respuesta, pon la respuesta como cadena vacía.
Si no hay ninguna pregunta, devuelve un JSON vacío: {{}}
Texto PDF:
{texto_pdf}
"""
part_text = Part.from_text(prompt)
response = model.generate_content(
[part_text],
generation_config=generation_config,
safety_settings=safety_settings,
stream=False
)
try:
data = json.loads(response.text.strip())
if isinstance(data, dict):
return data
else:
return {}
except:
return {}
def comparar_preguntas_respuestas(dict_docente: dict, dict_alumno: dict) -> str:
retroalimentacion = []
for pregunta, resp_correcta in dict_docente.items():
resp_alumno = dict_alumno.get(pregunta, None)
if resp_alumno is None:
retroalimentacion.append(f"**{pregunta}**\nNo fue asignada al alumno.\n")
else:
retroalimentacion.append(
f"**{pregunta}**\n"
f"Respuesta del alumno: {resp_alumno}\n"
f"Respuesta correcta: {resp_correcta}\n"
)
return "\n".join(retroalimentacion)
def revisar_examen(json_cred, pdf_docente, pdf_alumno):
try:
configurar_credenciales(json_cred.name)
vertexai.init(project="deploygpt", location="us-central1")
texto_docente = extraer_texto(pdf_docente.name)
texto_alumno = extraer_texto(pdf_alumno.name)
model = GenerativeModel(
"gemini-1.5-pro-001",
system_instruction=["Eres un parser estricto."]
)
dict_docente = parsear_con_llm(texto_docente, model)
dict_alumno = parsear_con_llm(texto_alumno, model)
feedback = comparar_preguntas_respuestas(dict_docente, dict_alumno)
if len(feedback.strip()) < 5:
return "No se encontraron preguntas o respuestas válidas."
summary_prompt = f"""
Eres un profesor experto. Te muestro la comparación de preguntas y respuestas:
{feedback}
Por favor, genera un breve resumen del desempeño del alumno
sin inventar preguntas adicionales.
"""
summary_part = Part.from_text(summary_prompt)
summary_resp = model.generate_content(
[summary_part],
generation_config=generation_config,
safety_settings=safety_settings,
stream=False
)
return f"{feedback}\n\n**Resumen**\n{summary_resp.text.strip()}"
except Exception as e:
return f"Error al procesar: {str(e)}"
import gradio as gr
interface = gr.Interface(
fn=revisar_examen,
inputs=[
gr.File(label="Credenciales JSON"),
gr.File(label="PDF Docente"),
gr.File(label="PDF Alumno")
],
outputs=gr.Markdown(),
title="Revisión de Exámenes con LLM (Permisivo)",
description="Sube credenciales, el PDF del docente y del alumno; se emplea un LLM para encontrar 'Pregunta/Respuesta' aun con variaciones."
)
interface.launch(debug=True)