cesar commited on
Commit
b54a6bc
verified
1 Parent(s): c16fa58

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +104 -55
app.py CHANGED
@@ -1,8 +1,19 @@
1
- import gradio as gr
2
- import base64
 
3
  import vertexai
4
  from vertexai.generative_models import GenerativeModel, Part, SafetySetting
5
- import os
 
 
 
 
 
 
 
 
 
 
6
 
7
  # Configuraci贸n del modelo y par谩metros globales
8
  generation_config = {
@@ -30,86 +41,124 @@ safety_settings = [
30
  ),
31
  ]
32
 
33
- def configurar_credenciales(json_path):
34
- """Configura las credenciales de Google Cloud usando un archivo JSON."""
35
  os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = json_path
36
 
37
- def revisar_examen(json_path, pdf_docente, pdf_alumno):
38
- """Funci贸n principal para comparar los PDFs del docente y del alumno."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  try:
40
- # Configurar las credenciales
41
- configurar_credenciales(json_path)
42
 
43
  # Inicializar Vertex AI
44
  vertexai.init(project="deploygpt", location="us-central1")
45
 
46
- # Leer los datos de los PDFs desde la ruta proporcionada por Gradio
47
- with open(pdf_docente.name, "rb") as docente_file:
48
- docente_data = docente_file.read()
49
-
50
- with open(pdf_alumno.name, "rb") as alumno_file:
51
- alumno_data = alumno_file.read()
52
-
53
- # Codificar los datos de los PDFs a base64
54
- document1 = Part.from_data(
55
- mime_type="application/pdf",
56
- data=base64.b64encode(docente_data).decode("utf-8"),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  )
58
 
59
- document2 = Part.from_data(
60
- mime_type="application/pdf",
61
- data=base64.b64encode(alumno_data).decode("utf-8"),
62
- )
 
 
63
 
64
- # Configuraci贸n del texto de instrucciones
65
- text1 = """Informaci贸n del examen
66
- Materia: bioquimica nutricion normal
67
- Grado/Nivel: universidad
68
- Tema: Metabolismo de lipidos
69
- Formato del examen: \\\"Preguntas de desarrollo\\\"
70
- Instrucciones para el asistente
71
- Adjunta los archivos PDF:integracion
72
- PDF del alumno: alumno
73
- Solicita la revisi贸n: \\\"Por favor, compara las respuestas del alumno en el PDF adjunto con las preguntas y respuestas del PDF del docente. Eval煤a cada respuesta como 'Correcta', 'Incorrecta', 'Incompleta' o 'Vac铆a'. Considera que el alumno solo respondi贸 a un subconjunto de las preguntas del examen. Para cada pregunta, indica si fue 'Asignada' o 'No asignada' al alumno. Proporciona retroalimentaci贸n detallada para cada respuesta de las preguntas asignadas, incluyendo la explicaci贸n de errores, la respuesta correcta (del PDF del docente) y sugerencias de temas para reforzar. Al final, ofrece una retroalimentaci贸n general sobre el desempe帽o del alumno y calcula el porcentaje de precisi贸n, bas谩ndote solo en las preguntas que le fueron asignadas.\\\""""
74
-
75
- textsi_1 = """Rol: Act煤a como un asistente de docente experto en la materia del examen de Bioquimica.
76
- Objetivo: Tu tarea principal es analizar las respuestas del alumno a las preguntas del examen, compar谩ndolas con la clave de respuestas y criterios de evaluaci贸n proporcionados en el PDF del docente. Debes identificar las respuestas correctas, incorrectas, incompletas y vac铆as, tomando en cuenta que el alumno pudo haber recibido un subconjunto aleatorio de las preguntas del examen. Proporciona retroalimentaci贸n detallada sobre los errores, 谩reas de mejora y temas que el alumno necesita reforzar. Adem谩s, debes calcular y mostrar el porcentaje de precisi贸n del alumno en el examen, considerando solo las preguntas que le fueron asignadas."""
77
-
78
- # Configurar el modelo
79
  model = GenerativeModel(
80
- "gemini-1.5-pro-001", # Cambiar a Gemini-2
81
  system_instruction=[textsi_1]
82
  )
