HiroJ commited on
Commit
0acb04a
·
unverified ·
1 Parent(s): da69113
Files changed (4) hide show
  1. .gitignore +2 -0
  2. app.py +52 -37
  3. custom_agent.py +195 -0
  4. requirements.txt +19 -1
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ .env
2
+ /venv/
app.py CHANGED
@@ -1,34 +1,28 @@
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
- class BasicAgent:
14
- def __init__(self):
15
- print("BasicAgent initialized.")
16
- def __call__(self, question: str) -> str:
17
- print(f"Agent received question (first 50 chars): {question[:50]}...")
18
- fixed_answer = "This is a default answer."
19
- print(f"Agent returning fixed answer: {fixed_answer}")
20
- return fixed_answer
21
-
22
- def run_and_submit_all( profile: gr.OAuthProfile | None):
23
  """
24
  Fetches all questions, runs the BasicAgent on them, submits all answers,
25
  and displays the results.
26
  """
27
  # --- Determine HF Space Runtime URL and Repo URL ---
28
- space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
29
 
30
  if profile:
31
- username= f"{profile.username}"
32
  print(f"User logged in: {username}")
33
  else:
34
  print("User not logged in.")
@@ -40,7 +34,7 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
40
 
41
  # 1. Instantiate Agent ( modify this part to create your agent)
42
  try:
43
- agent = BasicAgent()
44
  except Exception as e:
45
  print(f"Error instantiating agent: {e}")
46
  return f"Error initializing agent: {e}", None
@@ -55,16 +49,16 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
55
  response.raise_for_status()
56
  questions_data = response.json()
57
  if not questions_data:
58
- print("Fetched questions list is empty.")
59
- return "Fetched questions list is empty or invalid format.", None
60
  print(f"Fetched {len(questions_data)} questions.")
61
  except requests.exceptions.RequestException as e:
62
  print(f"Error fetching questions: {e}")
63
  return f"Error fetching questions: {e}", None
64
  except requests.exceptions.JSONDecodeError as e:
65
- print(f"Error decoding JSON response from questions endpoint: {e}")
66
- print(f"Response text: {response.text[:500]}")
67
- return f"Error decoding server response for questions: {e}", None
68
  except Exception as e:
69
  print(f"An unexpected error occurred fetching questions: {e}")
70
  return f"An unexpected error occurred fetching questions: {e}", None
@@ -81,18 +75,36 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
81
  continue
82
  try:
83
  submitted_answer = agent(question_text)
84
- answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
85
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
 
 
 
 
 
 
 
 
86
  except Exception as e:
87
- print(f"Error running agent on task {task_id}: {e}")
88
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
 
 
 
 
 
 
89
 
90
  if not answers_payload:
91
  print("Agent did not produce any answers to submit.")
92
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
93
 
94
- # 4. Prepare Submission
95
- submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
 
 
 
 
96
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
97
  print(status_update)
98
 
@@ -162,20 +174,19 @@ with gr.Blocks() as demo:
162
 
163
  run_button = gr.Button("Run Evaluation & Submit All Answers")
164
 
165
- status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
 
 
166
  # Removed max_rows=10 from DataFrame constructor
167
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
168
 
169
- run_button.click(
170
- fn=run_and_submit_all,
171
- outputs=[status_output, results_table]
172
- )
173
 
174
  if __name__ == "__main__":
175
- print("\n" + "-"*30 + " App Starting " + "-"*30)
176
  # Check for SPACE_HOST and SPACE_ID at startup for information
177
  space_host_startup = os.getenv("SPACE_HOST")
178
- space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
179
 
180
  if space_host_startup:
181
  print(f"✅ SPACE_HOST found: {space_host_startup}")
@@ -183,14 +194,18 @@ if __name__ == "__main__":
183
  else:
184
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
185
 
186
- if space_id_startup: # Print repo URLs if SPACE_ID is found
187
  print(f"✅ SPACE_ID found: {space_id_startup}")
188
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
189
- print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
 
 
190
  else:
191
- print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
 
 
192
 
