AlbertoFor commited on
Commit
731825e
·
1 Parent(s): 6a809e4

Added comments

Browse files
app.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import os
2
  import gradio as gr
3
  import requests
@@ -41,6 +42,7 @@ from tools.fetch_web_page import FetchWebPageTool
41
  load_dotenv(".env", override=True)
42
  BRAVE_API_KEY = os.getenv("BRAVE_API")
43
 
 
44
  class State(TypedDict):
45
  file_path : str
46
  file: Optional[str]
@@ -55,8 +57,10 @@ class State(TypedDict):
55
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
56
 
57
  # --- Basic Agent Definition ---
 
58
  class BasicAgent:
59
- def __init__(self):
 
60
  tools = [CodeGenTool(), PythonExecutionTool(temp_dir="./"), YoutubeTranscriptTool(),
61
  AnswerQuestionFromFileTool(), AnswerQuestionTool(), DownloadFile(),
62
  ReverseString(), WebSearchTool(), WikipediaTool(), AnswerExcelTool(), ChessTool(), AudioTool(), FetchWebPageTool()]
@@ -64,12 +68,12 @@ class BasicAgent:
64
  #llm = ChatGoogleGenerativeAI(
65
  # model="gemini-2.0-flash",
66
  # temperature=0)
67
- llm = ChatOpenAI(model="gpt-4.1-mini", temperature=0)
68
  self.llm_with_tools = llm.bind_tools(tools)
69
 
70
- builder = StateGraph(State)
71
 
72
- builder.add_node("assistant", self.assistant)
73
  builder.add_node("tools", ToolNode(tools))
74
  builder.add_node("final_answer", BasicAgent.final_answer)
75
  #builder.add_node("download_file", BasicAgent.download_file_node)
@@ -84,8 +88,8 @@ class BasicAgent:
84
  #builder.add_edge("parse_img", "assistant")
85
  #builder.add_edge("parse_pdf", "assistant")
86
  #builder.add_edge("parse_audio", "assistant")
87
- builder.add_conditional_edges(
88
- "assistant",
89
  tools_condition,
90
  path_map={
91
  "tools": "tools",
@@ -93,29 +97,31 @@ class BasicAgent:
93
  }
94
  )
95
 
96
- builder.add_edge("tools", "assistant")
97
  builder.add_edge("final_answer", END)
98
 
99
- self.react_graph = builder.compile()
100
 
101
 
102
  def __call__(self, question: str, task_id: str, file_name: Optional[str]) -> str:
 
103
  print(f"Agent received question (first 50 chars): {question[:50]}...")
104
 
105
- messages = [HumanMessage(question)]
106
- messages = self.react_graph.invoke({"messages": messages, "file_path": file_name, "question": question})
107
 
108
- with open(f'messages_{task_id}.txt', 'w', encoding='utf-8') as out:
109
  with redirect_stdout(out):
110
  for m in messages['messages']:
111
  m.pretty_print()
112
 
113
- final_answer = messages["messages"][-1].content.strip()
114
  print(f"Final answer is {final_answer}")
115
  return final_answer
116
 
117
 
118
  def assistant(self, state: State):
 
119
  if state["file_path"]:
120
  file_name = state["file_path"].split(".")[0]
121
  file_extension = state["file_path"].split(".")[1]
@@ -123,7 +129,7 @@ class BasicAgent:
123
  file_extension = None
124
  file_name = None
125
 
126
- prompt = f"""
127
  You are a general AI assistant. When I ask you a question:
128
 
129
  Share your reasoning process clearly.
@@ -158,12 +164,13 @@ class BasicAgent:
158
  Do **NOT** include the file extension in the URL and send WITHOUT MODIFICATION.
159
  """
160
 
161
- sys_msg = SystemMessage(content=prompt)
162
 
163
- time.sleep(40)
164
  return {"messages": [self.llm_with_tools.invoke([sys_msg] + state["messages"])]}
165
 
166
  def final_answer(state: State):
 
167
  system_prompt = f"""
168
  You will be given an answer and a question. You MUST remove EVERYTHING not needed from the answer and answer the question exactly without reporting "FINAL ANSWER".
169
  That is if you are being asked the number of something, you must not return the thought process, but just the number X.
@@ -245,7 +252,7 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
245
  print(f"An unexpected error occurred fetching questions: {e}")
246
  return f"An unexpected error occurred fetching questions: {e}", None
247
 
248
- # 3. Run your Agent
249
  results_log = []
250
  answers_payload = []
251
  print(f"Running agent on {len(questions_data)} questions...")
@@ -270,12 +277,13 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
270
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
271
 
272
  # 4. Prepare Submission
273
- submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
274
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
275
  print(status_update)
276
 
277
  # 5. Submit
278
  print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
 
279
  try:
280
  response = requests.post(submit_url, json=submission_data, timeout=60)
281
  response.raise_for_status()
@@ -318,12 +326,12 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
318
  return status_message, results_df
319
 
320
 
321
- # --- Build Gradio Interface using Blocks ---
322
  with gr.Blocks() as demo:
323
- gr.Markdown("# Basic Agent Evaluation Runner")
324
  gr.Markdown(
325
  """
