yplam commited on
Commit
2dfc476
·
1 Parent(s): 81917a3

Add simple tools

Browse files
Files changed (8) hide show
  1. .gitignore +178 -0
  2. README.md +16 -1
  3. agent.py +79 -0
  4. app.py +132 -83
  5. requirements.txt +4 -1
  6. tool/files.py +5 -0
  7. tool/math.py +3 -0
  8. tool/youtube.py +30 -0
.gitignore ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+
110
+ # pdm
111
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
112
+ #pdm.lock
113
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
114
+ # in version control.
115
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
116
+ .pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
121
+ __pypackages__/
122
+
123
+ # Celery stuff
124
+ celerybeat-schedule
125
+ celerybeat.pid
126
+
127
+ # SageMath parsed files
128
+ *.sage.py
129
+
130
+ # Environments
131
+ .env
132
+ .venv
133
+ env/
134
+ venv/
135
+ ENV/
136
+ env.bak/
137
+ venv.bak/
138
+
139
+ # Spyder project settings
140
+ .spyderproject
141
+ .spyproject
142
+
143
+ # Rope project settings
144
+ .ropeproject
145
+
146
+ # mkdocs documentation
147
+ /site
148
+
149
+ # mypy
150
+ .mypy_cache/
151
+ .dmypy.json
152
+ dmypy.json
153
+
154
+ # Pyre type checker
155
+ .pyre/
156
+
157
+ # pytype static type analyzer
158
+ .pytype/
159
+
160
+ # Cython debug symbols
161
+ cython_debug/
162
+
163
+ # PyCharm
164
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
165
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
166
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
167
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
168
+ #.idea/
169
+
170
+ # Ruff stuff:
171
+ .ruff_cache/
172
+
173
+ # PyPI configuration file
174
+ .pypirc
175
+
176
+ .env
177
+ venv/
178
+ graph.png
README.md CHANGED
@@ -12,4 +12,19 @@ hf_oauth: true
12
  hf_oauth_expiration_minutes: 480
13
  ---
14
 
15
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  hf_oauth_expiration_minutes: 480
13
  ---
14
 
15
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
16
+
17
+ ## Environment Configuration
18
+
19
+ 1. Copy the `.env.template` file to `.env`:
20
+ ```
21
+ cp .env.template .env
22
+ ```
23
+
24
+ 2. Edit the `.env` file with your configuration:
25
+ ```
26
+ # OpenAI API Configuration
27
+ OPENAI_API_KEY=your_openai_api_key_here
28
+ OPENAI_API_BASE=https://api.openai.com/v1
29
+ OPENAI_PROXY=http://127.0.0.1:7899
30
+ ```
agent.py ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from typing import Annotated, Optional, TypedDict
3
+ from langgraph.graph.message import add_messages
4
+ from langchain_core.messages import AnyMessage, SystemMessage, HumanMessage
5
+ from tool.files import read_file
6
+ from tool.math import divide
7
+ from langchain.chat_models import init_chat_model
8
+ from langgraph.graph import StateGraph, MessagesState, START, END
9
+ from langgraph.prebuilt import ToolNode
10
+
11
+ from tool.youtube import get_video_id, youtube_transcript
12
+
13
+
14
+
15
+ tools = [
16
+ get_video_id,
17
+ youtube_transcript,
18
+ read_file
19
+ ]
20
+
21
+ llm_with_tools = init_chat_model(
22
+ model="gpt-4o",
23
+ model_provider="openai",
24
+ max_retries=2,
25
+ openai_api_base=os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1"),
26
+ openai_api_key=os.getenv("OPENAI_API_KEY"),
27
+ openai_proxy=os.getenv("OPENAI_PROXY"),
28
+ ).bind_tools(tools)
29
+
30
+
31
+ class State(TypedDict):
32
+ input_file: Optional[str]
33
+ messages: Annotated[list[AnyMessage], add_messages]
34
+
35
+ def should_continue(state: State):
36
+ messages = state["messages"]
37
+ last_message = messages[-1]
38
+ if last_message.tool_calls:
39
+ return "tools"
40
+ return END
41
+
42
+
43
+
44
+ def agent(state: State):
45
+ system_message_content = "You are a helpful assistant that can read files and calling tools to answer questions. You should output results directly, without any additional text or explanation."
46
+ if state["input_file"]:
47
+ system_message_content += f"\nYou are given a file: {state['input_file']}"
48
+ system_message = SystemMessage(content=system_message_content)
49
+ messages = [system_message] + state["messages"]
50
+ return {"messages": [llm_with_tools.invoke(messages)]}
51
+
52
+
53
+ class Agent:
54
+ def __init__(self):
55
+ print("BasicAgent initialized.")
56
+
57
+ tool_node = ToolNode(tools)
58
+ graph_builder = StateGraph(State)
59
+ graph_builder.add_node("agent", agent)
60
+ graph_builder.add_node("tools", tool_node)
61
+
62
+ graph_builder.add_edge(START, "agent")
63
+ graph_builder.add_conditional_edges("agent", should_continue, ["tools", END])
64
+ graph_builder.add_edge("tools", "agent")
65
+ self.graph = graph_builder.compile()
66
+ try:
67
+ # Save graph visualization as PNG file
68
+ graph_viz = self.graph.get_graph()
69
+ with open("graph.png", "wb") as f:
70
+ f.write(graph_viz.draw_mermaid_png())
71
+ print("Graph visualization saved as 'graph.png'")
72
+ except Exception as e:
73
+ # Drawing requires graphviz to be installed
74
+ print(f"Could not save graph visualization: {str(e)}")
75
+ pass
76
+
77
+ def __call__(self, question: str, file_name: str|None) -> str:
78
+ result = self.graph.invoke({"input_file": file_name, "messages": [HumanMessage(content=question)]})
79
+ return result["messages"][-1].content
app.py CHANGED
@@ -1,34 +1,47 @@
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 +53,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
@@ -76,11 +89,17 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
76
  for item in questions_data:
