ksj47 commited on
Commit
ba44119
·
verified ·
1 Parent(s): e623f2e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +215 -224
app.py CHANGED
@@ -2,7 +2,7 @@ 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
@@ -11,82 +11,183 @@ import pandas as pd
11
  # load_dotenv()
12
 
13
  # --- Constants ---
14
-
15
- # TO:
16
- import google.generativeai as genai # For Gemini
17
 
18
  # ... (rest of your existing imports and constants)
19
 
20
  # --- Constants ---
21
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space" # This remains the same
22
 
23
- # --- Basic Agent Definition --
24
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
25
- class BasicAgent:
26
- def __init__(self, google_api_key: str | None = None): # Changed parameter name for clarity
27
- print("BasicAgent initializing with Google Gemini...")
28
 
29
- # Determine the Google API token
30
- token_to_use = google_api_key
31
- if not token_to_use:
32
- token_to_use = os.getenv("GOOGLE_API_KEY") # Standard environment variable for Google API keys
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  if not token_to_use:
35
  raise ValueError(
36
- "Google API key not found. Please set GOOGLE_API_KEY "
37
- "as a secret in your Hugging Face Space. This token is required for Gemini."
38
  )
39
 
 
 
 
 
40
  try:
41
- # Configure the Gemini client
42
- genai.configure(api_key=token_to_use)
43
-
44
- # Specify the Gemini model you want to use.
45
- # As of my last update, "gemini-1.5-pro-latest" is a good choice for high capability.
46
- # "gemini-pro" is also a valid and generally available option.
47
- # "gemini-2.5-pro" is not a known generally available model name as of now.
48
- # Please use a valid model name from: https://ai.google.dev/models/gemini
49
- self.model_name = "gemini-1.5-pro-latest" # Or "gemini-pro"
50
-
51
- # Create the GenerativeModel instance
52
- self.llm = genai.GenerativeModel(self.model_name)
53
-
54
- # Define generation configuration (optional, but good for consistency)
55
- self.generation_config = genai.types.GenerationConfig(
56
- temperature=0.1, # For more deterministic output, good for agents
57
- # max_output_tokens=512 # Equivalent to max_new_tokens
58
- # You can set other parameters here like top_p, top_k
59
  )
60
- # Define safety settings (important for Gemini to avoid overly restrictive blocking)
61
- # Adjust these based on your needs and if you encounter content blocking.
62
- self.safety_settings = [
63
- {
64
- "category": "HARM_CATEGORY_HARASSMENT",
65
- "threshold": "BLOCK_MEDIUM_AND_ABOVE" # Or BLOCK_ONLY_HIGH, BLOCK_NONE
66
- },
67
- {
68
- "category": "HARM_CATEGORY_HATE_SPEECH",
69
- "threshold": "BLOCK_MEDIUM_AND_ABOVE"
70
- },
71
- {
72
- "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
73
- "threshold": "BLOCK_MEDIUM_AND_ABOVE"
74
- },
75
- {
76
- "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
77
- "threshold": "BLOCK_MEDIUM_AND_ABOVE"
78
- }
79
- ]
80
-
81
- print(f"BasicAgent initialized with Google Gemini model: {self.model_name}")
82
  except Exception as e:
83
- print(f"Error initializing Google Gemini client: {e}")
84
- raise ValueError(f"Failed to initialize Gemini: {e}. Check API key and model name.")
85
 
86
  # Modified signature to accept task_id (though not used in this simple version yet)
87
  def __call__(self, question: str, task_id: str | None = None) -> str:
88
- print(f"Agent (Gemini) received question (Task ID: {task_id}, first 80 chars): {question[:80]}...")
89
 
 
 
 
90
  current_prompt = f"""You are a diligent and highly intelligent AI assistant. Your goal is to answer the given `Question` accurately and concisely.
91
  If the question requires multiple steps or information from tools, think step-by-step.
92
 
@@ -109,186 +210,51 @@ Example: If asked "What is 2+2?", your output should be "4".
109
  Now, please answer the following question:
110
  Question: {question}
111
 
112
- Answer:"""
113
 