326
- **Instructions:**
327
 
328
  1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
329
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
@@ -336,7 +344,7 @@ with gr.Blocks() as demo:
336
  """
337
  )
338
 
339
- gr.LoginButton()
340
 
341
  run_button = gr.Button("Run Evaluation & Submit All Answers")
342
 
@@ -350,6 +358,7 @@ with gr.Blocks() as demo:
350
  )
351
 
352
  if __name__ == "__main__":
 
353
  print("\n" + "-"*30 + " App Starting " + "-"*30)
354
  # Check for SPACE_HOST and SPACE_ID at startup for information
355
  space_host_startup = os.getenv("SPACE_HOST")
 
1
+ # Importing necessary libraries and modules
2
  import os
3
  import gradio as gr
4
  import requests
 
42
  load_dotenv(".env", override=True)
43
  BRAVE_API_KEY = os.getenv("BRAVE_API")
44
 
45
+ # Defining the State class which will hold various parameters related to the agent's state
46
  class State(TypedDict):
47
  file_path : str
48
  file: Optional[str]
 
57
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
58
 
59
  # --- Basic Agent Definition ---
60
+ # Defining the BasicAgent class which contains the logic for the AI agent
61
  class BasicAgent:
62
+ def __init__(self):
63
+ # Initializing the BasicAgent with tools and an LLM (Large Language Model)
64
  tools = [CodeGenTool(), PythonExecutionTool(temp_dir="./"), YoutubeTranscriptTool(),
65
  AnswerQuestionFromFileTool(), AnswerQuestionTool(), DownloadFile(),
66
  ReverseString(), WebSearchTool(), WikipediaTool(), AnswerExcelTool(), ChessTool(), AudioTool(), FetchWebPageTool()]
 
68
  #llm = ChatGoogleGenerativeAI(
69
  # model="gemini-2.0-flash",
70
  # temperature=0)
71
+ llm = ChatOpenAI(model="gpt-4.1-mini", temperature=0) # Configuring the LLM
72
  self.llm_with_tools = llm.bind_tools(tools)
73
 
74
+ builder = StateGraph(State) # Building a state graph for handling agent's state transitions
75
 
76
+ builder.add_node("assistant", self.assistant) # Adding nodes to the state graph
77
  builder.add_node("tools", ToolNode(tools))
78
  builder.add_node("final_answer", BasicAgent.final_answer)
79
  #builder.add_node("download_file", BasicAgent.download_file_node)
 
88
  #builder.add_edge("parse_img", "assistant")
89
  #builder.add_edge("parse_pdf", "assistant")
90
  #builder.add_edge("parse_audio", "assistant")
91
+ builder.add_conditional_edges( # Adding conditional edges to manage state transitions based on tools' availability
92
+ "assistant", # Starting with the assistant node
93
  tools_condition,
94
  path_map={
95
  "tools": "tools",
 
97
  }
98
  )
99
 
100
+ builder.add_edge("tools", "assistant") # Defining edges for state transitions
101
  builder.add_edge("final_answer", END)
102
 
103
+ self.react_graph = builder.compile() # Compiling the state graph into a reactive graph
104
 
105
 
106
  def __call__(self, question: str, task_id: str, file_name: Optional[str]) -> str:
107
+ # Handling the agent's main call
108
  print(f"Agent received question (first 50 chars): {question[:50]}...")
109
 
110
+ messages = [HumanMessage(question)] # Creating a list of human messages
111
+ messages = self.react_graph.invoke({"messages": messages, "file_path": file_name, "question": question}) # Invoking the reactive graph with the current state
112
 
113
+ with open(f'messages_{task_id}.txt', 'w', encoding='utf-8') as out: # Writing the messages to a file
114
  with redirect_stdout(out):
115
  for m in messages['messages']:
116
  m.pretty_print()
117
 
118
+ final_answer = messages["messages"][-1].content.strip() # Extracting the final answer from the messages
119
  print(f"Final answer is {final_answer}")
120
  return final_answer
121
 
122
 
123
  def assistant(self, state: State):
124
+ # Defining the assistant node which processes the state
125
  if state["file_path"]:
126
  file_name = state["file_path"].split(".")[0]
127
  file_extension = state["file_path"].split(".")[1]
 
129
  file_extension = None
130
  file_name = None
131
 
132
+ prompt = f""" # Constructing the prompt for the language model
133
  You are a general AI assistant. When I ask you a question:
134
 
135
  Share your reasoning process clearly.
 
164
  Do **NOT** include the file extension in the URL and send WITHOUT MODIFICATION.
165
  """
166
 
167
+ sys_msg = SystemMessage(content=prompt) # Creating a system message with the prompt
168
 
169
+ time.sleep(40) # Simulating a delay for processing
170
  return {"messages": [self.llm_with_tools.invoke([sys_msg] + state["messages"])]}
171
 
172
  def final_answer(state: State):
173
+ # Defining the final answer node which processes the state and returns an answer
174
  system_prompt = f"""
