M.Natale
modify app
80480f7
Raw
History Blame Contribute Delete
4.99 kB
from smolagents import tool, Tool
from youtube_transcript_api import YouTubeTranscriptApi
from urllib.parse import urlparse, parse_qs
import os
import ast
import operator as op
from typing import Any, Optional
from datetime import datetime
from smolagents import tool
@tool
def youtube_tool(video_url: str) -> str:
"""
Analyzes a YouTube video by extracting its transcript.
Args:
video_url (str): The full URL of the YouTube video.
Returns:
str: The transcript text of the video or an error message.
"""
try:
# Extract video ID from URL
parsed_url = urlparse(video_url)
if parsed_url.hostname == 'youtu.be':
video_id = parsed_url.path[1:]
else:
video_id = parse_qs(parsed_url.query).get('v', [None])[0]
if not video_id:
return "Error: Could not extract video ID from URL."
# Fetch transcript
transcript_list = YouTubeTranscriptApi.fetch(video_id)
# Combine transcript parts into a single string
full_text = " ".join([item['text'] for item in transcript_list])
return full_text
except Exception as e:
return f"Error analyzing YouTube video: {str(e)}"
@tool
def get_current_time() -> str:
"""Get the current date and time in a readable format."""
now = datetime.now()
return now.strftime("%Y-%m-%d %H:%M:%S")
@tool
def calculate_basic_math(expression: str) -> str:
"""
Safely evaluate basic mathematical expressions using AST.
Args:
expression: A string containing a mathematical expression like "2+2" or "10*5"
Returns:
The result of the calculation as a string
"""
# Safe operations mapping
SAFE_OPS = {
ast.Add: op.add,
ast.Sub: op.sub,
ast.Mult: op.mul,
ast.Div: op.truediv,
ast.Pow: op.pow,
ast.USub: op.neg
}
def _safe_eval(node):
"""Recursively evaluate AST nodes safely."""
if isinstance(node, ast.Num): # Numbers
return node.n
elif isinstance(node, ast.Constant): # Python 3.8+ constant nodes
return node.value
elif isinstance(node, ast.BinOp): # Binary operations
return SAFE_OPS[type(node.op)](_safe_eval(node.left), _safe_eval(node.right))
elif isinstance(node, ast.UnaryOp): # Unary operations
return SAFE_OPS[type(node.op)](_safe_eval(node.operand))
else:
raise ValueError(f"Unsupported operation: {type(node)}")
try:
# Parse expression into AST and evaluate safely
node = ast.parse(expression, mode='eval')
result = _safe_eval(node.body)
return f"Result: {result}"
except Exception as e:
return f"Error calculating '{expression}': {str(e)}"
@tool
def save_note(content: str, filename: Optional[str] = None) -> str:
"""
Save a note to a text file.
Args:
content: The content to save in the note
filename: Optional filename. If not provided, uses timestamp
Returns:
Success message with filename
"""
try:
if filename is None:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"note_{timestamp}.txt"
# Try to create notes directory, fall back to /tmp if permission denied
try:
os.makedirs("notes", exist_ok=True)
notes_dir = "notes"
except PermissionError:
notes_dir = "/tmp/notes"
os.makedirs(notes_dir, exist_ok=True)
filepath = os.path.join(notes_dir, filename)
with open(filepath, 'w', encoding='utf-8') as f:
f.write(content)
return f"✅ Note saved successfully to: {filepath}"
except Exception as e:
return f"❌ Error saving note: {str(e)}"
@tool
def list_saved_notes() -> str:
"""List all saved notes in the notes directory."""
try:
# Check both possible notes directories
all_files = []
for notes_dir in ["notes", "/tmp/notes"]:
if os.path.exists(notes_dir):
files = os.listdir(notes_dir)
txt_files = [f for f in files if f.endswith('.txt')]
all_files.extend([(f, notes_dir) for f in txt_files])
if not all_files:
return "📂 No notes found. Save a note first!"
file_list = "\n".join([f"- {file} ({location})" for file, location in sorted(all_files)])
return f"📂 Saved notes:\n{file_list}"
except Exception as e:
return f"❌ Error listing notes: {str(e)}"
class FinalAnswerTool(Tool):
name = "final_answer"
description = "Provides a final answer to the given problem."
inputs = {'answer': {'type': 'any', 'description': 'The final answer to the problem'}}
output_type = "any"
def forward(self, answer: Any) -> Any:
return answer
def __init__(self, *args, **kwargs):
self.is_initialized = False