ksj47 commited on
Commit
3eebe82
·
verified ·
1 Parent(s): 81917a3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +140 -33
app.py CHANGED
@@ -1,34 +1,107 @@
1
  import os
2
  import gradio as gr
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 ---
28
- space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
29
 
30
  if profile:
31
- username= f"{profile.username}"
32
  print(f"User logged in: {username}")
33
  else:
34
  print("User not logged in.")
@@ -38,20 +111,22 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
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
 
51
  # 2. Fetch Questions
52
  print(f"Fetching questions from: {questions_url}")
53
  try:
54
- response = requests.get(questions_url, timeout=15)
55
  response.raise_for_status()
56
  questions_data = response.json()
57
  if not questions_data:
@@ -73,20 +148,26 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
73
  results_log = []
74
  answers_payload = []
75
  print(f"Running agent on {len(questions_data)} questions...")
76
- for item in questions_data:
77
  task_id = item.get("task_id")
78
  question_text = item.get("question")
79
  if not task_id or question_text is None:
80
  print(f"Skipping item with missing task_id or question: {item}")
81
  continue
 
 
82
  try:
83
  submitted_answer = agent(question_text)
84
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
85
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
86
  except Exception as e:
87
  print(f"Error running agent on task {task_id}: {e}")
 
 
 
88
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
89
 
 
90
  if not answers_payload:
91
  print("Agent did not produce any answers to submit.")
92
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
@@ -117,8 +198,8 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
117
  try:
118
  error_json = e.response.json()
119
  error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
120
- except requests.exceptions.JSONDecodeError:
121
- error_detail += f" Response: {e.response.text[:500]}"
122
  status_message = f"Submission Failed: {error_detail}"
123
  print(status_message)
124
  results_df = pd.DataFrame(results_log)
@@ -133,7 +214,7 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
133
  print(status_message)
134
  results_df = pd.DataFrame(results_log)
135
  return status_message, results_df
136
- except Exception as e:
137
  status_message = f"An unexpected error occurred during submission: {e}"
138
  print(status_message)
139
  results_df = pd.DataFrame(results_log)
@@ -146,36 +227,56 @@ with gr.Blocks() as demo:
146
  gr.Markdown(
147
  """
148
  **Instructions:**
149
-
150
- 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
151
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
152
  3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
153
-
154
  ---
155
  **Disclaimers:**
156
- 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).
157
- 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.
 
 
 
158
  """
159
  )
160
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  gr.LoginButton()
162
 
 
163
  run_button = gr.Button("Run Evaluation & Submit All Answers")
164
 
165
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
166
- # Removed max_rows=10 from DataFrame constructor
167
- results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
168
 
 
 
169
  run_button.click(
170
  fn=run_and_submit_all,
 
 
171
  outputs=[status_output, results_table]
172
  )
173
 
174
  if __name__ == "__main__":
175
  print("\n" + "-"*30 + " App Starting " + "-"*30)
176
- # Check for SPACE_HOST and SPACE_ID at startup for information
177
  space_host_startup = os.getenv("SPACE_HOST")
178
- space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
179
 
180
  if space_host_startup:
181
  print(f"✅ SPACE_HOST found: {space_host_startup}")
@@ -183,12 +284,18 @@ if __name__ == "__main__":
183
  else:
184
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
185
 
186
- if space_id_startup: # Print repo URLs if SPACE_ID is found
187
  print(f"✅ SPACE_ID found: {space_id_startup}")
188
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
189
  print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
190
  else:
191
  print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
 
 
 
 
 
 
192
 
193
  print("-"*(60 + len(" App Starting ")) + "\n")
194
 
 
1
  import os
2
  import gradio as gr
3
  import requests
 
4
  import pandas as pd
5
+ from langchain_community.llms import HuggingFaceHub
6
+ # from dotenv import load_dotenv # Uncomment for local testing with a .env file
7
+
8
+ # For local testing, you might want to load environment variables from a .env file
9
+ # (ensure .env is in .gitignore and HUGGINGFACEHUB_API_TOKEN is defined in it)
10
+ # if os.path.exists(".env"):
11
+ # load_dotenv()
12
 
 
13
  # --- Constants ---
14
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
15
 
16
+ # --- Basic Agent Definition --
17
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
18
  class BasicAgent:
19
+ def __init__(self, hf_api_token: str | None = None):
20
+ print("BasicAgent initializing...")
21
+ # Determine the Hugging Face API token
22
+ # Priority: 1. hf_api_token argument (if passed),
23
+ # 2. HUGGINGFACEHUB_API_TOKEN env var,
24
+ # 3. HF_TOKEN env var (common for HF Spaces)
25
+ token_to_use = hf_api_token
26
+ if not token_to_use:
27
+ token_to_use = os.getenv("HUGGINGFACEHUB_API_TOKEN")
28
+ if not token_to_use:
29
+ token_to_use = os.getenv("HF_TOKEN")
30
+
31
+ if not token_to_use:
32
+ # This error will be caught by the agent instantiation try-except block
33
+ # in run_and_submit_all, and a message will be shown in the UI.
34
+ raise ValueError(
35
+ "Hugging Face API token not found. Please set HUGGINGFACEHUB_API_TOKEN or HF_TOKEN "
36
+ "as a secret in your Hugging Face Space. This token is required for the LLM."
37
+ )
38
+
39
+ # You can change the repo_id to any model on the Hugging Face Hub.
40
+ # Ensure the chosen model is suitable for instruction following / question answering.
41
+ # Examples: "mistralai/Mistral-7B-Instruct-v0.1", "google/flan-t5-large", "HuggingFaceH4/zephyr-7b-beta"
42
+ # Using a smaller, faster model for demonstration:
43
+ self.llm_repo_id = "mistralai/Mistral-7B-Instruct-v0.1"
44
+ try:
45
+ self.llm = HuggingFaceHub(
46
+ repo_id=self.llm_repo_id,
47
+ model_kwargs={"temperature": 0.1, "max_new_tokens": 150}, # Adjust max_new_tokens as needed
48
+ huggingfacehub_api_token=token_to_use
49
+ )
50
+ print(f"BasicAgent initialized with LLM: {self.llm_repo_id}")
51
+ except Exception as e:
52
+ print(f"Error initializing HuggingFaceHub: {e}")
53
+ raise ValueError(f"Failed to initialize LLM: {e}. Check token and model repo_id.")
54
+
55
+
56
  def __call__(self, question: str) -> str:
57
+ print(f"Agent received question (first 80 chars): {question[:80]}...")
58
+
59
+ # Prompt engineering is crucial.
60
+ # Instruct the LLM to provide a concise answer without any extra phrases.
61
+ # Per GAIA instructions: "make sure you don’t include the text “FINAL ANSWER”
62
+ # in your submission, just make your agent reply with the answer and nothing else"
63
+ prompt = f"""Answer the following question concisely. Provide only the answer, without any additional explanation, introductory phrases, or labels like "Answer:".
64
+
65
+ Question: {question}
66
+
67
+ Concise Answer:"""
68
+
69
+ try:
70
+ response = self.llm.invoke(prompt)
71
+ answer = response.strip()
72
+
73
+ # Further cleaning if the model still adds prefixes (common with some models)
74
+ # Convert to lower for case-insensitive prefix checking
75
+ answer_lower = answer.lower()
76
+ common_prefixes = ["answer:", "the answer is:", "concise answer:"]
77
+ for prefix in common_prefixes:
78
+ if answer_lower.startswith(prefix):
79
+ answer = answer[len(prefix):].strip()
80
+ break # Remove only the first matching prefix
81
+
82
+ print(f"Agent LLM raw response (first 80 chars): {response[:80]}...")
83
+ print(f"Agent final answer (first 80 chars): {answer[:80]}...")
84
+
85
+ if not answer: # Handle cases where the answer becomes empty after stripping
86
+ print("Warning: Agent produced an empty answer after cleaning.")
87
+ # Return a placeholder that indicates an issue but is still a string
88
+ return "Unable to generate a valid answer."
89
+
90
+ return answer
91
+ except Exception as e:
92
+ print(f"Error during LLM call for question '{question[:50]}...': {e}")
93
+ # Return an error message string, as the submission expects a string answer.
94
+ return f"AGENT_ERROR: LLM call failed. ({type(e).__name__})"
95
 
96
+ def run_and_submit_all(profile: gr.OAuthProfile | None):
97
  """
98
  Fetches all questions, runs the BasicAgent on them, submits all answers,
99
  and displays the results.
100
  """
101
+ space_id = os.getenv("SPACE_ID")
 
102
 
103
  if profile:
104
+ username = f"{profile.username}"
105
  print(f"User logged in: {username}")
106
  else:
107
  print("User not logged in.")
 
111
  questions_url = f"{api_url}/questions"
112
  submit_url = f"{api_url}/submit"
113
 
114
+ # 1. Instantiate Agent
115
  try:
116
+ # The BasicAgent will attempt to find the HF token from env variables.
117
  agent = BasicAgent()
118
  except Exception as e:
119
  print(f"Error instantiating agent: {e}")
120
+ # Return the error message to be displayed in the Gradio UI
121
+ return f"Error initializing agent: {str(e)}", None
122
+
123
+ agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main" if space_id else "local_run_no_space_id"
124
+ print(f"Agent code link: {agent_code}")
125
 
126
  # 2. Fetch Questions
127
  print(f"Fetching questions from: {questions_url}")
128
  try:
129
+ response = requests.get(questions_url, timeout=20) # Increased timeout
130
  response.raise_for_status()
131
  questions_data = response.json()
132
  if not questions_data:
 
148
  results_log = []
149
  answers_payload = []
150
  print(f"Running agent on {len(questions_data)} questions...")
