Spaces:
Runtime error
Runtime error
Fix
Browse files
app.py
CHANGED
|
@@ -22,13 +22,13 @@ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
|
|
| 22 |
|
| 23 |
@tool
|
| 24 |
def serper_search(query: str) -> str:
|
| 25 |
-
"""Enhanced web search using Serper API with
|
| 26 |
|
| 27 |
Args:
|
| 28 |
query (str): The search query to be executed.
|
| 29 |
|
| 30 |
Returns:
|
| 31 |
-
str:
|
| 32 |
"""
|
| 33 |
try:
|
| 34 |
api_key = os.getenv("SERPER_API_KEY")
|
|
@@ -36,51 +36,82 @@ def serper_search(query: str) -> str:
|
|
| 36 |
return "SERPER_API_KEY environment variable not found"
|
| 37 |
|
| 38 |
url = "https://google.serper.dev/search"
|
| 39 |
-
payload = json.dumps({
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
headers = {
|
| 41 |
'X-API-KEY': api_key,
|
| 42 |
'Content-Type': 'application/json'
|
| 43 |
}
|
|
|
|
| 44 |
response = requests.post(url, headers=headers, data=payload, timeout=30)
|
| 45 |
response.raise_for_status()
|
| 46 |
|
| 47 |
data = response.json()
|
| 48 |
results = []
|
| 49 |
|
|
|
|
| 50 |
if 'knowledgeGraph' in data:
|
| 51 |
kg = data['knowledgeGraph']
|
| 52 |
-
kg_info = f"KNOWLEDGE GRAPH: {kg.get('title', '')}
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
results.append(kg_info + "\n")
|
| 57 |
|
|
|
|
| 58 |
if 'organic' in data:
|
| 59 |
-
for i, item in enumerate(data['organic'][:
|
| 60 |
-
title = item.get('title', '')
|
| 61 |
-
snippet = item.get('snippet', '')
|
| 62 |
-
link = item.get('link', '')
|
| 63 |
-
result_text = f"RESULT {i+1}:\nTitle: {title}\nSnippet: {snippet}\nURL: {link}\n"
|
| 64 |
|
| 65 |
-
|
|
|
|
|
|
|
|
|
|
| 66 |
years = re.findall(r'\b(19|20)\d{2}\b', snippet)
|
| 67 |
-
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
| 69 |
|
| 70 |
-
if re.search(r'\
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
result_text += f"Amounts: {', '.join(amounts)}\n"
|
| 74 |
|
| 75 |
results.append(result_text)
|
| 76 |
|
|
|
|
| 77 |
if 'peopleAlsoAsk' in data:
|
| 78 |
-
paa = "\nPEOPLE ALSO ASK:
|
| 79 |
-
for item in data['peopleAlsoAsk'][:
|
| 80 |
-
|
|
|
|
|
|
|
| 81 |
results.append(paa)
|
| 82 |
|
| 83 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
|
| 85 |
except Exception as e:
|
| 86 |
return f"Search error: {str(e)}"
|
|
@@ -88,17 +119,19 @@ def serper_search(query: str) -> str:
|
|
| 88 |
|
| 89 |
@tool
|
| 90 |
def wikipedia_search(query: str) -> str:
|
| 91 |
-
"""
|
| 92 |
|
| 93 |
Args:
|
| 94 |
-
query (str): Wikipedia search query
|
| 95 |
|
| 96 |
Returns:
|
| 97 |
-
str:
|
| 98 |
"""
|
| 99 |
try:
|
| 100 |
results = []
|
| 101 |
-
|
|
|
|
|
|
|
| 102 |
direct_url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{clean_query}"
|
| 103 |
|
| 104 |
try:
|
|
@@ -106,33 +139,42 @@ def wikipedia_search(query: str) -> str:
|
|
| 106 |
if response.status_code == 200:
|
| 107 |
data = response.json()
|
| 108 |
if data.get('type') != 'disambiguation':
|
| 109 |
-
summary = f"WIKIPEDIA DIRECT MATCH:\nTitle: {data.get('title', '')}
|
| 110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
|
| 112 |
if 'coordinates' in data:
|
| 113 |
coords = data['coordinates']
|
| 114 |
-
summary += f"
|
| 115 |
-
|
| 116 |
-
extract = data.get('extract', '')
|
| 117 |
-
birth_match = re.search(r'born[^)]*(\d{1,2}\s+\w+\s+\d{4})', extract, re.IGNORECASE)
|
| 118 |
-
if birth_match:
|
| 119 |
-
summary += f"Birth date found: {birth_match.group(1)}\n"
|
| 120 |
-
|
| 121 |
-
death_match = re.search(r'died[^)]*(\d{1,2}\s+\w+\s+\d{4})', extract, re.IGNORECASE)
|
| 122 |
-
if death_match:
|
| 123 |
-
summary += f"Death date found: {death_match.group(1)}\n"
|
| 124 |
|
| 125 |
results.append(summary)
|
| 126 |
except:
|
| 127 |
pass
|
| 128 |
|
|
|
|
| 129 |
search_url = "https://en.wikipedia.org/w/api.php"
|
| 130 |
search_params = {
|
| 131 |
"action": "query",
|
| 132 |
"format": "json",
|
| 133 |
"list": "search",
|
| 134 |
"srsearch": query,
|
| 135 |
-
"srlimit":
|
|
|
|
| 136 |
}
|
| 137 |
|
| 138 |
try:
|
|
@@ -140,34 +182,42 @@ def wikipedia_search(query: str) -> str:
|
|
| 140 |
data = response.json()
|
| 141 |
|
| 142 |
if 'query' in data and 'search' in data['query']:
|
| 143 |
-
search_results = "WIKIPEDIA SEARCH RESULTS:
|
| 144 |
-
for item in data['query']['search']:
|
|
|
|
| 145 |
snippet = re.sub(r'<[^>]+>', '', item.get('snippet', ''))
|
| 146 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 147 |
results.append(search_results)
|
| 148 |
except:
|
| 149 |
pass
|
| 150 |
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
|
|
|
|
|
|
| 169 |
|
| 170 |
-
return "\n".join(results) if results else "No Wikipedia results found"
|
| 171 |
|
| 172 |
except Exception as e:
|
| 173 |
return f"Wikipedia search error: {str(e)}"
|
|
@@ -175,7 +225,7 @@ def wikipedia_search(query: str) -> str:
|
|
| 175 |
|
| 176 |
@tool
|
| 177 |
def youtube_analyzer(url: str) -> str:
|
| 178 |
-
"""
|
| 179 |
|
| 180 |
Args:
|
| 181 |
url (str): YouTube video URL to analyze.
|
|
@@ -184,6 +234,7 @@ def youtube_analyzer(url: str) -> str:
|
|
| 184 |
str: Comprehensive video analysis.
|
| 185 |
"""
|
| 186 |
try:
|
|
|
|
| 187 |
video_id_match = re.search(r'(?:v=|/|youtu\.be/)([A-Za-z0-9_-]{11})', url)
|
| 188 |
if not video_id_match:
|
| 189 |
return "Invalid YouTube URL format"
|
|
@@ -191,70 +242,126 @@ def youtube_analyzer(url: str) -> str:
|
|
| 191 |
video_id = video_id_match.group(1)
|
| 192 |
results = []
|
| 193 |
|
|
|
|
| 194 |
try:
|
| 195 |
oembed_url = f"https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v={video_id}&format=json"
|
| 196 |
response = requests.get(oembed_url, timeout=15)
|
| 197 |
|
| 198 |
if response.status_code == 200:
|
| 199 |
data = response.json()
|
| 200 |
-
basic_info = f"VIDEO
|
| 201 |
|
|
|
|
| 202 |
title = data.get('title', '').lower()
|
| 203 |
-
|
| 204 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 205 |
if duration_match:
|
| 206 |
-
basic_info += f"
|
|
|
|
| 207 |
|
| 208 |
results.append(basic_info)
|
| 209 |
-
except:
|
| 210 |
-
|
| 211 |
|
|
|
|
| 212 |
try:
|
| 213 |
-
video_url = f"https://www.youtube.com/watch?v={video_id}"
|
| 214 |
headers = {
|
| 215 |
-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
}
|
| 217 |
|
| 218 |
-
|
|
|
|
|
|
|
| 219 |
if response.status_code == 200:
|
| 220 |
content = response.text
|
| 221 |
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
|
|
|
| 226 |
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
|
| 231 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 232 |
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
if
|
| 236 |
-
results.append(f"
|
|
|
|
| 237 |
|
| 238 |
-
|
|
|
|
| 239 |
if duration_match:
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
|
|
|
| 243 |
|
|
|
|
| 244 |
desc_patterns = [
|
| 245 |
r'"description":{"simpleText":"([^"]+)"}',
|
| 246 |
-
r'"shortDescription":"([^"]+)"'
|
|
|
|
| 247 |
]
|
| 248 |
|
| 249 |
for pattern in desc_patterns:
|
| 250 |
desc_match = re.search(pattern, content)
|
| 251 |
if desc_match:
|
| 252 |
-
description = desc_match.group(1)
|
| 253 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 254 |
break
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 255 |
|
| 256 |
except Exception as e:
|
| 257 |
-
results.append(f"Enhanced
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 258 |
|
| 259 |
return "\n".join(results) if results else "Could not analyze video"
|
| 260 |
|
|
@@ -264,12 +371,11 @@ def youtube_analyzer(url: str) -> str:
|
|
| 264 |
|
| 265 |
@tool
|
| 266 |
def text_processor(text: str, operation: str = "analyze") -> str:
|
| 267 |
-
"""Advanced text processing
|
| 268 |
|
| 269 |
Args:
|
| 270 |
text (str): Text to process.
|
| 271 |
-
operation (str
|
| 272 |
-
Defaults to "analyze".
|
| 273 |
|
| 274 |
Returns:
|
| 275 |
str: Processed text results.
|
|
@@ -279,21 +385,32 @@ def text_processor(text: str, operation: str = "analyze") -> str:
|
|
| 279 |
return text[::-1]
|
| 280 |
|
| 281 |
elif operation == "decode":
|
|
|
|
| 282 |
if text.startswith("base64:"):
|
| 283 |
try:
|
| 284 |
decoded = base64.b64decode(text[7:]).decode('utf-8')
|
| 285 |
return f"Base64 decoded: {decoded}"
|
| 286 |
-
except:
|
| 287 |
-
return "
|
| 288 |
|
|
|
|
| 289 |
if '%' in text:
|
| 290 |
try:
|
| 291 |
decoded = urllib.parse.unquote(text)
|
| 292 |
return f"URL decoded: {decoded}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 293 |
except:
|
| 294 |
-
|
| 295 |
|
| 296 |
-
return f"No encoding
|
| 297 |
|
| 298 |
elif operation == "extract_numbers":
|
| 299 |
patterns = {
|
|
@@ -301,39 +418,60 @@ def text_processor(text: str, operation: str = "analyze") -> str:
|
|
| 301 |
'decimals': re.findall(r'\b\d+\.\d+\b', text),
|
| 302 |
'years': re.findall(r'\b(19|20)\d{2}\b', text),
|
| 303 |
'percentages': re.findall(r'\b\d+(?:\.\d+)?%', text),
|
| 304 |
-
'currencies': re.findall(r'\$[\d,]+(?:\.\d{2})?', text)
|
|
|
|
|
|
|
| 305 |
}
|
| 306 |
|
| 307 |
result = "EXTRACTED NUMBERS:\n"
|
| 308 |
for category, matches in patterns.items():
|
| 309 |
if matches:
|
| 310 |
-
|
|
|
|
| 311 |
|
| 312 |
-
return result
|
| 313 |
|
| 314 |
elif operation == "parse":
|
| 315 |
words = text.split()
|
| 316 |
sentences = re.split(r'[.!?]+', text)
|
|
|
|
| 317 |
|
| 318 |
analysis = f"TEXT ANALYSIS:\n"
|
| 319 |
analysis += f"Character count: {len(text)}\n"
|
| 320 |
analysis += f"Word count: {len(words)}\n"
|
| 321 |
-
analysis += f"Sentence count: {len(
|
| 322 |
|
| 323 |
if words:
|
| 324 |
-
analysis += f"First word: {words[0]}\n"
|
| 325 |
-
analysis += f"Last word: {words[-1]}\n"
|
| 326 |
-
analysis += f"Longest word: {max(words, key=len)}\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 327 |
|
|
|
|
| 328 |
if re.search(r'[А-Яа-я]', text):
|
| 329 |
-
analysis += "Cyrillic characters detected (Russian/Slavic)\n"
|
| 330 |
-
|
| 331 |
-
analysis += "Extended Latin characters detected\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 332 |
|
| 333 |
return analysis
|
| 334 |
|
| 335 |
-
else:
|
| 336 |
-
|
|
|
|
|
|
|
| 337 |
|
| 338 |
except Exception as e:
|
| 339 |
return f"Text processing error: {str(e)}"
|
|
@@ -341,90 +479,185 @@ def text_processor(text: str, operation: str = "analyze") -> str:
|
|
| 341 |
|
| 342 |
@tool
|
| 343 |
def math_solver(problem: str) -> str:
|
| 344 |
-
"""Advanced mathematical problem solver with
|
| 345 |
|
| 346 |
Args:
|
| 347 |
problem (str): Mathematical problem or structure to analyze.
|
| 348 |
|
| 349 |
Returns:
|
| 350 |
-
str: Mathematical analysis and solution
|
| 351 |
"""
|
| 352 |
try:
|
| 353 |
problem_lower = problem.lower()
|
| 354 |
|
| 355 |
if "commutative" in problem_lower:
|
| 356 |
-
return """COMMUTATIVITY ANALYSIS:
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 363 |
|
| 364 |
elif "chess" in problem_lower:
|
| 365 |
-
return """CHESS ANALYSIS FRAMEWORK:
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 417 |
|
| 418 |
else:
|
|
|
|
| 419 |
numbers = re.findall(r'-?\d+(?:\.\d+)?', problem)
|
|
|
|
|
|
|
|
|
|
| 420 |
if numbers:
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
Consider: arithmetic operations, algebraic manipulation,
|
| 425 |
-
pattern recognition, or formula application"""
|
| 426 |
|
| 427 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 428 |
|
| 429 |
except Exception as e:
|
| 430 |
return f"Math solver error: {str(e)}"
|
|
|
|
| 22 |
|
| 23 |
@tool
|
| 24 |
def serper_search(query: str) -> str:
|
| 25 |
+
"""Enhanced web search using Serper API with comprehensive result processing.
|
| 26 |
|
| 27 |
Args:
|
| 28 |
query (str): The search query to be executed.
|
| 29 |
|
| 30 |
Returns:
|
| 31 |
+
str: Detailed search results with structured information.
|
| 32 |
"""
|
| 33 |
try:
|
| 34 |
api_key = os.getenv("SERPER_API_KEY")
|
|
|
|
| 36 |
return "SERPER_API_KEY environment variable not found"
|
| 37 |
|
| 38 |
url = "https://google.serper.dev/search"
|
| 39 |
+
payload = json.dumps({
|
| 40 |
+
"q": query,
|
| 41 |
+
"num": 12,
|
| 42 |
+
"hl": "en",
|
| 43 |
+
"gl": "us"
|
| 44 |
+
})
|
| 45 |
headers = {
|
| 46 |
'X-API-KEY': api_key,
|
| 47 |
'Content-Type': 'application/json'
|
| 48 |
}
|
| 49 |
+
|
| 50 |
response = requests.post(url, headers=headers, data=payload, timeout=30)
|
| 51 |
response.raise_for_status()
|
| 52 |
|
| 53 |
data = response.json()
|
| 54 |
results = []
|
| 55 |
|
| 56 |
+
# Knowledge Graph extraction
|
| 57 |
if 'knowledgeGraph' in data:
|
| 58 |
kg = data['knowledgeGraph']
|
| 59 |
+
kg_info = f"KNOWLEDGE GRAPH:\nTitle: {kg.get('title', 'N/A')}\nDescription: {kg.get('description', 'N/A')}"
|
| 60 |
+
|
| 61 |
+
if 'attributes' in kg and kg['attributes']:
|
| 62 |
+
kg_info += "\nKey Facts:"
|
| 63 |
+
for key, value in list(kg['attributes'].items())[:5]:
|
| 64 |
+
kg_info += f"\n• {key}: {value}"
|
| 65 |
+
|
| 66 |
+
if 'entityType' in kg:
|
| 67 |
+
kg_info += f"\nType: {kg['entityType']}"
|
| 68 |
+
|
| 69 |
results.append(kg_info + "\n")
|
| 70 |
|
| 71 |
+
# Organic search results
|
| 72 |
if 'organic' in data:
|
| 73 |
+
for i, item in enumerate(data['organic'][:8]):
|
| 74 |
+
title = item.get('title', 'No title')
|
| 75 |
+
snippet = item.get('snippet', 'No snippet')
|
| 76 |
+
link = item.get('link', 'No link')
|
|
|
|
| 77 |
|
| 78 |
+
result_text = f"RESULT {i+1}:\nTitle: {title}\nSnippet: {snippet}\nURL: {link}"
|
| 79 |
+
|
| 80 |
+
# Extract specific data patterns
|
| 81 |
+
if re.search(r'\b(19|20)\d{2}\b', snippet):
|
| 82 |
years = re.findall(r'\b(19|20)\d{2}\b', snippet)
|
| 83 |
+
result_text += f"\nYears mentioned: {', '.join(set(years))}"
|
| 84 |
+
|
| 85 |
+
if re.search(r'\$[\d,]+(?:\.\d{2})?|\d+(?:,\d{3})*(?:\.\d{2})?\s*(?:million|billion|thousand)', snippet, re.IGNORECASE):
|
| 86 |
+
amounts = re.findall(r'\$[\d,]+(?:\.\d{2})?|\d+(?:,\d{3})*(?:\.\d{2})?\s*(?:million|billion|thousand)', snippet, re.IGNORECASE)
|
| 87 |
+
result_text += f"\nAmounts: {', '.join(amounts[:3])}"
|
| 88 |
|
| 89 |
+
if re.search(r'\b\d+(?:\.\d+)?\s*(?:albums?|songs?|tracks?|records?)\b', snippet, re.IGNORECASE):
|
| 90 |
+
music_counts = re.findall(r'\b\d+(?:\.\d+)?\s*(?:albums?|songs?|tracks?|records?)\b', snippet, re.IGNORECASE)
|
| 91 |
+
result_text += f"\nMusic counts: {', '.join(music_counts[:3])}"
|
|
|
|
| 92 |
|
| 93 |
results.append(result_text)
|
| 94 |
|
| 95 |
+
# People Also Ask section
|
| 96 |
if 'peopleAlsoAsk' in data:
|
| 97 |
+
paa = "\nPEOPLE ALSO ASK:"
|
| 98 |
+
for item in data['peopleAlsoAsk'][:4]:
|
| 99 |
+
question = item.get('question', '')
|
| 100 |
+
answer = item.get('snippet', '')
|
| 101 |
+
paa += f"\nQ: {question}\nA: {answer[:150]}..."
|
| 102 |
results.append(paa)
|
| 103 |
|
| 104 |
+
# News results if available
|
| 105 |
+
if 'news' in data:
|
| 106 |
+
news_section = "\nNEWS RESULTS:"
|
| 107 |
+
for item in data['news'][:3]:
|
| 108 |
+
title = item.get('title', '')
|
| 109 |
+
snippet = item.get('snippet', '')
|
| 110 |
+
date = item.get('date', '')
|
| 111 |
+
news_section += f"\n• {title} ({date}): {snippet[:100]}..."
|
| 112 |
+
results.append(news_section)
|
| 113 |
+
|
| 114 |
+
return "\n\n".join(results) if results else "No search results found"
|
| 115 |
|
| 116 |
except Exception as e:
|
| 117 |
return f"Search error: {str(e)}"
|
|
|
|
| 119 |
|
| 120 |
@tool
|
| 121 |
def wikipedia_search(query: str) -> str:
|
| 122 |
+
"""Comprehensive Wikipedia search with multiple API endpoints.
|
| 123 |
|
| 124 |
Args:
|
| 125 |
+
query (str): Wikipedia search query.
|
| 126 |
|
| 127 |
Returns:
|
| 128 |
+
str: Detailed Wikipedia information.
|
| 129 |
"""
|
| 130 |
try:
|
| 131 |
results = []
|
| 132 |
+
|
| 133 |
+
# Direct page lookup
|
| 134 |
+
clean_query = urllib.parse.quote(query.replace(" ", "_"))
|
| 135 |
direct_url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{clean_query}"
|
| 136 |
|
| 137 |
try:
|
|
|
|
| 139 |
if response.status_code == 200:
|
| 140 |
data = response.json()
|
| 141 |
if data.get('type') != 'disambiguation':
|
| 142 |
+
summary = f"WIKIPEDIA DIRECT MATCH:\nTitle: {data.get('title', 'N/A')}"
|
| 143 |
+
extract = data.get('extract', '')
|
| 144 |
+
summary += f"\nExtract: {extract}"
|
| 145 |
+
|
| 146 |
+
# Extract key dates and facts
|
| 147 |
+
if extract:
|
| 148 |
+
birth_dates = re.findall(r'born[^)]*?(\d{1,2}\s+\w+\s+\d{4})', extract, re.IGNORECASE)
|
| 149 |
+
if birth_dates:
|
| 150 |
+
summary += f"\nBirth: {birth_dates[0]}"
|
| 151 |
+
|
| 152 |
+
death_dates = re.findall(r'died[^)]*?(\d{1,2}\s+\w+\s+\d{4})', extract, re.IGNORECASE)
|
| 153 |
+
if death_dates:
|
| 154 |
+
summary += f"\nDeath: {death_dates[0]}"
|
| 155 |
+
|
| 156 |
+
# Extract discography info
|
| 157 |
+
album_counts = re.findall(r'(\d+)\s+(?:studio\s+)?albums?', extract, re.IGNORECASE)
|
| 158 |
+
if album_counts:
|
| 159 |
+
summary += f"\nAlbums mentioned: {', '.join(album_counts)}"
|
| 160 |
|
| 161 |
if 'coordinates' in data:
|
| 162 |
coords = data['coordinates']
|
| 163 |
+
summary += f"\nCoordinates: {coords.get('lat', '')}, {coords.get('lon', '')}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 164 |
|
| 165 |
results.append(summary)
|
| 166 |
except:
|
| 167 |
pass
|
| 168 |
|
| 169 |
+
# Search API
|
| 170 |
search_url = "https://en.wikipedia.org/w/api.php"
|
| 171 |
search_params = {
|
| 172 |
"action": "query",
|
| 173 |
"format": "json",
|
| 174 |
"list": "search",
|
| 175 |
"srsearch": query,
|
| 176 |
+
"srlimit": 8,
|
| 177 |
+
"srprop": "snippet|titlesnippet|size|wordcount"
|
| 178 |
}
|
| 179 |
|
| 180 |
try:
|
|
|
|
| 182 |
data = response.json()
|
| 183 |
|
| 184 |
if 'query' in data and 'search' in data['query']:
|
| 185 |
+
search_results = "WIKIPEDIA SEARCH RESULTS:"
|
| 186 |
+
for i, item in enumerate(data['query']['search']):
|
| 187 |
+
title = item.get('title', '')
|
| 188 |
snippet = re.sub(r'<[^>]+>', '', item.get('snippet', ''))
|
| 189 |
+
wordcount = item.get('wordcount', 0)
|
| 190 |
+
|
| 191 |
+
search_results += f"\n{i+1}. {title} ({wordcount} words)"
|
| 192 |
+
if snippet:
|
| 193 |
+
search_results += f"\n {snippet[:200]}..."
|
| 194 |
+
|
| 195 |
results.append(search_results)
|
| 196 |
except:
|
| 197 |
pass
|
| 198 |
|
| 199 |
+
# Category search for specific topics
|
| 200 |
+
if any(term in query.lower() for term in ['dinosaur', 'paleontology', 'fossil']):
|
| 201 |
+
try:
|
| 202 |
+
category_params = {
|
| 203 |
+
"action": "query",
|
| 204 |
+
"format": "json",
|
| 205 |
+
"list": "categorymembers",
|
| 206 |
+
"cmtitle": "Category:Dinosaurs",
|
| 207 |
+
"cmlimit": 5
|
| 208 |
+
}
|
| 209 |
+
response = requests.get(search_url, params=category_params, timeout=10)
|
| 210 |
+
cat_data = response.json()
|
| 211 |
+
|
| 212 |
+
if 'query' in cat_data and 'categorymembers' in cat_data['query']:
|
| 213 |
+
cat_results = "\nDINOSAUR CATEGORY RESULTS:"
|
| 214 |
+
for item in cat_data['query']['categorymembers']:
|
| 215 |
+
cat_results += f"\n• {item.get('title', '')}"
|
| 216 |
+
results.append(cat_results)
|
| 217 |
+
except:
|
| 218 |
+
pass
|
| 219 |
|
| 220 |
+
return "\n\n".join(results) if results else "No Wikipedia results found"
|
| 221 |
|
| 222 |
except Exception as e:
|
| 223 |
return f"Wikipedia search error: {str(e)}"
|
|
|
|
| 225 |
|
| 226 |
@tool
|
| 227 |
def youtube_analyzer(url: str) -> str:
|
| 228 |
+
"""Advanced YouTube video analyzer with transcript and metadata extraction.
|
| 229 |
|
| 230 |
Args:
|
| 231 |
url (str): YouTube video URL to analyze.
|
|
|
|
| 234 |
str: Comprehensive video analysis.
|
| 235 |
"""
|
| 236 |
try:
|
| 237 |
+
# Extract video ID
|
| 238 |
video_id_match = re.search(r'(?:v=|/|youtu\.be/)([A-Za-z0-9_-]{11})', url)
|
| 239 |
if not video_id_match:
|
| 240 |
return "Invalid YouTube URL format"
|
|
|
|
| 242 |
video_id = video_id_match.group(1)
|
| 243 |
results = []
|
| 244 |
|
| 245 |
+
# Basic video info via oEmbed
|
| 246 |
try:
|
| 247 |
oembed_url = f"https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v={video_id}&format=json"
|
| 248 |
response = requests.get(oembed_url, timeout=15)
|
| 249 |
|
| 250 |
if response.status_code == 200:
|
| 251 |
data = response.json()
|
| 252 |
+
basic_info = f"VIDEO METADATA:\nTitle: {data.get('title', 'N/A')}\nAuthor: {data.get('author_name', 'N/A')}"
|
| 253 |
|
| 254 |
+
# Extract duration from title if mentioned
|
| 255 |
title = data.get('title', '').lower()
|
| 256 |
+
duration_patterns = [
|
| 257 |
+
r'(\d+)\s*(?:minutes?|mins?)',
|
| 258 |
+
r'(\d+)\s*(?:hours?|hrs?)',
|
| 259 |
+
r'(\d+:\d+)'
|
| 260 |
+
]
|
| 261 |
+
|
| 262 |
+
for pattern in duration_patterns:
|
| 263 |
+
duration_match = re.search(pattern, title)
|
| 264 |
if duration_match:
|
| 265 |
+
basic_info += f"\nDuration mentioned in title: {duration_match.group(1)}"
|
| 266 |
+
break
|
| 267 |
|
| 268 |
results.append(basic_info)
|
| 269 |
+
except Exception as e:
|
| 270 |
+
results.append(f"oEmbed error: {str(e)}")
|
| 271 |
|
| 272 |
+
# Enhanced page scraping
|
| 273 |
try:
|
|
|
|
| 274 |
headers = {
|
| 275 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
| 276 |
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
|
| 277 |
+
'Accept-Language': 'en-US,en;q=0.5',
|
| 278 |
+
'Accept-Encoding': 'gzip, deflate',
|
| 279 |
+
'Connection': 'keep-alive',
|
| 280 |
+
'Upgrade-Insecure-Requests': '1'
|
| 281 |
}
|
| 282 |
|
| 283 |
+
video_url = f"https://www.youtube.com/watch?v={video_id}"
|
| 284 |
+
response = requests.get(video_url, headers=headers, timeout=25)
|
| 285 |
+
|
| 286 |
if response.status_code == 200:
|
| 287 |
content = response.text
|
| 288 |
|
| 289 |
+
# Extract view count
|
| 290 |
+
view_patterns = [
|
| 291 |
+
r'"viewCount":"(\d+)"',
|
| 292 |
+
r'"viewCount":{"simpleText":"([\d,]+)\s+views"}'
|
| 293 |
+
]
|
| 294 |
|
| 295 |
+
for pattern in view_patterns:
|
| 296 |
+
view_match = re.search(pattern, content)
|
| 297 |
+
if view_match:
|
| 298 |
+
views = view_match.group(1).replace(',', '')
|
| 299 |
+
try:
|
| 300 |
+
view_count = int(views)
|
| 301 |
+
results.append(f"VIEW COUNT: {view_count:,}")
|
| 302 |
+
except:
|
| 303 |
+
results.append(f"VIEW COUNT: {views}")
|
| 304 |
+
break
|
| 305 |
|
| 306 |
+
# Extract upload date
|
| 307 |
+
upload_patterns = [
|
| 308 |
+
r'"uploadDate":"([^"]+)"',
|
| 309 |
+
r'"publishDate":"([^"]+)"'
|
| 310 |
+
]
|
| 311 |
|
| 312 |
+
for pattern in upload_patterns:
|
| 313 |
+
upload_match = re.search(pattern, content)
|
| 314 |
+
if upload_match:
|
| 315 |
+
results.append(f"UPLOAD DATE: {upload_match.group(1)}")
|
| 316 |
+
break
|
| 317 |
|
| 318 |
+
# Extract exact duration
|
| 319 |
+
duration_match = re.search(r'"lengthSeconds":"(\d+)"', content)
|
| 320 |
if duration_match:
|
| 321 |
+
seconds = int(duration_match.group(1))
|
| 322 |
+
minutes = seconds // 60
|
| 323 |
+
secs = seconds % 60
|
| 324 |
+
results.append(f"DURATION: {minutes}:{secs:02d} ({seconds} seconds)")
|
| 325 |
|
| 326 |
+
# Enhanced description extraction
|
| 327 |
desc_patterns = [
|
| 328 |
r'"description":{"simpleText":"([^"]+)"}',
|
| 329 |
+
r'"shortDescription":"([^"]+)"',
|
| 330 |
+
r'"attributedDescription":{"content":"([^"]+)"}'
|
| 331 |
]
|
| 332 |
|
| 333 |
for pattern in desc_patterns:
|
| 334 |
desc_match = re.search(pattern, content)
|
| 335 |
if desc_match:
|
| 336 |
+
description = desc_match.group(1)
|
| 337 |
+
# Look for specific content patterns
|
| 338 |
+
if 'bird' in description.lower():
|
| 339 |
+
bird_numbers = re.findall(r'\b(\d+)\s+(?:bird|species|individual)', description.lower())
|
| 340 |
+
if bird_numbers:
|
| 341 |
+
results.append(f"BIRD COUNTS IN DESCRIPTION: {', '.join(bird_numbers)}")
|
| 342 |
+
|
| 343 |
+
results.append(f"DESCRIPTION EXCERPT: {description[:300]}...")
|
| 344 |
break
|
| 345 |
+
|
| 346 |
+
# Look for transcript indicators
|
| 347 |
+
if 'transcript' in content.lower() or 'captions' in content.lower():
|
| 348 |
+
results.append("TRANSCRIPT: Available (captions detected)")
|
| 349 |
+
|
| 350 |
+
# Extract channel info
|
| 351 |
+
channel_match = re.search(r'"author":"([^"]+)"', content)
|
| 352 |
+
if channel_match:
|
| 353 |
+
results.append(f"CHANNEL: {channel_match.group(1)}")
|
| 354 |
|
| 355 |
except Exception as e:
|
| 356 |
+
results.append(f"Enhanced scraping error: {str(e)}")
|
| 357 |
+
|
| 358 |
+
# Attempt to find related content
|
| 359 |
+
try:
|
| 360 |
+
search_query = f"site:youtube.com \"{video_id}\" transcript OR captions OR subtitles"
|
| 361 |
+
# This would be handled by the main search function
|
| 362 |
+
results.append(f"SEARCH SUGGESTION: {search_query}")
|
| 363 |
+
except:
|
| 364 |
+
pass
|
| 365 |
|
| 366 |
return "\n".join(results) if results else "Could not analyze video"
|
| 367 |
|
|
|
|
| 371 |
|
| 372 |
@tool
|
| 373 |
def text_processor(text: str, operation: str = "analyze") -> str:
|
| 374 |
+
"""Advanced text processing with multiple linguistic operations.
|
| 375 |
|
| 376 |
Args:
|
| 377 |
text (str): Text to process.
|
| 378 |
+
operation (str): Operation type (reverse, decode, analyze, extract_numbers, parse).
|
|
|
|
| 379 |
|
| 380 |
Returns:
|
| 381 |
str: Processed text results.
|
|
|
|
| 385 |
return text[::-1]
|
| 386 |
|
| 387 |
elif operation == "decode":
|
| 388 |
+
# Base64 decoding
|
| 389 |
if text.startswith("base64:"):
|
| 390 |
try:
|
| 391 |
decoded = base64.b64decode(text[7:]).decode('utf-8')
|
| 392 |
return f"Base64 decoded: {decoded}"
|
| 393 |
+
except Exception as e:
|
| 394 |
+
return f"Base64 decode failed: {str(e)}"
|
| 395 |
|
| 396 |
+
# URL decoding
|
| 397 |
if '%' in text:
|
| 398 |
try:
|
| 399 |
decoded = urllib.parse.unquote(text)
|
| 400 |
return f"URL decoded: {decoded}"
|
| 401 |
+
except Exception as e:
|
| 402 |
+
return f"URL decode failed: {str(e)}"
|
| 403 |
+
|
| 404 |
+
# Hex decoding
|
| 405 |
+
if re.match(r'^[0-9a-fA-F]+$', text.replace(' ', '')):
|
| 406 |
+
try:
|
| 407 |
+
hex_text = text.replace(' ', '')
|
| 408 |
+
decoded = bytes.fromhex(hex_text).decode('utf-8')
|
| 409 |
+
return f"Hex decoded: {decoded}"
|
| 410 |
except:
|
| 411 |
+
pass
|
| 412 |
|
| 413 |
+
return f"No recognized encoding in: {text[:100]}"
|
| 414 |
|
| 415 |
elif operation == "extract_numbers":
|
| 416 |
patterns = {
|
|
|
|
| 418 |
'decimals': re.findall(r'\b\d+\.\d+\b', text),
|
| 419 |
'years': re.findall(r'\b(19|20)\d{2}\b', text),
|
| 420 |
'percentages': re.findall(r'\b\d+(?:\.\d+)?%', text),
|
| 421 |
+
'currencies': re.findall(r'\$[\d,]+(?:\.\d{2})?', text),
|
| 422 |
+
'ranges': re.findall(r'\b\d+[-–]\d+\b', text),
|
| 423 |
+
'ordinals': re.findall(r'\b\d+(?:st|nd|rd|th)\b', text, re.IGNORECASE)
|
| 424 |
}
|
| 425 |
|
| 426 |
result = "EXTRACTED NUMBERS:\n"
|
| 427 |
for category, matches in patterns.items():
|
| 428 |
if matches:
|
| 429 |
+
unique_matches = list(set(matches))
|
| 430 |
+
result += f"{category.title()}: {', '.join(unique_matches)}\n"
|
| 431 |
|
| 432 |
+
return result if any(patterns.values()) else "No numbers found"
|
| 433 |
|
| 434 |
elif operation == "parse":
|
| 435 |
words = text.split()
|
| 436 |
sentences = re.split(r'[.!?]+', text)
|
| 437 |
+
clean_sentences = [s.strip() for s in sentences if s.strip()]
|
| 438 |
|
| 439 |
analysis = f"TEXT ANALYSIS:\n"
|
| 440 |
analysis += f"Character count: {len(text)}\n"
|
| 441 |
analysis += f"Word count: {len(words)}\n"
|
| 442 |
+
analysis += f"Sentence count: {len(clean_sentences)}\n"
|
| 443 |
|
| 444 |
if words:
|
| 445 |
+
analysis += f"First word: '{words[0]}'\n"
|
| 446 |
+
analysis += f"Last word: '{words[-1]}'\n"
|
| 447 |
+
analysis += f"Longest word: '{max(words, key=len)}' ({len(max(words, key=len))} chars)\n"
|
| 448 |
+
|
| 449 |
+
# Word frequency
|
| 450 |
+
word_freq = {}
|
| 451 |
+
for word in words:
|
| 452 |
+
word_lower = word.lower().strip('.,!?";')
|
| 453 |
+
word_freq[word_lower] = word_freq.get(word_lower, 0) + 1
|
| 454 |
+
|
| 455 |
+
if word_freq:
|
| 456 |
+
most_common = max(word_freq.items(), key=lambda x: x[1])
|
| 457 |
+
analysis += f"Most frequent word: '{most_common[0]}' ({most_common[1]} times)\n"
|
| 458 |
|
| 459 |
+
# Language detection patterns
|
| 460 |
if re.search(r'[А-Яа-я]', text):
|
| 461 |
+
analysis += "Language: Cyrillic characters detected (Russian/Slavic)\n"
|
| 462 |
+
elif re.search(r'[À-ÿ]', text):
|
| 463 |
+
analysis += "Language: Extended Latin characters detected\n"
|
| 464 |
+
elif re.search(r'[一-龯]', text):
|
| 465 |
+
analysis += "Language: Chinese characters detected\n"
|
| 466 |
+
else:
|
| 467 |
+
analysis += "Language: Appears to be English/Latin script\n"
|
| 468 |
|
| 469 |
return analysis
|
| 470 |
|
| 471 |
+
else: # default analyze
|
| 472 |
+
length = len(text)
|
| 473 |
+
preview = text[:200] + ('...' if length > 200 else '')
|
| 474 |
+
return f"TEXT PREVIEW:\nLength: {length} characters\nContent: {preview}"
|
| 475 |
|
| 476 |
except Exception as e:
|
| 477 |
return f"Text processing error: {str(e)}"
|
|
|
|
| 479 |
|
| 480 |
@tool
|
| 481 |
def math_solver(problem: str) -> str:
|
| 482 |
+
"""Advanced mathematical problem solver with domain-specific strategies.
|
| 483 |
|
| 484 |
Args:
|
| 485 |
problem (str): Mathematical problem or structure to analyze.
|
| 486 |
|
| 487 |
Returns:
|
| 488 |
+
str: Mathematical analysis and solution guidance.
|
| 489 |
"""
|
| 490 |
try:
|
| 491 |
problem_lower = problem.lower()
|
| 492 |
|
| 493 |
if "commutative" in problem_lower:
|
| 494 |
+
return """COMMUTATIVITY ANALYSIS GUIDE:
|
| 495 |
+
For operation * on set S to be commutative, a*b = b*a must hold for ALL pairs (a,b).
|
| 496 |
+
|
| 497 |
+
SYSTEMATIC CHECK METHOD:
|
| 498 |
+
1. Create operation table if not given
|
| 499 |
+
2. For each entry (i,j), check if it equals entry (j,i)
|
| 500 |
+
3. The table should be symmetric across the main diagonal
|
| 501 |
+
4. If ANY single pair fails, operation is NOT commutative
|
| 502 |
+
|
| 503 |
+
COMMON COUNTEREXAMPLE PATTERNS:
|
| 504 |
+
- Look for asymmetric entries: if a*b ≠ b*a
|
| 505 |
+
- Check corner cases and boundary elements
|
| 506 |
+
- Pay attention to identity elements and inverses
|
| 507 |
+
- Matrix multiplication is classic non-commutative example
|
| 508 |
+
|
| 509 |
+
TO PROVE NON-COMMUTATIVITY: Find ONE counterexample where a*b ≠ b*a
|
| 510 |
+
TO PROVE COMMUTATIVITY: Verify ALL pairs satisfy a*b = b*a"""
|
| 511 |
|
| 512 |
elif "chess" in problem_lower:
|
| 513 |
+
return """CHESS POSITION ANALYSIS FRAMEWORK:
|
| 514 |
+
|
| 515 |
+
IMMEDIATE ASSESSMENT:
|
| 516 |
+
1. Check for checks/threats to both kings
|
| 517 |
+
2. Identify all possible legal moves
|
| 518 |
+
3. Look for immediate tactical opportunities
|
| 519 |
+
|
| 520 |
+
TACTICAL PATTERNS TO EXAMINE:
|
| 521 |
+
- Pins: pieces unable to move due to exposing king/valuable piece
|
| 522 |
+
- Forks: single piece attacking multiple targets
|
| 523 |
+
- Skewers: forcing valuable piece to move, exposing less valuable one
|
| 524 |
+
- Discovered attacks: moving one piece reveals attack from another
|
| 525 |
+
- Double attacks: attacking two targets simultaneously
|
| 526 |
+
|
| 527 |
+
STRATEGIC CONSIDERATIONS:
|
| 528 |
+
- King safety and escape squares
|
| 529 |
+
- Piece activity and coordination
|
| 530 |
+
- Control of key squares (center, weak squares)
|
| 531 |
+
- Pawn structure advantages/disadvantages
|
| 532 |
+
- Material balance and exchanges
|
| 533 |
+
|
| 534 |
+
MOVE EVALUATION PRIORITY:
|
| 535 |
+
1. Forced moves (checks, captures, threats)
|
| 536 |
+
2. Tactical shots (combinations)
|
| 537 |
+
3. Improving piece positions
|
| 538 |
+
4. Prophylactic moves (preventing opponent threats)"""
|
| 539 |
+
|
| 540 |
+
elif any(term in problem_lower for term in ["prime", "factor", "divisible", "gcd", "lcm"]):
|
| 541 |
+
return """NUMBER THEORY PROBLEM SOLVING:
|
| 542 |
+
|
| 543 |
+
PRIMALITY TESTING:
|
| 544 |
+
- Check divisibility by primes up to √n
|
| 545 |
+
- Use divisibility rules (2,3,5,7,11...)
|
| 546 |
+
- For large numbers, use probabilistic tests
|
| 547 |
+
|
| 548 |
+
FACTORIZATION STRATEGIES:
|
| 549 |
+
1. Trial division by small primes
|
| 550 |
+
2. Look for perfect square factors
|
| 551 |
+
3. Use difference of squares: a² - b² = (a+b)(a-b)
|
| 552 |
+
4. Check for patterns in number sequences
|
| 553 |
+
|
| 554 |
+
GCD/LCM PROBLEMS:
|
| 555 |
+
- Use Euclidean algorithm for GCD
|
| 556 |
+
- LCM = (a×b)/GCD(a,b)
|
| 557 |
+
- Prime factorization method for multiple numbers
|
| 558 |
+
|
| 559 |
+
MODULAR ARITHMETIC:
|
| 560 |
+
- Use when dealing with remainders
|
| 561 |
+
- Fermat's Little Theorem for prime moduli
|
| 562 |
+
- Chinese Remainder Theorem for system of congruences"""
|
| 563 |
+
|
| 564 |
+
elif any(term in problem_lower for term in ["triangle", "circle", "area", "volume", "angle", "geometry"]):
|
| 565 |
+
return """GEOMETRY PROBLEM SOLVING APPROACH:
|
| 566 |
+
|
| 567 |
+
VISUALIZATION:
|
| 568 |
+
1. Draw accurate diagram if possible
|
| 569 |
+
2. Mark known values and unknowns
|
| 570 |
+
3. Identify geometric relationships
|
| 571 |
+
|
| 572 |
+
KEY FORMULAS TO CONSIDER:
|
| 573 |
+
- Triangle: Area = ½bh, Pythagorean theorem
|
| 574 |
+
- Circle: Area = πr², Circumference = 2πr
|
| 575 |
+
- Volume formulas for 3D shapes
|
| 576 |
+
- Trigonometric ratios (SOH-CAH-TOA)
|
| 577 |
+
|
| 578 |
+
SOLUTION STRATEGIES:
|
| 579 |
+
1. Similar triangles and proportions
|
| 580 |
+
2. Coordinate geometry when helpful
|
| 581 |
+
3. Law of sines/cosines for non-right triangles
|
| 582 |
+
4. Circle theorems and properties
|
| 583 |
+
5. Symmetry and transformation properties
|
| 584 |
+
|
| 585 |
+
COMMON TECHNIQUES:
|
| 586 |
+
- Auxiliary lines and constructions
|
| 587 |
+
- Angle chasing in polygons
|
| 588 |
+
- Using properties of special triangles (30-60-90, 45-45-90)"""
|
| 589 |
+
|
| 590 |
+
elif any(term in problem_lower for term in ["probability", "statistics", "combination", "permutation"]):
|
| 591 |
+
return """PROBABILITY & STATISTICS SOLUTION GUIDE:
|
| 592 |
+
|
| 593 |
+
PROBABILITY FUNDAMENTALS:
|
| 594 |
+
- P(A) = favorable outcomes / total outcomes
|
| 595 |
+
- P(A or B) = P(A) + P(B) - P(A and B)
|
| 596 |
+
- P(A and B) = P(A) × P(B|A) for dependent events
|
| 597 |
+
- P(A and B) = P(A) × P(B) for independent events
|
| 598 |
+
|
| 599 |
+
COUNTING PRINCIPLES:
|
| 600 |
+
- Permutations: P(n,r) = n!/(n-r)! (order matters)
|
| 601 |
+
- Combinations: C(n,r) = n!/(r!(n-r)!) (order doesn't matter)
|
| 602 |
+
- Multiplication principle for sequential choices
|
| 603 |
+
|
| 604 |
+
STATISTICS MEASURES:
|
| 605 |
+
- Mean: sum of values / count
|
| 606 |
+
- Median: middle value when ordered
|
| 607 |
+
- Mode: most frequent value
|
| 608 |
+
- Standard deviation: measure of spread
|
| 609 |
+
|
| 610 |
+
COMMON PROBLEM TYPES:
|
| 611 |
+
- Conditional probability (Bayes' theorem)
|
| 612 |
+
- Binomial distribution
|
| 613 |
+
- Normal distribution applications"""
|
| 614 |
+
|
| 615 |
+
elif any(term in problem_lower for term in ["sequence", "series", "pattern", "recursive"]):
|
| 616 |
+
return """SEQUENCE & PATTERN ANALYSIS:
|
| 617 |
+
|
| 618 |
+
PATTERN IDENTIFICATION:
|
| 619 |
+
1. Look for arithmetic progression: constant difference
|
| 620 |
+
2. Check for geometric progression: constant ratio
|
| 621 |
+
3. Examine polynomial patterns (quadratic, cubic)
|
| 622 |
+
4. Consider Fibonacci-type recursive relations
|
| 623 |
+
|
| 624 |
+
ANALYSIS METHODS:
|
| 625 |
+
- First differences, second differences
|
| 626 |
+
- Ratio between consecutive terms
|
| 627 |
+
- Look for alternating patterns
|
| 628 |
+
- Check for periodic behavior
|
| 629 |
+
|
| 630 |
+
COMMON SEQUENCES:
|
| 631 |
+
- Arithmetic: a, a+d, a+2d, ...
|
| 632 |
+
- Geometric: a, ar, ar², ...
|
| 633 |
+
- Quadratic: differences form arithmetic sequence
|
| 634 |
+
- Fibonacci: F(n) = F(n-1) + F(n-2)
|
| 635 |
+
|
| 636 |
+
FORMULA DERIVATION:
|
| 637 |
+
- Use known formulas for standard sequences
|
| 638 |
+
- Set up recurrence relations
|
| 639 |
+
- Use generating functions for complex patterns"""
|
| 640 |
|
| 641 |
else:
|
| 642 |
+
# Extract numbers and suggest general approach
|
| 643 |
numbers = re.findall(r'-?\d+(?:\.\d+)?', problem)
|
| 644 |
+
operations = re.findall(r'[+\-*/^=<>]', problem)
|
| 645 |
+
|
| 646 |
+
analysis = f"GENERAL MATHEMATICAL ANALYSIS:\n"
|
| 647 |
if numbers:
|
| 648 |
+
analysis += f"Numbers identified: {', '.join(numbers)}\n"
|
| 649 |
+
if operations:
|
| 650 |
+
analysis += f"Operations found: {', '.join(set(operations))}\n"
|
|
|
|
|
|
|
| 651 |
|
| 652 |
+
analysis += f"\nProblem excerpt: {problem[:150]}...\n"
|
| 653 |
+
analysis += "\nSUGGESTED APPROACH:\n"
|
| 654 |
+
analysis += "1. Identify the mathematical domain (algebra, geometry, etc.)\n"
|
| 655 |
+
analysis += "2. List known information and what needs to be found\n"
|
| 656 |
+
analysis += "3. Apply relevant formulas and theorems\n"
|
| 657 |
+
analysis += "4. Work step-by-step with clear reasoning\n"
|
| 658 |
+
analysis += "5. Verify the solution makes sense"
|
| 659 |
+
|
| 660 |
+
return analysis
|
| 661 |
|
| 662 |
except Exception as e:
|
| 663 |
return f"Math solver error: {str(e)}"
|