notsakeeb commited on
Commit
722688a
·
verified ·
1 Parent(s): 74ee3eb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +246 -90
app.py CHANGED
@@ -8,6 +8,10 @@ from langgraph.graph.message import add_messages
8
  from langchain_core.messages import AnyMessage, HumanMessage
9
  from langgraph.graph import START, StateGraph
10
  from langchain_google_genai import ChatGoogleGenerativeAI
 
 
 
 
11
 
12
  # (Keep Constants as is)
13
  # --- Constants ---
@@ -16,136 +20,285 @@ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
16
  # --- Basic Agent Definition ---
17
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
18
  gemini_api_key = os.getenv("GEMINI_API_KEY")
19
- tivaly_api_key = os.getenv()
20
- class BasicAgent:
21
- def __init__(self):
22
- print("BasicAgent initialized.")
23
- def __call__(self, question: str) -> str:
24
- print(f"Agent received question (first 50 chars): {question[:50]}...")
25
- fixed_answer = "This is a default answer."
26
- print(f"Agent returning fixed answer: {fixed_answer}")
27
- return fixed_answer
28
-
29
- def run_and_submit_all( profile: gr.OAuthProfile | None):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  """
31
- Fetches all questions, runs the BasicAgent on them, submits all answers,
32
- and displays the results.
33
  """
34
  # --- Determine HF Space Runtime URL and Repo URL ---
35
  space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
36
-
37
  if profile:
38
  username= f"{profile.username}"
39
  print(f"User logged in: {username}")
40
  else:
41
  print("User not logged in.")
42
  return "Please Login to Hugging Face with the button.", None
43
-
44
- api_url = DEFAULT_API_URL
45
- questions_url = f"{api_url}/questions"
46
- submit_url = f"{api_url}/submit"
47
-
48
- # 1. Instantiate Agent ( modify this part to create your agent)
49
  try:
50
- agent = BasicAgent()
51
  except Exception as e:
52
  print(f"Error instantiating agent: {e}")
53
  return f"Error initializing agent: {e}", None
54
- # 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)
 
55
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
56
  print(agent_code)
57
-
58
  # 2. Fetch Questions
59
- print(f"Fetching questions from: {questions_url}")
60
- try:
61
- response = requests.get(questions_url, timeout=15)
62
- response.raise_for_status()
63
- questions_data = response.json()
64
- if not questions_data:
65
- print("Fetched questions list is empty.")
66
- return "Fetched questions list is empty or invalid format.", None
67
- print(f"Fetched {len(questions_data)} questions.")
68
- except requests.exceptions.RequestException as e:
69
- print(f"Error fetching questions: {e}")
70
- return f"Error fetching questions: {e}", None
71
- except requests.exceptions.JSONDecodeError as e:
72
- print(f"Error decoding JSON response from questions endpoint: {e}")
73
- print(f"Response text: {response.text[:500]}")
74
- return f"Error decoding server response for questions: {e}", None
75
- except Exception as e:
76
- print(f"An unexpected error occurred fetching questions: {e}")
77
- return f"An unexpected error occurred fetching questions: {e}", None
78
-
79
  # 3. Run your Agent
80
  results_log = []
81
  answers_payload = []
82
  print(f"Running agent on {len(questions_data)} questions...")
 
83
  for item in questions_data:
84
  task_id = item.get("task_id")
85
  question_text = item.get("question")
 
86
  if not task_id or question_text is None:
87
  print(f"Skipping item with missing task_id or question: {item}")
88
  continue
 
 
 
 
 
 
 
 
89
  try:
90
- submitted_answer = agent(question_text)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
92
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
 
93
  except Exception as e:
94
- print(f"Error running agent on task {task_id}: {e}")
95
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
96
-
97
  if not answers_payload:
98
  print("Agent did not produce any answers to submit.")
99
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
100
-
101
  # 4. Prepare Submission
102
  submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
103
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
104
  print(status_update)
105
-
106
  # 5. Submit
