Adex2121 commited on
Commit
a58b995
·
1 Parent(s): d6585c7

Initial agent submission

Browse files
.gitignore ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ env/
12
+ venvAgentsHf/
13
+ venv/
14
+ ENV/
15
+ env.bak/
16
+ venv.bak/
17
+ *.egg
18
+ *.egg-info/
19
+ dist/
20
+ build/
21
+ .eggs/
22
+
23
+ # Installer logs
24
+ pip-log.txt
25
+ pip-delete-this-directory.txt
26
+
27
+ # Unit test / coverage reports
28
+ htmlcov/
29
+ .tox/
30
+ .nox/
31
+ .coverage
32
+ .cache
33
+ nosetests.xml
34
+ coverage.xml
35
+ *.cover
36
+ *.py,cover
37
+
38
+ # Pytest cache
39
+ .pytest_cache/
40
+
41
+ # MyPy
42
+ .mypy_cache/
43
+ .dmypy.json
44
+ dmypy.json
45
+
46
+ # Pyre
47
+ .pyre/
48
+
49
+ # Pytype
50
+ .pytype/
51
+
52
+ # Cython debug symbols
53
+ cython_debug/
54
+
55
+ # VSCode settings
56
+ .vscode/
57
+
58
+ # macOS
59
+ .DS_Store
60
+
61
+ # Jupyter
62
+ .ipynb_checkpoints
63
+
64
+ # dotenv
65
+ .env
66
+ .env.*
67
+
68
+ # Local test/output files
69
+ *.log
70
+ *.out
71
+ *.tmp
72
+
73
+ # Obsidian vault temporary/backup files
74
+ *.obsidian
agentsTools/toolVisitWebpage.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from smolagents import tool
2
+ import requests
3
+ from bs4 import BeautifulSoup
4
+
5
+ MAX_WEBPAGE_SIZE = 3000 # max characters to return from scraped content
6
+
7
+ @tool
8
+ def visit_webpage(url: str) -> dict:
9
+ """
10
+ Visits a webpage and extracts clean text from it.
11
+
12
+ Args:
13
+ url: The URL of the page to visit (e.g., https://en.wikipedia.org/wiki/OpenAI)
14
+
15
+ Returns:
16
+ dict: A dictionary containing:
17
+ - "text": Truncated page content
18
+ - "url": The original URL
19
+ - "status": HTTP status or error info
20
+ """
21
+ print(f" Tool:visit_webpage visiting {url}...")
22
+
23
+ try:
24
+ response = requests.get(url, timeout=10)
25
+ response.raise_for_status()
26
+
27
+ soup = BeautifulSoup(response.text, "html.parser")
28
+ text = soup.get_text(separator="\n", strip=True)
29
+ short_text = text[:MAX_WEBPAGE_SIZE]
30
+
31
+ print(f"✅ Extracted {len(short_text)} characters from {url}")
32
+ return {
33
+ "text": short_text,
34
+ "url": url,
35
+ "status": f"Success ({response.status_code})"
36
+ }
37
+
38
+ except Exception as e:
39
+ print(f"🚨 Error in visit_webpage: {e}")
40
+ return {
41
+ "text": "",
42
+ "url": url,
43
+ "status": f"Error: {e}"
44
+ }
agentsTools/tool_fetch_task_file.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from smolagents import tool
2
+ import os
3
+ import requests
4
+
5
+ DEFAULT_API_URL = os.getenv("AGENT_API_URL", "https://agents-course-unit4-scoring.hf.space")
6
+
7
+ @tool
8
+ def fetch_task_file(task_id: str) -> dict:
9
+ """
10
+ Fetches the file associated with a task ID using the API URL from env.
11
+
12
+ Args:
13
+ task_id: The task ID to fetch.
14
+
15
+ Returns:
16
+ dict: task_id, content, status
17
+ """
18
+ full_url = f"{DEFAULT_API_URL}/files/{task_id}"
19
+ print(f"📥 Tool:fetch_task_file requesting {full_url}")
20
+
21
+ try:
22
+ response = requests.get(full_url, timeout=10)
23
+
24
+ if response.status_code == 200:
25
+ return {
26
+ "task_id": task_id,
27
+ "content": response.text[:5000],
28
+ "status": "Success"
29
+ }
30
+
31
+ return {
32
+ "task_id": task_id,
33
+ "content": "",
34
+ "status": f"{response.status_code} - {response.reason}"
35
+ }
36
+
37
+ except Exception as e:
38
+ return {
39
+ "task_id": task_id,
40
+ "content": "",
41
+ "status": f"Error: {str(e)}"
42
+ }
agentsTools/tool_read_excel_as_json.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from smolagents import tool
2
+ import os
3
+ import requests
4
+ import pandas as pd
5
+ from io import BytesIO
6
+
7
+ DEFAULT_API_URL = os.getenv("AGENT_API_URL", "https://agents-course-unit4-scoring.hf.space")
8
+
9
+ @tool
10
+ def read_excel_as_json(task_id: str) -> dict:
11
+ """
12
+ Fetches and parses an Excel file as structured JSON for a given task_id.
13
+
14
+ Args:
15
+ task_id: The task ID to fetch.
16
+
17
+ Returns:
18
+ {
19
+ "task_id": str,
20
+ "sheets": {
21
+ "SheetName1": [ {col1: val1, col2: val2, ...}, ... ],
22
+ ...
23
+ },
24
+ "status": "Success" | "Error"
25
+ }
26
+ """
27
+ url = f"{DEFAULT_API_URL}/files/{task_id}"
28
+
29
+ try:
30
+ response = requests.get(url, timeout=10)
31
+ if response.status_code != 200:
32
+ return {"task_id": task_id, "sheets": {}, "status": f"{response.status_code} - Failed"}
33
+
34
+ xls = pd.ExcelFile(BytesIO(response.content))
35
+ sheets_json = {}
36
+
37
+ for sheet in xls.sheet_names:
38
+ df = xls.parse(sheet)
39
+ df = df.dropna(how="all") # Remove completely empty rows
40
+ rows = df.head(20).to_dict(orient="records") # limit to first 20 rows
41
+ sheets_json[sheet] = rows
42
+
43
+ return {
44
+ "task_id": task_id,
45
+ "sheets": sheets_json,
46
+ "status": "Success"
47
+ }
48
+
49
+ except Exception as e:
50
+ return {
51
+ "task_id": task_id,
52
+ "sheets": {},
53
+ "status": f"Error: {str(e)}"
54
+ }
app.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import requests
4
+ import pandas as pd
5
+
6
+ from smolagents import ToolCallingAgent, OpenAIServerModel
7
+ from smolagents import DuckDuckGoSearchTool, PythonInterpreterTool
8
+ from agentsTools.toolVisitWebpage import visit_webpage
9
+ from agentsTools.tool_fetch_task_file import fetch_task_file
10
+ from agentsTools.tool_read_excel_as_json import read_excel_as_json
11
+
12
+ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
13
+
14
+ class GeminiReActAgent:
15
+ def __init__(self):
16
+ self.model = OpenAIServerModel(
17
+ model_id="gemini-2.5-pro-preview-03-25",
18
+ api_base="https://generativelanguage.googleapis.com/v1beta/",
19
+ api_key=os.getenv("GEMINI_API_KEY_1")
20
+ )
21
+ self.agent = ToolCallingAgent(
22
+ tools=[
23
+ DuckDuckGoSearchTool(),
24
+ PythonInterpreterTool(),
25
+ visit_webpage,
26
+ fetch_task_file,
27
+ read_excel_as_json,
28
+ ],
29
+ model=self.model,
30
+ max_steps=8
31
+ )
32
+
33
+ def __call__(self, question: str, taskid: str) -> str:
34
+ prompt = """
35
+ You are an intelligent assistant answering questions step-by-step.
36
+ Use tools only when necessary. You can take up to 8 steps.
37
+ You have access to tools such as a web search, Python execution, and file reading.
38
+ Use the task ID {tid} if you need to fetch additional data.
39
+
40
+ Think aloud, justify each step. Conclude your process with:
41
+ FINAL ANSWER = [your answer here]
42
+
43
+ Question: {q}
44
+ """.format(tid=taskid, q=question)
45
+
46
+ result = self.agent.run(prompt)
47
+ return result
48
+
49
+ def submit_eval_run(profile: gr.OAuthProfile | None):
50
+ space_id = os.getenv("SPACE_ID")
51
+ if profile:
52
+ username = profile.username
53
+ else:
54
+ return "Please login to Hugging Face first.", None
55
+
56
+ agent = GeminiReActAgent()
57
+ agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
58
+
59
+ try:
60
+ response = requests.get(f"{DEFAULT_API_URL}/questions", timeout=15)
61
+ response.raise_for_status()
62
+ questions_data = response.json()
63
+ except Exception as e:
64
+ return f"Failed to fetch questions: {e}", None
65
+
66
+ results_log = []
67
+ answers_payload = []
68
+ for item in questions_data:
69
+ task_id = item.get("task_id")
70
+ question_text = item.get("question")
71
+ if not task_id or question_text is None:
72
+ continue
73
+ try:
74
+ submitted_answer = agent(question_text, task_id)
75
+ answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
76
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
77
+ except Exception as e:
78
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"ERROR: {e}"})
79
+
80
+ if not answers_payload:
81
+ return "Agent did not return any answers.", pd.DataFrame(results_log)
82
+
83
+ submission_data = {
84
+ "username": username,
85
+ "agent_code": agent_code,
86
+ "answers": answers_payload
87
+ }
88
+
89
+ try:
90
+ response = requests.post(f"{DEFAULT_API_URL}/submit", json=submission_data, timeout=60)
91
+ response.raise_for_status()
92
+ result = response.json()
93
+ summary = (
94
+ f"Submission Successful!\n"
95
+ f"User: {result.get('username')}\n"
96
+ f"Score: {result.get('score')}% ({result.get('correct_count')}/{result.get('total_attempted')})\n"
97
+ f"Message: {result.get('message', 'No message received.')}"
98
+ )
99
+ return summary, pd.DataFrame(results_log)
100
+ except Exception as e:
101
+ return f"Submission failed: {e}", pd.DataFrame(results_log)
102
+
103
+ with gr.Blocks() as demo:
104
+ gr.Markdown("# Gemini Agent Submission Tool")
105
+ gr.LoginButton()
106
+ btn = gr.Button("Submit Answers")
107
+ status = gr.Textbox(label="Submission Status")
108
+ table = gr.DataFrame(label="Answers Log")
109
+ btn.click(fn=submit_eval_run, outputs=[status, table])
110
+
111
+ demo.launch(debug=True, share=False)
requirements.txt ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ aiofiles==24.1.0
2
+ annotated-types==0.7.0
3
+ anyio==4.9.0
4
+ Authlib==1.5.2
5
+ beautifulsoup4==4.13.4
6
+ bs4==0.0.2
7
+ certifi==2025.1.31
8
+ cffi==1.17.1
9
+ charset-normalizer==3.4.1
10
+ click==8.1.8
11
+ colorama==0.4.6
12
+ cryptography==44.0.2
13
+ distro==1.9.0
14
+ duckduckgo_search==8.0.1
15
+ fastapi==0.115.12
16
+ ffmpy==0.5.0
17
+ filelock==3.18.0
18
+ fsspec==2025.3.2
19
+ gradio==5.26.0
20
+ gradio_client==1.9.0
21
+ groovy==0.1.2
22
+ h11==0.16.0
23
+ httpcore==1.0.9
24
+ httpx==0.28.1
25
+ huggingface-hub==0.30.2
26
+ idna==3.10
27
+ itsdangerous==2.2.0
28
+ Jinja2==3.1.6
29
+ jiter==0.9.0
30
+ lxml==5.4.0
31
+ markdown-it-py==3.0.0
32
+ markdownify==1.1.0
33
+ MarkupSafe==3.0.2
34
+ mdurl==0.1.2
35
+ numpy==2.2.5
36
+ openai==1.76.0
37
+ orjson==3.10.16
38
+ packaging==25.0
39
+ pandas==2.2.3
40
+ pillow==11.2.1
41
+ primp==0.15.0
42
+ pycparser==2.22
43
+ pydantic==2.11.3
44
+ pydantic_core==2.33.1
45
+ pydub==0.25.1
46
+ Pygments==2.19.1
47
+ python-dateutil==2.9.0.post0
48
+ python-dotenv==1.1.0
49
+ python-multipart==0.0.20
50
+ pytz==2025.2
51
+ PyYAML==6.0.2
52
+ requests==2.32.3
53
+ rich==14.0.0
54
+ ruff==0.11.7
55
+ safehttpx==0.1.6
56
+ semantic-version==2.10.0
57
+ shellingham==1.5.4
58
+ six==1.17.0
59
+ smolagents==1.14.0
60
+ sniffio==1.3.1
61
+ soupsieve==2.7
62
+ starlette==0.46.2
63
+ tomlkit==0.13.2
64
+ tqdm==4.67.1
65
+ typer==0.15.2
66
+ typing-inspection==0.4.0
67
+ typing_extensions==4.13.2
68
+ tzdata==2025.2
69
+ urllib3==2.4.0
70
+ uvicorn==0.34.2
71
+ websockets==15.0.1