114
  try:
115
- print(f"Sending to Gemini (first 200 chars of prompt): {current_prompt[:200]}...")
116
-
117
- # FROM: response_text = self.llm.invoke(current_prompt)
118
- # TO: Use Gemini's generate_content method
119
- response = self.llm.generate_content(
120
- current_prompt,
121
- generation_config=self.generation_config,
122
- safety_settings=self.safety_settings
123
- )
124
-
125
- # Extract the text from the Gemini response object
126
- # Need to handle potential errors or blocked content
127
- if response.candidates:
128
- if response.candidates[0].content.parts:
129
- response_text = response.candidates[0].content.parts[0].text
130
- else: # Content might be empty if blocked or other issues
131
- response_text = ""
132
- print("Warning: Gemini response has no content parts.")
133
- if response.prompt_feedback and response.prompt_feedback.block_reason:
134
- print(f"Prompt blocked by Gemini. Reason: {response.prompt_feedback.block_reason_message or response.prompt_feedback.block_reason}")
135
- return f"AGENT_ERROR: Prompt blocked by Gemini ({response.prompt_feedback.block_reason})."
136
- else: # No candidates means something went wrong, possibly blocking
137
- response_text = ""
138
- print("Warning: Gemini response has no candidates.")
139
- if response.prompt_feedback and response.prompt_feedback.block_reason:
140
- print(f"Prompt blocked by Gemini. Reason: {response.prompt_feedback.block_reason_message or response.prompt_feedback.block_reason}")
141
- return f"AGENT_ERROR: Prompt blocked by Gemini ({response.prompt_feedback.block_reason})."
142
- return "AGENT_ERROR: Gemini returned no candidates in response."
143
-
144
-
145
  answer = response_text.strip()
146
 
147
- # (Your existing cleaning logic can largely remain the same)
 
 
 
148
  if "Answer:" in answer:
 
149
  answer = answer.split("Answer:")[-1].strip()
150
 
 
151
  common_prefixes_to_remove = [
152
  "The answer is", "My answer is", "Based on the information", "The final answer is",
153
  "Here is the answer", "I found that", "It seems that"
154
- ]
155
  for prefix in common_prefixes_to_remove:
156
  if answer.lower().startswith(prefix.lower()):
157
  answer = answer[len(prefix):].strip()
 
158
  if answer.startswith(":") or answer.startswith("."):
159
  answer = answer[1:].strip()
160
- break
161
- if "Final Answer:" in answer:
162
- answer = answer.split("Final Answer:")[-1].strip()
 
 
163
 
164
- print(f"Agent (Gemini) LLM raw response (first 80 chars): {response_text[:80]}...")
165
- print(f"Agent (Gemini) cleaned answer (first 80 chars): {answer[:80]}...")
166
 
167
  if not answer:
168
- print("Warning: Agent (Gemini) produced an empty answer after cleaning.")
169
- return "Unable to generate a valid answer from Gemini."
170
 
171
  return answer
172
  except Exception as e:
173
- # Check if it's a specific Google API error for more details
174
- if hasattr(e, 'message'): # google.api_core.exceptions often have a message attribute
175
- error_message = e.message
176
- else:
177
- error_message = str(e)
178
- print(f"Error during Gemini LLM call for question '{question[:50]}...': {error_message}")
179
- return f"AGENT_ERROR: Gemini LLM call failed. ({type(e).__name__}: {error_message})"
180
-
181
- # ... (The rest of your `run_and_submit_all` function and Gradio UI code remains unchanged) ...
182
-
183
- # At the end of the file, in the __main__ block, update the warning message:
184
- # if __name__ == "__main__":
185
- # ... (existing startup prints) ...
186
-
187
- # TO: Check for GOOGLE_API_KEY
188
- if not os.getenv("GOOGLE_API_KEY"):
189
- print("⚠️ WARNING: GOOGLE_API_KEY environment variable not found.")
190
- print(" The Gemini agent will likely fail to initialize. Please set this token in your Space secrets.")
191
-
192
- # ... (rest of existing startup prints and demo.launch()) ...
193
- # --- Basic Agent Definition --
194
- # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
195
- # class BasicAgent:
196
- # def __init__(self, hf_api_token: str | None = None):
197
- # print("BasicAgent initializing...")
198
- # token_to_use = hf_api_token or os.getenv("HUGGINGFACEHUB_API_TOKEN") or os.getenv("HF_TOKEN")
199
-
200
- # if not token_to_use:
201
- # raise ValueError(
202
- # "Hugging Face API token not found. Please set HUGGINGFACEHUB_API_TOKEN or HF_TOKEN "
203
- # "as a secret in your Hugging Face Space. This token is required for the LLM."
204
- # )
205
-
206
- # self.llm_repo_id = "mistralai/Mistral-7B-Instruct-v0.1" # Or your preferred model
207
- # try:
208
- # self.llm = HuggingFaceHub(
209
- # repo_id=self.llm_repo_id,
210
- # # Increased max_new_tokens as the ReAct prompt is long and might generate a longer thought process
211
- # # Temperature 0.0 for more deterministic ReAct output, 0.1 is also fine.
212
- # model_kwargs={"temperature": 0.1, "max_new_tokens": 512},
213
- # huggingfacehub_api_token=token_to_use
214
- # )
215
- # print(f"BasicAgent initialized with LLM: {self.llm_repo_id}")
216
- # except Exception as e:
217
- # print(f"Error initializing HuggingFaceHub: {e}")
218
- # raise ValueError(f"Failed to initialize LLM: {e}. Check token and model repo_id.")
219
-
220
- # # Modified signature to accept task_id (though not used in this simple version yet)
221
- # def __call__(self, question: str, task_id: str | None = None) -> str:
222
- # print(f"Agent received question (Task ID: {task_id}, first 80 chars): {question[:80]}...")
223
-
224
- # # Prompt engineering is crucial.
225
- # # The `question` variable (method argument) is now correctly inserted here.
226
- # # This is a single-shot prompt. A true ReAct agent would have a loop.
227
- # current_prompt = f"""You are a diligent and highly intelligent AI assistant. Your goal is to answer the given `Question` accurately and concisely.
228
- # If the question requires multiple steps or information from tools, think step-by-step.
229
-
230
- # **Available Tools (Conceptual - for your reasoning process, actual tool calls are not implemented in this version):**
231
-
232
- # 1. **`GAIAFileLookup(filename: str) -> str`**: Retrieves file content.
233
- # 2. **`Calculator(expression: str) -> str`**: Performs calculations.
234
- # 3. **`LLM_Query(sub_question: str) -> str`**: For general knowledge.
235
-
236
- # **Output Format Expectation:**
237
- # While you might reason using a "Thought:", "Action:", "Observation:" cycle internally, for this specific task, your final output should be ONLY the direct answer to the question.
238
- # Example: If asked "What is 2+2?", your output should be "4".
239
-
240
- # **Key Guidelines for GAIA Submission:**
241
- # 1. **Conciseness:** The final answer must be precise and directly address the question.
242
- # 2. **No "FINAL ANSWER" Prefix in Submission:** Do NOT include "FINAL ANSWER:" or "The answer is:" in your actual response. Just the answer value.
243
-
244
- # ---
245
-
246
- # Now, please answer the following question:
247
- # Question: {question}
248
-
249
- # Answer:""" # Modified to guide the LLM towards a direct answer for this simplified agent
250
-
251
- # try:
252
- # print(f"Sending to LLM (first 200 chars of prompt): {current_prompt[:200]}...")
253
- # response_text = self.llm.invoke(current_prompt)
254
- # answer = response_text.strip()
255
-
256
- # # Further cleaning if the model still adds prefixes or explanations
257
- # # This is important because we are not doing a full ReAct loop to extract "Final Answer:"
258
-
259
- # # Try to find "Answer:" if the LLM adds it despite instructions
260
- # if "Answer:" in answer:
261
- # # Take text after the last occurrence of "Answer:"
262
- # answer = answer.split("Answer:")[-1].strip()
263
-
264
- # # Remove common conversational prefixes that might slip through
265
- # common_prefixes_to_remove = [
266
- # "The answer is", "My answer is", "Based on the information", "The final answer is",
267
- # "Here is the answer", "I found that", "It seems that"
268
- # ] # Case-insensitive removal
269
- # for prefix in common_prefixes_to_remove:
270
- # if answer.lower().startswith(prefix.lower()):
271
- # answer = answer[len(prefix):].strip()
272
- # # If the first character is now a colon or period, remove it
273
- # if answer.startswith(":") or answer.startswith("."):
274
- # answer = answer[1:].strip()
275
- # break # Only remove one such prefix
276
 