107
- print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  try:
109
- response = requests.post(submit_url, json=submission_data, timeout=60)
110
- response.raise_for_status()
111
- result_data = response.json()
112
- final_status = (
113
- f"Submission Successful!\n"
114
- f"User: {result_data.get('username')}\n"
115
- f"Overall Score: {result_data.get('score', 'N/A')}% "
116
- f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
117
- f"Message: {result_data.get('message', 'No message received.')}"
118
- )
119
- print("Submission successful.")
120
- results_df = pd.DataFrame(results_log)
121
- return final_status, results_df
122
- except requests.exceptions.HTTPError as e:
123
- error_detail = f"Server responded with status {e.response.status_code}."
124
- try:
125
- error_json = e.response.json()
126
- error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
127
- except requests.exceptions.JSONDecodeError:
128
- error_detail += f" Response: {e.response.text[:500]}"
129
- status_message = f"Submission Failed: {error_detail}"
130
- print(status_message)
131
- results_df = pd.DataFrame(results_log)
132
- return status_message, results_df
133
- except requests.exceptions.Timeout:
134
- status_message = "Submission Failed: The request timed out."
135
- print(status_message)
136
- results_df = pd.DataFrame(results_log)
137
- return status_message, results_df
138
- except requests.exceptions.RequestException as e:
139
- status_message = f"Submission Failed: Network error - {e}"
140
- print(status_message)
141
- results_df = pd.DataFrame(results_log)
142
- return status_message, results_df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  except Exception as e:
144
- status_message = f"An unexpected error occurred during submission: {e}"
145
- print(status_message)
146
- results_df = pd.DataFrame(results_log)
147
- return status_message, results_df
 
 
 
 
 
 
 
148
 
 
149
 
150
  # --- Build Gradio Interface using Blocks ---
151
  with gr.Blocks() as demo:
@@ -153,11 +306,9 @@ with gr.Blocks() as demo:
153
  gr.Markdown(
154
  """
155
  **Instructions:**
156
-
157
  1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
158
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
159
  3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
160
-
161
  ---
162
  **Disclaimers:**
163
  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).
@@ -168,6 +319,7 @@ with gr.Blocks() as demo:
168
  gr.LoginButton()
169
 
170
  run_button = gr.Button("Run Evaluation & Submit All Answers")
 
171
 
172
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
173
  # Removed max_rows=10 from DataFrame constructor
@@ -177,6 +329,10 @@ with gr.Blocks() as demo:
177
  fn=run_and_submit_all,
178
  outputs=[status_output, results_table]
179
  )
 
 
 
 
180
 
181
  if __name__ == "__main__":
182
  print("\n" + "-"*30 + " App Starting " + "-"*30)
 
8
  from langchain_core.messages import AnyMessage, HumanMessage
9
  from langgraph.graph import START, StateGraph
10
  from langchain_google_genai import ChatGoogleGenerativeAI
11
+ from ToolSet import toolset
12
+ from utils.final_answer import extract_final_answer
13
+ from utils.handle_file import handle_attachment
14
+ from assignment_api import get_all_questions, get_one_random_question, submit
15
 
16
  # (Keep Constants as is)
17
  # --- Constants ---
 
20
  # --- Basic Agent Definition ---
21
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
22
  gemini_api_key = os.getenv("GEMINI_API_KEY")
23
+ tivaly_api_key = os.getenv("TAVILY_API_KEY")
24
+
25
+ llm = ChatGoogleGenerativeAI(
26
+ model="gemini-2.0-flash",
27
+ temperature=0,
28
+ google_api_key = gemini_api_key
29
+ )
30
+
31
+ llm_with_tools = llm.bind_tools(toolset)
32
+
33
+ sys_prompt_file = open("sys_prompt.txt")
34
+ sys_prompt = sys_prompt_file.read()
35
+
36
+ class AgentState(TypedDict):
37
+ messages: Annotated[list[AnyMessage], add_messages]
38
+
39
+ def assistant(state: AgentState):
40
+ return {
41
+ "messages": [llm_with_tools.invoke([sys_prompt]+state["messages"])],
42
+ }
43
+
44
+ builder = StateGraph(AgentState)
45
+
46
+ builder.add_node("assistant", assistant)
47
+ builder.add_node("tools", ToolNode(available_tools))
48
+
49
+ builder.add_edge(START, "assistant")
50
+ builder.add_conditional_edges(
51
+ "assistant",
52
+ tools_condition
53
+ )
54
+ builder.add_edge("tools","assistant")
55
+
56
+ gaia_agent = builder.compile()
57
+
58
+ def run_and_submit_all(profile: gr.OAuthProfile | None):
59
  """
60
+ Fetches all questions, runs the agent on them, submits all answers,
61
+ and displays the results. Handles attachments if present.
62
  """
63
  # --- Determine HF Space Runtime URL and Repo URL ---
64
  space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
 
65
  if profile:
66
  username= f"{profile.username}"
67
  print(f"User logged in: {username}")
68
  else:
69
  print("User not logged in.")
70
  return "Please Login to Hugging Face with the button.", None
71
+
72
+ # 1. Instantiate Agent (modify this part to create your agent)
 
 
 
 
73
  try:
74
+ agent = my_agent
75
  except Exception as e:
76
  print(f"Error instantiating agent: {e}")
77
  return f"Error initializing agent: {e}", None
78
+
79
+ # In the case of an app running as a hugging Face space, this link points toward your codebase (useful for others so please keep it public)
80
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
81
  print(agent_code)
82
+
83
  # 2. Fetch Questions
84
+ questions_data = get_all_questions()
85
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  # 3. Run your Agent
87
  results_log = []
88
  answers_payload = []
89
  print(f"Running agent on {len(questions_data)} questions...")
90
+
91
  for item in questions_data:
92
  task_id = item.get("task_id")
93
  question_text = item.get("question")
94
+
95
  if not task_id or question_text is None:
96
  print(f"Skipping item with missing task_id or question: {item}")
97
  continue
98
+
99
+ # 2.2 Handle attachment if present
100
+ attachment_info = None
101
+ if "file_name" in item and item["file_name"]:
102
+ file_name = item.get("file_name")
103
+ attachment_info = handle_attachment(task_id, file_name)
104
+ print(f"Attachment handling result: {attachment_info['status']}")
105
+
106
  try:
107
+ # Prepare messages based on attachment handling
108
+ messages = [
109
+ SystemMessage(content=SYSTEM_PROMPT),
110
+ SystemMessage(content=f"Current task id: {task_id}")
111
+ ]
112
+
113
+ # If we have an attachment that Claude can process directly
114
+ if attachment_info and attachment_info["status"] == "success" and attachment_info["handling"] == "direct":
115
+ # Encode content for direct inclusion
116
+ encoded_content = base64.b64encode(attachment_info["raw_content"]).decode('utf-8')
117
+ content_type = attachment_info["content_type"]
118
+
119
+ # Create multimodal message
120
+ if content_type.startswith('image/'):
121
+ multimodal_content = [
122
+ {"type": "text", "text": question_text},
123
+ {
124
+ "type": "image",
125
+ "source": {
126
+ "type": "base64",
127
+ "media_type": content_type,
128
+ "data": encoded_content
129
+ }
130
+ }
131
+ ]
132
+ elif content_type == "application/pdf" or "spreadsheet" in content_type or "excel" in content_type or "csv" in content_type:
133
+ multimodal_content = [
134
+ {"type": "text", "text": question_text},
135
+ {
136
+ "type": "file",
137
+ "source": {
138
+ "type": "base64",
139
+ "media_type": content_type,
140
+ "data": encoded_content
141
+ },
142
+ "name": attachment_info["file_name"]
143
+ }
144
+ ]
145
+
146
+ messages.append(HumanMessage(content=multimodal_content))
147
+
148
+ # If we have an attachment that needs tool processing
149
+ elif attachment_info and attachment_info["status"] == "success" and attachment_info["handling"] == "tool":
150
+ # Add info about the file to the question
151
+ file_info = (
152
+ f"{question_text}\n\n"
153
+ f"Note: This task has an attached file that can be accessed at: {attachment_info['file_path']}\n"
154
+ f"File type: {attachment_info['content_type']}"
155
+ )
156
+ messages.append(HumanMessage(content=file_info))
157
+
158
+ # If no attachment or error with attachment
159
+ else:
160
+ messages.append(HumanMessage(content=question_text))
161
+
162
+ # Invoke the agent with the prepared messages
163
+ agent_answer = agent.invoke({"messages": messages},{"recursion_limit": 50})
164
+ submitted_answer = extract_final_answer(agent_answer['messages'][-1].content)
165
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
166
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
167
+
168
  except Exception as e:
169
+ print(f"Error running agent on task {task_id}: {e}")
170
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
171
+
172
  if not answers_payload:
173
  print("Agent did not produce any answers to submit.")
174
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
175
+
176
  # 4. Prepare Submission
177
  submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
178
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
179
  print(status_update)
180
+
181
  # 5. Submit
182
+ return submit(submission_data, results_log)
183
+
184
+ def run_and_submit_one( profile: gr.OAuthProfile | None):
185
+ # --- Determine HF Space Runtime URL and Repo URL ---
186
+ space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
187
+
188
+ if profile:
189
+ username= f"{profile.username}"
190
+ print(f"User logged in: {username}")
191
+ else:
192
+ print("User not logged in.")
193
+ return "Please Login to Hugging Face with the button.", None
194
+
195
+ # 1. Instantiate Agent ( modify this part to create your agent)
196
  try:
197
+ agent = my_agent
198
+ except Exception as e:
199
+ print(f"Error instantiating agent: {e}")
200
+ return f"Error initializing agent: {e}", None
201
+ # 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)
202
+ agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
203
+ print(agent_code)
204
+
205
+ # 2. Fetch Questions
206
+ questions_data = get_one_random_question()
207
+ print("questions_data:", questions_data)
208
+
209
+ # 2.2 Handle attachment if present
210
+ attachment_info = None
211
+ if "file_name" in questions_data and questions_data["file_name"]:
212
+ task_id = questions_data.get("task_id")
213
+ file_name = questions_data.get("file_name")
214
+ attachment_info = handle_attachment(task_id, file_name)
215
+ print(f"Attachment handling result: {attachment_info['status']}")
216
+
217
+ # 3. Run your Agent
218
+ results_log = []
219
+ answers_payload = []
220
+ print(f"Running agent on {len(questions_data)} questions...")
221
+
222
+ task_id = questions_data.get("task_id")
223
+ question_text = questions_data.get("question")
224
+
225
+ if not task_id or question_text is None:
226
+ print(f"Skipping item with missing task_id or question")
227
+ try:
228
+ # Prepare messages based on attachment handling
229
+ messages = [
230
+ SystemMessage(content=SYSTEM_PROMPT),
231
+ SystemMessage(content=f"Current task id: {task_id}")
232
+ ]
233
+
234
+ # If we have an attachment that Claude can process directly
235
+ if attachment_info and attachment_info["status"] == "success" and attachment_info["handling"] == "direct":
236
+ # Encode content for direct inclusion
237
+ encoded_content = base64.b64encode(attachment_info["raw_content"]).decode('utf-8')
238
+ content_type = attachment_info["content_type"]
239
+
240
+ # Create multimodal message
241
+ if content_type.startswith('image/'):
242
+ multimodal_content = [
243
+ {"type": "text", "text": question_text},
244
+ {
245
+ "type": "image",
246
+ "source": {
247
+ "type": "base64",
248
+ "media_type": content_type,
249
+ "data": encoded_content
250
+ }
251
+ }
252
+ ]
253
+ elif content_type == "application/pdf" or "spreadsheet" in content_type or "excel" in content_type or "csv" in content_type:
254
+ multimodal_content = [
255
+ {"type": "text", "text": question_text},
256
+ {
257
+ "type": "file",
258
+ "source": {
259
+ "type": "base64",
260
+ "media_type": content_type,
261
+ "data": encoded_content
262
+ },
263
+ "name": attachment_info["file_name"]
264
+ }
265
+ ]
266
+
267
+ messages.append(HumanMessage(content=multimodal_content))
268
+
269
+ # If we have an attachment that needs tool processing
270
+ elif attachment_info and attachment_info["status"] == "success" and attachment_info["handling"] == "tool":
271
+ # Add info about the file to the question
272
+ file_info = (
273
+ f"{question_text}\n\n"
274
+ f"Note: This task has an attached file that can be accessed at: {attachment_info['file_path']}\n"
275
+ f"File type: {attachment_info['content_type']}"
276
+ )
277
+ messages.append(HumanMessage(content=file_info))
278
+
279
+ # If no attachment or error with attachment
280
+ else:
281
+ messages.append(HumanMessage(content=question_text))
282
+
283
+ # Invoke the agent with the prepared messages
284
+ agent_answer = agent.invoke({"messages": messages},{"recursion_limit": 50})
285
+ submitted_answer = extract_final_answer(agent_answer['messages'][-1].content)
286
+ answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
287
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
288
  except Exception as e:
289
+ print(f"Error running agent on task {task_id}: {e}")
290
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
291
+
292
+ if not answers_payload:
293
+ print("Agent did not produce any answers to submit.")
294
+ return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
295
+
296
+ # 4. Prepare Submission
297
+ submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
298
+ status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
299
+ print(status_update)
300
 
301
+ return submit(submission_data, results_log)
302
 
303
  # --- Build Gradio Interface using Blocks ---
304
  with gr.Blocks() as demo:
 
306
  gr.Markdown(
307
  """
308
  **Instructions:**
 
309
  1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
310
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
311
  3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
 
312
  ---
313
  **Disclaimers:**
314
  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).
 
319
  gr.LoginButton()
320
 
321
  run_button = gr.Button("Run Evaluation & Submit All Answers")
322
+ run_one_button = gr.Button("Run one question and submit")
323
 
324
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
325
  # Removed max_rows=10 from DataFrame constructor
 
329
  fn=run_and_submit_all,
330
  outputs=[status_output, results_table]
331
  )
332
+ run_one_button.click(
333
+ fn=run_and_submit_one,
334
+ outputs=[status_output, results_table]
335
+ )
336
 
337
  if __name__ == "__main__":
338
  print("\n" + "-"*30 + " App Starting " + "-"*30)