keenthinker commited on
Commit
48066dd
·
verified ·
1 Parent(s): 966e533

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +190 -134
app.py CHANGED
@@ -1,142 +1,198 @@
1
- from smolagents import CodeAgent, tool, OpenAIServerModel
 
2
  import requests
3
- import io
4
- from PIL import Image
5
- from constants import DEFAULT_API_URL
6
 
 
 
 
 
 
 
7
  class BasicAgent:
8
- def __init__(self, OPENROUTER_API: str, OPENROUTER_MODEL: str, api_url: str):
9
- self.api_url = api_url
10
- self.model = OpenAIServerModel(
11
- model_id=OPENROUTER_MODEL,
12
- api_base="https://openrouter.ai/api/v1",
13
- api_key=OPENROUTER_API
14
- )
15
- self.agent = None
16
-
17
- def initialize_agent(self):
18
- self.agent = CodeAgent(
19
- model=self.model,
20
- tools=[get_file],
21
- add_base_tools=True,
22
- additional_authorized_imports=['pandas', 'io']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  )
24
- # self.agent.tools.pop('visit_webpage') # replacing tool
25
- return self.agent
26
-
27
-
28
- def run(self, input: tuple):
29
- id, question, file = input
30
-
31
- # check if has image
32
- img = None
33
- if file and file.split('.')[1] == 'png':
34
- img = [Image.open(get_file(file))]
35
-
36
- # make a prompt
37
- prompt = f"""
38
- You are CodeAgent assistant. The user asks you a question and you provide them with a verified and specific answer.
39
- As an agent you have some tools to use. You may use them on demand.
40
- Your normal workflow should follow the following sequence:
41
- 1. You received the question and (in some cases) additional information as a file_id. You analize it.
42
- 2. At the planning stage you making a sequence of steps to complete this task in planning variable
43
- 3. At the execution stage you provide an executable python code which will be parsed and executed by the program.
44
- Remember to provide executable code here, without any additional characters which may crash the execution and parsing.
45
- 4. After execution you decide whether you had a final result an you can close the task providing this result or you should continue.
46
- If ccontinue, review you previous planning sequence: what is done, what should be change in this plan or what we should add to it?
47
- EACH STEP INCLUDES BOTH PLANNING AND EXECUTIONS STAGES:
48
- * you provide planning in a separate variable at the beggining of your answer, variable name: planning
49
- * execution is the rest code where you trying to achive the planned goals.
50
-
51
- The example:
52
- User: What is Axelord?
53
- [Step 1]
54
- Agent:
55
- Planning stage:
56
- planning = "
57
- Okay, user want me to tell him what is Axelord. I do not have this answer in my memory so I need to find it.
58
- Plan:
59
- 1. To search: What is Axelord.
60
- 2. Provide an aswer.
61
- "
62
- Execution stage:
63
- query = "What is Axelord?"
64
- search_result = web_search(query)
65
- print(search_result)
66
- Result:
67
- The pages about this topic.
68
- Output:
69
- None
70
- [Step 2]
71
- Agent:
72
- Planning stage:
73
- planning = "
74
- Okay, I found some websites about that.
75
- Plan:
76
- 1. To search: What is Axelord. - DONE.
77
- 2. Visit the webpage to get more inforamtion.
78
- 3. Provide an answer.
79
- "
80
- Execution stage:
81
- url = "https://en.wikipedia.org/wiki/Axelord"
82
- wikipedia_page = visit_webpage(url)
83
- print(wikipedia_page)
84
- Result:
85
- page html output which contains an answer.
86
- Output:
87
- FinalAnswerTool(Answer)
88
-
89
- In the example above you saw how you can use searching tools, but you also has some others.
90
- You complete the task step by step. You recognise when the planning stage and you can do planning, and when
91
- the execution stage and you MUST provide an executable python code.
92
-
93
- The user's question is:
94
- {question}
95
-
96
  ---
97
- Additional information you may use:
98
- file_id: {file}
99
-
100
- IMPORTANT:
101
- * You do not answer in plain text.
102
- * You only answer in python code. Every plain text you need to provide you should include in a text variable
103
- * You may receive both images sometimes as a context. Do not forget to use them to handle the task.
104
  """
 
105
 
106
- # run
107
- return self.agent.run(
108
- task = prompt,
109
- images = img
110
- )
111
 