277
- # # If the LLM generated a ReAct-style "Final Answer:", extract from it.
278
- # if "Final Answer:" in answer:
279
- # answer = answer.split("Final Answer:")[-1].strip()
280
-
281
- # print(f"Agent LLM raw response (first 80 chars): {response_text[:80]}...")
282
- # print(f"Agent cleaned answer (first 80 chars): {answer[:80]}...")
283
-
284
- # if not answer:
285
- # print("Warning: Agent produced an empty answer after cleaning.")
286
- # return "Unable to generate a valid answer."
287
-
288
- # return answer
289
- # except Exception as e:
290
- # print(f"Error during LLM call for question '{question[:50]}...': {e}")
291
- # return f"AGENT_ERROR: LLM call failed. ({type(e).__name__})"
292
 
293
  def run_and_submit_all(profile: gr.OAuthProfile | None):
294
  """
@@ -310,7 +276,8 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
310
 
311
  # 1. Instantiate Agent
312
  try:
313
- agent = BasicAgent()
 
314
  except Exception as e:
315
  print(f"Error instantiating agent: {e}")
316
  return f"Error initializing agent: {str(e)}", None
@@ -422,14 +389,14 @@ with gr.Blocks() as demo:
422
  gr.Markdown(
423
  """
424
  **Instructions:**
425
- 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.
426
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
427
  3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
428
  ---
429
  **Disclaimers:**
430
  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).
431
  This space provides a basic setup. For better GAIA scores, you might need to:
432
- - Choose a more powerful LLM.
433
  - Implement a proper ReAct loop with tool parsing and execution.
434
  - Implement actual tool usage (e.g., `/files/{task_id}`, calculator).
