vandenn commited on
Commit
4a34730
·
1 Parent(s): 3ac96c7

Move HF files to this repository

Browse files
Files changed (12) hide show
  1. .env.example +2 -1
  2. .gitattributes +35 -0
  3. Makefile +4 -1
  4. README.md +15 -22
  5. app.py +5 -0
  6. pyproject.toml +4 -2
  7. requirements.txt +175 -0
  8. src/agent.py +12 -0
  9. src/main.py +0 -12
  10. src/settings.py +2 -1
  11. src/util.py +214 -0
  12. uv.lock +0 -0
.env.example CHANGED
@@ -1 +1,2 @@
1
- DUMMY_ENV_VAR=
 
 
1
+ HF_TOKEN=
2
+ DEFAULT_API_URL=https://agents-course-unit4-scoring.hf.space
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
Makefile CHANGED
@@ -7,5 +7,8 @@ lint:
7
  uv tool run ruff check --fix src
8
  uv tool run ruff format src
9
 
 
 
 
10
  run:
11
- uv run src/main.py
 
7
  uv tool run ruff check --fix src
8
  uv tool run ruff format src
9
 
10
+ sync-requirements:
11
+ uv export --no-hashes --format requirements-txt > requirements.txt
12
+
13
  run:
14
+ uv run app.py
README.md CHANGED
@@ -1,22 +1,15 @@
1
- <div align="center">
2
-
3
- # (Repository Name Here)
4
-
5
- ![python](https://img.shields.io/badge/python-3.11-blue)
6
-
7
- (description)
8
-
9
- </div>
10
-
11
- # 📄 Overview
12
-
13
- - (overview here)
14
-
15
- # 🛠 Setup
16
-
17
- Make sure you have `uv` installed in your system, then run:
18
- ```bash
19
- make init
20
- make run
21
- ```
22
- (other setup here)
 
1
+ ---
2
+ title: vandenn Agents Course Final
3
+ emoji: 🕵🏻‍♂️
4
+ colorFrom: indigo
5
+ colorTo: indigo
6
+ sdk: gradio
7
+ sdk_version: 5.25.2
8
+ app_file: app.py
9
+ pinned: false
10
+ hf_oauth: true
11
+ # optional, default duration is 8 hours/480 minutes. Max duration is 30 days/43200 minutes.
12
+ hf_oauth_expiration_minutes: 480
13
+ ---
14
+
15
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
app.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ from src.agent import BasicAgent
2
+ from src.util import initialize
3
+
4
+ if __name__ == "__main__":
5
+ initialize(BasicAgent())
pyproject.toml CHANGED
@@ -1,13 +1,15 @@
1
  [project]
2
- name = "project-name-here"
3
  version = "0.1.0"
4
- description = "Add your description here"
5
  readme = "README.md"
6
  requires-python = ">=3.11"
7
  dependencies = [
8
  "dotenv>=0.9.9",
 
9
  "pandas>=2.3.0",
10
  "pydantic-settings>=2.9.1",
 
11
  ]
12
 
13
  [tool.ruff]
 
1
  [project]
2
+ name = "agents-course-final"
3
  version = "0.1.0"
4
+ description = "vandenn's Agents Course Final Output in HuggingFace"
5
  readme = "README.md"
6
  requires-python = ">=3.11"
7
  dependencies = [
8
  "dotenv>=0.9.9",
9
+ "gradio[oauth]>=5.34.1",
10
  "pandas>=2.3.0",
11
  "pydantic-settings>=2.9.1",
12
+ "requests>=2.32.4",
13
  ]
14
 
15
  [tool.ruff]
requirements.txt ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This file was autogenerated by uv via the following command:
2
+ # uv export --no-hashes --format requirements-txt
3
+ aiofiles==24.1.0
4
+ # via gradio
5
+ annotated-types==0.7.0
6
+ # via pydantic
7
+ anyio==4.9.0
8
+ # via
9
+ # gradio
10
+ # httpx
11
+ # starlette
12
+ audioop-lts==0.2.1 ; python_full_version >= '3.13'
13
+ # via gradio
14
+ certifi==2025.6.15
15
+ # via
16
+ # httpcore
17
+ # httpx
18
+ # requests
19
+ charset-normalizer==3.4.2
20
+ # via requests
21
+ click==8.2.1 ; sys_platform != 'emscripten'
22
+ # via
23
+ # typer
24
+ # uvicorn
25
+ colorama==0.4.6 ; sys_platform == 'win32'
26
+ # via
27
+ # click
28
+ # tqdm
29
+ dotenv==0.9.9
30
+ # via agents-course-final
31
+ fastapi==0.115.13
32
+ # via gradio
33
+ ffmpy==0.6.0
34
+ # via gradio
35
+ filelock==3.18.0
36
+ # via huggingface-hub
37
+ fsspec==2025.5.1
38
+ # via
39
+ # gradio-client
40
+ # huggingface-hub
41
+ gradio==5.34.1
42
+ # via agents-course-final
43
+ gradio-client==1.10.3
44
+ # via gradio
45
+ groovy==0.1.2
46
+ # via gradio
47
+ h11==0.16.0
48
+ # via
49
+ # httpcore
50
+ # uvicorn
51
+ hf-xet==1.1.4 ; platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'
52
+ # via huggingface-hub
53
+ httpcore==1.0.9
54
+ # via httpx
55
+ httpx==0.28.1
56
+ # via
57
+ # gradio
58
+ # gradio-client
59
+ # safehttpx
60
+ huggingface-hub==0.33.0
61
+ # via
62
+ # gradio
63
+ # gradio-client
64
+ idna==3.10
65
+ # via
66
+ # anyio
67
+ # httpx
68
+ # requests
69
+ jinja2==3.1.6
70
+ # via gradio
71
+ markdown-it-py==3.0.0 ; sys_platform != 'emscripten'
72
+ # via rich
73
+ markupsafe==3.0.2
74
+ # via
75
+ # gradio
76
+ # jinja2
77
+ mdurl==0.1.2 ; sys_platform != 'emscripten'
78
+ # via markdown-it-py
79
+ numpy==2.3.0
80
+ # via
81
+ # gradio
82
+ # pandas
83
+ orjson==3.10.18
84
+ # via gradio
85
+ packaging==25.0
86
+ # via
87
+ # gradio
88
+ # gradio-client
89
+ # huggingface-hub
90
+ pandas==2.3.0
91
+ # via
92
+ # agents-course-final
93
+ # gradio
94
+ pillow==11.2.1
95
+ # via gradio
96
+ pydantic==2.11.6
97
+ # via
98
+ # fastapi
99
+ # gradio
100
+ # pydantic-settings
101
+ pydantic-core==2.33.2
102
+ # via pydantic
103
+ pydantic-settings==2.9.1
104
+ # via agents-course-final
105
+ pydub==0.25.1
106
+ # via gradio
107
+ pygments==2.19.1 ; sys_platform != 'emscripten'
108
+ # via rich
109
+ python-dateutil==2.9.0.post0
110
+ # via pandas
111
+ python-dotenv==1.1.0
112
+ # via
113
+ # dotenv
114
+ # pydantic-settings
115
+ python-multipart==0.0.20
116
+ # via gradio
117
+ pytz==2025.2
118
+ # via pandas
119
+ pyyaml==6.0.2
120
+ # via
121
+ # gradio
122
+ # huggingface-hub
123
+ requests==2.32.4
124
+ # via
125
+ # agents-course-final
126
+ # huggingface-hub
127
+ rich==14.0.0 ; sys_platform != 'emscripten'
128
+ # via typer
129
+ ruff==0.11.13
130
+ # via gradio
131
+ safehttpx==0.1.6
132
+ # via gradio
133
+ semantic-version==2.10.0
134
+ # via gradio
135
+ shellingham==1.5.4 ; sys_platform != 'emscripten'
136
+ # via typer
137
+ six==1.17.0
138
+ # via python-dateutil
139
+ sniffio==1.3.1
140
+ # via anyio
141
+ starlette==0.46.2
142
+ # via
143
+ # fastapi
144
+ # gradio
145
+ tomlkit==0.13.3
146
+ # via gradio
147
+ tqdm==4.67.1
148
+ # via huggingface-hub
149
+ typer==0.16.0 ; sys_platform != 'emscripten'
150
+ # via gradio
151
+ typing-extensions==4.14.0
152
+ # via
153
+ # anyio
154
+ # fastapi
155
+ # gradio
156
+ # gradio-client
157
+ # huggingface-hub
158
+ # pydantic
159
+ # pydantic-core
160
+ # typer
161
+ # typing-inspection
162
+ typing-inspection==0.4.1
163
+ # via
164
+ # pydantic
165
+ # pydantic-settings
166
+ tzdata==2025.2
167
+ # via pandas
168
+ urllib3==2.5.0
169
+ # via
170
+ # gradio
171
+ # requests
172
+ uvicorn==0.34.3 ; sys_platform != 'emscripten'
173
+ # via gradio
174
+ websockets==15.0.1
175
+ # via gradio-client
src/agent.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from src.util import BaseAgent
2
+
3
+
4
+ class BasicAgent(BaseAgent):
5
+ def __init__(self):
6
+ print("BasicAgent initialized.")
7
+
8
+ def run(self, question: str) -> str:
9
+ print(f"Agent received question (first 50 chars): {question[:50]}...")
10
+ fixed_answer = "This is the BasicAgent's default answer."
11
+ print(f"Agent returning fixed answer: {fixed_answer}")
12
+ return fixed_answer
src/main.py DELETED
@@ -1,12 +0,0 @@
1
- import numpy as np
2
- import pandas as pd
3
-
4
- from settings import settings
5
-
6
- if __name__ == "__main__":
7
- print("Hello world!")
8
-
9
- x = pd.Series([1, 2, 3, np.nan])
10
- print(x)
11
-
12
- print(f"Dummy Env Var: {settings.dummy_env_var}")
 
 
 
 
 
 
 
 
 
 
 
 
 
src/settings.py CHANGED
@@ -6,7 +6,8 @@ load_dotenv()
6
 
7
 
8
  class Settings(BaseSettings):
9
- dummy_env_var: str = Field(default=...)
 
10
 
11
 
12
  settings = Settings() # from settings import settings
 
6
 
7
 
8
  class Settings(BaseSettings):
9
+ hf_token: str = Field(default=...)
10
+ default_api_url: str = Field(default=...)
11
 
12
 
13
  settings = Settings() # from settings import settings
src/util.py ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from abc import ABC, abstractmethod
3
+
4
+ import gradio as gr
5
+ import pandas as pd
6
+ import requests
7
+
8
+ from src.settings import settings
9
+
10
+
11
+ class BaseAgent(ABC):
12
+ @abstractmethod
13
+ def run(self, question: str) -> str:
14
+ print(f"Agent received question (first 50 chars): {question[:50]}...")
15
+ fixed_answer = "This is the BaseAgent's default answer."
16
+ print(f"Agent returning fixed answer: {fixed_answer}")
17
+ return fixed_answer
18
+
19
+
20
+ def initialize(agent: BaseAgent) -> None:
21
+ print("\n" + "-" * 30 + " App Starting " + "-" * 30)
22
+ # Check for SPACE_HOST and SPACE_ID at startup for information
23
+ space_host_startup = os.getenv("SPACE_HOST")
24
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
25
+
26
+ if space_host_startup:
27
+ print(f"✅ SPACE_HOST found: {space_host_startup}")
28
+ print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
29
+ else:
30
+ print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
31
+
32
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
33
+ print(f"✅ SPACE_ID found: {space_id_startup}")
34
+ print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
35
+ print(
36
+ f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main"
37
+ )
38
+ else:
39
+ print(
40
+ "ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined."
41
+ )
42
+
43
+ print("-" * (60 + len(" App Starting ")) + "\n")
44
+
45
+ print("Launching Gradio Interface for Basic Agent Evaluation...")
46
+ launch_gradio_ui(agent)
47
+
48
+
49
+ def launch_gradio_ui(agent: BaseAgent) -> None:
50
+ def run_button_callback(profile: gr.OAuthProfile | None):
51
+ return run_and_submit_all(agent, profile)
52
+
53
+ with gr.Blocks() as demo:
54
+ gr.Markdown("# Basic Agent Evaluation Runner")
55
+ gr.Markdown(
56
+ """
57
+ **Instructions:**
58
+
59
+ 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
60
+ 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
61
+ 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
62
+
63
+ ---
64
+ **Disclaimers:**
65
+ 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).
66
+ 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.
67
+ """
68
+ )
69
+
70
+ gr.LoginButton()
71
+
72
+ run_button = gr.Button("Run Evaluation & Submit All Answers")
73
+
74
+ status_output = gr.Textbox(
75
+ label="Run Status / Submission Result", lines=5, interactive=False
76
+ )
77
+ # Removed max_rows=10 from DataFrame constructor
78
+ results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
79
+
80
+ run_button.click(fn=run_button_callback, outputs=[status_output, results_table])
81
+ demo.launch(debug=True, share=False)
82
+
83
+
84
+ def run_and_submit_all(agent: BaseAgent, profile: gr.OAuthProfile | None):
85
+ """
86
+ Fetches all questions, runs the BasicAgent on them, submits all answers,
87
+ and displays the results.
88
+ """
89
+ # --- Determine HF Space Runtime URL and Repo URL ---
90
+ space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
91
+
92
+ if profile:
93
+ username = f"{profile.username}"
94
+ print(f"User logged in: {username}")
95
+ else:
96
+ print("User not logged in.")
97
+ return "Please Login to Hugging Face with the button.", None
98
+
99
+ api_url = settings.default_api_url
100
+ questions_url = f"{api_url}/questions"
101
+ submit_url = f"{api_url}/submit"
102
+
103
+ # 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)
104
+ agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
105
+ print(agent_code)
106
+
107
+ # Fetch Questions
108
+ print(f"Fetching questions from: {questions_url}")
109
+ try:
110
+ response = requests.get(questions_url, timeout=15)
111
+ response.raise_for_status()
112
+ questions_data = response.json()
113
+ if not questions_data:
114
+ print("Fetched questions list is empty.")
115
+ return "Fetched questions list is empty or invalid format.", None
116
+ print(f"Fetched {len(questions_data)} questions.")
117
+ except requests.exceptions.RequestException as e:
118
+ print(f"Error fetching questions: {e}")
119
+ return f"Error fetching questions: {e}", None
120
+ except requests.exceptions.JSONDecodeError as e:
121
+ print(f"Error decoding JSON response from questions endpoint: {e}")
122
+ print(f"Response text: {response.text[:500]}")
123
+ return f"Error decoding server response for questions: {e}", None
124
+ except Exception as e:
125
+ print(f"An unexpected error occurred fetching questions: {e}")
126
+ return f"An unexpected error occurred fetching questions: {e}", None
127
+
128
+ # Run your Agent
129
+ results_log = []
130
+ answers_payload = []
131
+ print(f"Running agent on {len(questions_data)} questions...")
132
+ for item in questions_data:
133
+ task_id = item.get("task_id")
134
+ question_text = item.get("question")
135
+ if not task_id or question_text is None:
136
+ print(f"Skipping item with missing task_id or question: {item}")
137
+ continue
138
+ try:
139
+ submitted_answer = agent.run(question_text)
140
+ answers_payload.append(
141
+ {"task_id": task_id, "submitted_answer": submitted_answer}
142
+ )
143
+ results_log.append(
144
+ {
145
+ "Task ID": task_id,
146
+ "Question": question_text,
147
+ "Submitted Answer": submitted_answer,
148
+ }
149
+ )
150
+ except Exception as e:
151
+ print(f"Error running agent on task {task_id}: {e}")
152
+ results_log.append(
153
+ {
154
+ "Task ID": task_id,
155
+ "Question": question_text,
156
+ "Submitted Answer": f"AGENT ERROR: {e}",
157
+ }
158
+ )
159
+
160
+ if not answers_payload:
161
+ print("Agent did not produce any answers to submit.")
162
+ return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
163
+
164
+ # Prepare Submission
165
+ submission_data = {
166
+ "username": username.strip(),
167
+ "agent_code": agent_code,
168
+ "answers": answers_payload,
169
+ }
170
+ status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
171
+ print(status_update)
172
+
173
+ # Submit
174
+ print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
175
+ try:
176
+ response = requests.post(submit_url, json=submission_data, timeout=60)
177
+ response.raise_for_status()
178
+ result_data = response.json()
179
+ final_status = (
180
+ f"Submission Successful!\n"
181
+ f"User: {result_data.get('username')}\n"
182
+ f"Overall Score: {result_data.get('score', 'N/A')}% "
183
+ f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
184
+ f"Message: {result_data.get('message', 'No message received.')}"
185
+ )
186
+ print("Submission successful.")
187
+ results_df = pd.DataFrame(results_log)
188
+ return final_status, results_df
189
+ except requests.exceptions.HTTPError as e:
190
+ error_detail = f"Server responded with status {e.response.status_code}."
191
+ try:
192
+ error_json = e.response.json()
193
+ error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
194
+ except requests.exceptions.JSONDecodeError:
195
+ error_detail += f" Response: {e.response.text[:500]}"
196
+ status_message = f"Submission Failed: {error_detail}"
197
+ print(status_message)
198
+ results_df = pd.DataFrame(results_log)
199
+ return status_message, results_df
200
+ except requests.exceptions.Timeout:
201
+ status_message = "Submission Failed: The request timed out."
202
+ print(status_message)
203
+ results_df = pd.DataFrame(results_log)
204
+ return status_message, results_df
205
+ except requests.exceptions.RequestException as e:
206
+ status_message = f"Submission Failed: Network error - {e}"
207
+ print(status_message)
208
+ results_df = pd.DataFrame(results_log)
209
+ return status_message, results_df
210
+ except Exception as e:
211
+ status_message = f"An unexpected error occurred during submission: {e}"
212
+ print(status_message)
213
+ results_df = pd.DataFrame(results_log)
214
+ return status_message, results_df
uv.lock CHANGED
The diff for this file is too large to render. See raw diff