112
- # tools
113
- @tool
114
- def get_file(file_id: str) -> io.BytesIO | io.StringIO | None:
115
- """A tool that fetches the file's content from the server.
116
- Use it every time you need to get file for completing the task.
117
- IMPORTANT: ONLY USE IT WHEN THE FILE_ID ARGUMENT IS NOT EMPTY.
118
- YOU MUST ENSURE THAT FILE_ID ARGUMENT IS NOT EMPTY WHEN YOU USE IT.
119
- Args:
120
- file_id: id of a file required to fetch
121
- Returns:
122
- io.BytesIO: file emulation for .xlsx or .png files. You can use this object as a file itself. It is already converted to BytesIO.
123
- io.StringIO: file emulation for .py files. You can use this object as a file itself. It is already converted to StringIO.
124
- """
125
- # make request
126
- response = requests.get(DEFAULT_API_URL+'/files/'+file_id.split('.')[0], timeout=15)
127
- response.raise_for_status()
128
-
129
- # prepare the output
130
- file_format = file_id.split('.')[1]
131
- match file_format:
132
- case 'png':
133
- print('png uploaded')
134
- return io.BytesIO(response.content)
135
- case 'xlsx':
136
- print('xlsx uploaded')
137
- return io.BytesIO(response.content)
138
- case 'py':
139
- print('py uploaded')
140
- return io.StringIO(response.text)
141
- case _:
142
- return None
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
  import requests
4
+ import inspect
5
+ import pandas as pd
6
+ from agent import Mod4Agent
7
 
8
+ # (Keep Constants as is)
9
+ # --- Constants ---
10
+ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
11
+
12
+ # --- Basic Agent Definition ---
13
+ # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
14
  class BasicAgent:
15
+ def __init__(self):
16
+ print("BasicAgent initialized.")
17
+ def __call__(self, question: str) -> str:
18
+ print(f"Agent received question (first 50 chars): {question[:50]}...")
19
+ fixed_answer = "This is a default answer."
20
+ print(f"Agent returning fixed answer: {fixed_answer}")
21
+ return fixed_answer
22
+
23
+ def run_and_submit_all( profile: gr.OAuthProfile | None):
24
+ """
25
+ Fetches all questions, runs the BasicAgent on them, submits all answers,
26
+ and displays the results.
27
+ """
28
+ # --- Determine HF Space Runtime URL and Repo URL ---
29
+ space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
30
+
31
+ if profile:
32
+ username= f"{profile.username}"
33
+ print(f"User logged in: {username}")
34
+ else:
35
+ print("User not logged in.")
36
+ return "Please Login to Hugging Face with the button.", None
37
+
38
+ api_url = DEFAULT_API_URL
39
+ questions_url = f"{api_url}/questions"
40
+ submit_url = f"{api_url}/submit"
41
+
42
+ # 1. Instantiate Agent ( modify this part to create your agent)
43
+ try:
44
+ #agent = BasicAgent()
45
+ agent = Mod4Agent()
46
+ except Exception as e:
47
+ print(f"Error instantiating agent: {e}")
48
+ return f"Error initializing agent: {e}", None
49
+ # 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)
50
+ agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
51
+ print(agent_code)
52
+
53
+ # 2. Fetch Questions
54
+ print(f"Fetching questions from: {questions_url}")
55
+ try:
56
+ response = requests.get(questions_url, timeout=15)
57
+ response.raise_for_status()
58
+ questions_data = response.json()
59
+ if not questions_data:
60
+ print("Fetched questions list is empty.")
61
+ return "Fetched questions list is empty or invalid format.", None
62
+ print(f"Fetched {len(questions_data)} questions.")
63
+ except requests.exceptions.RequestException as e:
64
+ print(f"Error fetching questions: {e}")
65
+ return f"Error fetching questions: {e}", None
66
+ except requests.exceptions.JSONDecodeError as e:
67
+ print(f"Error decoding JSON response from questions endpoint: {e}")
68
+ print(f"Response text: {response.text[:500]}")
69
+ return f"Error decoding server response for questions: {e}", None
70
+ except Exception as e:
71
+ print(f"An unexpected error occurred fetching questions: {e}")
72
+ return f"An unexpected error occurred fetching questions: {e}", None
73
+
74
+ # 3. Run your Agent
75
+ results_log = []
76
+ answers_payload = []
77
+ print(f"Running agent on {len(questions_data)} questions...")
78
+ for item in questions_data:
79
+ task_id = item.get("task_id")
80
+ question_text = item.get("question")
81
+ if not task_id or question_text is None:
82
+ print(f"Skipping item with missing task_id or question: {item}")
83
+ continue
84
+ try:
85
+ submitted_answer = agent(question_text)
86
+ answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
87
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
88
+ except Exception as e:
89
+ print(f"Error running agent on task {task_id}: {e}")
90
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
91
+
92
+ if not answers_payload:
93
+ print("Agent did not produce any answers to submit.")
94
+ return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
95
+
96
+ # 4. Prepare Submission
97
+ submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
98
+ status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
99
+ print(status_update)
100
+
101
+ # 5. Submit
102
+ print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
103
+ try:
104
+ response = requests.post(submit_url, json=submission_data, timeout=60)
105
+ response.raise_for_status()
106
+ result_data = response.json()
107
+ final_status = (
108
+ f"Submission Successful!\n"
109
+ f"User: {result_data.get('username')}\n"
110
+ f"Overall Score: {result_data.get('score', 'N/A')}% "
111
+ f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
112
+ f"Message: {result_data.get('message', 'No message received.')}"
113
  )