435
  """
@@ -437,18 +404,33 @@ with gr.Blocks() as demo:
437
 
438
  hf_profile_state = gr.State(None)
439
 
440
- def login_handler(profile: gr.OAuthProfile | None):
441
- if profile:
442
- print(f"Profile captured: {profile.username}")
443
- return profile
444
-
445
- gr.LoginButton()
 
 
 
 
 
 
 
 
446
  run_button = gr.Button("Run Evaluation & Submit All Answers")
447
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
448
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
449
 
 
 
 
 
450
  run_button.click(
451
  fn=run_and_submit_all,
 
 
 
452
  outputs=[status_output, results_table]
453
  )
454
 
@@ -470,9 +452,18 @@ if __name__ == "__main__":
470
  else:
471
  print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
472
 
 
473
  if not (os.getenv("HUGGINGFACEHUB_API_TOKEN") or os.getenv("HF_TOKEN")):
474
  print("⚠️ WARNING: HUGGINGFACEHUB_API_TOKEN or HF_TOKEN environment variable not found.")
475
  print(" The LLM agent will likely fail to initialize. Please set this token in your Space secrets.")
 
 
 
 
 
 
 
 
476
 
477
  print("-"*(60 + len(" App Starting ")) + "\n")
478
  print("Launching Gradio Interface for Basic Agent Evaluation...")
 
2
  import gradio as gr
3
  import requests
4
  import pandas as pd
5
+ from langchain_community.llms import HuggingFaceHub # Uncommented for 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
 
11
  # load_dotenv()
12
 
13
  # --- Constants ---
14
+ # import google.generativeai as genai # For Gemini - Commented out
 
 
15
 
16
  # ... (rest of your existing imports and constants)
17
 
18
  # --- Constants ---
19
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space" # This remains the same
20
 
21
+ # --- Basic Agent Definition -- (Gemini Agent Commented Out) ---
22
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
23
+ # class BasicAgent:
24
+ # def __init__(self, google_api_key: str | None = None): # Changed parameter name for clarity
25
+ # print("BasicAgent initializing with Google Gemini...")
26
 
27
+ # # Determine the Google API token
28
+ # token_to_use = google_api_key
29
+ # if not token_to_use:
30
+ # token_to_use = os.getenv("GOOGLE_API_KEY") # Standard environment variable for Google API keys
31
+
32
+ # if not token_to_use:
33
+ # raise ValueError(
34
+ # "Google API key not found. Please set GOOGLE_API_KEY "
35
+ # "as a secret in your Hugging Face Space. This token is required for Gemini."
36
+ # )
37
+
38
+ # try:
39
+ # # Configure the Gemini client
40
+ # genai.configure(api_key=token_to_use)
41
+
42
+ # self.model_name = "gemini-1.5-pro-latest" # Or "gemini-pro"
43
+
44
+ # self.llm = genai.GenerativeModel(self.model_name)
45
+
46
+ # self.generation_config = genai.types.GenerationConfig(
47
+ # temperature=0.1,
48
+ # )
49
+ # self.safety_settings = [
50
+ # {
51
+ # "category": "HARM_CATEGORY_HARASSMENT",
52
+ # "threshold": "BLOCK_MEDIUM_AND_ABOVE"
53
+ # },
54
+ # {
55
+ # "category": "HARM_CATEGORY_HATE_SPEECH",
56
+ # "threshold": "BLOCK_MEDIUM_AND_ABOVE"
57
+ # },
58
+ # {
59
+ # "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
60
+ # "threshold": "BLOCK_MEDIUM_AND_ABOVE"
61
+ # },
62
+ # {
63
+ # "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
64
+ # "threshold": "BLOCK_MEDIUM_AND_ABOVE"
65
+ # }
66
+ # ]
67
+
68
+ # print(f"BasicAgent initialized with Google Gemini model: {self.model_name}")
69
+ # except Exception as e:
70
+ # print(f"Error initializing Google Gemini client: {e}")
71
+ # raise ValueError(f"Failed to initialize Gemini: {e}. Check API key and model name.")
72
+
73
+ # def __call__(self, question: str, task_id: str | None = None) -> str:
74
+ # print(f"Agent (Gemini) received question (Task ID: {task_id}, first 80 chars): {question[:80]}...")
75
+
76
+ # current_prompt = f"""You are a diligent and highly intelligent AI assistant. Your goal is to answer the given `Question` accurately and concisely.
77
+ # If the question requires multiple steps or information from tools, think step-by-step.
78
+ # **Available Tools (Conceptual - for your reasoning process, actual tool calls are not implemented in this version):**
79
+ # 1. **`GAIAFileLookup(filename: str) -> str`**: Retrieves file content.
80
+ # 2. **`Calculator(expression: str) -> str`**: Performs calculations.
81
+ # 3. **`LLM_Query(sub_question: str) -> str`**: For general knowledge.
82
+ # **Output Format Expectation:**
83
+ # While you might reason using a "Thought:", "Action:", "Observation:" cycle internally, for this specific task, your final output should be ONLY the direct answer to the question.
84
+ # Example: If asked "What is 2+2?", your output should be "4".
85
+ # **Key Guidelines for GAIA Submission:**
86
+ # 1. **Conciseness:** The final answer must be precise and directly address the question.
87
+ # 2. **No "FINAL ANSWER" Prefix in Submission:** Do NOT include "FINAL ANSWER:" or "The answer is:" in your actual response. Just the answer value.
88
+ # ---
89
+ # Now, please answer the following question:
90
+ # Question: {question}
91
+ # Answer:"""
92
+
93
+ # try:
94
+ # print(f"Sending to Gemini (first 200 chars of prompt): {current_prompt[:200]}...")
95
+
96
+ # response = self.llm.generate_content(
97
+ # current_prompt,
98
+ # generation_config=self.generation_config,
99
+ # safety_settings=self.safety_settings
100
+ # )
101
+
102
+ # if response.candidates:
103
+ # if response.candidates[0].content.parts:
104
+ # response_text = response.candidates[0].content.parts[0].text
105
+ # else:
106
+ # response_text = ""
107
+ # print("Warning: Gemini response has no content parts.")
108
+ # if response.prompt_feedback and response.prompt_feedback.block_reason:
109
+ # print(f"Prompt blocked by Gemini. Reason: {response.prompt_feedback.block_reason_message or response.prompt_feedback.block_reason}")
110
+ # return f"AGENT_ERROR: Prompt blocked by Gemini ({response.prompt_feedback.block_reason})."
111
+ # else:
112
+ # response_text = ""
113
+ # print("Warning: Gemini response has no candidates.")
114
+ # if response.prompt_feedback and response.prompt_feedback.block_reason:
115
+ # print(f"Prompt blocked by Gemini. Reason: {response.prompt_feedback.block_reason_message or response.prompt_feedback.block_reason}")
116
+ # return f"AGENT_ERROR: Prompt blocked by Gemini ({response.prompt_feedback.block_reason})."
117
+ # return "AGENT_ERROR: Gemini returned no candidates in response."
118
+
119
+
120
+ # answer = response_text.strip()
121
+
122
+ # if "Answer:" in answer:
123
+ # answer = answer.split("Answer:")[-1].strip()
124
+
125
+ # common_prefixes_to_remove = [
126
+ # "The answer is", "My answer is", "Based on the information", "The final answer is",
127
+ # "Here is the answer", "I found that", "It seems that"
128
+ # ]
129
+ # for prefix in common_prefixes_to_remove:
130
+ # if answer.lower().startswith(prefix.lower()):
131
+ # answer = answer[len(prefix):].strip()
132
+ # if answer.startswith(":") or answer.startswith("."):
133
+ # answer = answer[1:].strip()
134
+ # break
135
+ # if "Final Answer:" in answer:
136
+ # answer = answer.split("Final Answer:")[-1].strip()
137
+
138
+ # print(f"Agent (Gemini) LLM raw response (first 80 chars): {response_text[:80]}...")
139
+ # print(f"Agent (Gemini) cleaned answer (first 80 chars): {answer[:80]}...")
140
+
141
+ # if not answer:
142
+ # print("Warning: Agent (Gemini) produced an empty answer after cleaning.")
143
+ # return "Unable to generate a valid answer from Gemini."
144
+
145
+ # return answer
146
+ # except Exception as e:
147
+ # if hasattr(e, 'message'):
148
+ # error_message = e.message
149
+ # else:
150
+ # error_message = str(e)
151
+ # print(f"Error during Gemini LLM call for question '{question[:50]}...': {error_message}")
152
+ # return f"AGENT_ERROR: Gemini LLM call failed. ({type(e).__name__}: {error_message})"
153
+
154
+ # --- Basic Agent Definition -- (HuggingFaceHub Agent Activated) ---
155
+ # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
156
+ class BasicAgent:
157
+ def __init__(self, hf_api_token: str | None = None):
158
+ print("BasicAgent initializing with HuggingFaceHub...")
159
+ token_to_use = hf_api_token or os.getenv("HUGGINGFACEHUB_API_TOKEN") or os.getenv("HF_TOKEN")
160
 
