Spaces:
Sleeping
Sleeping
File size: 6,070 Bytes
b54a6bc 7cba34a b54a6bc 7cba34a d35d511 7cba34a d329e85 7cba34a b54a6bc e341366 4d995a1 b54a6bc 7cba34a b54a6bc e341366 d35d511 b54a6bc 1e129b0 b54a6bc 1e129b0 b54a6bc 1e129b0 b54a6bc 1e129b0 b54a6bc 1e129b0 b54a6bc 7cba34a b54a6bc 7cba34a b54a6bc 7cba34a b54a6bc 7cba34a f61af4a |
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 |
mport gradio as gr
import PyPDF2
import os
import vertexai
from vertexai.generative_models import GenerativeModel, Part, SafetySetting
import base64
"""
Este código se encarga de:
1. Leer un archivo de credenciales JSON para configurar Google Cloud.
2. Inicializar Vertex AI en la región us-central1.
3. Extraer preguntas y respuestas de dos PDFs: uno del docente y otro del alumno.
4. Filtrar únicamente las preguntas realmente respondidas por el alumno.
5. Enviar ese contenido filtrado al modelo generativo (Gemini 1.5), con instrucciones para que
NO mencione preguntas no respondidas.
"""
# Configuración del modelo y parámetros globales
generation_config = {
"max_output_tokens": 8192,
"temperature": 0,
"top_p": 0.75,
}
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:
"""Extraer texto de todas las páginas de un PDF."""
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_preguntas_respuestas(texto: str) -> dict:
"""Dado un texto con formato, retorna un dict {pregunta: respuesta}."""
# Buscamos líneas que inicien con "Pregunta" y "Respuesta"
lineas = texto.split("\n")
resultado = {}
pregunta_actual = None
for linea in lineas:
linea_str = linea.strip()
if linea_str.lower().startswith("pregunta"):
pregunta_actual = linea_str
resultado[pregunta_actual] = ""
elif linea_str.lower().startswith("respuesta") and pregunta_actual:
# No mezclamos en la misma línea "Pregunta X:"
# sino que esperamos "Pregunta X" en una línea y "Respuesta X" en la siguiente
# si el formateo es distinto, ajusta aquí.
# Tomamos lo que está después de ':'
partes = linea_str.split(":", 1)
if len(partes) > 1:
respuesta = partes[1].strip()
resultado[pregunta_actual] = respuesta
return resultado
def revisar_examen(json_cred, pdf_docente, pdf_alumno):
try:
# Configurar credenciales
configurar_credenciales(json_cred.name)
# Inicializar Vertex AI
vertexai.init(project="deploygpt", location="us-central1")
# Extraer texto de ambos PDFs
docente_texto = extraer_texto(pdf_docente.name)
alumno_texto = extraer_texto(pdf_alumno.name)
# Parsear preguntas y respuestas
preguntas_docente = parsear_preguntas_respuestas(docente_texto)
respuestas_alumno = parsear_preguntas_respuestas(alumno_texto)
# Filtrar solo preguntas respondidas
preguntas_filtradas = {}
for pregunta_doc, resp_doc in preguntas_docente.items():
if pregunta_doc in respuestas_alumno:
# El alumno respondió esta pregunta
preguntas_filtradas[pregunta_doc] = {
"respuesta_doc": resp_doc,
"respuesta_alumno": respuestas_alumno[pregunta_doc]
}
if not preguntas_filtradas:
return "El alumno no respondió ninguna de las preguntas del docente."
# Construir un texto que contenga únicamente las preguntas respondidas
# e instrucciones claras para no alucinar preguntas.
# Vamos a pasarlo en 1 solo Part, para forzar a que la LLM no confunda.
contenido_final = """Instrucciones: Solo hay estas preguntas respondidas por el alumno.
No menciones preguntas que no estén en esta lista. Para cada pregunta, analiza la respuesta.
Al final, da un resumen.
"""
for i, (p, data) in enumerate(preguntas_filtradas.items(), 1):
contenido_final += f"\nPregunta {i}: {p}\n" \
f"Respuesta del alumno: {data['respuesta_alumno']}\n" \
f"Respuesta correcta (docente): {data['respuesta_doc']}\n"
# Creamos un Part con el contenido filtrado
part_filtrado = Part(
mime_type="text/plain",
text=contenido_final,
)
# System instruction, for clarity
textsi_1 = """Actúa como un asistente de docente experto en Bioquímica.
No menciones preguntas que el alumno no respondió.
Analiza únicamente las preguntas provistas en el texto.
Calcula un porcentaje de precisión basado en las respuestas incluidas.
"""
model = GenerativeModel(
"gemini-1.5-pro-001",
system_instruction=[textsi_1]
)
# Llamada al modelo con las partes.
response = model.generate_content(
[part_filtrado],
generation_config=generation_config,
safety_settings=safety_settings,
stream=False,
)
return response.text
except Exception as e:
return f"Error al procesar: {str(e)}"
# Interfaz Gradio
interface = gr.Interface(
fn=revisar_examen,
inputs=[
gr.File(label="Credenciales JSON"),
gr.File(label="PDF Docente"),
gr.File(label="PDF Alumno")
],
outputs=gr.Textbox(label="Resultado"),
title="Revisión de Exámenes",
description="Sube tus credenciales, el PDF del docente y el del alumno para revisar las respuestas sin alucinaciones."
)
interface.launch(debug=True)
|