175
  You will be given an answer and a question. You MUST remove EVERYTHING not needed from the answer and answer the question exactly without reporting "FINAL ANSWER".
176
  That is if you are being asked the number of something, you must not return the thought process, but just the number X.
 
252
  print(f"An unexpected error occurred fetching questions: {e}")
253
  return f"An unexpected error occurred fetching questions: {e}", None
254
 
255
+ # Running the agent on the fetched questions
256
  results_log = []
257
  answers_payload = []
258
  print(f"Running agent on {len(questions_data)} questions...")
 
277
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
278
 
279
  # 4. Prepare Submission
280
+ submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload} # Preparing the data for submission
281
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
282
  print(status_update)
283
 
284
  # 5. Submit
285
  print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
286
+ # Submitting the answers
287
  try:
288
  response = requests.post(submit_url, json=submission_data, timeout=60)
289
  response.raise_for_status()
 
326
  return status_message, results_df
327
 
328
 
329
+ # Building the Gradio interface using Blocks
330
  with gr.Blocks() as demo:
331
+ gr.Markdown("# Basic Agent Evaluation Runner") # Title of the interface
332
  gr.Markdown(
333
  """
334
+ # Instructions for the interface usage
335
 
336
  1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
337
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
 
344
  """
345
  )
346
 
347
+ gr.LoginButton() # Login button for Hugging Face account
348
 
349
  run_button = gr.Button("Run Evaluation & Submit All Answers")
350
 
 
358
  )
359
 
360
  if __name__ == "__main__":
361
+ # Launching Gradio interface for the application
362
  print("\n" + "-"*30 + " App Starting " + "-"*30)
363
  # Check for SPACE_HOST and SPACE_ID at startup for information
364
  space_host_startup = os.getenv("SPACE_HOST")
tools/answer_excel.py CHANGED
@@ -1,24 +1,28 @@
 
1
  from langchain_core.tools.base import BaseTool
2
  from langchain_experimental.agents.agent_toolkits import create_pandas_dataframe_agent
3
  import pandas as pd
4
  from langchain_google_genai import ChatGoogleGenerativeAI
5
  from langchain.agents.agent_types import AgentType
6
 
 
7
  class AnswerExcelTool(BaseTool):
8
  name : str = "answer_excel_tool"
9
  description: str = "Given the path to a file containing an excel file and a query, this tool tries to get an answer by querying the excel file. Provide the whole question in input. Another agent will later break down the task."
10
 
11
  def _run(self, query: str, file_path: str) -> str:
12
- df = pd.read_excel(file_path)
 
13
 
14
- llm = ChatGoogleGenerativeAI(model="gemini-2.0-flash", temperature=0)
15
 
16
  agent_executor = create_pandas_dataframe_agent(
 
17
  llm,
18
  df,
19
  agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
20
  verbose=True,
21
- allow_dangerous_code=True # IMPORTANT: Understand the risks
22
  )
23
 
24
- return agent_executor(query)
 
1
+ # Importing necessary libraries and modules
2
  from langchain_core.tools.base import BaseTool
3
  from langchain_experimental.agents.agent_toolkits import create_pandas_dataframe_agent
4
  import pandas as pd
5
  from langchain_google_genai import ChatGoogleGenerativeAI
6
  from langchain.agents.agent_types import AgentType
7
 
8
+ # Defining the AnswerExcelTool class which extends BaseTool
9
  class AnswerExcelTool(BaseTool):
10
  name : str = "answer_excel_tool"
11
  description: str = "Given the path to a file containing an excel file and a query, this tool tries to get an answer by querying the excel file. Provide the whole question in input. Another agent will later break down the task."
12
 
13
  def _run(self, query: str, file_path: str) -> str:
14
+ # Method to run the tool, using a query and the file path to an Excel file
15
+ df = pd.read_excel(file_path) # Reading the Excel file into a DataFrame
16
 
17
+ llm = ChatGoogleGenerativeAI(model="gemini-2.0-flash", temperature=0) # Configuring the LLM
18
 
19
  agent_executor = create_pandas_dataframe_agent(
20
+ # Creating a Pandas DataFrame agent with the LLM and DataFrame
21
  llm,
22
  df,
23
  agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
24
  verbose=True,
25
+ allow_dangerous_code=True # IMPORTANT: Understand the risks
26
  )
27
 
28
+ return agent_executor(query) # Executing the query using the agent
tools/answer_question.py CHANGED
@@ -1,3 +1,4 @@
 
1
  from langchain_google_genai import ChatGoogleGenerativeAI
2
  from pydantic import PrivateAttr
3
  from langchain_core.tools.base import BaseTool
@@ -6,6 +7,7 @@ from langchain_openai import ChatOpenAI
6
  import time
7
  from openai import OpenAI
