keenthinker commited on
Commit
f6bfa8e
·
verified ·
1 Parent(s): 10b3bde

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +136 -196
app.py CHANGED
@@ -1,202 +1,142 @@
1
- import os
2
- import gradio as gr
3
  import requests
4
- import inspect
5
- import pandas as pd
6
- from agent import BasicAgent
7
- from constants import DEFAULT_API_URL, OPENROUTER_MODEL
8
-
9
- # (Keep Constants as is)
10
- # --- Constants ---
11
- DEFAULT_API_URL = DEFAULT_API_URL
12
- OPENROUTER_API = os.getenv("OPENROUTER_API")
13
- OPENROUTER_MODEL = OPENROUTER_MODEL
14
-
15
- # --- Basic Agent Definition ---
16
- # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
17
- class Agent:
18
- def __init__(self):
19
- self.agent = BasicAgent(OPENROUTER_API, OPENROUTER_MODEL, DEFAULT_API_URL)
20
- self.agent.initialize_agent()
21
- print("BasicAgent initialized.")
22
- def __call__(self, input: tuple):
23
- return self.agent.run(input)
24
-
25
-
26
-
27
- def run_and_submit_all( profile: gr.OAuthProfile | None):
28
- """
29
- Fetches all questions, runs the BasicAgent on them, submits all answers,
30
- and displays the results.
31
- """
32
- # --- Determine HF Space Runtime URL and Repo URL ---
33
- space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
34
-
35
- if profile:
36
- username= f"{profile.username}"
37
- print(f"User logged in: {username}")
38
- else:
39
- print("User not logged in.")
40
- return "Please Login to Hugging Face with the button.", None
41
-
42
- api_url = DEFAULT_API_URL
43
- questions_url = f"{api_url}/questions"
44
- submit_url = f"{api_url}/submit"
45
-
46
- # 1. Instantiate Agent ( modify this part to create your agent)
47
- try:
48
- agent = Agent()
49
- except Exception as e:
50
- print(f"Error instantiating agent: {e}")
51
- return f"Error initializing agent: {e}", None
52
- # 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)
53
- agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
54
- print(agent_code)
55
-
56
- # 2. Fetch Questions
57
- print(f"Fetching questions from: {questions_url}")
58
- try:
59
- response = requests.get(questions_url, timeout=15)
60
- response.raise_for_status()
61
- questions_data = response.json()
62
- if not questions_data:
63
- print("Fetched questions list is empty.")
64
- return "Fetched questions list is empty or invalid format.", None
65
- print(f"Fetched {len(questions_data)} questions.")
66
- except requests.exceptions.RequestException as e:
67
- print(f"Error fetching questions: {e}")
68
- return f"Error fetching questions: {e}", None
69
- except requests.exceptions.JSONDecodeError as e:
70
- print(f"Error decoding JSON response from questions endpoint: {e}")
71
- print(f"Response text: {response.text[:500]}")
72
- return f"Error decoding server response for questions: {e}", None
73
- except Exception as e:
74
- print(f"An unexpected error occurred fetching questions: {e}")
75
- return f"An unexpected error occurred fetching questions: {e}", None
76
-
77
- # 3. Run your Agent
78
- results_log = []
79
- answers_payload = []
80
- print(f"Running agent on {len(questions_data)} questions...")
81
- for item in questions_data:
82
- task_id = item.get("task_id")
83
- question_text = item.get("question")
84
- file_name = item.get("file_name")
85
- if not task_id or question_text is None:
86
- print(f"Skipping item with missing task_id or question: {item}")
87
- continue
88
- try:
89
- submitted_answer = agent(input=(task_id, question_text, file_name))
90
- answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
91
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
92
- except Exception as e:
93
- print(f"Error running agent on task {task_id}: {e}")
94
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
95
-
96
- if not answers_payload:
97
- print("Agent did not produce any answers to submit.")
98
- return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
99
-
100
- # 4. Prepare Submission
101
- submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
102
- status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
103
- print(status_update)
104
-
105
- # 5. Submit
106
- print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
107
- try:
108
- response = requests.post(submit_url, json=submission_data, timeout=60)
109
- response.raise_for_status()
110
- result_data = response.json()
111
- final_status = (
112
- f"Submission Successful!\n"
113
- f"User: {result_data.get('username')}\n"
114
- f"Overall Score: {result_data.get('score', 'N/A')}% "
115
- f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
116
- f"Message: {result_data.get('message', 'No message received.')}"
117
  )
118
- print("Submission successful.")
119
- results_df = pd.DataFrame(results_log)
120
- return final_status, results_df
121
- except requests.exceptions.HTTPError as e:
122
- error_detail = f"Server responded with status {e.response.status_code}."
123
- try:
124
- error_json = e.response.json()
125
- error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
126
- except requests.exceptions.JSONDecodeError:
127
- error_detail += f" Response: {e.response.text[:500]}"
128
- status_message = f"Submission Failed: {error_detail}"
129
- print(status_message)
130
- results_df = pd.DataFrame(results_log)
131
- return status_message, results_df
132
- except requests.exceptions.Timeout:
133
- status_message = "Submission Failed: The request timed out."
134
- print(status_message)
135
- results_df = pd.DataFrame(results_log)
136
- return status_message, results_df
137
- except requests.exceptions.RequestException as e:
138
- status_message = f"Submission Failed: Network error - {e}"
139
- print(status_message)
140
- results_df = pd.DataFrame(results_log)
141
- return status_message, results_df
142
- except Exception as e:
143
- status_message = f"An unexpected error occurred during submission: {e}"
144
- print(status_message)
145
- results_df = pd.DataFrame(results_log)
146
- return status_message, results_df
147
-
148
-
149
- # --- Build Gradio Interface using Blocks ---
150
- with gr.Blocks() as demo:
151
- gr.Markdown("# Basic Agent Evaluation Runner")
152
- gr.Markdown(
153
- """
154
- **Instructions:**
155
-
156
- 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
157
- 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
158
- 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
159
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  ---
161
- **Disclaimers:**
162
- 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).
163
- 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.
 
 
 
 
164
  """
165
- )
166
-
167
- gr.LoginButton()
168
-
169
- run_button = gr.Button("Run Evaluation & Submit All Answers")
170
 
171
- status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
172
- # Removed max_rows=10 from DataFrame constructor
173
- results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
174
-
175
- run_button.click(
176
- fn=run_and_submit_all,
177
- outputs=[status_output, results_table]
178
- )
179
-
180
- if __name__ == "__main__":
181
- print("\n" + "-"*30 + " App Starting " + "-"*30)
182
- # Check for SPACE_HOST and SPACE_ID at startup for information
183
- space_host_startup = os.getenv("SPACE_HOST")
184
- space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
185
-
186
- if space_host_startup:
187
- print(f"✅ SPACE_HOST found: {space_host_startup}")
188
- print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
189
- else:
190
- print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
191
-
192
- if space_id_startup: # Print repo URLs if SPACE_ID is found
193
- print(f"✅ SPACE_ID found: {space_id_startup}")
194
- print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
195
- print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
196
- else:
197
- print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
198
-
199
- print("-"*(60 + len(" App Starting ")) + "\n")
200
 
201
- print("Launching Gradio Interface for Basic Agent Evaluation...")
202
- demo.launch(debug=True, share=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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