193
- print("-"*(60 + len(" App Starting ")) + "\n")
194
 
195
  print("Launching Gradio Interface for Basic Agent Evaluation...")
196
- demo.launch(debug=True, share=False)
 
1
  import os
2
  import gradio as gr
3
  import requests
 
4
  import pandas as pd
5
+ from custom_agent import CustomAgent
6
 
7
  # (Keep Constants as is)
8
  # --- Constants ---
9
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
10
 
11
+
12
  # --- Basic Agent Definition ---
13
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
14
+
15
+
16
+ def run_and_submit_all(profile: gr.OAuthProfile | None):
 
 
 
 
 
 
 
17
  """
18
  Fetches all questions, runs the BasicAgent on them, submits all answers,
19
  and displays the results.
20
  """
21
  # --- Determine HF Space Runtime URL and Repo URL ---
22
+ space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
23
 
24
  if profile:
25
+ username = f"{profile.username}"
26
  print(f"User logged in: {username}")
27
  else:
28
  print("User not logged in.")
 
34
 
35
  # 1. Instantiate Agent ( modify this part to create your agent)
36
  try:
37
+ agent = CustomAgent()
38
  except Exception as e:
39
  print(f"Error instantiating agent: {e}")
40
  return f"Error initializing agent: {e}", None
 
49
  response.raise_for_status()
50
  questions_data = response.json()
51
  if not questions_data:
52
+ print("Fetched questions list is empty.")
53
+ return "Fetched questions list is empty or invalid format.", None
54
  print(f"Fetched {len(questions_data)} questions.")
55
  except requests.exceptions.RequestException as e:
56
  print(f"Error fetching questions: {e}")
57
  return f"Error fetching questions: {e}", None
58
  except requests.exceptions.JSONDecodeError as e:
59
+ print(f"Error decoding JSON response from questions endpoint: {e}")
60
+ print(f"Response text: {response.text[:500]}")
61
+ return f"Error decoding server response for questions: {e}", None
62
  except Exception as e:
63
  print(f"An unexpected error occurred fetching questions: {e}")
64
  return f"An unexpected error occurred fetching questions: {e}", None
 
75
  continue
76
  try:
77
  submitted_answer = agent(question_text)
78
+ answers_payload.append(
79
+ {"task_id": task_id, "submitted_answer": submitted_answer}
80
+ )
81
+ results_log.append(
82
+ {
83
+ "Task ID": task_id,
84
+ "Question": question_text,
85
+ "Submitted Answer": submitted_answer,
86
+ }
87
+ )
88
  except Exception as e:
89
+ print(f"Error running agent on task {task_id}: {e}")
90
+ results_log.append(
91
+ {
92
+ "Task ID": task_id,
93
+ "Question": question_text,
94
+ "Submitted Answer": f"AGENT ERROR: {e}",
95
+ }
96
+ )
97
 
98
  if not answers_payload:
99
  print("Agent did not produce any answers to submit.")
100
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
101
 
102
+ # 4. Prepare Submission
103
+ submission_data = {
104
+ "username": username.strip(),
105
+ "agent_code": agent_code,
106
+ "answers": answers_payload,
107
+ }
108
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
109
  print(status_update)
110
 
 
174
 
175
  run_button = gr.Button("Run Evaluation & Submit All Answers")
176
 
177
+ status_output = gr.Textbox(
178
+ label="Run Status / Submission Result", lines=5, interactive=False
179
+ )
180
  # Removed max_rows=10 from DataFrame constructor
181
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
182
 
183
+ run_button.click(fn=run_and_submit_all, outputs=[status_output, results_table])
 
 
 
184
 
185
  if __name__ == "__main__":
186
+ print("\n" + "-" * 30 + " App Starting " + "-" * 30)
187
  # Check for SPACE_HOST and SPACE_ID at startup for information
188
  space_host_startup = os.getenv("SPACE_HOST")
189
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
190
 
191
  if space_host_startup:
192
  print(f"✅ SPACE_HOST found: {space_host_startup}")
 