77
  task_id = item.get("task_id")
78
  question_text = item.get("question")
 
 
79
  if not task_id or question_text is None:
80
  print(f"Skipping item with missing task_id or question: {item}")
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:
@@ -95,83 +114,107 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
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
-
99
- # 5. Submit
100
- print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
101
- try:
102
- response = requests.post(submit_url, json=submission_data, timeout=60)
103
- response.raise_for_status()
104
- result_data = response.json()
105
- final_status = (
106
- f"Submission Successful!\n"
107
- f"User: {result_data.get('username')}\n"
108
- f"Overall Score: {result_data.get('score', 'N/A')}% "
109
- f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
110
- f"Message: {result_data.get('message', 'No message received.')}"
111
- )
112
- print("Submission successful.")
113
- results_df = pd.DataFrame(results_log)
114
- return final_status, results_df
115
- except requests.exceptions.HTTPError as e:
116
- error_detail = f"Server responded with status {e.response.status_code}."
117
  try:
118
- error_json = e.response.json()
119
- error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
120
- except requests.exceptions.JSONDecodeError:
121
- error_detail += f" Response: {e.response.text[:500]}"
122
- status_message = f"Submission Failed: {error_detail}"
123
- print(status_message)
124
- results_df = pd.DataFrame(results_log)
125
- return status_message, results_df
126
- except requests.exceptions.Timeout:
127
- status_message = "Submission Failed: The request timed out."
128
- print(status_message)
129
- results_df = pd.DataFrame(results_log)
130
- return status_message, results_df
131
- except requests.exceptions.RequestException as e:
132
- status_message = f"Submission Failed: Network error - {e}"
133
- print(status_message)
134
- results_df = pd.DataFrame(results_log)
135
- return status_message, results_df
136
- except Exception as e:
137
- status_message = f"An unexpected error occurred during submission: {e}"
138
- print(status_message)
139
- results_df = pd.DataFrame(results_log)
140
- return status_message, results_df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
 
 
 
 
 
 
 
 
142
 
143
- # --- Build Gradio Interface using Blocks ---
144
- with gr.Blocks() as demo:
145
- gr.Markdown("# Basic Agent Evaluation Runner")
146
- gr.Markdown(
147
- """
148
- **Instructions:**
149
 
150
- 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
151
- 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
152
- 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
 
 
 
 
 
153
 
154
- ---
155
- **Disclaimers:**
156
- 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).
157
- 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.
158
- """
159
- )
160
 
161
- gr.LoginButton()
 
 
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")
@@ -192,5 +235,11 @@ if __name__ == "__main__":
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
+ from dotenv import load_dotenv
3
  import gradio as gr
