File size: 4,985 Bytes
80480f7
cbf2549
 
80480f7
 
 
 
 
 
cbf2549
 
d0ba1a4
cbf2549
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80480f7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
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