161
  if not token_to_use:
162
  raise ValueError(
163
+ "Hugging Face API token not found. Please set HUGGINGFACEHUB_API_TOKEN or HF_TOKEN "
164
+ "as a secret in your Hugging Face Space. This token is required for the LLM."
165
  )
166
 
167
+ self.llm_repo_id = "mistralai/Mistral-7B-Instruct-v0.1" # Or your preferred model
168
+ # self.llm_repo_id = "HuggingFaceH4/zephyr-7b-beta" # Another option
169
+ # self.llm_repo_id = "google/gemma-7b-it" # Another option, ensure you have access/agreed to terms
170
+
171
  try:
172
+ self.llm = HuggingFaceHub(
173
+ repo_id=self.llm_repo_id,
174
+ # Increased max_new_tokens as the ReAct prompt is long and might generate a longer thought process
175
+ # Temperature 0.0 for more deterministic ReAct output, 0.1 is also fine.
176
+ model_kwargs={"temperature": 0.1, "max_new_tokens": 512},
177
+ huggingfacehub_api_token=token_to_use
 
 
 
 
 
 
 
 
 
 
 
 
178
  )
179
+ print(f"BasicAgent initialized with LLM: {self.llm_repo_id}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  except Exception as e:
181
+ print(f"Error initializing HuggingFaceHub: {e}")
182
+ raise ValueError(f"Failed to initialize LLM: {e}. Check token and model repo_id.")
183
 
184
  # Modified signature to accept task_id (though not used in this simple version yet)
185
  def __call__(self, question: str, task_id: str | None = None) -> str:
186
+ print(f"Agent (HF) received question (Task ID: {task_id}, first 80 chars): {question[:80]}...")
187
 
188
+ # Prompt engineering is crucial.
189
+ # The `question` variable (method argument) is now correctly inserted here.
190
+ # This is a single-shot prompt. A true ReAct agent would have a loop.
191
  current_prompt = f"""You are a diligent and highly intelligent AI assistant. Your goal is to answer the given `Question` accurately and concisely.
192
  If the question requires multiple steps or information from tools, think step-by-step.
193
 
 
210
  Now, please answer the following question:
211
  Question: {question}
212
 
213
+ Answer:""" # Modified to guide the LLM towards a direct answer for this simplified agent
214
 
215
  try:
216
+ print(f"Sending to LLM (HF Hub) (first 200 chars of prompt): {current_prompt[:200]}...")
217
+ # Langchain's HuggingFaceHub.invoke expects a string and returns a string
218
+ response_text = self.llm.invoke(current_prompt)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
  answer = response_text.strip()
220
 
221
+ # Further cleaning if the model still adds prefixes or explanations
222
+ # This is important because we are not doing a full ReAct loop to extract "Final Answer:"
223
+
224
+ # Try to find "Answer:" if the LLM adds it despite instructions
225
  if "Answer:" in answer:
226
+ # Take text after the last occurrence of "Answer:"
227
  answer = answer.split("Answer:")[-1].strip()
228
 
229
+ # Remove common conversational prefixes that might slip through
230
  common_prefixes_to_remove = [
231
  "The answer is", "My answer is", "Based on the information", "The final answer is",
232
  "Here is the answer", "I found that", "It seems that"
233
+ ] # Case-insensitive removal
234
  for prefix in common_prefixes_to_remove:
235
  if answer.lower().startswith(prefix.lower()):
236
  answer = answer[len(prefix):].strip()
237
+ # If the first character is now a colon or period, remove it
238
  if answer.startswith(":") or answer.startswith("."):
239
  answer = answer[1:].strip()
240
+ break # Only remove one such prefix
241
+
242
+ # If the LLM generated a ReAct-style "Final Answer:", extract from it.
243
+ if "Final Answer:" in answer: # Check if "Final Answer:" exists in the string
244
+ answer = answer.split("Final Answer:")[-1].strip() # Get content after "Final Answer:"
245
 
246
+ print(f"Agent (HF) LLM raw response (first 80 chars): {response_text[:80]}...")
247
+ print(f"Agent (HF) cleaned answer (first 80 chars): {answer[:80]}...")
248
 
249
  if not answer:
250
+ print("Warning: Agent (HF) produced an empty answer after cleaning.")
251
+ return "AGENT_ERROR: LLM produced an empty answer." # More specific error
252
 
253
  return answer
254
  except Exception as e:
255
+ print(f"Error during LLM call for question '{question[:50]}...': {e}")
256
+ return f"AGENT_ERROR: LLM call failed. ({type(e).__name__}: {str(e)})"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
 
259
  def run_and_submit_all(profile: gr.OAuthProfile | None):
260
  """
 
276
 
277
  # 1. Instantiate Agent
278
  try:
279
+ # This will now instantiate the HuggingFaceHub BasicAgent
280
+ agent = BasicAgent()
281
  except Exception as e:
282
  print(f"Error instantiating agent: {e}")
283
  return f"Error initializing agent: {str(e)}", None
 
389
  gr.Markdown(
390
  """
391
  **Instructions:**
392
+ 1. This Space uses a `BasicAgent` with an LLM from HuggingFace Hub. Ensure you have set your `HUGGINGFACEHUB_API_TOKEN` or `HF_TOKEN` in the Space secrets for the LLM to work.
393
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
394
  3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
395
  ---
396
  **Disclaimers:**
397
  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).
