Datawithsarah commited on
Commit
781c86d
·
1 Parent(s): 09b53af

switched to Langgrah

Browse files
Files changed (2) hide show
  1. app.py +29 -262
  2. requirements.txt +5 -11
app.py CHANGED
@@ -1,249 +1,44 @@
 
1
  import os
 
2
  import gradio as gr
3
- import pandas as pd
4
  import requests
5
- import subprocess
6
- import json
7
- import csv
8
- import openpyxl
9
- import whisper
10
- from typing import Optional
11
- from bs4 import BeautifulSoup
12
- from duckduckgo_search import DDGS
13
- from smolagents import CodeAgent, tool
14
-
15
- # (Keep Constants as is)
16
- # --- Constants ---
17
- DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
18
-
19
- # --- Basic Agent Definition ---
20
- # ----- THIS IS WHERE YOU CAN BUILD WHAT YOU WANT ------
21
- class ClaudeServerModel:
22
- """
23
- ClaudeServerModel wraps Anthropic Claude API for smolagents-style usage.
24
- """
25
-
26
- def __init__(self, api_key: str, model_id: str = "claude-3-opus-20240229", temperature: float = 0.0):
27
- self.api_key = api_key
28
- self.model_id = model_id
29
- self.temperature = temperature
30
-
31
- def complete(self, prompt: str, stop_sequences: list[str] = None) -> str:
32
- headers = {
33
- "x-api-key": self.api_key,
34
- "anthropic-version": "2023-06-01",
35
- "content-type": "application/json"
36
- }
37
-
38
- body = {
39
- "model": self.model_id,
40
- "max_tokens": 1024,
41
- "temperature": self.temperature,
42
- "prompt": f"\n\nHuman: {prompt}\n\nAssistant:"
43
- }
44
-
45
- # Claude expects stop_sequences as "stop_sequences", if passed
46
- if stop_sequences:
47
- body["stop_sequences"] = stop_sequences
48
 
49
- response = requests.post("https://api.anthropic.com/v1/complete", headers=headers, json=body)
50
- response.raise_for_status()
51
- return response.json()["completion"].strip()
52
 
53
- def __call__(self, prompt: str, stop_sequences: list[str] = None) -> str:
54
- return self.complete(prompt, stop_sequences=stop_sequences)
55
 
 
56
  # --- Constants ---
57
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
58
 
