Spaces:
Running
Running
Final_Assignment
#1
by
MartinHummel
- opened
- .gitignore +0 -6
- agent/__init__.py +0 -2
- agent/gaia_agent.py +0 -94
- app.py +7 -41
- local_benchmark.py +0 -26
- requirements.txt +1 -19
- tools/__init__.py +0 -2
- tools/audio_transcriber.py +0 -25
- tools/excel_sum_tool.py +0 -17
- tools/file_parser.py +0 -44
- tools/image_chess_solver.py +0 -50
- tools/vegetable_classifier_tool.py +0 -17
- tools/wikipedia_tool.py +0 -29
- tools/youtube_tool.py +0 -47
.gitignore
DELETED
@@ -1,6 +0,0 @@
|
|
1 |
-
.git
|
2 |
-
tools/__pycache__
|
3 |
-
*.py~
|
4 |
-
__pycache__/
|
5 |
-
.env
|
6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
agent/__init__.py
DELETED
@@ -1,2 +0,0 @@
|
|
1 |
-
# tools/__init__.py
|
2 |
-
|
|
|
|
|
|
agent/gaia_agent.py
DELETED
@@ -1,94 +0,0 @@
|
|
1 |
-
import os
|
2 |
-
from langchain.agents import initialize_agent, AgentType
|
3 |
-
from langchain.tools import Tool
|
4 |
-
#from langchain_community.llms import OpenAI
|
5 |
-
from tools.wikipedia_tool import wiki_search
|
6 |
-
from tools.vegetable_classifier_tool import vegetable_classifier_2022
|
7 |
-
from tools.vegetable_classifier_tool import vegetable_classifier_2022
|
8 |
-
from tools.excel_sum_tool import excel_food_sales_sum
|
9 |
-
from tools.audio_transcriber import transcribe_audio
|
10 |
-
from tools.file_parser import parse_file_and_summarize
|
11 |
-
from tools.image_chess_solver import solve_chess_image
|
12 |
-
from tools.youtube_tool import extract_video_id, get_youtube_transcript
|
13 |
-
from langchain.agents.agent import AgentExecutor
|
14 |
-
from langchain_community.chat_models import ChatOpenAI
|
15 |
-
|
16 |
-
def create_langchain_agent() -> AgentExecutor:
|
17 |
-
llm = ChatOpenAI(
|
18 |
-
model_name="gpt-4o",
|
19 |
-
temperature=0.1,
|
20 |
-
openai_api_key=os.getenv("OPENAI_API_KEY"),
|
21 |
-
)
|
22 |
-
|
23 |
-
tools = [
|
24 |
-
Tool(name="wikipedia_search", func=wiki_search, description="Use to get factual info from Wikipedia.", return_direct=False),
|
25 |
-
Tool(name="youtube_transcript", func=get_youtube_transcript, description="Extract transcripts from YouTube videos.", return_direct=False),
|
26 |
-
Tool(name="audio_transcriber", func=transcribe_audio, description="Transcribe uploaded audio files."),
|
27 |
-
Tool(name="chess_image_solver", func=solve_chess_image, description="Solve chess puzzles from images."),
|
28 |
-
Tool(name="file_parser", func=parse_file_and_summarize, description="Parse and analyze Excel or CSV files."),
|
29 |
-
Tool(name="vegetable_classifier_2022", func=vegetable_classifier_2022, description="Classify and extract only vegetables, excluding botanical fruits, based on a comma-separated list of food items."),
|
30 |
-
Tool(name="excel_food_sales_sum", func=excel_food_sales_sum, description="Parse uploaded Excel file and return total food-related sales."),
|
31 |
-
]
|
32 |
-
|
33 |
-
agent_kwargs = {
|
34 |
-
"prefix": (
|
35 |
-
"You are a helpful AI assistant completing GAIA benchmark tasks.\n"
|
36 |
-
"You MUST use the tools provided to answer the user's question. Do not answer from your own knowledge.\n"
|
37 |
-
"Carefully analyze the question to determine the most appropriate tool to use.\n"
|
38 |
-
"Here are guidelines for using the tools:\n"
|
39 |
-
"- Use 'wikipedia_search' to find factual information about topics, events, people, etc. (e.g., 'Use wikipedia_search to find the population of France').\n"
|
40 |
-
"- Use 'youtube_transcript' to extract transcripts from YouTube videos when the question requires understanding the video content. (e.g., 'Use youtube_transcript to summarize the key points of this video').\n"
|
41 |
-
"- Use 'audio_transcriber' to transcribe uploaded audio files. (e.g., 'Use audio_transcriber to get the text from this audio recording').\n"
|
42 |
-
"- Use 'chess_image_solver' to analyze and solve chess puzzles from images. (e.g., 'Use chess_image_solver to determine the best move in this chess position').\n"
|
43 |
-
"- Use 'file_parser' to parse and analyze data from Excel or CSV files. (e.g., 'Use file_parser to calculate the average sales from this data').\n"
|
44 |
-
"- Use 'vegetable_classifier_2022' to classify a list of food items and extract only the vegetables. (e.g., 'Use vegetable_classifier_2022 to get a list of the vegetables in this grocery list').\n"
|
45 |
-
"- Use 'excel_food_sales_sum' to extract total food sales from excel files. (e.g., 'Use excel_food_sales_sum to calculate the total food sales').\n"
|
46 |
-
"Do NOT guess or make up answers. If a tool cannot provide the answer, truthfully respond that you were unable to find the information.\n"
|
47 |
-
),
|
48 |
-
"suffix": (
|
49 |
-
"Use the tools to research or calculate the answer.\n"
|
50 |
-
"If a tool fails, explain the reason for the failure instead of hallucinating an answer.\n"
|
51 |
-
"Provide concise and direct answers as requested in the questions. Do not add extra information unless explicitly asked for.\n"
|
52 |
-
"For example, if asked for a number, return only the number. If asked for a list, return only the list.\n"
|
53 |
-
),
|
54 |
-
"input_variables": ["input", "agent_scratchpad"]
|
55 |
-
}
|
56 |
-
|
57 |
-
agent = initialize_agent(
|
58 |
-
tools=tools,
|
59 |
-
llm=llm,
|
60 |
-
agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,
|
61 |
-
handle_parsing_errors=True,
|
62 |
-
verbose=True,
|
63 |
-
max_iterations=10,
|
64 |
-
max_execution_time=60,
|
65 |
-
agent_kwargs=agent_kwargs # Place the agent_kwargs here
|
66 |
-
)
|
67 |
-
|
68 |
-
return agent
|
69 |
-
|
70 |
-
|
71 |
-
'''
|
72 |
-
agent = initialize_agent(
|
73 |
-
tools=tools,
|
74 |
-
llm=llm,
|
75 |
-
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
|
76 |
-
handle_parsing_errors=True,
|
77 |
-
verbose=True,
|
78 |
-
max_iterations=10,
|
79 |
-
max_execution_time=60,
|
80 |
-
agent_kwargs={
|
81 |
-
"prefix": (
|
82 |
-
"You are a helpful AI assistant completing GAIA benchmark tasks.\n"
|
83 |
-
"You must ALWAYS use the tools provided to answer the user's question.\n"
|
84 |
-
"Do NOT guess or respond directly from your own knowledge.\n"
|
85 |
-
),
|
86 |
-
"suffix": (
|
87 |
-
"Use the tools to research or calculate the answer.\n"
|
88 |
-
"If a tool fails, explain that instead of hallucinating an answer.\n"
|
89 |
-
"Return only the final answer as a short response (e.g., a number, name, or sentence).\n"
|
90 |
-
),
|
91 |
-
}
|
92 |
-
)
|
93 |
-
'''
|
94 |
-
return agent
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app.py
CHANGED
@@ -4,18 +4,6 @@ import requests
|
|
4 |
import inspect
|
5 |
import pandas as pd
|
6 |
|
7 |
-
#from langchain.agents import initialize_agent, AgentType
|
8 |
-
from agent.gaia_agent import create_langchain_agent
|
9 |
-
#from langchain_community.llms import OpenAI
|
10 |
-
from langchain.tools import Tool
|
11 |
-
from agent.gaia_agent import create_langchain_agent
|
12 |
-
|
13 |
-
from tools.wikipedia_tool import wiki_search
|
14 |
-
from tools.youtube_tool import get_youtube_transcript
|
15 |
-
from tools.audio_transcriber import transcribe_audio
|
16 |
-
from tools.image_chess_solver import solve_chess_image
|
17 |
-
from tools.file_parser import parse_file_and_summarize
|
18 |
-
|
19 |
# (Keep Constants as is)
|
20 |
# --- Constants ---
|
21 |
DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
|
@@ -24,25 +12,14 @@ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
|
|
24 |
# ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
|
25 |
class BasicAgent:
|
26 |
def __init__(self):
|
27 |
-
print("
|
28 |
-
self.agent = create_langchain_agent()
|
29 |
-
|
30 |
def __call__(self, question: str) -> str:
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
return result
|
36 |
-
except Exception as e:
|
37 |
-
return f"Agent error: {e}"
|
38 |
-
|
39 |
-
|
40 |
-
def manual_test(question):
|
41 |
-
agent = BasicAgent()
|
42 |
-
return agent(question)
|
43 |
|
44 |
def run_and_submit_all( profile: gr.OAuthProfile | None):
|
45 |
-
|
46 |
"""
|
47 |
Fetches all questions, runs the BasicAgent on them, submits all answers,
|
48 |
and displays the results.
|
@@ -169,9 +146,11 @@ with gr.Blocks() as demo:
|
|
169 |
gr.Markdown(
|
170 |
"""
|
171 |
**Instructions:**
|
|
|
172 |
1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
|
173 |
2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
|
174 |
3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
|
|
|
175 |
---
|
176 |
**Disclaimers:**
|
177 |
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).
|
@@ -180,14 +159,6 @@ with gr.Blocks() as demo:
|
|
180 |
)
|
181 |
|
182 |
gr.LoginButton()
|
183 |
-
|
184 |
-
manual_input = gr.Textbox(label="Try the Agent Manually", placeholder="How many studio albums where published by Mercedes Sosa between 2000 and 2009 (included)? You can use the latest v2022 version of wikipedia.")
|
185 |
-
manual_output = gr.Textbox(label="Agent Response", lines=4, interactive=False)
|
186 |
-
manual_test_button = gr.Button("Run Agent Locally")
|
187 |
-
manual_test_button.click(fn=manual_test, inputs=[manual_input], outputs=[manual_output])
|
188 |
-
|
189 |
-
print(manual_input.placeholder )
|
190 |
-
|
191 |
|
192 |
run_button = gr.Button("Run Evaluation & Submit All Answers")
|
193 |
|
@@ -200,7 +171,6 @@ with gr.Blocks() as demo:
|
|
200 |
outputs=[status_output, results_table]
|
201 |
)
|
202 |
|
203 |
-
|
204 |
if __name__ == "__main__":
|
205 |
print("\n" + "-"*30 + " App Starting " + "-"*30)
|
206 |
# Check for SPACE_HOST and SPACE_ID at startup for information
|
@@ -221,10 +191,6 @@ if __name__ == "__main__":
|
|
221 |
print("βΉοΈ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
|
222 |
|
223 |
print("-"*(60 + len(" App Starting ")) + "\n")
|
224 |
-
|
225 |
-
#from tools.wikipedia_tool import wiki_search
|
226 |
-
#print(wiki_search("Mercedes Sosa discography"))
|
227 |
-
|
228 |
|
229 |
print("Launching Gradio Interface for Basic Agent Evaluation...")
|
230 |
demo.launch(debug=True, share=False)
|
|
|
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"
|
|
|
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.
|
|
|
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).
|
|
|
159 |
)
|
160 |
|
161 |
gr.LoginButton()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
162 |
|
163 |
run_button = gr.Button("Run Evaluation & Submit All Answers")
|
164 |
|
|
|
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
|
|
|
191 |
print("βΉοΈ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
|
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)
|
local_benchmark.py
DELETED
@@ -1,26 +0,0 @@
|
|
1 |
-
from agent.gaia_agent import create_langchain_agent
|
2 |
-
|
3 |
-
questions = [
|
4 |
-
"How many studio albums were published by Mercedes Sosa between 2000 and 2009 (included)?",
|
5 |
-
"In the video https://www.youtube.com/watch?v=u1xXCYZ4VYM, what is the highest number of bird species to be on screen at once?",
|
6 |
-
"Reverse the string 'etisoppo eht'.",
|
7 |
-
"What country had the least number of athletes at the 1928 Summer Olympics? Return the IOC country code.",
|
8 |
-
"From the chessboard image at path 'chess_1.png', what is the best move?",
|
9 |
-
"The attached Excel file contains food and drink sales. What are the total sales for food (excluding drinks)?",
|
10 |
-
"Give me a comma-separated, alphabetized list of botanical vegetables from this: milk, eggs, flour, plums, lettuce, celery, broccoli, bell pepper, zucchini.",
|
11 |
-
"Where were the Vietnamese specimens described by Kuznetzov in Nedoshivinaβs 2010 paper eventually deposited? (City name only.)",
|
12 |
-
"What is the name of the novel where a Martian child grows up on Earth and founds a church?",
|
13 |
-
"Summarize the Wikipedia page on 'TaishΕ Tamai'."
|
14 |
-
]
|
15 |
-
|
16 |
-
agent = create_langchain_agent()
|
17 |
-
|
18 |
-
print("Running local benchmark...")
|
19 |
-
|
20 |
-
for idx, question in enumerate(questions):
|
21 |
-
print(f"\nQUESTION {idx + 1}: {question}")
|
22 |
-
try:
|
23 |
-
answer = agent.invoke({"input": question})
|
24 |
-
print("ANSWER:", answer)
|
25 |
-
except Exception as e:
|
26 |
-
print("β Error:", e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
requirements.txt
CHANGED
@@ -1,20 +1,2 @@
|
|
1 |
gradio
|
2 |
-
requests
|
3 |
-
transformers
|
4 |
-
huggingface_hub
|
5 |
-
langchain-community
|
6 |
-
langchain
|
7 |
-
openai
|
8 |
-
wikipedia
|
9 |
-
pytube
|
10 |
-
whisper
|
11 |
-
pillow
|
12 |
-
opencv-python
|
13 |
-
python-docx
|
14 |
-
PyMuPDF
|
15 |
-
youtube-transcript-api
|
16 |
-
openai-whisper
|
17 |
-
ffmpeg-python
|
18 |
-
python-chess
|
19 |
-
openpyxl
|
20 |
-
gradio[oauth]
|
|
|
1 |
gradio
|
2 |
+
requests
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tools/__init__.py
DELETED
@@ -1,2 +0,0 @@
|
|
1 |
-
# tools/__init__.py
|
2 |
-
|
|
|
|
|
|
tools/audio_transcriber.py
DELETED
@@ -1,25 +0,0 @@
|
|
1 |
-
# tools/audio_transcriber.py
|
2 |
-
|
3 |
-
import os
|
4 |
-
import tempfile
|
5 |
-
import whisper
|
6 |
-
|
7 |
-
# Load Whisper model only once (tiny, base, or small recommended for speed)
|
8 |
-
MODEL_NAME = "base"
|
9 |
-
whisper_model = whisper.load_model(MODEL_NAME)
|
10 |
-
|
11 |
-
def transcribe_audio(audio_file_path: str) -> str:
|
12 |
-
"""
|
13 |
-
Transcribes speech from an audio file using OpenAI Whisper.
|
14 |
-
|
15 |
-
Args:
|
16 |
-
audio_file_path (str): Path to the local audio file (.mp3, .wav, etc.).
|
17 |
-
|
18 |
-
Returns:
|
19 |
-
str: Transcribed text or error message.
|
20 |
-
"""
|
21 |
-
try:
|
22 |
-
result = whisper_model.transcribe(audio_file_path)
|
23 |
-
return result["text"].strip()
|
24 |
-
except Exception as e:
|
25 |
-
return f"Transcription error: {str(e)}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tools/excel_sum_tool.py
DELETED
@@ -1,17 +0,0 @@
|
|
1 |
-
|
2 |
-
from langchain.tools import tool
|
3 |
-
|
4 |
-
@tool
|
5 |
-
def excel_food_sales_sum(file_path: str) -> str:
|
6 |
-
"""
|
7 |
-
Parses the Excel file and returns total sales of items classified as food.
|
8 |
-
Assumes 'Item Type' and 'Sales USD' columns.
|
9 |
-
"""
|
10 |
-
try:
|
11 |
-
df = pd.read_excel(file_path)
|
12 |
-
df.columns = [col.strip().lower() for col in df.columns]
|
13 |
-
food_rows = df[df['item type'].str.lower().str.contains("food")]
|
14 |
-
total = food_rows['sales usd'].sum()
|
15 |
-
return f"{total:.2f}"
|
16 |
-
except Exception as e:
|
17 |
-
return f"Excel parsing failed: {str(e)}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tools/file_parser.py
DELETED
@@ -1,44 +0,0 @@
|
|
1 |
-
# tools/file_parser.py
|
2 |
-
|
3 |
-
import pandas as pd
|
4 |
-
import os
|
5 |
-
|
6 |
-
def parse_file_and_summarize(file_path: str, query: str = "") -> str:
|
7 |
-
"""
|
8 |
-
Reads a CSV or Excel file and optionally answers a simple question about it.
|
9 |
-
|
10 |
-
Args:
|
11 |
-
file_path (str): Path to the file (.csv or .xlsx).
|
12 |
-
query (str): Optional freeform instruction (e.g. "total food sales").
|
13 |
-
|
14 |
-
Returns:
|
15 |
-
str: Summary or result from the file.
|
16 |
-
"""
|
17 |
-
try:
|
18 |
-
_, ext = os.path.splitext(file_path.lower())
|
19 |
-
if ext == ".csv":
|
20 |
-
df = pd.read_csv(file_path)
|
21 |
-
elif ext in [".xls", ".xlsx"]:
|
22 |
-
df = pd.read_excel(file_path)
|
23 |
-
else:
|
24 |
-
return "Unsupported file format. Please upload CSV or Excel."
|
25 |
-
|
26 |
-
if df.empty:
|
27 |
-
return "The file is empty or unreadable."
|
28 |
-
|
29 |
-
if not query:
|
30 |
-
return f"Loaded file with {df.shape[0]} rows and {df.shape[1]} columns.\nColumns: {', '.join(df.columns)}"
|
31 |
-
|
32 |
-
# Very basic natural language query handling (expand with LLM if needed)
|
33 |
-
if "total" in query.lower() and "food" in query.lower():
|
34 |
-
food_rows = df[df['category'].str.lower() == "food"]
|
35 |
-
if "sales" in df.columns:
|
36 |
-
total = food_rows["sales"].sum()
|
37 |
-
return f"Total food sales: ${total:.2f}"
|
38 |
-
else:
|
39 |
-
return "Could not find 'sales' column in the file."
|
40 |
-
else:
|
41 |
-
return "Query not supported. Please specify a clearer question."
|
42 |
-
|
43 |
-
except Exception as e:
|
44 |
-
return f"File parsing error: {str(e)}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tools/image_chess_solver.py
DELETED
@@ -1,50 +0,0 @@
|
|
1 |
-
# tools/image_chess_solver.py
|
2 |
-
|
3 |
-
import chess
|
4 |
-
import chess.engine
|
5 |
-
import tempfile
|
6 |
-
from PIL import Image
|
7 |
-
|
8 |
-
# Path to your Stockfish binary (update if needed)
|
9 |
-
STOCKFISH_PATH = "/usr/bin/stockfish"
|
10 |
-
|
11 |
-
def analyze_position_from_fen(fen: str, time_limit: float = 1.0) -> str:
|
12 |
-
"""
|
13 |
-
Uses Stockfish to analyze the best move from a given FEN string.
|
14 |
-
|
15 |
-
Args:
|
16 |
-
fen (str): ForsythβEdwards Notation of the board.
|
17 |
-
time_limit (float): Time to let Stockfish think.
|
18 |
-
|
19 |
-
Returns:
|
20 |
-
str: Best move in algebraic notation.
|
21 |
-
"""
|
22 |
-
try:
|
23 |
-
board = chess.Board(fen)
|
24 |
-
engine = chess.engine.SimpleEngine.popen_uci(STOCKFISH_PATH)
|
25 |
-
result = engine.play(board, chess.engine.Limit(time=time_limit))
|
26 |
-
engine.quit()
|
27 |
-
return board.san(result.move)
|
28 |
-
except Exception as e:
|
29 |
-
return f"Stockfish error: {e}"
|
30 |
-
|
31 |
-
def solve_chess_image(image_path: str) -> str:
|
32 |
-
"""
|
33 |
-
Stub function for image-to-FEN. Replace with actual OCR/vision logic.
|
34 |
-
|
35 |
-
Args:
|
36 |
-
image_path (str): Path to chessboard image.
|
37 |
-
|
38 |
-
Returns:
|
39 |
-
str: Best move or error.
|
40 |
-
"""
|
41 |
-
# Placeholder FEN for development (e.g., black to move, guaranteed mate)
|
42 |
-
sample_fen = "6k1/5ppp/8/8/8/8/5PPP/6K1 b - - 0 1"
|
43 |
-
|
44 |
-
try:
|
45 |
-
print(f"Simulating FEN extraction from image: {image_path}")
|
46 |
-
# Replace the above with actual OCR image-to-FEN logic
|
47 |
-
best_move = analyze_position_from_fen(sample_fen)
|
48 |
-
return f"Detected FEN: {sample_fen}\nBest move for Black: {best_move}"
|
49 |
-
except Exception as e:
|
50 |
-
return f"Image analysis error: {e}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tools/vegetable_classifier_tool.py
DELETED
@@ -1,17 +0,0 @@
|
|
1 |
-
# vegetable_classifier_tool.py
|
2 |
-
from langchain.tools import tool
|
3 |
-
|
4 |
-
@tool
|
5 |
-
def vegetable_classifier_2022(question: str) -> str:
|
6 |
-
"""
|
7 |
-
Classifies common grocery items from a 2022 Wikipedia-based classification.
|
8 |
-
Returns a comma-separated list of vegetables excluding all botanical fruits.
|
9 |
-
"""
|
10 |
-
known_vegetables = {
|
11 |
-
"broccoli", "celery", "lettuce", "zucchini", "green beans",
|
12 |
-
"sweet potatoes", "corn", "acorns", "peanuts", "rice", "flour"
|
13 |
-
}
|
14 |
-
# Accept question but only extract known food items
|
15 |
-
input_items = [item.strip().lower() for item in question.split(',')]
|
16 |
-
found = sorted([item for item in input_items if item in known_vegetables])
|
17 |
-
return ", ".join(found)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tools/wikipedia_tool.py
DELETED
@@ -1,29 +0,0 @@
|
|
1 |
-
# tools/wikipedia_tool.py
|
2 |
-
import wikipedia
|
3 |
-
|
4 |
-
wikipedia.set_lang("en")
|
5 |
-
|
6 |
-
def wiki_search(query: str) -> str:
|
7 |
-
"""
|
8 |
-
Safe Wikipedia summary tool with disambiguation and fallback protection.
|
9 |
-
"""
|
10 |
-
try:
|
11 |
-
return wikipedia.summary(query, sentences=3)
|
12 |
-
except wikipedia.DisambiguationError as e:
|
13 |
-
# Try the first disambiguation option if available
|
14 |
-
if e.options:
|
15 |
-
try:
|
16 |
-
return wikipedia.summary(e.options[0], sentences=3)
|
17 |
-
except Exception as inner:
|
18 |
-
return f"Disambiguation fallback failed: {inner}"
|
19 |
-
return "Disambiguation error: No options available."
|
20 |
-
except wikipedia.PageError:
|
21 |
-
search_results = wikipedia.search(query)
|
22 |
-
if not search_results:
|
23 |
-
return "No relevant Wikipedia page found."
|
24 |
-
try:
|
25 |
-
return wikipedia.summary(search_results[0], sentences=3)
|
26 |
-
except Exception as inner:
|
27 |
-
return f"Wikipedia fallback summary error: {inner}"
|
28 |
-
except Exception as e:
|
29 |
-
return f"Wikipedia general error: {e}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tools/youtube_tool.py
DELETED
@@ -1,47 +0,0 @@
|
|
1 |
-
# tools/youtube_tool.py
|
2 |
-
|
3 |
-
from youtube_transcript_api import YouTubeTranscriptApi
|
4 |
-
from youtube_transcript_api._errors import TranscriptsDisabled, NoTranscriptFound
|
5 |
-
import re
|
6 |
-
|
7 |
-
def extract_video_id(url: str) -> str:
|
8 |
-
"""
|
9 |
-
Extracts the video ID from a YouTube URL.
|
10 |
-
|
11 |
-
Args:
|
12 |
-
url (str): The full YouTube video URL.
|
13 |
-
|
14 |
-
Returns:
|
15 |
-
str: The extracted video ID or raises ValueError.
|
16 |
-
"""
|
17 |
-
patterns = [
|
18 |
-
r"youtube\.com/watch\?v=([a-zA-Z0-9_-]{11})",
|
19 |
-
r"youtu\.be/([a-zA-Z0-9_-]{11})"
|
20 |
-
]
|
21 |
-
for pattern in patterns:
|
22 |
-
match = re.search(pattern, url)
|
23 |
-
if match:
|
24 |
-
return match.group(1)
|
25 |
-
raise ValueError("Invalid YouTube URL or unable to extract video ID.")
|
26 |
-
|
27 |
-
def get_youtube_transcript(url: str) -> str:
|
28 |
-
"""
|
29 |
-
Fetches the transcript text for a given YouTube video.
|
30 |
-
|
31 |
-
Args:
|
32 |
-
url (str): The YouTube video URL.
|
33 |
-
|
34 |
-
Returns:
|
35 |
-
str: Combined transcript text or an error message.
|
36 |
-
"""
|
37 |
-
try:
|
38 |
-
video_id = extract_video_id(url)
|
39 |
-
transcript_list = YouTubeTranscriptApi.get_transcript(video_id)
|
40 |
-
full_text = " ".join([entry["text"] for entry in transcript_list])
|
41 |
-
return full_text.strip()[:2000] # Truncate to 2000 chars to prevent token overflow
|
42 |
-
except TranscriptsDisabled:
|
43 |
-
return "This video has transcripts disabled."
|
44 |
-
except NoTranscriptFound:
|
45 |
-
return "No transcript was found for this video."
|
46 |
-
except Exception as e:
|
47 |
-
return f"Transcript error: {str(e)}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|