398
  This space provides a basic setup. For better GAIA scores, you might need to:
399
+ - Choose a more powerful LLM (e.g., from the `llm_repo_id` options in `BasicAgent` or others).
400
  - Implement a proper ReAct loop with tool parsing and execution.
401
  - Implement actual tool usage (e.g., `/files/{task_id}`, calculator).
402
  """
 
404
 
405
  hf_profile_state = gr.State(None)
406
 
407
+ # This handler is not strictly necessary for the profile data itself if just using gr.LoginButton()
408
+ # but can be useful if you need to react to login events beyond what the button click does.
409
+ # For this app, `profile` argument to `run_and_submit_all` is handled directly by Gradio if login is used.
410
+ # def login_handler(profile: gr.OAuthProfile | None):
411
+ # if profile:
412
+ # print(f"Profile captured: {profile.username}")
413
+ # return profile
414
+
415
+ # The LoginButton itself enables OAuth.
416
+ # When `run_and_submit_all` is called, if the user is logged in,
417
+ # Gradio automatically passes the gr.OAuthProfile object as the first argument
418
+ # if the function signature expects it (like `profile: gr.OAuthProfile | None`).
419
+ login_button = gr.LoginButton()
420
+
421
  run_button = gr.Button("Run Evaluation & Submit All Answers")
422
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
423
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
424
 
425
+ # The `login_button` itself doesn't need to be an input to `run_and_submit_all`
426
+ # if `run_and_submit_all` is typed with `gr.OAuthProfile | None` as its first argument.
427
+ # Gradio handles passing the profile automatically on click if the user is logged in.
428
+ # If the user is not logged in, `profile` will be `None`.
429
  run_button.click(
430
  fn=run_and_submit_all,
431
+ # No explicit inputs needed here if the first arg of fn is type-hinted with gr.OAuthProfile
432
+ # and you are using gr.LoginButton(). Gradio handles this.
433
+ # inputs=[hf_profile_state], # Not needed if using gr.OAuthProfile type hint
434
  outputs=[status_output, results_table]
435
  )
436
 
 
452
  else:
453
  print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
454
 
455
+ # Updated token check for HuggingFace Hub
456
  if not (os.getenv("HUGGINGFACEHUB_API_TOKEN") or os.getenv("HF_TOKEN")):
457
  print("⚠️ WARNING: HUGGINGFACEHUB_API_TOKEN or HF_TOKEN environment variable not found.")
458
  print(" The LLM agent will likely fail to initialize. Please set this token in your Space secrets.")
459
+ # else: # Optional: confirm if token is found
460
+ # print("✅ HUGGINGFACEHUB_API_TOKEN or HF_TOKEN found (or assumed to be set).")
461
+
462
+
463
+ # Commented out the GOOGLE_API_KEY check as it's no longer relevant for this agent
464
+ # if not os.getenv("GOOGLE_API_KEY"):
465
+ # print("⚠️ WARNING: GOOGLE_API_KEY environment variable not found.")
466
+ # print(" The Gemini agent will likely fail to initialize. Please set this token in your Space secrets.")
467
 
468
  print("-"*(60 + len(" App Starting ")) + "\n")
469
  print("Launching Gradio Interface for Basic Agent Evaluation...")