""" Search tools for finding song lyrics and related information. """ import time import random from typing import Dict, List, Any from loguru import logger from smolagents import DuckDuckGoSearchTool class ThrottledDuckDuckGoSearchTool(DuckDuckGoSearchTool): """ A wrapper around DuckDuckGoSearchTool that adds a delay between requests to avoid rate limiting issues. This tool implements a delay mechanism to prevent hitting DuckDuckGo's rate limits. Each search request will be followed by a random delay within the specified range. """ def __init__(self, min_delay: float = 7.0, max_delay: float = 15.0, **kwargs): """ Initialize the throttled search tool with delay parameters. Args: min_delay: Minimum delay in seconds between requests (default: 5.0) max_delay: Maximum delay in seconds between requests (default: 5.0) **kwargs: Additional arguments to pass to DuckDuckGoSearchTool """ super().__init__(**kwargs) self.min_delay = min_delay self.max_delay = max_delay self.name = "search" # Keep the same name as the parent class logger.info(f"Initialized ThrottledDuckDuckGoSearchTool with delay range: {min_delay}-{max_delay}s") def forward(self, query: str) -> List[Dict[str, Any]]: """ Execute a search with a delay to avoid rate limiting. Args: query: The search query string Returns: List of search results """ # Add a random delay before the search to avoid rate limiting delay = random.uniform(self.min_delay, self.max_delay) logger.info(f"Throttling DuckDuckGo search for {delay:.2f} seconds before query: '{query}'") time.sleep(delay) # Call the parent class implementation try: results = super().forward(query) # Add another delay after the search to ensure spacing between requests time.sleep(random.uniform(self.min_delay / 2, self.max_delay / 2)) return results except Exception as e: logger.error(f"Error in DuckDuckGo search: {str(e)}") # Return empty results on error to allow the agent to continue return [{"title": "Search error", "href": "", "body": f"Error performing search: {str(e)}"}]