Spaces:
Sleeping
Sleeping
"""Tool definitions and utility functions for the agent""" | |
from typing import List, Dict, Any | |
import os | |
from dotenv import load_dotenv | |
from llama_index.core.tools import BaseTool, FunctionTool | |
from llama_index.readers.wikipedia import WikipediaReader | |
from llama_index.readers.web import SimpleWebPageReader | |
from llama_index.core.schema import Document | |
import wikipedia | |
# Load environment variables | |
load_dotenv() | |
# --- Text Processing Tools --- | |
def text_reverser(text: str) -> str: | |
""" | |
Reverse the given text. Useful for answering questions that are written backwards. | |
Args: | |
text: The text to reverse | |
Returns: | |
The reversed text | |
""" | |
return text[::-1] | |
# --- Math Tools --- | |
def simple_calculator(operation: str, a: float, b: float) -> float: | |
""" | |
Perform a simple calculation. | |
Args: | |
operation: One of 'add', 'subtract', 'multiply', 'divide' | |
a: First number | |
b: Second number | |
Returns: | |
The result of the calculation | |
""" | |
if operation == "add": | |
return a + b | |
elif operation == "subtract": | |
return a - b | |
elif operation == "multiply": | |
return a * b | |
elif operation == "divide": | |
if b == 0: | |
raise ValueError("Cannot divide by zero") | |
return a / b | |
else: | |
raise ValueError(f"Unknown operation: {operation}") | |
# --- Information Retrieval Tools --- | |
def wikipedia_search(query: str, num_results: int = 2) -> str: | |
""" | |
Search Wikipedia for information. | |
Args: | |
query: The search query | |
num_results: Number of results to return (default: 2) | |
Returns: | |
A formatted string with the search results | |
""" | |
try: | |
# First try with LlamaIndex WikipediaReader | |
reader = WikipediaReader() | |
docs = reader.load_data(query=query, max_docs=num_results) | |
if docs: | |
results = [] | |
for i, doc in enumerate(docs, 1): | |
title = doc.metadata.get("title", "Unknown Title") | |
content = doc.text[:1000] + "..." if len(doc.text) > 1000 else doc.text | |
results.append(f"Result {i}: {title}\n{content}\n") | |
return "\n".join(results) | |
else: | |
# If no results from LlamaIndex, try with direct Wikipedia package | |
print(f"No results from LlamaIndex WikipediaReader for '{query}', trying direct Wikipedia package...") | |
return _fallback_wikipedia_search(query, num_results) | |
except Exception as e: | |
print(f"Error with LlamaIndex WikipediaReader: {str(e)}") | |
# Fall back to direct Wikipedia package | |
print(f"Falling back to direct Wikipedia package...") | |
try: | |
return _fallback_wikipedia_search(query, num_results) | |
except Exception as fallback_error: | |
print(f"Fallback also failed: {fallback_error}") | |
return f"Error searching Wikipedia: Unable to retrieve information about '{query}'. Please try a different search term or approach." | |
def _fallback_wikipedia_search(query: str, num_results: int = 2) -> str: | |
""" | |
Fallback implementation using the direct Wikipedia package. | |
""" | |
# First search for pages | |
search_results = wikipedia.search(query, results=num_results) | |
if not search_results: | |
return f"No Wikipedia results found for '{query}'." | |
results = [] | |
for i, page_title in enumerate(search_results, 1): | |
try: | |
# Get the page content | |
page = wikipedia.page(page_title) | |
title = page.title | |
# Get a summary instead of full content | |
content = page.summary[:1000] + "..." if len(page.summary) > 1000 else page.summary | |
results.append(f"Result {i}: {title}\n{content}\n") | |
except wikipedia.exceptions.DisambiguationError as e: | |
# Handle disambiguation pages | |
options = e.options[:5] # Limit to 5 options | |
results.append(f"Result {i}: Multiple options found for '{page_title}':\n" + | |
"\n".join([f"- {opt}" for opt in options])) | |
except wikipedia.exceptions.PageError: | |
# Skip pages that don't exist | |
continue | |
except Exception as e: | |
results.append(f"Result {i}: Error retrieving information for '{page_title}': {str(e)}") | |
if not results: | |
return f"Could not retrieve valid information for '{query}'." | |
return "\n".join(results) | |
def web_search(url: str) -> str: | |
""" | |
Fetch and extract content from a specific web page. | |
Args: | |
url: The URL of the web page to search | |
Returns: | |
The extracted content from the web page | |
""" | |
try: | |
reader = SimpleWebPageReader() | |
docs = reader.load_data(urls=[url]) | |
if not docs: | |
return f"No content found for URL: {url}" | |
# Just return the content of the first document | |
return docs[0].text | |
except Exception as e: | |
return f"Error retrieving web page: {str(e)}" | |
# --- Tool Selection and Routing --- | |
def get_tools() -> List[BaseTool]: | |
"""Create and return a list of tools for the agent.""" | |
text_reverser_tool = FunctionTool.from_defaults( | |
fn=text_reverser, | |
name="text_reverser", | |
description="Reverses the given text. Useful for processing reversed questions or text.", | |
) | |
calculator_tool = FunctionTool.from_defaults( | |
fn=simple_calculator, | |
name="calculator", | |
description="Performs simple calculations: add, subtract, multiply, divide.", | |
) | |
wikipedia_tool = FunctionTool.from_defaults( | |
fn=wikipedia_search, | |
name="wikipedia_search", | |
description="Searches Wikipedia for information on a topic.", | |
) | |
web_tool = FunctionTool.from_defaults( | |
fn=web_search, | |
name="web_search", | |
description="Fetches and extracts content from a specific web page.", | |
) | |
return [ | |
text_reverser_tool, | |
calculator_tool, | |
wikipedia_tool, | |
web_tool | |
] | |
if __name__ == "__main__": | |
print("This module defines tools for the agent. Run app.py or standalone_debug.py to test the agent.") |