194
  else:
195
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
196
 
197
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
198
  print(f"✅ SPACE_ID found: {space_id_startup}")
199
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
200
+ print(
201
+ f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main"
202
+ )
203
  else:
204
+ print(
205
+ "ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined."
206
+ )
207
 
208
+ print("-" * (60 + len(" App Starting ")) + "\n")
209
 
210
  print("Launching Gradio Interface for Basic Agent Evaluation...")
211
+ demo.launch(debug=True, share=False)
custom_agent.py ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langgraph.prebuilt import create_react_agent
2
+ from langchain_community.tools.tavily_search import TavilySearchResults
3
+ from langchain_community.document_loaders import WikipediaLoader
4
+ from langchain_community.document_loaders import ArxivLoader
5
+ from dotenv import load_dotenv, find_dotenv
6
+ from langchain_core.tools import tool
7
+ from langchain_huggingface import HuggingFaceEmbeddings
8
+ from langchain_community.vectorstores import SupabaseVectorStore
9
+ from langchain_core.messages import HumanMessage
10
+ from supabase import create_client, Client
11
+ import os
12
+
13
+ load_dotenv(find_dotenv())
14
+
15
+ DEFAULT_PROMPT = """
16
+ 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]. YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings. 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. If you are asked for a string, don't use articles, neither abbreviations (e.g. for cities), and write the digits in plain text unless specified otherwise. If you are asked for a comma separated list, apply the above rules depending of whether the element to be put in the list is a number or a string.
17
+
18
+ """
19
+
20
+
21
+ @tool
22
+ def wiki_search(query: str) -> str:
23
+ """Search Wikipedia for a query and return maximum 2 results.
24
+
25
+ Args:
26
+ query: The search query."""
27
+ search_docs = WikipediaLoader(query=query, load_max_docs=2).load()
28
+ formatted_search_docs = "\n\n---\n\n".join(
29
+ [
30
+ f'<Document source="{doc.metadata["source"]}" page="{doc.metadata.get("page", "")}"/>\n{doc.page_content}\n</Document>'
31
+ for doc in search_docs
32
+ ]
33
+ )
34
+ return {"wiki_results": formatted_search_docs}
35
+
36
+
37
+ @tool
38
+ def web_search(query: str) -> str:
39
+ """Search Tavily for a query and return maximum 3 results.
40
+
41
+ Args:
42
+ query: The search query."""
43
+ search_docs = TavilySearchResults(max_results=3).invoke(query=query)
44
+ formatted_search_docs = "\n\n---\n\n".join(
45
+ [
46
+ f'<Document source="{doc.metadata["source"]}" page="{doc.metadata.get("page", "")}"/>\n{doc.page_content}\n</Document>'
47
+ for doc in search_docs
48
+ ]
49
+ )
50
+ return {"web_results": formatted_search_docs}
51
+
52
+
53
+ @tool
54
+ def arvix_search(query: str) -> str:
55
+ """Search Arxiv for a query and return maximum 3 result.
56
+
57
+ Args:
58
+ query: The search query."""
59
+ search_docs = ArxivLoader(query=query, load_max_docs=3).load()
60
+ formatted_search_docs = "\n\n---\n\n".join(
61
+ [
62
+ f'<Document source="{doc.metadata["source"]}" page="{doc.metadata.get("page", "")}"/>\n{doc.page_content[:1000]}\n</Document>'
63
+ for doc in search_docs
64
+ ]
65
+ )
66
+ return {"arvix_results": formatted_search_docs}
67
+
68
+
69
+ @tool
70
+ def multiply(a: int, b: int) -> int:
71
+ """Multiply two numbers.
72
+ Args:
73
+ a: first int
74
+ b: second int
75
+ """
76
+ return a * b
77
+
78
+
79
+ @tool
80
+ def add(a: int, b: int) -> int:
81
+ """Add two numbers.
82
+
83
+ Args:
84
+ a: first int
85
+ b: second int
86
+ """
87
+ return a + b
88
+
89
+
90
+ @tool
91
+ def subtract(a: int, b: int) -> int:
92
+ """Subtract two numbers.
93
+
94
+ Args:
95
+ a: first int
96
+ b: second int
97
+ """
98
+ return a - b
99
+
100
+
101
+ @tool
102
+ def divide(a: int, b: int) -> int:
103
+ """Divide two numbers.
104
+
105
+ Args:
106
+ a: first int
107
+ b: second int
108
+ """
109
+ if b == 0:
110
+ raise ValueError("Cannot divide by zero.")
111
+ return a / b
112
+
113
+
114
+ @tool
115
+ def modulus(a: int, b: int) -> int:
116
+ """Get the modulus of two numbers.
117
+
118
+ Args:
119
+ a: first int
120
+ b: second int
121
+ """
122
+ return a % b
123
+
124
+
125
+ class CustomAgent:
126
+ def __init__(self):
127
+ print("CustomAgent initialized.")
128
+
129
+ # Initialize embeddings and vector store
130
+ self.embeddings = HuggingFaceEmbeddings(
131
+ model_name="sentence-transformers/all-mpnet-base-v2"
132
+ )
133
+ print(os.environ.get("SUPABASE_URL"))
134
+ print(os.environ.get("SUPABASE_SERVICE_KEY"))
135
+
136
+ self.supabase: Client = create_client(
137
+ os.environ.get("SUPABASE_URL"), os.environ.get("SUPABASE_SERVICE_ROLE_KEY")
138
+ )
139
+
140
+ self.vector_store = SupabaseVectorStore(
141
+ client=self.supabase,
142
+ embedding=self.embeddings,
143
+ table_name="documents_1",
144
+ query_name="match_documents_1",
145
+ )
146
+
147
+ # Create the agent
148
+ self.agent = create_react_agent(
149
+ model="openai:gpt-4-1106-preview",
150
+ tools=[
151
+ web_search,
152
+ add,
153
+ subtract,
154
+ multiply,
155
+ divide,
156
+ modulus,
157
+ wiki_search,
158
+ arvix_search,
159
+ ],
160
+ prompt=DEFAULT_PROMPT,
161
+ )
162
+
163
+ def retriever(self, query: str):
164
+ """Retriever"""
165
+ similar_question = self.vector_store.similarity_search(query)
166
+ return HumanMessage(
167
+ content=f"Here I provide a similar question and answer for reference: \n\n{similar_question[0].page_content}",
168
+ )
169
+
170
+ def __call__(self, question: str) -> str:
171
+ """Run the agent on a question and return the answer."""
172
+ print(f"CustomAgent received question (first 50 chars): {question[:50]}...")
173
+
174
+ try:
175
+ answer = self.agent.invoke(
176
+ {
177
+ "messages": [
178
+ self.retriever(question),
179
+ HumanMessage(content=question),
180
+ ]
181
+ }
182
+ )
183
+ result = answer["messages"][-1].content
184
+ print(f"CustomAgent returning answer: {result}")
185
+ return result
186
+ except Exception as e:
187
+ print(f"Error in CustomAgent: {e}")
188
+ return f"Error: {e}"
189
+
190
+
191
+ if __name__ == "__main__":
192
+ agent = CustomAgent()
193
+ agent(
194
+ 'What was the volume in m^3 of the fish bag that was calculated in the University of Leicester paper "Can Hiccup Supply Enough Fish to Maintain a Dragon\u2019s Diet?"'
195
+ )
requirements.txt CHANGED
@@ -1,2 +1,20 @@
1
  gradio
2
- requests
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  gradio
2
+ requests
3
+ langchain
4
+ langchain-community
5
+ langchain-core
6
+ langchain-google-genai
7
+ langchain-huggingface
8
+ langchain-tavily
9
+ langchain-chroma
10
+ langgraph
11
+ huggingface_hub
12
+ supabase
13
+ arxiv
14
+ pymupdf
15
+ wikipedia
16
+ pgvector
17
+ python-dotenv
18
+ pytesseract
19
+ matplotlib
20
+ sentence-transformers