8
 
 
9
  class AnswerQuestionTool(BaseTool):
10
  name : str = "answer_question_tool"
11
  description: str = "Use this tool to answer any elementary question that you can solve without needing access to any external tool. Simply provide the question in input, reporting the whole question including desired output format. You can use this tool for example for vegetable classification."
@@ -13,6 +15,7 @@ class AnswerQuestionTool(BaseTool):
13
  _system_prompt = PrivateAttr()
14
 
15
  def __init__(self):
 
16
  super().__init__()
17
  #self._llm = ChatGoogleGenerativeAI(
18
  # model="gemini-2.0-flash",
@@ -30,15 +33,18 @@ class AnswerQuestionTool(BaseTool):
30
  """)
31
 
32
  def _run(self, question: str) -> str:
 
33
  human_message = HumanMessage(
 
34
  content=[
35
  {"type": "text", "text": question},
36
  ]
37
  )
38
 
39
- time.sleep(5)
40
- client = OpenAI()
41
  response = client.responses.create(
 
42
  model="o4-mini",
43
  messages = [
44
  {
@@ -50,4 +56,4 @@ class AnswerQuestionTool(BaseTool):
50
  )
51
  #response = self._llm.invoke([self._system_prompt, human_message])
52
 
53
- return response
 
1
+ # Importing necessary libraries and modules
2
  from langchain_google_genai import ChatGoogleGenerativeAI
3
  from pydantic import PrivateAttr
4
  from langchain_core.tools.base import BaseTool
 
7
  import time
8
  from openai import OpenAI
9
 
10
+ # Defining the AnswerQuestionTool class which extends BaseTool
11
  class AnswerQuestionTool(BaseTool):
12
  name : str = "answer_question_tool"
13
  description: str = "Use this tool to answer any elementary question that you can solve without needing access to any external tool. Simply provide the question in input, reporting the whole question including desired output format. You can use this tool for example for vegetable classification."
 
15
  _system_prompt = PrivateAttr()
16
 
17
  def __init__(self):
18
+ # Initializing the AnswerQuestionTool
19
  super().__init__()
20
  #self._llm = ChatGoogleGenerativeAI(
21
  # model="gemini-2.0-flash",
 
33
  """)
34
 
35
  def _run(self, question: str) -> str:
36
+ # Method to run the tool and get an answer for the given question
37
  human_message = HumanMessage(
38
+ # Creating a human message with the question content
39
  content=[
40
  {"type": "text", "text": question},
41
  ]
42
  )
43
 
