Final_Assignment_Template / multiple_tools.py
cowrycode's picture
Update multiple_tools.py
4aeb22f verified
import os
import json
from dotenv import load_dotenv
from llama_index.core.tools import FunctionTool
from llama_index.tools.google import GoogleSearchToolSpec
from llama_index.tools.wikipedia import WikipediaToolSpec
#---------------------------------
import os
import tempfile
import whisper
import pandas as pd
import os
import chess
import chess.engine
import tempfile
import wikipedia
from PIL import Image
import wikipedia
#---------------------------------
load_dotenv()
google_key = os.getenv("GOOGLE_SECRET_KEY")
my_search_engine = os.getenv("Google_WebSearch_Engine")
g_search = GoogleSearchToolSpec(key=google_key, engine=my_search_engine, num=3)
#Wikipedia Search Tool
wikipedia_tool = WikipediaToolSpec()
wikipedia_search_tool = FunctionTool.from_defaults(wikipedia_tool.search_data)
# wikipedia.set_lang("en")
# def wiki_search(query: str) -> str:
# """
# Safe Wikipedia summary tool with disambiguation and fallback protection.
# """
# try:
# return wikipedia.summary(query, sentences=3)
# except wikipedia.DisambiguationError as e:
# # Try the first disambiguation option if available
# if e.options:
# try:
# return wikipedia.summary(e.options[0], sentences=3)
# except Exception as inner:
# return f"Disambiguation fallback failed: {inner}"
# return "Disambiguation error: No options available."
# except wikipedia.PageError:
# search_results = wikipedia.search(query)
# if not search_results:
# return "No relevant Wikipedia page found."
# try:
# return wikipedia.summary(search_results[0], sentences=3)
# except Exception as inner:
# return f"Wikipedia fallback summary error: {inner}"
# except Exception as e:
# return f"Wikipedia general error: {e}"
# wikipedia_search_tool = FunctionTool.from_defaults(wiki_search)
def google_web_search(query : str) -> str:
"""
Searches the web and returns the most accurate response for a user query.
Args:
query (str): The query string to search for.
Returns:
str: The snippet of the first search result along with its source link.
"""
result = g_search.google_search(query)
output = result[0]
if "huggingface.co" in output["link"]:
output = result[1]
print(output)
return f"Result: {output['snippet']} Source: {output['link']}"
google_web_search_tool = FunctionTool.from_defaults(google_web_search)
def round_to_two_decimals(value):
"""
Round a number to two decimal places.
Args:
value (float): The value to be round to 2 decimal places.
Raises:
ValueError: If the 'value' is not an integer or a float.
"""
return round(float(value), 2)
round_to_two_decimals_tool = FunctionTool.from_defaults(round_to_two_decimals)
def text_inverter(text: str) -> str:
"""
Handles sentence writen backward:
- Reverses it and returns the reverse version
- Ignore if text is not written backwords
Args:
text (str): The text writen backwards to be reversed
"""
decoded = text[::-1]
print(decoded)
text_inverter_tool = FunctionTool.from_defaults(text_inverter)
#---------------------
MODEL_NAME = "base"
whisper_model = whisper.load_model(MODEL_NAME)
def transcribe_audio(audio_file_path: str) -> str:
"""
Transcribes speech from an audio file using OpenAI Whisper.
Args:
audio_file_path (str): Path to the local audio file (.mp3, .wav, etc.).
Returns:
str: Transcribed text or error message.
"""
try:
result = whisper_model.transcribe(audio_file_path)
return result["text"].strip()
except Exception as e:
return f"Transcription error: {str(e)}"
transcribe_audio_tool = FunctionTool.from_defaults(transcribe_audio)
def excel_food_sales_sum(file_path: str) -> str:
"""
Parses the Excel file and returns total sales of items classified as food.
Assumes 'Item Type' and 'Sales USD' columns.
"""
try:
df = pd.read_excel(file_path)
df.columns = [col.strip().lower() for col in df.columns]
food_rows = df[df['item type'].str.lower().str.contains("food")]
total = food_rows['sales usd'].sum()
return f"{total:.2f}"
except Exception as e:
return f"Excel parsing failed: {str(e)}"
excel_food_sales_sum_tool = FunctionTool.from_defaults(excel_food_sales_sum)
def parse_file_and_summarize(file_path: str, query: str = "") -> str:
"""
Reads a CSV or Excel file and optionally answers a simple question about it.
Args:
file_path (str): Path to the file (.csv or .xlsx).
query (str): Optional freeform instruction (e.g. "total food sales").
Returns:
str: Summary or result from the file.
"""
try:
_, ext = os.path.splitext(file_path.lower())
if ext == ".csv":
df = pd.read_csv(file_path)
elif ext in [".xls", ".xlsx"]:
df = pd.read_excel(file_path)
else:
return "Unsupported file format. Please upload CSV or Excel."
if df.empty:
return "The file is empty or unreadable."
if not query:
return f"Loaded file with {df.shape[0]} rows and {df.shape[1]} columns.\nColumns: {', '.join(df.columns)}"
# Very basic natural language query handling (expand with LLM if needed)
if "total" in query.lower() and "food" in query.lower():
food_rows = df[df['category'].str.lower() == "food"]
if "sales" in df.columns:
total = food_rows["sales"].sum()
return f"Total food sales: ${total:.2f}"
else:
return "Could not find 'sales' column in the file."
else:
return "Query not supported. Please specify a clearer question."
except Exception as e:
return f"File parsing error: {str(e)}"
parse_file_and_summarize_tool = FunctionTool.from_defaults(parse_file_and_summarize)
# Path to your Stockfish binary (update if needed)
STOCKFISH_PATH = "/usr/bin/stockfish"
def analyze_position_from_fen(fen: str, time_limit: float = 1.0) -> str:
"""
Uses Stockfish to analyze the best move from a given FEN string.
Args:
fen (str): Forsyth–Edwards Notation of the board.
time_limit (float): Time to let Stockfish think.
Returns:
str: Best move in algebraic notation.
"""
try:
board = chess.Board(fen)
engine = chess.engine.SimpleEngine.popen_uci(STOCKFISH_PATH)
result = engine.play(board, chess.engine.Limit(time=time_limit))
engine.quit()
return board.san(result.move)
except Exception as e:
return f"Stockfish error: {e}"
def solve_chess_image(image_path: str) -> str:
"""
Stub function for image-to-FEN. Replace with actual OCR/vision logic.
Args:
image_path (str): Path to chessboard image.
Returns:
str: Best move or error.
"""
# Placeholder FEN for development (e.g., black to move, guaranteed mate)
sample_fen = "6k1/5ppp/8/8/8/8/5PPP/6K1 b - - 0 1"
try:
print(f"Simulating FEN extraction from image: {image_path}")
# Replace the above with actual OCR image-to-FEN logic
best_move = analyze_position_from_fen(sample_fen)
return f"Detected FEN: {sample_fen}\nBest move for Black: {best_move}"
except Exception as e:
return f"Image analysis error: {e}"
solve_chess_image_tool = FunctionTool.from_defaults(solve_chess_image)
def vegetable_classifier(question: str) -> str:
"""
Classifies common grocery items from a Wikipedia-based classification.
Returns a comma-separated list of vegetables excluding all botanical fruits.
"""
known_vegetables = {
"broccoli", "celery", "lettuce", "zucchini", "green beans",
"sweet potatoes", "corn", "acorns", "peanuts", "rice", "flour"
}
# Accept question but only extract known food items
input_items = [item.strip().lower() for item in question.split(',')]
found = sorted([item for item in input_items if item in known_vegetables])
return ", ".join(found)
vegetable_classifier_tool = FunctionTool.from_defaults(vegetable_classifier)