4
  import requests
5
  import inspect
6
  import pandas as pd
7
 
8
+ from agent import Agent
9
+
10
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
11
+ DEFAULT_SPACE_ID = "yplam/Final_Assignment_Template"
12
 
13
+ def download_file(filename: str) -> str:
14
+ """
15
+ Downloads a file from the API and returns the path to the local file.
16
+ """
17
+ return None
18
+ if filename is None or filename == "":
19
+ return None
20
+ print(f"Downloading file: {filename}")
21
+ file_url = f"{DEFAULT_API_URL}/files/{filename}"
22
+ local_path = os.path.join(tempfile.gettempdir(), filename)
23
+ response = requests.get(file_url, timeout=15)
24
+ try:
25
+ with open(local_path, 'wb') as f:
26
+ f.write(response.content)
27
+ print(f"Successfully downloaded file to: {local_path}")
28
+ return local_path
29
+ except Exception as e:
30
+ print(f"Error downloading file {filename}: {e}")
31
+ return None
32
+
33
 
34
+ def run_all( username: str|None, submit: bool = True):
35
  """
36
  Fetches all questions, runs the BasicAgent on them, submits all answers,
37
  and displays the results.
38
  """
39
  # --- Determine HF Space Runtime URL and Repo URL ---
40
  space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
41
+ if not space_id:
42
+ space_id = DEFAULT_SPACE_ID
43
 
44
+ if username:
 
45
  print(f"User logged in: {username}")
46
  else:
47
  print("User not logged in.")
 
53
 
54
  # 1. Instantiate Agent ( modify this part to create your agent)
55
  try:
56
+ agent = Agent()
57
  except Exception as e:
58
  print(f"Error instantiating agent: {e}")
59
  return f"Error initializing agent: {e}", None
 
89
  for item in questions_data:
90
  task_id = item.get("task_id")
91
  question_text = item.get("question")
92
+ file_name = item.get("file_name") or ""
93
+ file_path = download_file(file_name)
94
  if not task_id or question_text is None:
95
  print(f"Skipping item with missing task_id or question: {item}")
96
  continue
97
  try:
98
+ print("-"*100)
99
+ print(f"Running agent on task {task_id}: {question_text}")
100
+ submitted_answer = agent(question_text, "")
101
+ print(f"Submitted answer: {submitted_answer}")
102
+ print("-"*100)
103
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
104
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
105
  except Exception as e:
 
114
  submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
115
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
116
  print(status_update)
117
+
118
+ if submit:
119
+ print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  try:
121
+ response = requests.post(submit_url, json=submission_data, timeout=60)
122
+ response.raise_for_status()
123
+ result_data = response.json()
124
+ final_status = (
125
+ f"Submission Successful!\n"
126
+ f"User: {result_data.get('username')}\n"
127
+ f"Overall Score: {result_data.get('score', 'N/A')}% "
128
+ f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
129
+ f"Message: {result_data.get('message', 'No message received.')}"
130
+ )
131
+ print("Submission successful.")
132
+ results_df = pd.DataFrame(results_log)
133
+ return final_status, results_df
134
+ except requests.exceptions.HTTPError as e:
135
+ error_detail = f"Server responded with status {e.response.status_code}."
136
+ try:
137
+ error_json = e.response.json()
138
+ error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
139
+ except requests.exceptions.JSONDecodeError:
140
+ error_detail += f" Response: {e.response.text[:500]}"
141
+ status_message = f"Submission Failed: {error_detail}"
142
+ print(status_message)
143
+ results_df = pd.DataFrame(results_log)
144
+ return status_message, results_df
145
+ except requests.exceptions.Timeout:
146
+ status_message = "Submission Failed: The request timed out."
147
+ print(status_message)
148
+ results_df = pd.DataFrame(results_log)
149
+ return status_message, results_df
150
+ except requests.exceptions.RequestException as e:
151
+ status_message = f"Submission Failed: Network error - {e}"
152
+ print(status_message)
153
+ results_df = pd.DataFrame(results_log)
154
+ return status_message, results_df
155
+ except Exception as e:
156
+ status_message = f"An unexpected error occurred during submission: {e}"
157
+ print(status_message)
158
+ results_df = pd.DataFrame(results_log)
159
+ return status_message, results_df
160
+ else:
161
+ return "Submission skipped.", pd.DataFrame(results_log)
162
+
163
+ def run_and_submit_all( profile: gr.OAuthProfile | None):
164
+ username = profile.username if profile else None
165
+ return run_all(username)
166
+
167
+
168
+ def run_local_agent():
169
+ return run_all('yplam', False)
170
+
171
 
