Spaces:
Sleeping
Sleeping
File size: 7,557 Bytes
5dfcdef 6109e7b 5dfcdef |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
from langchain_community.document_loaders import WikipediaLoader
from langchain_community.document_loaders import ArxivLoader
from langchain_community.retrievers import WikipediaRetriever
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_community.tools import DuckDuckGoSearchResults
from langchain_core.tools import tool
import io
import openpyxl
import os
# from smolagents import tool
import requests
from PIL import Image
from bs4 import BeautifulSoup
@tool
def web_search(query: str) -> dict:
"""Search Tavily for a query and return maximum 3 results.
Args:
query: The search query."""
search_docs = DuckDuckGoSearchResults(max_results=3, output_format='list').invoke(query)
formatted_search_docs = "\n\n---\n\n".join(
[
f'<Document source="{doc.get("link", "")}" title="{doc.get("title", "")}"/>\n{doc.get("snippet", "")}\n</Document>'
for doc in search_docs
]
)
return {"web_results": formatted_search_docs}
# @tool
# def wiki_search(query: str) -> dict:
# """Search Wikipedia for a query and return maximum 2 results.
# Args:
# query: The search query."""
# search_docs = WikipediaLoader(query=query, load_max_docs=2).load()
# formatted_search_docs = "\n\n---\n\n".join(
# [
# f'<Document source="{doc.metadata["source"]}" page="{doc.metadata.get("page", "")}"/>\n{doc.page_content}\n</Document>'
# for doc in search_docs
# ])
# return {"wiki_results": formatted_search_docs}
# @tool
# def wiki_search(query: str) -> dict:
# """Search Wikipedia for a query and return maximum 2 results.
# Args:
# query: The search query."""
# search_docs = WikipediaRetriever(load_max_docs=5).invoke(query)
# formatted_search_docs = "\n\n---\n\n".join(
# [
# f'<Document source="{doc.metadata["source"]}" page="{doc.metadata.get("page", "")}"/>\n{doc.page_content}\n</Document>'
# for doc in search_docs
# ])
# return {"wiki_results": formatted_search_docs}
@tool
def wiki_search(query: str) -> dict:
"""Search Wikipedia for a query and return maximum 1 results.
Args:
query: The search query."""
search_docs = WikipediaRetriever(load_max_docs=1, top_k_results=2).invoke(query)
wiki_results = []
for doc in search_docs:
url = doc.metadata["source"] if doc else ""
print(url)
response = requests.get(url)
response_text = response.text
soup = BeautifulSoup(response_text, "html.parser")
wiki_results.append(' '.join(soup.get_text().split())[:20000])
return {"wiki_results": wiki_results}
@tool
def reverse_string(query: str) -> dict:
"""Reverse the input string.
Args:
query: The input string to reverse."""
return {"reversed_string": query[::-1]}
@tool
def calculator(expression: str) -> dict:
"""Perform mathematical calculations and return the result.
This calculator can handle:
- Basic arithmetic: +, -, *, /, % (modulus)
- Parentheses for order of operations
- Decimal numbers
- Multiple operations in one expression
Args:
expression: A mathematical expression as a string
Returns:
A string containing the calculation result
Examples:
calculator("25 * 4") -> "100"
calculator("100 / 5") -> "20.0"
calculator("(15 + 30) * 2") -> "90"
calculator("50 - 20 + 10") -> "40"
calculator("17 % 5") -> "2"
calculator("100 % 7") -> "2"
calculator("(20 + 5) % 8") -> "5"
"""
try:
# Clean the expression
expression = expression.strip()
# Validate that the expression only contains safe characters (now including %)
allowed_chars = set('0123456789+-*/.()% ')
if not all(c in allowed_chars for c in expression):
raise ValueError("Expression contains invalid characters. Only numbers and +, -, *, /, %, (, ) are allowed.")
result = eval(expression)
# Format the result
if isinstance(result, float) and result.is_integer():
return str(int(result))
else:
return str(result)
except ZeroDivisionError:
return "Error: Cannot divide by zero or modulus by zero"
except SyntaxError:
return f"Error: Invalid mathematical expression: {expression}"
except Exception as e:
return f"Error: {str(e)}"
@tool
def tool_read_files(filepath: str) -> str:
"""
Downloads a .py or .xlsx file from a remote URL and returns its contents as plain text.
Raises a recoverable exception if the file does not end with .py or .xlsx.
Args:
filepath: The path to the Python (.py) or Excel (.xlsx) file.
"""
root_url = "https://agents-course-unit4-scoring.hf.space/files/"
# Strip the file extension from the url before downloading
base, ext = os.path.splitext(filepath)
url = root_url + base
if filepath.endswith('.py'):
response = requests.get(url)
if response.status_code != 200:
raise Exception(f"Recoverable: Failed to download file from {url}")
return response.text
elif filepath.endswith('.xlsx'):
response = requests.get(url)
if response.status_code != 200:
raise Exception(f"Recoverable: Failed to download file from {url}")
wb = openpyxl.load_workbook(io.BytesIO(response.content), data_only=True)
result = []
for sheet in wb.worksheets:
result.append(f"# Sheet: {sheet.title}")
for row in sheet.iter_rows(values_only=True):
result.append(','.join([str(cell) if cell is not None else '' for cell in row]))
return '\n'.join(result)
else:
raise Exception("Recoverable: Only .py and .xlsx files can be read with this tool.")
@tool
def tool_download_image(filepath: str) -> str:
"""
Downloads an image file (.png, .jpg, .jpeg) from a remote URL and returns useful information about the image.
This includes the image URL and basic metadata like dimensions and format.
Raises a recoverable exception if the file is not a supported image type.
Args:
filepath: The path to the image file.
"""
root_url = "https://agents-course-unit4-scoring.hf.space/files/"
base, ext = os.path.splitext(filepath)
url = root_url + base
if ext.lower() in ['.png', '.jpg', '.jpeg']:
response = requests.get(url)
if response.status_code != 200:
raise Exception(f"Recoverable: Failed to download image from {url}")
# Get image metadata using Pillow
try:
img = Image.open(io.BytesIO(response.content))
width, height = img.size
format = img.format
mode = img.mode
# Return useful information about the image
return f"Image URL: {url}\nFormat: {format}\nDimensions: {width}x{height}\nMode: {mode}"
except ImportError:
# Fallback if PIL is not available
content_type = response.headers.get('Content-Type', 'unknown')
content_length = response.headers.get('Content-Length', 'unknown')
return f"Content-Type: {content_type}\nSize: {content_length} bytes"
else:
raise Exception("Recoverable: Only .png, .jpg, and .jpeg files can be processed with this tool.")
|