File size: 11,669 Bytes
a1c1d9a
7319d31
 
a1c1d9a
7319d31
 
 
 
 
 
 
 
 
 
a1c1d9a
7319d31
 
 
7b71bd5
7319d31
 
 
 
 
 
a1c1d9a
 
 
 
7319d31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a1c1d9a
 
 
 
 
 
 
 
 
 
7319d31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a1c1d9a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7319d31
 
 
 
 
 
 
 
 
a1c1d9a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7319d31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a1c1d9a
 
 
7319d31
a1c1d9a
 
 
7319d31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a1c1d9a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7b71bd5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a1c1d9a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7b71bd5
 
a1c1d9a
 
7b71bd5
 
 
a1c1d9a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# tools/langchain_tools.py
"""
LangChain-compatible tool wrappers for our existing tools
Complete integration of multimodal, search, math, and YouTube tools
"""

from langchain_core.tools import tool
from typing import Optional
import os
from dotenv import load_dotenv

# Load environment variables FIRST, before any tool imports
load_dotenv()

from .multimodal_tools import MultimodalTools, analyze_transcript as _analyze_transcript, analyze_excel, analyze_python
from .search_tools import SearchTools
from .math_tools import MathTools
from .youtube_tools import YouTubeTools
from .wikipedia_tools import search_wikipedia, get_wikipedia_page, wikipedia_summary

# Initialize tool instances (now env vars are available)
multimodal_tools = MultimodalTools()
search_tools = SearchTools()
youtube_tools = YouTubeTools()

# =============================================================================
# MULTIMODAL TOOLS
# =============================================================================

@tool
def extract_text(image_path: str) -> str:
    """Extract text from an image using OCR"""
    return multimodal_tools.extract_text_from_image(image_path)

@tool
def analyze_image_tool(image_path: str, question: str = "Describe this image in detail") -> str:
    """Analyze an image and answer questions about it"""
    return multimodal_tools.analyze_image(image_path, question)

@tool
def analyze_audio_tool(transcript: str, question: str = "Summarize this audio content") -> str:
    """Analyze audio content via transcript"""
    return multimodal_tools.analyze_audio_transcript(transcript, question)

@tool
def analyze_excel_tool(file_path: str, question: str) -> str:
    """Analyze Excel or CSV files to answer questions about the data"""
    return analyze_excel(file_path, question)

# =============================================================================
# SEARCH TOOLS
# =============================================================================

@tool
def search_tool(query: str, max_results: int = 10) -> str:
    """Search the web for information"""
    results = search_tools.search(query, max_results)
    if not results:
        return "No search results found"
    
    # Format results for the LLM
    formatted_results = []
    for i, result in enumerate(results, 1):
        title = result.get('title', 'No title')
        content = result.get('content', 'No content')
        url = result.get('url', 'No URL')
        formatted_results.append(f"{i}. {title}\n{content[:200]}...\nSource: {url}\n")
    
    return "\n".join(formatted_results)

@tool
def search_news_tool(query: str, max_results: int = 10) -> str:
    """Search for news articles about a topic"""
    results = search_tools.search_news(query, max_results)
    if not results:
        return "No news results found"
    
    # Format results for the LLM
    formatted_results = []
    for i, result in enumerate(results, 1):
        title = result.get('title', 'No title')
        content = result.get('content', 'No content')
        url = result.get('url', 'No URL')
        formatted_results.append(f"{i}. {title}\n{content[:200]}...\nSource: {url}\n")
    
    return "\n".join(formatted_results)

@tool
def search_academic_tool(query: str, max_results: int = 10) -> str:
    """Search for academic research and papers"""
    results = search_tools.search_academic(query, max_results)
    if not results:
        return "No academic results found"
    
    # Format results for the LLM
    formatted_results = []
    for i, result in enumerate(results, 1):
        title = result.get('title', 'No title')
        content = result.get('content', 'No content')
        url = result.get('url', 'No URL')
        formatted_results.append(f"{i}. {title}\n{content[:200]}...\nSource: {url}\n")
    
    return "\n".join(formatted_results)

# =============================================================================
# YOUTUBE TOOLS
# =============================================================================

@tool
def extract_youtube_transcript(url: str, language_code: str = 'en') -> str:
    """Extract transcript/captions from a YouTube video"""
    captions = youtube_tools.get_captions(url, language_code)
    if captions:
        return captions
    else:
        return "No captions available for this video"

@tool
def get_youtube_info(url: str) -> str:
    """Get information about a YouTube video"""
    info = youtube_tools.get_video_info(url)
    if info:
        return f"Title: {info.get('title', 'Unknown')}\nAuthor: {info.get('author', 'Unknown')}\nDuration: {info.get('length', 0)} seconds\nViews: {info.get('views', 0):,}"
    else:
        return "Could not retrieve video information"

@tool
def get_youtube_playlist_info(playlist_url: str) -> str:
    """Get information about a YouTube playlist"""
    info = youtube_tools.get_playlist_info(playlist_url)
    if info:
        return f"Playlist: {info.get('title', 'Unknown')}\nVideos: {info.get('video_count', 0)}\nOwner: {info.get('owner', 'Unknown')}"
    else:
        return "Could not retrieve playlist information"

# =============================================================================
# MATH TOOLS - Basic Operations
# =============================================================================

@tool
def add(a: float, b: float) -> float:
    """Add two numbers"""
    return MathTools.add(a, b)

@tool
def subtract(a: float, b: float) -> float:
    """Subtract two numbers"""
    return MathTools.subtract(a, b)

@tool
def multiply(a: float, b: float) -> float:
    """Multiply two numbers"""
    return MathTools.multiply(a, b)

