sqfoo commited on
Commit
03cd67b
·
verified ·
1 Parent(s): a46597b

Upload two files: agent.py and run.py [remove the agent class]

Browse files
Files changed (2) hide show
  1. agent.py +129 -0
  2. run.py +203 -0
agent.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from typing import TypedDict, List, Dict, Any, Optional
3
+ from langgraph.graph import StateGraph, START, END
4
+ from langchain_anthropic import ChatAnthropic
5
+ from langchain_core.tools import tool
6
+ from langchain_core.messages import HumanMessage
7
+ from langchain_core.prompts import ChatPromptTemplate
8
+
9
+ # %pip install -qU duckduckgo-search langchain-community
10
+ # pip install requests
11
+ # pip install pandas
12
+ # pip install pypdf
13
+
14
+
15
+ class AgentState(TypedDict):
16
+ messages: List
17
+ current_question: str
18
+ final_answer: str
19
+
20
+ # 1. Web Browsing
21
+ from langchain_community.tools import DuckDuckGoSearchRun
22
+ from langchain_community.document_loaders import ImageCaptionLoader
23
+ import requests
24
+ import pandas as pd
25
+ from pypdf import PdfReader
26
+
27
+ @tool
28
+ def web_search(query: str) -> str:
29
+ """Allows search through DuckDuckGo.
30
+ Args:
31
+ query: what you want to search
32
+ """
33
+ search = DuckDuckGoSearchRun()
34
+ results = search.invoke(query)
35
+ return "\n".join(results)
36
+
37
+ @tool
38
+ def visit_webpage(url: str) -> str:
39
+ """Fetches raw HTML content of a web page.
40
+ Args:
41
+ url: the webpage url
42
+ """
43
+ try:
44
+ response = requests.get(url, timeout=5)
45
+ return response.text
46
+ except Exception as e:
47
+ return f"[ERROR fetching {url}]: {str(e)}"
48
+
49
+ # 4. File Reading
50
+ @tool
51
+ def read_file(dir: str) -> str:
52
+ """Read the content of the provided file
53
+ Args:
54
+ dir: the filepath
55
+ """
56
+ extension = dir.split['.'][-1]
57
+ if extension == 'xlsx':
58
+ dataframe = pd.read_excel(dir)
59
+ return dataframe.to_string()
60
+ elif extension == 'pdf':
61
+ reader = PdfReader(dir)
62
+ contents = [p.extract_text() for p in reader.pages]
63
+ return "\n".join(contents)
64
+ else:
65
+ with open(dir) as f:
66
+ return f.read()
67
+
68
+ # 5. Image Open
69
+ @tool
70
+ def image_caption(dir: str) -> str:
71
+ """Understand the content of the provided image
72
+ Args:
73
+ dir: the image url link
74
+ """
75
+ loader = ImageCaptionLoader(images=[dir])
76
+ metadata = loader.load()
77
+ return metadata[0].page_content
78
+
79
+ # 2. Coding
80
+ # 3. Multi-Modality
81
+
82
+
83
+
84
+ # ("human", f"Question: {question}\nReport to validate: {final_answer}")
85
+ class BasicAgent:
86
+ def __init__(self):
87
+ model = ChatAnthropic(
88
+ model="claude-3-5-sonnet-20240620",
89
+ temperature=0,
90
+ max_tokens=20000,
91
+ timeout=None,
92
+ max_retries=2,
93
+ api_key=os.getenv("ANTHROPIC_API_KEY"),
94
+ # other params...
95
+ )
96
+ # System Prompt for few shot prompting
97
+ self.sys_prompt = """"
98
+ You are a general AI assistant. I will ask you a question. Report your thoughts, and finish your answer with the following template: FINAL ANSWER: [YOUR FINAL ANSWER].
99
+ YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separared list of numbers and/or strings.
100
+ If you are asked for a number, don't use comma to write your number neither use units such as $ or percent sign unless specified otherwise.
101
+ If you are asked for a string, don't use articles, neither abbreviations (eg. for cities), and write the digits in plain text unless specified otherwise.
102
+ If you are asked for a comma separated list, apply the above rules depending of whether the element to put in the list is a number or a string.
103
+
104
+ There are few tools provided: web_search, visit_webpage, read_file and image_caption.
105
+ Here are few examples demonstrating how to call and use the tools.
106
+ """
107
+ self.app = self.__graph_compile__()
108
+ tools = [web_search, visit_webpage, read_file, image_caption]
109
+ self.model = model.bind_tools(tools) # LLM with tools
110
+ # self.agent = CodeAgent(tools=[DuckDuckGoSearchTool()], model=model)
111
+ print("BasicAgent initialized.")
112
+
113
+ def __call__(self, question: str) -> str:
114
+ print(f"Agent received question (first 50 chars): {question[:50]}...")
115
+ prompt_msg = [
116
+ ("system", self.sys_prompt),
117
+ ("human", f"Question: {question}")
118
+ ]
119
+ response = self.model.invoke(prompt_msg)
120
+ fixed_answer = response.content
121
+ # fixed_answer = "This is a default answer."
122
+ print(f"Agent returning fixed answer: {fixed_answer}")
123
+ return fixed_answer
124
+
125
+ # Maybe we no need this one
126
+ def __graph_compile__(self):
127
+ graph = StateGraph(AgentState)
128
+
129
+ pass
run.py ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ # from smolagents import CodeAgent, DuckDuckGoSearchTool, OpenAIServerModel, VLLMModel, HfApiModel
14
+ # class BasicAgent:
15
+ # def __init__(self):
16
+ # # model = OpenAIServerModel(model_id="gpt-4o")
17
+ # # model = VLLMModel(model_id="HuggingFaceTB/SmolLM-135M-Instruct")
18
+ # model = HfApiModel("Qwen/Qwen2.5-Coder-32B-Instruct")
19
+ # self.agent = CodeAgent(tools=[DuckDuckGoSearchTool()], model=model)
20
+ # print("BasicAgent initialized.")
21
+ # def __call__(self, question: str) -> str:
22
+ # print(f"Agent received question (first 50 chars): {question[:50]}...")
23
+ # fixed_answer = self.agent.run(question)
24
+ # # fixed_answer = "This is a default answer."
25
+ # print(f"Agent returning fixed answer: {fixed_answer}")
26
+ # return fixed_answer
27
+ from agent import BasicAgent
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:
152
+ gr.Markdown("# Basic Agent Evaluation Runner")
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).
164
+ 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.
165
+ """
166
+ )
167
+
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
174
+ results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
175
+
176
+ run_button.click(
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)
183
+ # Check for SPACE_HOST and SPACE_ID at startup for information
184
+ space_host_startup = os.getenv("SPACE_HOST")
185
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
186
+
187
+ if space_host_startup:
188
+ print(f"✅ SPACE_HOST found: {space_host_startup}")
189
+ print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
190
+ else:
191
+ print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
192
+
193
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
194
+ print(f"✅ SPACE_ID found: {space_id_startup}")
195
+ print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
196
+ print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
197
+ else:
198
+ print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
199
+
200
+ print("-"*(60 + len(" App Starting ")) + "\n")
201
+
202
+ print("Launching Gradio Interface for Basic Agent Evaluation...")
203
+ demo.launch(debug=True, share=False)