172
+ def build_gradio_interface():
173
+ # --- Build Gradio Interface using Blocks ---
174
+ with gr.Blocks() as demo:
175
+ gr.Markdown("# Basic Agent Evaluation Runner")
176
+ gr.Markdown(
177
+ """
178
+ **Instructions:**
179
 
180
+ 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
181
+ 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
182
+ 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
 
 
 
183
 
184
+ ---
185
+ **Disclaimers:**
186
+ 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).
187
+ 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.
188
+ """
189
+ )
190
+
191
+ gr.LoginButton()
192
 
193
+ run_button = gr.Button("Run Evaluation & Submit All Answers")
 
 
 
 
 
194
 
195
+ status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
196
+ # Removed max_rows=10 from DataFrame constructor
197
+ results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
198
 
199
+ run_button.click(
200
+ fn=run_and_submit_all,
201
+ outputs=[status_output, results_table]
202
+ )
203
+ return demo
204
 
205
+ def run_fixed_agent():
206
+ try:
207
+ agent = Agent()
208
+ question_text = "Examine the video at https://www.youtube.com/watch?v=1htKBjuUWec.\n\nWhat does Teal'c say in response to the question \"Isn't that hot?\""
209
+ answer = agent(question_text, "")
210
+ print(f"\nQuestion: {question_text}")
211
+ print(f"Answer: {answer}")
212
+ except Exception as e:
213
+ print(f"Error running agent: {e}")
214
 
 
 
 
 
215
 
216
  if __name__ == "__main__":
217
+ load_dotenv()
218
  print("\n" + "-"*30 + " App Starting " + "-"*30)
219
  # Check for SPACE_HOST and SPACE_ID at startup for information
220
  space_host_startup = os.getenv("SPACE_HOST")
 
235
 
236
  print("-"*(60 + len(" App Starting ")) + "\n")
237
 
238
+ if not space_id_startup:
239
+ print("Running locally.")
240
+ run_local_agent()
241
+ exit()
242
+
243
  print("Launching Gradio Interface for Basic Agent Evaluation...")
244
+ demo = build_gradio_interface()
245
  demo.launch(debug=True, share=False)
requirements.txt CHANGED
@@ -1,2 +1,5 @@
1
  gradio
2
- requests
 
 
 
 
1
  gradio
2
+ requests
3
+ langgraph
4
+ langchain_openai
5
+ python-dotenv
tool/files.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ def read_file(file_path: str) -> str:
2
+ """Reads the content of a file and returns it as a string."""
3
+ print(f"Reading file: {file_path}")
4
+ with open(file_path, 'r') as file:
5
+ return file.read()
tool/math.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ def divide(a: int, b: int) -> float:
2
+ """Divide a and b - for Master Wayne's occasional calculations."""
3
+ return a / b
tool/youtube.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from youtube_transcript_api import YouTubeTranscriptApi
3
+ from youtube_transcript_api.proxies import GenericProxyConfig
4
+
5
+ def youtube_transcript(video_id: str) -> str:
6
+ """
7
+ Extracts the transcript from a YouTube video id
8
+ """
9
+ print(f"Extracting transcript from: {video_id}")
10
+ try:
11
+ ytt_api = YouTubeTranscriptApi(
12
+ proxy_config=GenericProxyConfig(
13
+ http_url=os.getenv("PROXY_URL"),
14
+ https_url=os.getenv("PROXY_URL"),
15
+ )
16
+ )
17
+ transcript = ytt_api.fetch(video_id)
18
+ print(f"Transcript: {transcript}")
19
+ return transcript
20
+ except Exception as e:
21
+ print(f"Error extracting transcript: {e}")
22
+ return ""
23
+
24
+ def get_video_id(url: str) -> str:
25
+ """
26
+ Extracts the video id from a YouTube url
27
+ """
28
+ print(f"Extracting video id from: {url}")
29
+ return url.split("v=")[1]
30
+