dracero commited on
Commit
bfac228
·
verified ·
1 Parent(s): 5fbf54a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +70 -369
app.py CHANGED
@@ -3,378 +3,25 @@ import gradio as gr
3
  import requests
4
  import inspect
5
  import pandas as pd
6
- import json
7
- import time
8
- from typing import List, Dict, Any, Optional, Union
9
 
 
10
  # --- Constants ---
11
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
12
 
13
- # --- Improved Agent Definition ---
14
- class GAIAAgent:
15
- """
16
- Agent optimizado para responder preguntas del nivel 1 de GAIA.
17
- Utiliza un modelo de lenguaje grande (LLM) para generar respuestas.
18
- """
19
- def __init__(self, model_name="anthropic/claude-3-haiku-20240307"):
20
- """
21
- Inicializa el agente GAIA.
22
-
23
- Args:
24
- model_name: Nombre del modelo a utilizar (por defecto claude-3-haiku)
25
- """
26
- self.model = self._initialize_model(model_name)
27
- print(f"GAIAAgent initialized with model: {model_name}")
28
-
29
- # Instrucciones para responder preguntas
30
- self.system_prompt = """
31
- Eres un agente de IA diseñado para responder preguntas del GAIA (Generative AI Assessment) nivel 1.
32
- Tu objetivo es proporcionar respuestas precisas, claras y concisas.
33
-
34
- Para preguntas de conocimiento general:
35
- - Proporciona información factual y precisa
36
- - Evita especulaciones o información no verificada
37
-
38
- Para razonamiento lógico:
39
- - Descompón el problema en pasos lógicos
40
- - Explica claramente tu razonamiento
41
-
42
- Para matemáticas:
43
- - Muestra los pasos de tu cálculo
44
- - Verifica tus respuestas
45
-
46
- Para instrucciones directas:
47
- - Sigue exactamente lo que se te pide
48
- - Proporciona exactamente lo solicitado, ni más ni menos
49
-
50
- Proporciona respuestas breves y al punto. No incluyas explicaciones adicionales a menos que sean necesarias.
51
- """
52
-
53
- def _initialize_model(self, model_name):
54
- """
55
- Inicializa el modelo especificado. Configura los parámetros según el modelo elegido.
56
-
57
- Args:
58
- model_name: Nombre/identificador del modelo a utilizar
59
-
60
- Returns:
61
- str: Nombre del modelo configurado
62
- """
63
- # Configurar tokens de API si están disponibles
64
- self.hf_token = os.getenv("HF_TOKEN")
65
- self.openai_token = os.getenv("OPENAI_API_KEY")
66
- self.anthropic_token = os.getenv("ANTHROPIC_API_KEY")
67
-
68
- # Configuración específica según el modelo seleccionado
69
- if "anthropic" in model_name or "claude" in model_name:
70
- self.api_type = "anthropic"
71
- if not self.anthropic_token:
72
- print("⚠️ Anthropic API Key no encontrada. Se usará el sistema de fallback.")
73
- else:
74
- print(f"✅ Usando modelo Anthropic: {model_name}")
75
-
76
- elif "openai" in model_name or "gpt" in model_name:
77
- self.api_type = "openai"
78
- if not self.openai_token:
79
- print("⚠️ OpenAI API Key no encontrada. Se usará el sistema de fallback.")
80
- else:
81
- print(f"✅ Usando modelo OpenAI: {model_name}")
82
-
83
- else:
84
- # Por defecto usar HuggingFace Inference API
85
- self.api_type = "huggingface"
86
- if not self.hf_token:
87
- print("⚠️ HuggingFace Token no encontrado. La API puede tener limitaciones de uso.")
88
- print(f"✅ Usando modelo HuggingFace: {model_name}")
89
-
90
- return model_name
91
-
92
- ios fundamentales, llegaría a una conclusión razonada."
93
-
94
  def __call__(self, question: str) -> str:
95
- """
96
- Procesa la pregunta y devuelve una respuesta.
97
-
98
- Args:
99
- question: La pregunta o instrucción a responder
100
-
101
- Returns:
102
- str: La respuesta generada
103
- """
104
- # Registrar la pregunta recibida
105
- print(f"GAIAAgent recibió pregunta: {question[:100]}...")
106
-
107
- try:
108
- # Análisis preliminar de la pregunta
109
- question_type = self._analyze_question_type(question)
110
- print(f"Tipo de pregunta detectado: {question_type}")
111
-
112
- # Preprocesamiento de la pregunta
113
- processed_question = self._preprocess_question(question)
114
-
115
- # Para preguntas matemáticas simples, usar un solver específico
116
- if question_type == "mathematical" and self._is_simple_math(processed_question):
117
- try:
118
- math_answer = self._solve_math_problem(processed_question)
119
- if math_answer:
120
- return math_answer
121
- except Exception as math_error:
122
- print(f"Error en cálculo matemático: {math_error}")
123
- # Continuar con el flujo normal
124
-
125
- # Llamada al modelo
126
- response = self._call_api(processed_question)
127
-
128
- # Verificación de calidad de respuesta
129
- if not response or len(response.strip()) < 5:
130
- print("⚠️ Respuesta vacía o muy corta del modelo. Usando sistema de fallback.")
131
- response = self._generate_fallback_response(question_type, processed_question)
132
-
133
- # Postprocesamiento de la respuesta
134
- final_answer = self._postprocess_answer(response, question)
135
-
136
- print(f"GAIAAgent generó respuesta ({len(final_answer)} caracteres): {final_answer[:100]}...")
137
- return final_answer
138
-
139
- except Exception as e:
140
- error_msg = f"Error al procesar la pregunta: {str(e)}"
141
- print(error_msg)
142
-
143
- # Intentar generar una respuesta de emergencia basada en el tipo de pregunta
144
- try:
145
- question_type = self._analyze_question_type(question)
146
- fallback_response = self._generate_fallback_response(question_type, question)
147
- return fallback_response
148
- except:
149
- # Respuesta de emergencia básica en caso de error total
150
- return "Basado en mi análisis, la respuesta a esta pregunta involucra considerar múltiples factores relevantes y llegar a una conclusión lógica."
151
-
152
- def _analyze_question_type(self, question: str) -> str:
153
- """
154
- Analiza el tipo de pregunta para mejor direccionamiento.
155
-
156
- Args:
157
- question: La pregunta a analizar
158
-
159
- Returns:
160
- str: Tipo de pregunta detectado
161
- """
162
- question_lower = question.lower()
163
-
164
- # Verificación por palabras clave
165
- if any(word in question_lower for word in ["suma", "resta", "multiplica", "divide", "calcula",
166
- "cuánto es", "resultado de", "valor de", "+", "-", "*", "/"]):
167
- return "mathematical"
168
-
169
- elif any(word in question_lower for word in ["capital de", "país", "continente", "ciudad",
170
- "dónde está", "dónde se encuentra"]):
171
- return "geographical"
172
-
173
- elif any(word in question_lower for word in ["quién", "autor", "escribió", "compuso",
174
- "inventó", "descubrió", "creó"]):
175
- return "factual_person"
176
-
177
- elif any(word in question_lower for word in ["cuándo", "fecha", "año", "siglo", "periodo"]):
178
- return "factual_temporal"
179
-
180
- elif any(word in question_lower for word in ["qué es", "define", "definición", "significa",
181
- "explica", "describe"]):
182
- return "definitional"
183
-
184
- elif any(word in question_lower for word in ["cuál", "qué", "dónde"]):
185
- return "factual_general"
186
-
187
- elif any(word in question_lower for word in ["por qué", "razón", "causa", "motivo"]):
188
- return "explanatory"
189
-
190
- elif "si" in question_lower and any(word in question_lower for word in ["entonces", "luego", "por tanto"]):
191
- return "logical"
192
-
193
- elif any(word in question_lower for word in ["cómo", "procedimiento", "pasos", "método"]):
194
- return "procedural"
195
-
196
- elif any(word in question_lower for word in ["ordena", "clasifica", "enumera", "lista"]):
197
- return "organizational"
198
-
199
- else:
200
- return "general"
201
-
202
- def _is_simple_math(self, question: str) -> bool:
203
- """
204
- Determina si la pregunta es un problema matemático simple que se puede resolver directamente.
205
-
206
- Args:
207
- question: La pregunta a analizar
208
-
209
- Returns:
210
- bool: True si es un problema matemático simple
211
- """
212
- # Detectar patrones de operaciones matemáticas simples
213
- import re
214
-
215
- # Buscar patrones numéricos con operadores
216
- math_pattern = r'\b\d+\s*[\+\-\*\/]\s*\d+\b'
217
- if re.search(math_pattern, question):
218
- return True
219
-
220
- # Buscar números explícitos en la pregunta
221
- numbers = re.findall(r'\b\d+\b', question)
222
- if len(numbers) >= 2:
223
- # Verificar si hay palabras clave de operación
224
- ops = ["suma", "resta", "multiplica", "divide", "más", "menos", "por", "entre"]
225
- if any(op in question.lower() for op in ops):
226
- return True
227
-
228
- return False
229
-
230
- def _solve_math_problem(self, question: str) -> str:
231
- """
232
- Resuelve problemas matemáticos simples.
233
-
234
- Args:
235
- question: La pregunta matemática
236
-
237
- Returns:
238
- str: La respuesta calculada
239
- """
240
- import re
241
-
242
- # Limpiamos y preparamos el texto
243
- math_text = question.lower().replace('?', '').strip()
244
-
245
- # Extraer números
246
- numbers = re.findall(r'\b\d+\.?\d*\b', math_text)
247
- if len(numbers) < 2:
248
- return ""
249
-
250
- # Determinar operación
251
- operation = None
252
- if any(op in math_text for op in ["suma", "más", "sumar", "adicionar", "+"]):
253
- operation = "suma"
254
- elif any(op in math_text for op in ["resta", "menos", "restar", "diferencia", "-"]):
255
- operation = "resta"
256
- elif any(op in math_text for op in ["multiplica", "por", "multiplicar", "producto", "*", "x"]):
257
- operation = "multiplicacion"
258
- elif any(op in math_text for op in ["divide", "entre", "dividir", "cociente", "/", "÷"]):
259
- operation = "division"
260
- else:
261
- return ""
262
-
263
- # Realizar cálculo
264
- try:
265
- num1 = float(numbers[0])
266
- num2 = float(numbers[1])
267
-
268
- if operation == "suma":
269
- result = num1 + num2
270
- return f"La suma de {num1} y {num2} es {result}"
271
- elif operation == "resta":
272
- result = num1 - num2
273
- return f"La resta de {num1} menos {num2} es {result}"
274
- elif operation == "multiplicacion":
275
- result = num1 * num2
276
- return f"La multiplicación de {num1} por {num2} es {result}"
277
- elif operation == "division":
278
- if num2 == 0:
279
- return "No se puede dividir por cero."
280
- result = num1 / num2
281
- return f"La división de {num1} entre {num2} es {result}"
282
-
283
- except Exception as e:
284
- print(f"Error en cálculo: {e}")
285
- return ""
286
-
287
- return ""
288
-
289
- def _generate_fallback_response(self, question_type: str, question: str) -> str:
290
- """
291
- Genera una respuesta de fallback basada en el tipo de pregunta.
292
-
293
- Args:
294
- question_type: Tipo de pregunta identificado
295
- question: La pregunta original
296
-
297
- Returns:
298
- str: Respuesta de fallback
299
- """
300
- # Respuestas específicas para cada tipo de pregunta
301
- if question_type == "mathematical":
302
- return "Para resolver este problema matemático, analizaría los valores y aplicaría las operaciones aritméticas necesarias para obtener el resultado correcto."
303
-
304
- elif question_type == "geographical":
305
- return "Según mi conocimiento de geografía mundial, esta ubicación se encuentra en la región correspondiente, considerando sus características geopolíticas y físicas."
306
-
307
- elif question_type == "factual_person":
308
- return "Basado en los registros históricos y biográficos, esta persona es conocida por sus contribuciones significativas en su campo de especialización."
309
-
310
- elif question_type == "factual_temporal":
311
- return "Este evento ocurrió en el período histórico relevante, considerando el contexto cronológico y los acontecimientos relacionados de la época."
312
-
313
- elif question_type == "definitional":
314
- return "Este concepto se refiere a un conjunto de principios y elementos interrelacionados que constituyen un campo específico del conocimiento, con aplicaciones prácticas y teóricas."
315
-
316
- elif question_type == "explanatory":
317
- return "Este fenómeno se explica por la combinación de factores causales que interactúan de manera compleja, generando el resultado observado a través de mecanismos específicos."
318
-
319
- elif question_type == "logical":
320
- return "Siguiendo los principios de razonamiento lógico, si se aceptan las premisas dadas, entonces la conclusión válida sería la que se deriva directamente de ellas."
321
-
322
- elif question_type == "procedural":
323
- return "El procedimiento adecuado consiste en seguir una secuencia de pasos ordenados para lograr el objetivo, cumpliendo con los requisitos y estándares establecidos."
324
-
325
- else:
326
- return "Basado en un análisis comprehensivo de la información disponible, la respuesta más precisa considera múltiples factores y perspectivas relevantes para este tema."
327
-
328
- def _preprocess_question(self, question: str) -> str:
329
- """
330
- Preprocesa la pregunta para mejorar la calidad de la respuesta.
331
-
332
- Args:
333
- question: La pregunta original
334
-
335
- Returns:
336
- str: La pregunta procesada
337
- """
338
- # Limpieza básica
339
- processed = question.strip()
340
-
341
- # Asegurarse de que termina con signo de interrogación si es una pregunta
342
- if not processed.endswith('?') and ('?' in processed or any(word in processed.lower() for word in
343
- ["qué", "cómo", "cuándo", "dónde", "por qué", "cuál", "quién"])):
344
- processed += '?'
345
-
346
- return processed
347
-
348
- def _postprocess_answer(self, answer: str, original_question: str) -> str:
349
- """
350
- Postprocesa la respuesta para asegurar calidad y relevancia.
351
-
352
- Args:
353
- answer: La respuesta generada por el modelo
354
- original_question: La pregunta original
355
-
356
- Returns:
357
- str: La respuesta procesada
358
- """
359
- # Limpieza básica
360
- processed = answer.strip()
361
-
362
- # Asegurarse de que la respuesta no es demasiado larga
363
- if len(processed) > 1000:
364
- # Truncar y añadir indicador
365
- processed = processed[:997] + "..."
366
-
367
- # Asegurarse de que la respuesta no es vacía
368
- if not processed:
369
- processed = "Basado en la información disponible, la respuesta más precisa sería una evaluación cuidadosa de los factores relevantes."
370
-
371
- return processed
372
 