44
+ time.sleep(5) # Adding a delay for rate limits
45
+ client = OpenAI() # Initializing the OpenAI client
46
  response = client.responses.create(
47
+ # Creating a response using OpenAI's API
48
  model="o4-mini",
49
  messages = [
50
  {
 
56
  )
57
  #response = self._llm.invoke([self._system_prompt, human_message])
58
 
59
+ return response # Returning the response from the OpenAI API
tools/answer_question_from_file.py CHANGED
@@ -1,3 +1,4 @@
 
1
  from langchain_core.tools.base import BaseTool
2
  from langchain_core.messages import AnyMessage, SystemMessage, HumanMessage
3
  from langchain_google_genai import ChatGoogleGenerativeAI
@@ -7,15 +8,16 @@ from dotenv import load_dotenv
7
  import whisper
8
  import base64
9
 
10
- load_dotenv(".env", override=True)
11
 
12
- AZURE_OPENAI_ENDPOINT = os.getenv("AZURE_OPENAI_ENDPOINT")
13
  AZURE_OPENAI_API_KEY = os.getenv("AZURE_OPENAI_API_KEY")
14
  OPENAI_API_VERSION = os.getenv("OPENAI_API_VERSION_GEN", "2023-12-01-preview") # Default API version
15
  # AZURE_OPENAI_DEPLOYMENT_NAME will be used as the 'model' for API calls
16
  AZURE_OPENAI_DEPLOYMENT_NAME = "gpt-4.1"
17
 
18
 
 
19
  class AnswerQuestionFromFileTool(BaseTool):
20
  name: str = "answer_question_from_file_tool"
21
  description: str = """
@@ -29,8 +31,9 @@ class AnswerQuestionFromFileTool(BaseTool):
29
  _llm = PrivateAttr()
30
 
31
  def __init__(self):
 
32
  super().__init__()
33
- self._llm = ChatGoogleGenerativeAI(
34
  model="gemini-2.0-flash",
35
  temperature=0)
36
 
 
1
+ # Importing necessary libraries and modules
2
  from langchain_core.tools.base import BaseTool
3
  from langchain_core.messages import AnyMessage, SystemMessage, HumanMessage
4
  from langchain_google_genai import ChatGoogleGenerativeAI
 
8
  import whisper
9
  import base64
10
 
11
+ load_dotenv(".env", override=True) # Loading environment variables
12
 
13
+ AZURE_OPENAI_ENDPOINT = os.getenv("AZURE_OPENAI_ENDPOINT") # Fetching Azure OpenAI endpoint from environment
14
  AZURE_OPENAI_API_KEY = os.getenv("AZURE_OPENAI_API_KEY")
15
  OPENAI_API_VERSION = os.getenv("OPENAI_API_VERSION_GEN", "2023-12-01-preview") # Default API version
16
  # AZURE_OPENAI_DEPLOYMENT_NAME will be used as the 'model' for API calls
17
  AZURE_OPENAI_DEPLOYMENT_NAME = "gpt-4.1"
18
 
19
 
20
+ # Defining the AnswerQuestionFromFileTool class which extends BaseTool
21
  class AnswerQuestionFromFileTool(BaseTool):
22
  name: str = "answer_question_from_file_tool"
23
  description: str = """
 
31
  _llm = PrivateAttr()
32
 
33
  def __init__(self):
34
+ # Initializing the AnswerQuestionFromFileTool
35
  super().__init__()
36
+ self._llm = ChatGoogleGenerativeAI( # Setting up the LLM with specific parameters
37
  model="gemini-2.0-flash",
38
  temperature=0)
39
 
tools/audio_tool.py CHANGED
@@ -1,3 +1,4 @@
 
1
  from langchain_core.tools.base import BaseTool
2
  import whisper
3
  from langchain_google_genai import ChatGoogleGenerativeAI
@@ -9,11 +10,13 @@ import torch
9
  from langchain_openai import ChatOpenAI
10
  import time
11
 
 
12
  class AudioTool(BaseTool):
13
  name : str = "answer_question_audio_tool"
14
  description: str = "This tool will reply to a query based on the audio given the path of a locally stored file. This file DOES NOT DOWNLOAD the file from the web. Run the download_file_tool first"
15
 
16
  def _run(self, query: str, file_path: str) -> str:
 
17
  try:
18
  #pipe = pipeline(
19
  # task="automatic-speech-recognition",
@@ -24,7 +27,7 @@ class AudioTool(BaseTool):
24
  #)
25
  #result = pipe(str(Path("./") / Path(file_path)), return_timestamps=True)
26
  model = whisper.load_model("base")
27
- result = model.transcribe(audio=str(Path("./") / Path(file_path)), language='en')
28
  except Exception as e:
29
  print("Exception", e)
30
 
@@ -48,9 +51,9 @@ Always prioritize accuracy and strict adherence to the user's stated needs befor
48
  time.sleep(5)
49
  llm = ChatOpenAI(model="gpt-4.1-mini", temperature=0)
50
 
51
- response = llm.invoke([system_message, human_message])
52
 
53
- return response
54
 
55
 
56
 
 
1
+ # Importing necessary libraries and modules
2
  from langchain_core.tools.base import BaseTool
3
  import whisper
4
  from langchain_google_genai import ChatGoogleGenerativeAI
 
10
  from langchain_openai import ChatOpenAI
11
  import time
12
 
13
+ # Defining the AudioTool class which extends BaseTool
14
  class AudioTool(BaseTool):
15
  name : str = "answer_question_audio_tool"
16
  description: str = "This tool will reply to a query based on the audio given the path of a locally stored file. This file DOES NOT DOWNLOAD the file from the web. Run the download_file_tool first"
17
 
18
  def _run(self, query: str, file_path: str) -> str:
19
+ # Method to transcribe the provided audio file and answer the query using LLM
20
  try:
21
  #pipe = pipeline(
22
  # task="automatic-speech-recognition",
 
27
  #)
28
  #result = pipe(str(Path("./") / Path(file_path)), return_timestamps=True)
29
  model = whisper.load_model("base")
30
+ result = model.transcribe(audio=str(Path("./") / Path(file_path)), language='en') # Transcribing the audio using Whisper model
31
  except Exception as e:
32
  print("Exception", e)
33
 
 
51
  time.sleep(5)
52
  llm = ChatOpenAI(model="gpt-4.1-mini", temperature=0)
53
 
54
+ response = llm.invoke([system_message, human_message]) # Getting the response from the LLM
55
 
56
+ return response # Returning the response from the LLM
57
 
58
 
59
 
tools/chess_tool.py CHANGED
@@ -1,16 +1,21 @@
 
1
  from langchain_core.tools.base import BaseTool
2
  from chessimg2pos import predict_fen
3
  from stockfish import Stockfish
4
  import chess
5
 
 
6
  class ChessTool(BaseTool):
7
  name : str = "chess_tool"
8
  description : str = "Given the path of an image, this tool returns the best next move that can be done on the chessboard. You must give ONLY the PATH of the image here! Pass in input b or w as color_turn based on whose turn is it. Use w if unspecified."
9
 
10
  def _run(self, img_path: str, color_turn: str) -> str:
 
11
  # Get the FEN string
12
- fen = predict_fen("./downloaded_files/image.png")
13
 
 
 
14
  if color_turn == "b":
15
  ranks = fen.split('/')
16
  rotated_matrix = []
@@ -25,17 +30,18 @@ class ChessTool(BaseTool):
25
  fen = f"{final_fen} {color_turn} - - 0 1"
26
 
27
  try:
 
28
  stockfish = Stockfish(path="C:/Users/FORMAGGA/Documents/personal/stockfish-windows-x86-64-avx2/stockfish/stockfish-windows-x86-64-avx2.exe")
29
 
30
  stockfish.set_fen_position(fen)
31
 
32
- next_move = str(stockfish.get_best_move())
33
  except Exception as e:
34
  print("Exception", e)
35
  raise e
36
 
37
- piece = stockfish.get_what_is_on_square(next_move[:2])
38
 
39
- next_move_fen = piece.name + next_move[2:]
40
 
41
- return next_move_fen
 
1
+ # Importing necessary libraries and modules
2
  from langchain_core.tools.base import BaseTool
3
  from chessimg2pos import predict_fen
4
  from stockfish import Stockfish
5
  import chess
6
 
7
+ # Defining the ChessTool class which extends BaseTool
8
  class ChessTool(BaseTool):
9
  name : str = "chess_tool"
10
  description : str = "Given the path of an image, this tool returns the best next move that can be done on the chessboard. You must give ONLY the PATH of the image here! Pass in input b or w as color_turn based on whose turn is it. Use w if unspecified."
11
 
12
  def _run(self, img_path: str, color_turn: str) -> str:
13
+ # Method to analyze the chessboard image and return the best move
14
  # Get the FEN string
15
+ fen = predict_fen("./downloaded_files/image.png") # Predicting the FEN string from the chessboard image
16
 
17
+ # The fen predicted is always with a1 at the bottom left.
18
+ # If it's black turn than the bottom left is h8, you need to reverse the positions retrieved.
19
  if color_turn == "b":
20
  ranks = fen.split('/')
21
  rotated_matrix = []
 
30
  fen = f"{final_fen} {color_turn} - - 0 1"
31
 
32
  try:
33
+ # Initializing Stockfish chess engine
34
  stockfish = Stockfish(path="C:/Users/FORMAGGA/Documents/personal/stockfish-windows-x86-64-avx2/stockfish/stockfish-windows-x86-64-avx2.exe")
35
 
36
  stockfish.set_fen_position(fen)
37
 
38
+ next_move = str(stockfish.get_best_move()) # Getting the best move from Stockfish
39
  except Exception as e:
40
  print("Exception", e)
41
  raise e
42
 
43
+ piece = stockfish.get_what_is_on_square(next_move[:2]) # Getting the piece on the starting square of the move
44
 
45
+ next_move_fen = piece.name + next_move[2:] # Constructing the FEN representation of the move
46
 
47
+ return next_move_fen # Returning the best move in FEN format
tools/code_exec.py CHANGED
@@ -1,3 +1,4 @@
 
1
  from langchain_core.tools.base import BaseTool, ToolException
2
  from typing import Optional
3
  import subprocess
@@ -5,12 +6,11 @@ import tempfile
5
  import os
6
  from pydantic import PrivateAttr
7
 
 
8
  class PythonExecutionTool(BaseTool):
9
- """
10
- A LangChain “tool” that takes a string of Python code,
11
- writes it to a temporary .py file, executes it in a fresh
12
- Python subprocess, captures stdout/stderr, and returns the result.
13
- """
14
 
15
  name : str = "python_execution"
16
  description : str = (
@@ -28,6 +28,7 @@ class PythonExecutionTool(BaseTool):
28
  *,
29
  temp_dir: Optional[str] = None
30
  ):
 
31
  """
32
  :param python_executable: Path to the Python interpreter to invoke.
33
  :param timeout: Maximum seconds to allow the code to run.
 
1
+ # Importing necessary libraries and modules
2
  from langchain_core.tools.base import BaseTool, ToolException
3
  from typing import Optional
4
  import subprocess
 
6
  import os
7
  from pydantic import PrivateAttr
8
 
9
+ # Defining the PythonExecutionTool class which extends BaseTool
10
  class PythonExecutionTool(BaseTool):
11
+ # A LangChain “tool” that takes a string of Python code,
12
+ # writes it to a temporary .py file, executes it in a fresh
13
+ # Python subprocess, captures stdout/stderr, and returns the result.
 
 
14
 
15
  name : str = "python_execution"
16
  description : str = (
 
28
  *,
29
  temp_dir: Optional[str] = None
30
  ):
31
+
32
  """
33
  :param python_executable: Path to the Python interpreter to invoke.
34
  :param timeout: Maximum seconds to allow the code to run.
tools/download_file.py CHANGED
@@ -64,8 +64,6 @@ class DownloadFile(BaseTool):
64
  return "The file extension is not valid."
65
  else:
66
  msg = "There was an error downloading the file."
67
- file = None
68
- b64_file = None
69
 
70
  return msg
71
 
 
64
  return "The file extension is not valid."
65
  else:
66
  msg = "There was an error downloading the file."
 
 
67
 
68
  return msg
69
 
tools/fetch_web_page.py CHANGED
@@ -1,12 +1,15 @@
 
1
  from langchain_core.tools.base import BaseTool
2
  from typing import List
3
  import requests
4
 
 
5
  class FetchWebPageTool(BaseTool):
6
  name : str = "fetch_web_page_tool"
7
  description: str = "Provided the urls of 1 or more web pages, this tool returns the full content of the web page. This tool needs to be called AFTER calling the web_page_tool. It's important to fetch only pages which are useful to your task!"
8
 
9
  def _run(self, urls: List[str]) -> List[str]:
10
- pages = [requests.get(url).text for url in urls]
 
11
 
12
- return pages
 
1
+ # Importing necessary libraries and modules
2
  from langchain_core.tools.base import BaseTool
3
  from typing import List
4
  import requests
5
 
6
+ # Defining the FetchWebPageTool class which extends BaseTool
7
  class FetchWebPageTool(BaseTool):
8
  name : str = "fetch_web_page_tool"
9
  description: str = "Provided the urls of 1 or more web pages, this tool returns the full content of the web page. This tool needs to be called AFTER calling the web_page_tool. It's important to fetch only pages which are useful to your task!"
10
 
11
  def _run(self, urls: List[str]) -> List[str]:
12
+ # Method to fetch the full content of the provided web pages
13
+ pages = [requests.get(url).text for url in urls] # Fetching the content of each URL
14
 
15
+ return pages # Returning the fetched content of the web pages
tools/web_search.py CHANGED
@@ -1,3 +1,4 @@
 
1
  from langchain_core.tools.base import BaseTool
2
  from dotenv import load_dotenv
3
  from langchain_community.utilities import DuckDuckGoSearchAPIWrapper
@@ -9,44 +10,22 @@ from langchain_community.document_loaders import WebBaseLoader
9
  import json
10
  import requests
11
 
12
- load_dotenv(".env", override=True)
13
-
14
 
 
15
  class WebSearchTool(BaseTool):
16
  name: str = "web_search_tool"
17
  description: str = "Perform a web search and extract concise factual answers. The query should be concise, below 400 characters. Use for online facts not in GAIA/Wikipedia—e.g. sports stats, Olympic participation, published papers, museum specimen locations, competition winners, and other up-to-date info."
18
- #_search: BraveSearch = PrivateAttr()
19
  _search: TavilySearch = PrivateAttr()
20
 
21
  def __init__(self):
 
22
  super().__init__()
23
- #wrapper = DuckDuckGoSearchAPIWrapper(region="en", max_results=2)
24
- #self._search = DuckDuckGoSearchResults(api_wrapper=wrapper, output_format="json")
25
-
26
- self._search = TavilySearch(max_results=3, topic="general")
27
-
28
- def _run_old(self, query: str) -> str:
29
- json_str = self._search.run(query) # list[Document]
30
- docs = json.loads(json_str)
31
- urls = [doc["link"] for doc in docs]
32
- print(urls)
33
- pages = [requests.get(url) for url in urls]
34
-
35
- res = "\n\n---\n\n".join(
36
- page.text for page in pages
37
- )
38
-
39
- try:
40
- with open("./web_search.txt", "wt", encoding="utf-8") as f:
41
- f.write(str(res))
42
- except Exception as e:
43
- print(e)
44
-
45
- return res
46
 
47
  def _run(self, query: str) -> dict:
48
- # import pdb;pdb.set_trace()
49
- search_results = []
50
- search_results.append(self._search.run(query))
51
 
52
- return search_results
 
1
+ # Importing necessary libraries and modules
2
  from langchain_core.tools.base import BaseTool
3
  from dotenv import load_dotenv
4
  from langchain_community.utilities import DuckDuckGoSearchAPIWrapper
 
10
  import json
11
  import requests
12
 
13
+ load_dotenv(".env", override=True) # Loading environment variables
 
14
 
15
+ # Defining the WebSearchTool class which extends BaseTool
16
  class WebSearchTool(BaseTool):
17
  name: str = "web_search_tool"
18
  description: str = "Perform a web search and extract concise factual answers. The query should be concise, below 400 characters. Use for online facts not in GAIA/Wikipedia—e.g. sports stats, Olympic participation, published papers, museum specimen locations, competition winners, and other up-to-date info."
 
19
  _search: TavilySearch = PrivateAttr()
20
 
21
  def __init__(self):
22
+ # Initializing the WebSearchTool
23
  super().__init__()
24
+ self._search = TavilySearch(max_results=3, topic="general") # Setting up the TavilySearch with specific parameters
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
  def _run(self, query: str) -> dict:
27
+ # Method to run the web search tool with the given query
28
+ search_results = [] # Initializing the list for search results
29
+ search_results.append(self._search.run(query)) # Performing the search and adding the results to the list
30
 
31
+ return search_results # Returning the search results
tools/wikipedia.py CHANGED
@@ -1,3 +1,4 @@
 
1
  from langchain_community.tools import WikipediaQueryRun
2
  from langchain_community.utilities import WikipediaAPIWrapper
3
  from pydantic import PrivateAttr
@@ -7,33 +8,32 @@ import requests
7
  from bs4 import BeautifulSoup
8
  import wikipedia
9
 
10
-
11
  class WikipediaTool(BaseTool):
12
  name: str = "wikipedia_tool"
13
  description: str = "Search Wikipedia for a given query, retrieving the corresponding page's HTML content. The query should not contain any noise and ask for something specific."
14
- #_wikipedia = PrivateAttr()
15
 
16
  def __init__(self):
 
17
  super().__init__()
18
- #self._wikipedia = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper(lang="en", doc_content_chars_max=100000, top_k_results=1))
19
-
20
 
21
  def _run(self, query: str):
22
- print(f"wikipedia_search_html called with query='{query}'")
 
23
  # Step 1: Get Wikipedia HTML
24
- page = wikipedia.page(query)
25
- html = page.html()
26
 
27
  # Step 2: Parse HTML
28
- soup = BeautifulSoup(html, "html.parser")
29
- content_div = soup.find("div", class_="mw-parser-output")
30
  # content_div = soup.find("table", class_="wikitable")
31
  if not content_div:
32
  return ""
33
 
34
  # Step 3: Find all tags to remove (style, script, sup, infobox, etc.)
35
- to_decompose = []
36
- for tag in content_div.find_all():
37
  tag_classes = tag.get("class", [])
38
  if (
39
  tag.name in ["style", "script", "sup"]
@@ -42,7 +42,7 @@ class WikipediaTool(BaseTool):
42
  to_decompose.append(tag)
43
 
44
  # Remove them after collecting
45
- for tag in to_decompose:
46
  tag.decompose()
47
 
48
- return str(content_div)
 
1
+ # Importing necessary libraries and modules
2
  from langchain_community.tools import WikipediaQueryRun
3
  from langchain_community.utilities import WikipediaAPIWrapper
4
  from pydantic import PrivateAttr
 
8
  from bs4 import BeautifulSoup
9
  import wikipedia
10
 
11
+ # Defining the WikipediaTool class which extends BaseTool
12
  class WikipediaTool(BaseTool):
13
  name: str = "wikipedia_tool"
14
  description: str = "Search Wikipedia for a given query, retrieving the corresponding page's HTML content. The query should not contain any noise and ask for something specific."
 
15
 
16
  def __init__(self):
17
+ # Initializing the WikipediaTool
18
  super().__init__()
 
 
19
 
20
  def _run(self, query: str):
21
+ # Method to run the Wikipedia tool with the given query
22
+ print(f"wikipedia_search_html called with query='{query}'") # Logging the query
23
  # Step 1: Get Wikipedia HTML
24
+ page = wikipedia.page(query) # Fetching the Wikipedia page for the query
25
+ html = page.html() # Extracting the HTML content of the page
26
 
27
  # Step 2: Parse HTML
28
+ soup = BeautifulSoup(html, "html.parser") # Parsing the HTML content
29
+ content_div = soup.find("div", class_="mw-parser-output") # Finding the content division
30
  # content_div = soup.find("table", class_="wikitable")
31
  if not content_div:
32
  return ""
33
 
34
  # Step 3: Find all tags to remove (style, script, sup, infobox, etc.)
35
+ to_decompose = [] # Collecting tags to be removed
36
+ for tag in content_div.find_all(): # Looping through all tags in the content division
37
  tag_classes = tag.get("class", [])
38
  if (
39
  tag.name in ["style", "script", "sup"]
 
42
  to_decompose.append(tag)
43
 
44
  # Remove them after collecting
45
+ for tag in to_decompose: # Decompose and remove the collected tags
46
  tag.decompose()
47
 
48
+ return str(content_div) # Returning the cleaned content division as string
tools/youtube_transcript.py CHANGED
@@ -15,10 +15,13 @@ class YoutubeTranscriptTool(BaseTool):
15
  Returns:
16
  The transcript as a single string.
17
  """
 
18
  re_match = re.search(r"watch\?v=([^&]+)", youtube_link)
19
  if not re_match:
20
  raise ValueError(f"Invalid YouTube URL: {youtube_link}")
21
  video_id = re_match.group(1)
 
 
22
  ytt_api = YouTubeTranscriptApi()
23
  fetched_transcript = ytt_api.fetch(video_id)
24
 
 
15
  Returns:
16
  The transcript as a single string.
17
  """
18
+ # Get the video ID from the youtube URL
19
  re_match = re.search(r"watch\?v=([^&]+)", youtube_link)
20
  if not re_match:
21
  raise ValueError(f"Invalid YouTube URL: {youtube_link}")
22
  video_id = re_match.group(1)
23
+
24
+ # Initialize the transcriptAPI and retrieve the transcript for the given videoID
25
  ytt_api = YouTubeTranscriptApi()
26
  fetched_transcript = ytt_api.fetch(video_id)
27