83
 
84
- # Generar la revisi贸n
85
  response = model.generate_content(
86
- [document1, document2, text1],
87
  generation_config=generation_config,
88
  safety_settings=safety_settings,
89
  stream=False,
90
  )
91
 
92
- # Acceder al texto de la respuesta
93
- feedback = response.text
94
-
95
- return feedback
96
 
97
  except Exception as e:
98
  return f"Error al procesar: {str(e)}"
99
 
100
- # Crear la interfaz con Gradio
101
  interface = gr.Interface(
102
  fn=revisar_examen,
103
  inputs=[
104
- gr.File(label="Archivo de Credenciales JSON"),
105
- gr.File(label="PDF del Docente (Preguntas y Respuestas)"),
106
- gr.File(label="PDF del Alumno (Respuestas)")
107
  ],
108
- outputs=gr.Textbox(label="Retroalimentaci贸n del Examen"),
109
- title="Revisi贸n Autom谩tica de Ex谩menes",
110
- description="Sube el archivo de credenciales JSON de Google Cloud, el PDF del docente y el PDF del alumno para recibir una evaluaci贸n detallada."
111
  )
112
 
113
- # Lanzar la interfaz
114
  interface.launch(debug=True)
115
-
 
1
+ mport gradio as gr
2
+ import PyPDF2
3
+ import os
4
  import vertexai
5
  from vertexai.generative_models import GenerativeModel, Part, SafetySetting
6
+ import base64
7
+
8
+ """
9
+ Este c贸digo se encarga de:
10
+ 1. Leer un archivo de credenciales JSON para configurar Google Cloud.
11
+ 2. Inicializar Vertex AI en la regi贸n us-central1.
12
+ 3. Extraer preguntas y respuestas de dos PDFs: uno del docente y otro del alumno.
13
+ 4. Filtrar 煤nicamente las preguntas realmente respondidas por el alumno.
14
+ 5. Enviar ese contenido filtrado al modelo generativo (Gemini 1.5), con instrucciones para que
15
+ NO mencione preguntas no respondidas.
16
+ """
17
 
18
  # Configuraci贸n del modelo y par谩metros globales
19
  generation_config = {
 
41
  ),
42
  ]
43
 
44
+ def configurar_credenciales(json_path: str):
 
45
  os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = json_path
46
 
47
+ def extraer_texto(pdf_path: str) -> str:
48
+ """Extraer texto de todas las p谩ginas de un PDF."""
49
+ texto_total = ""
50
+ with open(pdf_path, "rb") as f:
51
+ lector = PyPDF2.PdfReader(f)
52
+ for page in lector.pages:
53
+ texto_total += page.extract_text() or ""
54
+ return texto_total
55
+
56
+ def parsear_preguntas_respuestas(texto: str) -> dict:
57
+ """Dado un texto con formato, retorna un dict {pregunta: respuesta}."""
58
+ # Buscamos l铆neas que inicien con "Pregunta" y "Respuesta"
59
+ lineas = texto.split("\n")
60
+ resultado = {}
61
+ pregunta_actual = None
62
+
63
+ for linea in lineas:
64
+ linea_str = linea.strip()
65
+ if linea_str.lower().startswith("pregunta"):
66
+ pregunta_actual = linea_str
67
+ resultado[pregunta_actual] = ""
68
+ elif linea_str.lower().startswith("respuesta") and pregunta_actual:
69
+ # No mezclamos en la misma l铆nea "Pregunta X:"
70
+ # sino que esperamos "Pregunta X" en una l铆nea y "Respuesta X" en la siguiente
71
+ # si el formateo es distinto, ajusta aqu铆.
72
+ # Tomamos lo que est谩 despu茅s de ':'
73
+ partes = linea_str.split(":", 1)
74
+ if len(partes) > 1:
75
+ respuesta = partes[1].strip()
76
+ resultado[pregunta_actual] = respuesta
77
+ return resultado
78
+
79
+ def revisar_examen(json_cred, pdf_docente, pdf_alumno):
80
  try:
81
+ # Configurar credenciales
82
+ configurar_credenciales(json_cred.name)
83
 
84
  # Inicializar Vertex AI
85
  vertexai.init(project="deploygpt", location="us-central1")
86
 
87
+ # Extraer texto de ambos PDFs
88
+ docente_texto = extraer_texto(pdf_docente.name)
89
+ alumno_texto = extraer_texto(pdf_alumno.name)
90
+
91
+ # Parsear preguntas y respuestas
92
+ preguntas_docente = parsear_preguntas_respuestas(docente_texto)
93
+ respuestas_alumno = parsear_preguntas_respuestas(alumno_texto)
94
+
95
+ # Filtrar solo preguntas respondidas
96
+ preguntas_filtradas = {}
97
+ for pregunta_doc, resp_doc in preguntas_docente.items():
98
+ if pregunta_doc in respuestas_alumno:
99
+ # El alumno respondi贸 esta pregunta
100
+ preguntas_filtradas[pregunta_doc] = {
101
+ "respuesta_doc": resp_doc,
102
+ "respuesta_alumno": respuestas_alumno[pregunta_doc]
103
+ }
104
+
105
+ if not preguntas_filtradas:
106
+ return "El alumno no respondi贸 ninguna de las preguntas del docente."
107
+
108
+ # Construir un texto que contenga 煤nicamente las preguntas respondidas
109
+ # e instrucciones claras para no alucinar preguntas.
110
+ # Vamos a pasarlo en 1 solo Part, para forzar a que la LLM no confunda.
111
+ contenido_final = """Instrucciones: Solo hay estas preguntas respondidas por el alumno.
112
+ No menciones preguntas que no est茅n en esta lista. Para cada pregunta, analiza la respuesta.
113
+ Al final, da un resumen.
114
+ """
115
+ for i, (p, data) in enumerate(preguntas_filtradas.items(), 1):
116
+ contenido_final += f"\nPregunta {i}: {p}\n" \
117
+ f"Respuesta del alumno: {data['respuesta_alumno']}\n" \
118
+ f"Respuesta correcta (docente): {data['respuesta_doc']}\n"
119
+
120
+ # Creamos un Part con el contenido filtrado
121
+ part_filtrado = Part(
122
+ mime_type="text/plain",
123
+ text=contenido_final,
124
  )
125
 
126
+ # System instruction, for clarity
127
+ textsi_1 = """Act煤a como un asistente de docente experto en Bioqu铆mica.
128
+ No menciones preguntas que el alumno no respondi贸.
129
+ Analiza 煤nicamente las preguntas provistas en el texto.
130
+ Calcula un porcentaje de precisi贸n basado en las respuestas incluidas.
131
+ """
132
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  model = GenerativeModel(
134
+ "gemini-1.5-pro-001",
135
  system_instruction=[textsi_1]
136
  )
137
 
138
+ # Llamada al modelo con las partes.
139
  response = model.generate_content(
140
+ [part_filtrado],
141
  generation_config=generation_config,
142
  safety_settings=safety_settings,
143
  stream=False,
144
  )
145
 
146
+ return response.text
 
 
 
147
 
148
  except Exception as e:
149
  return f"Error al procesar: {str(e)}"
150
 
151
+ # Interfaz Gradio
152
  interface = gr.Interface(
153
  fn=revisar_examen,
154
  inputs=[
155
+ gr.File(label="Credenciales JSON"),
156
+ gr.File(label="PDF Docente"),
157
+ gr.File(label="PDF Alumno")
158
  ],
159
+ outputs=gr.Textbox(label="Resultado"),
160
+ title="Revisi贸n de Ex谩menes",
161
+ description="Sube tus credenciales, el PDF del docente y el del alumno para revisar las respuestas sin alucinaciones."
162
  )
163
 
 
164
  interface.launch(debug=True)