373
-
374
- # --- Modificar la función run_and_submit_all para usar nuestro nuevo agente ---
375
- def run_and_submit_all(profile: gr.OAuthProfile | None):
376
  """
377
- Fetches all questions, runs the GAIAAgent on them, submits all answers,
378
  and displays the results.
379
  """
380
  # --- Determine HF Space Runtime URL and Repo URL ---
@@ -391,13 +38,13 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
391
  questions_url = f"{api_url}/questions"
392
  submit_url = f"{api_url}/submit"
393
 
394
- # 1. Instantiate Agent (reemplazamos BasicAgent con nuestro GAIAAgent)
395
  try:
396
- agent = GAIAAgent()
397
  except Exception as e:
398
  print(f"Error instantiating agent: {e}")
399
  return f"Error initializing agent: {e}", None
400
- # In the case of an app running as a hugging Face space, this link points toward your codebase
401
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
402
  print(agent_code)
403
 
@@ -490,4 +137,58 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
490
  status_message = f"An unexpected error occurred during submission: {e}"
491
  print(status_message)
492
  results_df = pd.DataFrame(results_log)
493
- return status_message, results_df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  import requests
4
  import inspect
5
  import pandas as pd
 
 
 
6
 
7
+ # (Keep Constants as is)
8
  # --- Constants ---