@tool
def divide(a: float, b: float) -> str:
    """Divide two numbers"""
    result = MathTools.divide(a, b)
    return str(result)

@tool
def power(base: float, exponent: float) -> float:
    """Calculate base raised to the power of exponent"""
    return MathTools.power(base, exponent)

# =============================================================================
# MATH TOOLS - Advanced Operations
# =============================================================================

@tool
def factorial(n: int) -> str:
    """Calculate factorial of a number"""
    result = MathTools.factorial(n)
    return str(result)

@tool
def square_root(n: float) -> str:
    """Calculate square root of a number"""
    result = MathTools.square_root(n)
    return str(result)

@tool
def percentage(part: float, whole: float) -> str:
    """Calculate percentage"""
    result = MathTools.percentage(part, whole)
    return str(result)

@tool
def average(numbers: str) -> str:
    """Calculate average of numbers (provide as comma-separated string)"""
    try:
        number_list = [float(x.strip()) for x in numbers.split(',')]
        result = MathTools.average(number_list)
        return str(result)
    except Exception as e:
        return f"Error parsing numbers: {str(e)}"

@tool
def calculate_expression(expression: str) -> str:
    """Calculate a mathematical expression safely"""
    from .math_tools import calculate_expression as calc_expr
    return str(calc_expr(expression))

@tool
def absolute_value(n: float) -> float:
    """Calculate absolute value of a number"""
    return MathTools.absolute(n)

@tool
def round_number(n: float, decimals: int = 2) -> float:
    """Round number to specified decimal places"""
    return MathTools.round_number(n, decimals)

@tool
def min_value(numbers: str) -> str:
    """Find minimum value in a list of numbers (provide as comma-separated string)"""
    try:
        number_list = [float(x.strip()) for x in numbers.split(',')]
        result = MathTools.min_value(number_list)
        return str(result)
    except Exception as e:
        return f"Error parsing numbers: {str(e)}"

@tool
def max_value(numbers: str) -> str:
    """Find maximum value in a list of numbers (provide as comma-separated string)"""
    try:
        number_list = [float(x.strip()) for x in numbers.split(',')]
        result = MathTools.max_value(number_list)
        return str(result)
    except Exception as e:
        return f"Error parsing numbers: {str(e)}"

@tool
def compound_interest(principal: float, rate: float, time: float, compounds_per_year: int = 1) -> str:
    """Calculate compound interest"""
    result = MathTools.calculate_compound_interest(principal, rate, time, compounds_per_year)
    return str(result)

@tool
def solve_quadratic(a: float, b: float, c: float) -> str:
    """Solve quadratic equation ax² + bx + c = 0"""
    result = MathTools.solve_quadratic(a, b, c)
    return str(result)

@tool
def analyze_python_tool(file_path: str, question: str = "What is the final output of this code?") -> str:
    """Read and analyze Python code files, can execute code to get results"""
    return analyze_python(file_path, question)
# =============================================================================
# TOOL COLLECTIONS FOR EASY IMPORT
# =============================================================================
@tool
def analyze_youtube_frames(url: str, question: str = "Describe what happens in this video") -> str:
    """Extract frames from YouTube video and analyze visual content"""
    youtube_tools = YouTubeTools()
    return youtube_tools.analyze_video_content(url, question)

@tool
def extract_video_slides(url: str) -> str:
    """Extract and analyze slides from educational YouTube videos"""
    youtube_tools = YouTubeTools()
    results = youtube_tools.analyze_video_slides(url)
    
    if 'error' in results:
        return results['error']
    
    # Format slide analysis for LLM
    slide_content = []
    for frame in results.get('frames_analyzed', []):
        if 'slide' in frame.get('analysis', '').lower():
            slide_content.append(f"Slide {frame['frame_number']}: {frame['analysis']}")
    
    if slide_content:
        return "\n\n".join(slide_content)
    else:
        return results.get('analysis_summary', 'No slides detected in video')
# Add Wikipedia tools
@tool
def search_wikipedia_tool(query: str, language: str = 'en') -> str:
    """Search Wikipedia for information about a topic"""
    return search_wikipedia(query, language)

@tool
def get_wikipedia_page_tool(page_title: str, language: str = 'en') -> str:
    """Retrieve a specific Wikipedia page by title"""
    return get_wikipedia_page(page_title, language)

@tool
def wikipedia_summary_tool(query: str, language: str = 'en') -> str:
    """Get a concise Wikipedia summary about a topic"""
    return wikipedia_summary(query, language)

# Core tools (matching original template)
CORE_TOOLS = [
    extract_text,
    analyze_image_tool,
    analyze_audio_tool,
    extract_youtube_transcript,
    add,
    subtract,
    multiply,
    divide,
    search_tool
]

# Extended tools with new Excel functionality
EXTENDED_TOOLS = CORE_TOOLS + [
    analyze_excel_tool,  # NEW: Excel/CSV analysis
     analyze_youtube_frames,  # ✅ NEW: Frame extraction and analysis
    extract_video_slides,    # ✅ NEW: Slide detection
    analyze_python_tool,
    search_news_tool,
     search_wikipedia_tool,      # ✅ NEW: Wikipedia search
    get_wikipedia_page_tool,    # ✅ NEW: Specific Wikipedia pages
    wikipedia_summary_tool,     # ✅ NEW: Wikipedia summaries
    search_academic_tool,
    get_youtube_info,
    get_youtube_playlist_info,
    calculate_expression,
    factorial,
    square_root,
    percentage,
    average
]

# All available tools
ALL_TOOLS = EXTENDED_TOOLS + [
    power,
    absolute_value,
    round_number,
    min_value,
    max_value,
    compound_interest,
    solve_quadratic
]

# Default export (for backwards compatibility)
tools = CORE_TOOLS