151
+ for i, item in enumerate(questions_data):
152
  task_id = item.get("task_id")
153
  question_text = item.get("question")
154
  if not task_id or question_text is None:
155
  print(f"Skipping item with missing task_id or question: {item}")
156
  continue
157
+
158
+ print(f"\nProcessing question {i+1}/{len(questions_data)}, Task ID: {task_id}")
159
  try:
160
  submitted_answer = agent(question_text)
161
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
162
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
163
  except Exception as e:
164
  print(f"Error running agent on task {task_id}: {e}")
165
+ # Ensure a placeholder is added for submission to maintain structure
166
+ error_answer = f"AGENT_RUNTIME_ERROR: {type(e).__name__}"
167
+ answers_payload.append({"task_id": task_id, "submitted_answer": error_answer})
168
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
169
 
170
+
171
  if not answers_payload:
172
  print("Agent did not produce any answers to submit.")
173
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
 
198
  try:
199
  error_json = e.response.json()
200
  error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
201
+ except requests.exceptions.JSONDecodeError: # Renamed from JSONDecodeError for clarity
202
+ error_detail += f" Response: {e.response.text[:500]}" # Log part of the response
203
  status_message = f"Submission Failed: {error_detail}"
204
  print(status_message)
205
  results_df = pd.DataFrame(results_log)
 
214
  print(status_message)
215
  results_df = pd.DataFrame(results_log)
216
  return status_message, results_df
217
+ except Exception as e: # Catch any other unexpected errors during submission
218
  status_message = f"An unexpected error occurred during submission: {e}"
219
  print(status_message)
220
  results_df = pd.DataFrame(results_log)
 
227
  gr.Markdown(
228
  """
229
  **Instructions:**
230
+ 1. This Space uses a `BasicAgent` with an LLM. Ensure you have set your `HUGGINGFACEHUB_API_TOKEN` or `HF_TOKEN` in the Space secrets for the LLM to work.
 
231
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
232
  3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
 
233
  ---
234
  **Disclaimers:**
235
+ 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 using an LLM).
236
+ This space provides a basic setup. For better GAIA scores, you might need to:
237
+ - Choose a more powerful LLM.
238
+ - Improve prompt engineering.
239
+ - Implement tool usage for questions requiring file access or external actions (the API provides `/files/{task_id}`).
240
  """
241
  )
242
 
243
+ # Session state to hold the Hugging Face profile (token and username)
244
+ # This isn't strictly necessary for this version as token is read from env for LLM
245
+ # but good practice if profile info is needed elsewhere.
246
+ hf_profile_state = gr.State(None)
247
+
248
+ # Wrap LoginButton with a function to capture the profile
249
+ def login_handler(profile: gr.OAuthProfile | None):
250
+ if profile:
251
+ print(f"Profile captured: {profile.username}")
252
+ # If you wanted to pass profile.token to agent:
253
+ # BasicAgent(hf_api_token=profile.token) - but env var method is preferred for LLM token
254
+ return profile
255
+
256
+ # The gr.LoginButton() automatically provides the profile to functions that list it as an input
257
+ # So, `run_and_submit_all` will receive it directly when triggered by `run_button`.
258
+ # No explicit state management for profile passing to `run_and_submit_all` is needed here.
259
  gr.LoginButton()
260
 
261
+
262
  run_button = gr.Button("Run Evaluation & Submit All Answers")
263
 
264
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
265
+ results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True) # Removed max_rows
 
266
 
267
+ # The profile from gr.LoginButton() is implicitly passed as the first argument
268
+ # to `run_and_submit_all` if its signature includes it.
269
  run_button.click(
270
  fn=run_and_submit_all,
271
+ # No explicit inputs needed here if `gr.LoginButton` handles profile passing.
272
+ # If explicit passing was needed from a state: inputs=[hf_profile_state],
273
  outputs=[status_output, results_table]
274
  )
275
 
276
  if __name__ == "__main__":
277
  print("\n" + "-"*30 + " App Starting " + "-"*30)
 
278
  space_host_startup = os.getenv("SPACE_HOST")
279
+ space_id_startup = os.getenv("SPACE_ID")
280
 
281
  if space_host_startup:
282
  print(f"✅ SPACE_HOST found: {space_host_startup}")
 
284
  else:
285
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
286
 
287
+ if space_id_startup:
288
  print(f"✅ SPACE_ID found: {space_id_startup}")
289
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
290
  print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
291
  else:
292
  print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
293
+
294
+ # Check for HF_TOKEN at startup as a hint for the user
295
+ if not (os.getenv("HUGGINGFACEHUB_API_TOKEN") or os.getenv("HF_TOKEN")):
296
+ print("⚠️ WARNING: HUGGINGFACEHUB_API_TOKEN or HF_TOKEN environment variable not found.")
297
+ print(" The LLM agent will likely fail to initialize. Please set this token in your Space secrets.")
298
+
299
 
300
  print("-"*(60 + len(" App Starting ")) + "\n")
301