9
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
10
 
11
+ # --- Basic Agent Definition ---
12
+ # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
13
+ class BasicAgent:
14
+ def __init__(self):
15
+ print("BasicAgent initialized.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  def __call__(self, question: str) -> str:
17
+ print(f"Agent received question (first 50 chars): {question[:50]}...")
18
+ fixed_answer = "This is a default answer."
19
+ print(f"Agent returning fixed answer: {fixed_answer}")
20
+ return fixed_answer
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
+ def run_and_submit_all( profile: gr.OAuthProfile | None):
 
 
23
  """
24
+ Fetches all questions, runs the BasicAgent on them, submits all answers,
25
  and displays the results.
26
  """
27
  # --- Determine HF Space Runtime URL and Repo URL ---
 
38
  questions_url = f"{api_url}/questions"
39
  submit_url = f"{api_url}/submit"
40
 
41
+ # 1. Instantiate Agent ( modify this part to create your agent)
42
  try:
43
+ agent = BasicAgent()
44
  except Exception as e:
45
  print(f"Error instantiating agent: {e}")
46
  return f"Error initializing agent: {e}", None
47
+ # In the case of an app running as a hugging Face space, this link points toward your codebase ( usefull for others so please keep it public)
48
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
49
  print(agent_code)
50
 
 
137
  status_message = f"An unexpected error occurred during submission: {e}"
138
  print(status_message)
139
  results_df = pd.DataFrame(results_log)
140
+ return status_message, results_df
141
+
142
+
143
+ # --- Build Gradio Interface using Blocks ---
144
+ with gr.Blocks() as demo:
145
+ gr.Markdown("# Basic Agent Evaluation Runner")
146
+ gr.Markdown(
147
+ """
148
+ **Instructions:**
149
+ 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
150
+ 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
151
+ 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
152
+ ---
153
+ **Disclaimers:**
154
+ Once clicking on the "submit button, it can take quite some time ( this is the time for the agent to go through all the questions).
155
+ This space provides a basic setup and is intentionally sub-optimal to encourage you to develop your own, more robust solution. For instance for the delay process of the submit button, a solution could be to cache the answers and submit in a seperate action or even to answer the questions in async.
156
+ """
157
+ )
158
+
159
+ gr.LoginButton()
160
+
161
+ run_button = gr.Button("Run Evaluation & Submit All Answers")
162
+
163
+ status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
164
+ # Removed max_rows=10 from DataFrame constructor
165
+ results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
166
+
167
+ run_button.click(
168
+ fn=run_and_submit_all,
169
+ outputs=[status_output, results_table]
170
+ )
171
+
172
+ if __name__ == "__main__":
173
+ print("\n" + "-"*30 + " App Starting " + "-"*30)
174
+ # Check for SPACE_HOST and SPACE_ID at startup for information
175
+ space_host_startup = os.getenv("SPACE_HOST")
176
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
177
+
178
+ if space_host_startup:
179
+ print(f"✅ SPACE_HOST found: {space_host_startup}")
180
+ print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
181
+ else:
182
+ print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
183
+
184
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
185
+ print(f"✅ SPACE_ID found: {space_id_startup}")
186
+ print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
187
+ print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
188
+ else:
189
+ print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
190
+
191
+ print("-"*(60 + len(" App Starting ")) + "\n")
192
+
193
+ print("Launching Gradio Interface for Basic Agent Evaluation...")
194
+ demo.launch(debug=True, share=False)