Spaces:
Sleeping
Sleeping
add tools
Browse files- src/tools.py +133 -104
src/tools.py
CHANGED
|
@@ -14,6 +14,8 @@ import requests
|
|
| 14 |
import whisper
|
| 15 |
import wikipedia
|
| 16 |
from bs4 import BeautifulSoup
|
|
|
|
|
|
|
| 17 |
from openpyxl import load_workbook
|
| 18 |
from smolagents import tool
|
| 19 |
|
|
@@ -138,141 +140,61 @@ def fetch_webpage_content(url: str, max_length: int = 3000) -> str:
|
|
| 138 |
return f"Error fetching webpage {url}: {str(e)}"
|
| 139 |
|
| 140 |
|
| 141 |
-
# === MATHEMATICAL OPERATIONS ===
|
| 142 |
-
|
| 143 |
-
|
| 144 |
@tool
|
| 145 |
-
def
|
| 146 |
"""
|
| 147 |
-
|
| 148 |
|
| 149 |
Args:
|
| 150 |
-
|
| 151 |
|
| 152 |
Returns:
|
| 153 |
-
|
| 154 |
"""
|
| 155 |
try:
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
# Convert strings to numbers if needed
|
| 160 |
-
converted_numbers = []
|
| 161 |
-
for num in numbers:
|
| 162 |
-
if isinstance(num, str):
|
| 163 |
-
try:
|
| 164 |
-
converted_numbers.append(float(num) if "." in num else int(num))
|
| 165 |
-
except ValueError:
|
| 166 |
-
return f"Error: '{num}' is not a valid number"
|
| 167 |
-
else:
|
| 168 |
-
converted_numbers.append(num)
|
| 169 |
-
|
| 170 |
-
result = sum(converted_numbers)
|
| 171 |
-
return f"Sum of {converted_numbers} = {result}"
|
| 172 |
-
|
| 173 |
except Exception as e:
|
| 174 |
-
return f"
|
| 175 |
|
| 176 |
|
| 177 |
@tool
|
| 178 |
-
def
|
| 179 |
"""
|
| 180 |
-
|
| 181 |
|
| 182 |
Args:
|
| 183 |
-
|
| 184 |
|
| 185 |
Returns:
|
| 186 |
-
|
| 187 |
"""
|
| 188 |
try:
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
# Convert strings to numbers if needed
|
| 193 |
-
converted_numbers = []
|
| 194 |
-
for num in numbers:
|
| 195 |
-
if isinstance(num, str):
|
| 196 |
-
try:
|
| 197 |
-
converted_numbers.append(float(num) if "." in num else int(num))
|
| 198 |
-
except ValueError:
|
| 199 |
-
return f"Error: '{num}' is not a valid number"
|
| 200 |
-
else:
|
| 201 |
-
converted_numbers.append(num)
|
| 202 |
-
|
| 203 |
-
result = 1
|
| 204 |
-
for num in converted_numbers:
|
| 205 |
-
result *= num
|
| 206 |
-
|
| 207 |
-
return f"Product of {converted_numbers} = {result}"
|
| 208 |
-
|
| 209 |
-
except Exception as e:
|
| 210 |
-
return f"Error multiplying numbers: {str(e)}"
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
@tool
|
| 214 |
-
def divide_numbers(dividend: int | float, divisor: int | float) -> str:
|
| 215 |
-
"""
|
| 216 |
-
Divide two numbers.
|
| 217 |
-
|
| 218 |
-
Args:
|
| 219 |
-
dividend: The number to be divided
|
| 220 |
-
divisor: The number to divide by
|
| 221 |
-
|
| 222 |
-
Returns:
|
| 223 |
-
Result of division as string
|
| 224 |
-
"""
|
| 225 |
-
try:
|
| 226 |
-
# Convert strings to numbers if needed
|
| 227 |
-
if isinstance(dividend, str):
|
| 228 |
-
dividend = float(dividend) if "." in dividend else int(dividend)
|
| 229 |
-
if isinstance(divisor, str):
|
| 230 |
-
divisor = float(divisor) if "." in divisor else int(divisor)
|
| 231 |
-
|
| 232 |
-
if divisor == 0:
|
| 233 |
-
return "Error: Cannot divide by zero"
|
| 234 |
-
|
| 235 |
-
result = dividend / divisor
|
| 236 |
-
return f"{dividend} ÷ {divisor} = {result}"
|
| 237 |
-
|
| 238 |
-
except ValueError as e:
|
| 239 |
-
return f"Error: Invalid number format - {str(e)}"
|
| 240 |
except Exception as e:
|
| 241 |
-
return f"
|
| 242 |
|
| 243 |
|
| 244 |
@tool
|
| 245 |
-
def
|
| 246 |
"""
|
| 247 |
-
|
| 248 |
|
| 249 |
Args:
|
| 250 |
-
|
| 251 |
-
whole: The whole value
|
| 252 |
|
| 253 |
Returns:
|
| 254 |
-
|
| 255 |
"""
|
| 256 |
try:
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
if isinstance(whole, str):
|
| 261 |
-
whole = float(whole) if "." in whole else int(whole)
|
| 262 |
-
|
| 263 |
-
if whole == 0:
|
| 264 |
-
return "Error: Cannot calculate percentage with zero as whole"
|
| 265 |
-
|
| 266 |
-
percentage = (part / whole) * 100
|
| 267 |
-
return f"{part} is {percentage:.2f}% of {whole}"
|
| 268 |
-
|
| 269 |
-
except ValueError as e:
|
| 270 |
-
return f"Error: Invalid number format - {str(e)}"
|
| 271 |
except Exception as e:
|
| 272 |
-
return f"
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
# === FILE PROCESSING TOOLS ===
|
| 276 |
|
| 277 |
|
| 278 |
@tool
|
|
@@ -661,3 +583,110 @@ def count_items_in_list(items_text: str, separator: str = ",") -> str:
|
|
| 661 |
|
| 662 |
except Exception as e:
|
| 663 |
return f"Error counting items: {str(e)}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
import whisper
|
| 15 |
import wikipedia
|
| 16 |
from bs4 import BeautifulSoup
|
| 17 |
+
from langchain_community.tools import DuckDuckGoSearchRun, WikipediaQueryRun
|
| 18 |
+
from langchain_community.utilities import ArxivAPIWrapper, WikipediaAPIWrapper
|
| 19 |
from openpyxl import load_workbook
|
| 20 |
from smolagents import tool
|
| 21 |
|
|
|
|
| 140 |
return f"Error fetching webpage {url}: {str(e)}"
|
| 141 |
|
| 142 |
|
|
|
|
|
|
|
|
|
|
| 143 |
@tool
|
| 144 |
+
def arxiv_search(query: str) -> str:
|
| 145 |
"""
|
| 146 |
+
Search arXiv papers.
|
| 147 |
|
| 148 |
Args:
|
| 149 |
+
query: Search query or paper ID (e.g., "1605.08386")
|
| 150 |
|
| 151 |
Returns:
|
| 152 |
+
str: arXiv paper information
|
| 153 |
"""
|
| 154 |
try:
|
| 155 |
+
arxiv = ArxivAPIWrapper()
|
| 156 |
+
docs = arxiv.run(query)
|
| 157 |
+
return str(docs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
except Exception as e:
|
| 159 |
+
return f"arXiv search error: {str(e)}"
|
| 160 |
|
| 161 |
|
| 162 |
@tool
|
| 163 |
+
def wikipedia_search_tool(query: str) -> str:
|
| 164 |
"""
|
| 165 |
+
Search Wikipedia using LangChain's WikipediaQueryRun.
|
| 166 |
|
| 167 |
Args:
|
| 168 |
+
query: Search query
|
| 169 |
|
| 170 |
Returns:
|
| 171 |
+
str: Wikipedia search results
|
| 172 |
"""
|
| 173 |
try:
|
| 174 |
+
wikipedia = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper())
|
| 175 |
+
result = wikipedia.run(query)
|
| 176 |
+
return result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 177 |
except Exception as e:
|
| 178 |
+
return f"Wikipedia search error: {str(e)}"
|
| 179 |
|
| 180 |
|
| 181 |
@tool
|
| 182 |
+
def duckduckgo_search(query: str) -> str:
|
| 183 |
"""
|
| 184 |
+
Search using DuckDuckGo.
|
| 185 |
|
| 186 |
Args:
|
| 187 |
+
query: Search query
|
|
|
|
| 188 |
|
| 189 |
Returns:
|
| 190 |
+
str: DuckDuckGo search results
|
| 191 |
"""
|
| 192 |
try:
|
| 193 |
+
search = DuckDuckGoSearchRun()
|
| 194 |
+
result = search.invoke(query)
|
| 195 |
+
return result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 196 |
except Exception as e:
|
| 197 |
+
return f"DuckDuckGo search error: {str(e)}"
|
|
|
|
|
|
|
|
|
|
| 198 |
|
| 199 |
|
| 200 |
@tool
|
|
|
|
| 583 |
|
| 584 |
except Exception as e:
|
| 585 |
return f"Error counting items: {str(e)}"
|
| 586 |
+
|
| 587 |
+
|
| 588 |
+
@tool
|
| 589 |
+
def ocr_tool(image_path: str) -> str:
|
| 590 |
+
"""
|
| 591 |
+
Extract text from images using OCR.
|
| 592 |
+
|
| 593 |
+
Args:
|
| 594 |
+
image_path: Path to image file
|
| 595 |
+
|
| 596 |
+
Returns:
|
| 597 |
+
str: Extracted text
|
| 598 |
+
"""
|
| 599 |
+
try:
|
| 600 |
+
import pytesseract
|
| 601 |
+
from PIL import Image
|
| 602 |
+
|
| 603 |
+
image = Image.open(image_path)
|
| 604 |
+
text = pytesseract.image_to_string(image)
|
| 605 |
+
return f"OCR text from {image_path}:\n{text.strip()}"
|
| 606 |
+
|
| 607 |
+
except ImportError:
|
| 608 |
+
return "Error: pytesseract not installed. Install with: pip install pytesseract"
|
| 609 |
+
except Exception as e:
|
| 610 |
+
return f"OCR error: {str(e)}"
|
| 611 |
+
|
| 612 |
+
|
| 613 |
+
@tool
|
| 614 |
+
def image_captioning_tool(image_path: str) -> str:
|
| 615 |
+
"""
|
| 616 |
+
Generate basic image information (placeholder for actual captioning).
|
| 617 |
+
|
| 618 |
+
Args:
|
| 619 |
+
image_path: Path to image file
|
| 620 |
+
|
| 621 |
+
Returns:
|
| 622 |
+
str: Basic image information
|
| 623 |
+
"""
|
| 624 |
+
try:
|
| 625 |
+
from PIL import Image
|
| 626 |
+
|
| 627 |
+
image = Image.open(image_path)
|
| 628 |
+
width, height = image.size
|
| 629 |
+
mode = image.mode
|
| 630 |
+
format_type = image.format
|
| 631 |
+
|
| 632 |
+
caption = f"Image: {image_path}\n"
|
| 633 |
+
caption += f"Dimensions: {width}x{height} pixels\n"
|
| 634 |
+
caption += f"Mode: {mode}\n"
|
| 635 |
+
caption += f"Format: {format_type}\n"
|
| 636 |
+
caption += "Note: For detailed content description, integrate with a vision model."
|
| 637 |
+
|
| 638 |
+
return caption
|
| 639 |
+
|
| 640 |
+
except Exception as e:
|
| 641 |
+
return f"Image info error: {str(e)}"
|
| 642 |
+
|
| 643 |
+
|
| 644 |
+
@tool
|
| 645 |
+
def visual_qa_tool(image_path: str, question: str) -> str:
|
| 646 |
+
"""
|
| 647 |
+
Answer questions about images (placeholder for actual VQA).
|
| 648 |
+
|
| 649 |
+
Args:
|
| 650 |
+
image_path: Path to image file
|
| 651 |
+
question: Question about the image
|
| 652 |
+
|
| 653 |
+
Returns:
|
| 654 |
+
str: Basic response about the image
|
| 655 |
+
"""
|
| 656 |
+
try:
|
| 657 |
+
from PIL import Image
|
| 658 |
+
|
| 659 |
+
image = Image.open(image_path)
|
| 660 |
+
width, height = image.size
|
| 661 |
+
mode = image.mode
|
| 662 |
+
|
| 663 |
+
response = f"Question: {question}\n"
|
| 664 |
+
response += f"Image: {image_path} ({width}x{height}, {mode})\n"
|
| 665 |
+
response += "Note: For actual visual QA, integrate with a vision-language model."
|
| 666 |
+
|
| 667 |
+
return response
|
| 668 |
+
|
| 669 |
+
except Exception as e:
|
| 670 |
+
return f"Visual QA error: {str(e)}"
|
| 671 |
+
|
| 672 |
+
|
| 673 |
+
all_tools = [
|
| 674 |
+
wikipedia_search,
|
| 675 |
+
web_search_duckduckgo,
|
| 676 |
+
fetch_webpage_content,
|
| 677 |
+
arxiv_search,
|
| 678 |
+
wikipedia_search_tool,
|
| 679 |
+
duckduckgo_search,
|
| 680 |
+
load_csv_file,
|
| 681 |
+
load_excel_file,
|
| 682 |
+
read_text_file,
|
| 683 |
+
transcribe_audio_file,
|
| 684 |
+
analyze_chess_position,
|
| 685 |
+
reverse_string,
|
| 686 |
+
reverse_words_in_string,
|
| 687 |
+
analyze_table_commutativity,
|
| 688 |
+
count_items_in_list,
|
| 689 |
+
ocr_tool,
|
| 690 |
+
image_captioning_tool,
|
| 691 |
+
visual_qa_tool,
|
| 692 |
+
]
|