59
- def download_file(file_name: str) -> None:
60
- if not os.path.exists(file_name):
61
- url = f"{DEFAULT_API_URL}/files/{file_name.split('.')[0]}"
62
- r = requests.get(url)
63
- with open(file_name, "wb") as f:
64
- f.write(r.content)
65
-
66
- @tool
67
- def open_file_as_text(file_name: str, filetype: Optional[str] = "txt") -> str:
68
- """
69
- Opens and reads a file based on its type.
70
-
71
- Args:
72
- file_name (str): The name of the file to open (should be available after download).
73
- filetype (Optional[str]): The type of file - one of 'txt', 'json', 'csv', 'xlsx', or 'mp3'. Defaults to 'txt'.
74
-
75
- Returns:
76
- str: File content as text, or transcription if an audio file.
77
- """
78
- download_file(file_name)
79
- try:
80
- if filetype == "txt":
81
- with open(file_name, "r", encoding="utf-8") as f:
82
- return f.read()
83
- elif filetype == "json":
84
- with open(file_name, "r", encoding="utf-8") as f:
85
- data = json.load(f)
86
- return json.dumps(data, indent=2)
87
- elif filetype == "csv":
88
- with open(file_name, "r", encoding="utf-8") as f:
89
- reader = csv.reader(f)
90
- rows = list(reader)
91
- return "\n".join([", ".join(row) for row in rows])
92
- elif filetype == "xlsx":
93
- wb = openpyxl.load_workbook(file_name, data_only=True)
94
- sheet = wb.active
95
- content = []
96
- for row in sheet.iter_rows(values_only=True):
97
- content.append(", ".join(str(cell) if cell is not None else "" for cell in row))
98
- return "\n".join(content)
99
- elif filetype == "mp3":
100
- w = whisper.load_model("base")
101
- res = w.transcribe(file_name)
102
- return res["text"]
103
- else:
104
- return f"Unsupported filetype '{filetype}'."
105
- except Exception as e:
106
- return f"Error opening file '{file_name}': {str(e)}"
107
-
108
-
109
- @tool
110
- def web_search(query: str) -> str:
111
- """
112
- Performs a web search using DuckDuckGo and returns the top results.
113
-
114
- Args:
115
- query (str): Search query string.
116
-
117
- Returns:
118
- str: Top search results formatted as title, snippet, and URL.
119
- """
120
- try:
121
- with DDGS() as ddgs:
122
- results = ddgs.text(query, max_results=3)
123
- if not results:
124
- return "No results found."
125
- return "\n\n".join([f"Title: {r['title']}\nSnippet: {r['body']}\nURL: {r['href']}" for r in results])
126
- except Exception as e:
127
- return f"Error during search: {str(e)}"
128
-
129
-
130
- @tool
131
- def read_wikipedia_page(url: str) -> str:
132
- """
133
- Reads and extracts clean text content from a Wikipedia page.
134
-
135
- Args:
136
- url (str): Full URL to the Wikipedia page.
137
-
138
- Returns:
139
- str: Sectioned and readable content from the page, including paragraphs, lists, and tables.
140
- """
141
- headers = {"User-Agent": "Mozilla/5.0"}
142
- resp = requests.get(url, headers=headers, timeout=10)
143
- resp.raise_for_status()
144
- soup = BeautifulSoup(resp.text, "html.parser")
145
- content_div = soup.find('div', id='mw-content-text')
146
- parts = []
147
- for elem in content_div.find_all(['h2', 'h3', 'p', 'ul', 'ol', 'table']):
148
- if elem.name in ['h2', 'h3']:
149
- parts.append("\n\n" + elem.get_text(strip=True) + "\n")
150
- elif elem.name in ['p', 'ul', 'ol']:
151
- parts.append(elem.get_text(strip=True))
152
- elif elem.name == 'table':
153
- parts.append(parse_wikipedia_table(elem))
154
- return "\n".join(parts)
155
-
156
-
157
- @tool
158
- def smart_paginate_around_query(full_text: str, query: str) -> list:
159
- """
160
- Splits full text into focused windows surrounding the query keyword.
161
-
162
- Args:
163
- full_text (str): The large text content to paginate.
164
- query (str): Keyword or phrase to center each window on.
165
-
166
- Returns:
167
- list: List of substrings centered around the query within the original text.
168
- """
169
- before_chars = 1000
170
- after_chars = 3000
171
- q = query.lower()
172
- text_lower = full_text.lower()
173
- pages = []
174
- start = 0
175
- while True:
176
- idx = text_lower.find(q, start)
177
- if idx == -1:
178
- break
179
- s = max(0, idx - before_chars)
180
- e = min(len(full_text), idx + len(q) + after_chars)
181
- pages.append(full_text[s:e])
182
- start = e
183
- return pages
184
-
185
-
186
- @tool
187
- def reverse_sentence(text: str) -> str:
188
- """
189
- Reverses the input text string.
190
-
191
- Args:
192
- text (str): A string to reverse.
193
-
194
- Returns:
195
- str: Reversed string.
196
- """
197
- return text[::-1]
198
-
199
 
200
- @tool
201
- def run_python_code(file_name: str) -> str:
202
- """
203
- Executes a Python script and returns the output.
204
 
205
- Args:
206
- file_name (str): Name of the Python file to execute.
 
 
 
207
 
208
- Returns:
209
- str: Printed standard output or error message from the script.
210
- """
211
- download_file(file_name)
212
- try:
213
- result = subprocess.run(["python", file_name], capture_output=True, text=True, timeout=10)
214
- if result.returncode != 0:
215
- return f"Error: {result.stderr.strip()}"
216
- return result.stdout.strip()
217
- except Exception as e:
218
- return f"Execution failed: {e}"
219
 
220
- # Agent Setup
221
- tools = [
222
- open_file_as_text,
223
- web_search,
224
- read_wikipedia_page,
225
- smart_paginate_around_query,
226
- reverse_sentence,
227
- run_python_code
228
- ]
229
-
230
- model = ClaudeServerModel(
231
- api_key=os.getenv("CLAUDE_API_KEY"),
232
- model_id="claude-3-opus-20240229"
233
- )
234
-
235
- agent = CodeAgent(
236
- model=model,
237
- tools=tools,
238
- additional_authorized_imports=["pandas", "numpy", "datetime", "json", "re", "math", "os", "requests", "csv", "urllib"]
239
- )
240
 
241
  def run_and_submit_all( profile: gr.OAuthProfile | None):
242
  """
243
  Fetches all questions, runs the BasicAgent on them, submits all answers,
244
  and displays the results.
245
  """
246
- # Determine HF Space Runtime URL and Repo URL
247
  space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
248
 
249
  if profile:
@@ -257,18 +52,13 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
257
  questions_url = f"{api_url}/questions"
258
  submit_url = f"{api_url}/submit"
259
 
260
- # Instantiate Agent ( modify this part to create your agent)
261
  try:
262
- agent = CodeAgent(
263
- model=model,
264
- tools=tools,
265
- additional_authorized_imports=["pandas", "numpy", "datetime", "json", "re", "math", "os", "requests", "csv",
266
- "urllib"]
267
- )
268
  except Exception as e:
269
  print(f"Error instantiating agent: {e}")
270
  return f"Error initializing agent: {e}", None
271
- # 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)
272
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
273
  print(agent_code)
274
 
@@ -300,37 +90,14 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
300
  for item in questions_data:
301
  task_id = item.get("task_id")
302
  question_text = item.get("question")
303
- file_name = item.get("file_name")
304
  if not task_id or question_text is None:
305
  print(f"Skipping item with missing task_id or question: {item}")
306
  continue
 
 
 
307
  try:
308
- full_prompt = f"""
309
- You are a precise answering agent optimized for exact-match benchmarks like GAIA.
310
-
311
- Your job is to:
312
- - Use tools (e.g., `web_search`, `read_wikipedia_page`, `smart_paginate_around_query`, `reverse_sentence`, `open_file_as_text`, etc.) only when needed.
313
- - Never make assumptions. Do not guess.
314
- - Use `read_wikipedia_page` to read full content if snippets from `web_search` are not enough.
315
- - Use `smart_paginate_around_query` with 1-3 keyword terms — never full questions.
316
- - Use `reverse_sentence` for any reverse operation, never do it manually.
317
- - Use the provided `file_name` field for file tasks, not filenames inside the question.
318
- - Output formats:
319
- - Numbers: Digits only, no commas, $, or %.
320
- - Strings: No articles, abbreviations, or spelled-out numbers unless required.
321
- - Lists: Comma separated, single space after each comma.
322
- - At the end, print only the final answer. No explanation, no reasoning.
323
-
324
- Example:
325
- If asked, “What is the capital of France?”
326
- Respond:
327
- print("Paris")
328
-
329
- Question:
330
- {question_text}
331
-
332
- File to use (if needed): {file_name}"""
333
- submitted_answer = agent.run(full_prompt)
334
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
335
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
336
  except Exception as e:
 
1
+ """ Basic Agent Evaluation Runner"""
2
  import os
3
+ import inspect
4
  import gradio as gr
 
5
  import requests
6
+ import pandas as pd
7
+ import time
8
+ from langchain_core.messages import HumanMessage
9
+ from agent import build_graph
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
 
 
 
11
 
 
 
12
 
13
+ # (Keep Constants as is)
14
  # --- Constants ---
15
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
16
 
17
+ # --- Basic Agent Definition ---
18
+ # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
 
 
 
 
20
 
21
+ class BasicAgent:
22
+ """A langgraph agent."""
23
+ def __init__(self):
24
+ print("BasicAgent initialized.")
25
+ self.graph = build_graph()
26
 
27
+ def __call__(self, question: str) -> str:
28
+ print(f"Agent received question (first 50 chars): {question[:50]}...")
29
+ # Wrap the question in a HumanMessage from langchain_core
30
+ messages = [HumanMessage(content=question)]
31
+ messages = self.graph.invoke({"messages": messages})
32
+ answer = messages['messages'][-1].content
33
+ return answer[14:]
 
 
 
 
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
  def run_and_submit_all( profile: gr.OAuthProfile | None):
37
  """
38
  Fetches all questions, runs the BasicAgent on them, submits all answers,
39
  and displays the results.
40
  """
41
+ # --- Determine HF Space Runtime URL and Repo URL ---
42
  space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
43
 
44
  if profile:
 
52
  questions_url = f"{api_url}/questions"
53
  submit_url = f"{api_url}/submit"
54
 
55
+ # 1. Instantiate Agent ( modify this part to create your agent)
56
  try:
57
+ agent = BasicAgent()
 
 
 
 
 
58
  except Exception as e:
59
  print(f"Error instantiating agent: {e}")
60
  return f"Error initializing agent: {e}", None
61
+ # 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)
62
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
63
  print(agent_code)
64
 
 
90
  for item in questions_data:
91
  task_id = item.get("task_id")
92
  question_text = item.get("question")
 
93
  if not task_id or question_text is None:
94
  print(f"Skipping item with missing task_id or question: {item}")
95
  continue
96
+
97
+ # time.sleep(10)
98
+
99
  try:
100
+ submitted_answer = agent(question_text)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
102
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
103
  except Exception as e:
requirements.txt CHANGED
@@ -1,11 +1,5 @@
1
- gradio==5.28.0
2
- smolagents==1.14.0
3
- pandas==2.2.3
4
- requests==2.32.3
5
- beautifulsoup4==4.13.4
6
- duckduckgo-search==8.0.1
7
- openpyxl==3.1.5
8
- whisper==1.1.10
9
- torch==2.1.0
10
- ffmpeg-python==0.2.0
11
- python-dotenv==1.1.0
 
1
+ langgraph
2
+ langchain-core
3
+ gradio
4
+ pandas
5
+ requests