114
+ print("Submission successful.")
115
+ results_df = pd.DataFrame(results_log)
116
+ return final_status, results_df
117
+ except requests.exceptions.HTTPError as e:
118
+ error_detail = f"Server responded with status {e.response.status_code}."
119
+ try:
120
+ error_json = e.response.json()
121
+ error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
122
+ except requests.exceptions.JSONDecodeError:
123
+ error_detail += f" Response: {e.response.text[:500]}"
124
+ status_message = f"Submission Failed: {error_detail}"
125
+ print(status_message)
126
+ results_df = pd.DataFrame(results_log)
127
+ return status_message, results_df
128
+ except requests.exceptions.Timeout:
129
+ status_message = "Submission Failed: The request timed out."
130
+ print(status_message)
131
+ results_df = pd.DataFrame(results_log)
132
+ return status_message, results_df
133
+ except requests.exceptions.RequestException as e:
134
+ status_message = f"Submission Failed: Network error - {e}"
135
+ print(status_message)
136
+ results_df = pd.DataFrame(results_log)
137
+ return status_message, results_df
138
+ except Exception as e:
139
+ status_message = f"An unexpected error occurred during submission: {e}"
140
+ print(status_message)
141
+ results_df = pd.DataFrame(results_log)
142
+ return status_message, results_df
143
+
144
+
145
+ # --- Build Gradio Interface using Blocks ---
146
+ with gr.Blocks() as demo:
147
+ gr.Markdown("# Basic Agent Evaluation Runner")
148
+ gr.Markdown(
149
+ """
150
+ **Instructions:**
151
+
152
+ 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
153
+ 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
154
+ 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
155
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  ---
157
+ **Disclaimers:**
158
+ 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).
159
+ 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.
 
 
 
 
160
  """
161
+ )
162
 
163
+ gr.LoginButton()
 
 
 
 
164
 
165
+ run_button = gr.Button("Run Evaluation & Submit All Answers")
166
+
167
+ status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
168
+ # Removed max_rows=10 from DataFrame constructor
169
+ results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
170
+
171
+ run_button.click(
172
+ fn=run_and_submit_all,
173
+ outputs=[status_output, results_table]
174
+ )
175
+
176
+ if __name__ == "__main__":
177
+ print("\n" + "-"*30 + " App Starting " + "-"*30)
178
+ # Check for SPACE_HOST and SPACE_ID at startup for information
179
+ space_host_startup = os.getenv("SPACE_HOST")
180
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
181
+
182
+ if space_host_startup:
183
+ print(f"✅ SPACE_HOST found: {space_host_startup}")
184
+ print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
185
+ else:
186
+ print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
187
+
188
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
189
+ print(f"✅ SPACE_ID found: {space_id_startup}")
190
+ print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
191
+ print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
192
+ else:
193
+ print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
194
+
195
+ print("-"*(60 + len(" App Starting ")) + "\n")
196
+
197
+ print("Launching Gradio Interface for Basic Agent Evaluation...")
198
+ demo.launch(debug=True, share=False)