|
|
from .search_base import SearchBase |
|
|
from .tool import Tool,Toolkit |
|
|
from googlesearch import search as google_f_search |
|
|
from typing import Dict, Any, List, Optional |
|
|
from evoagentx.core.logging import logger |
|
|
|
|
|
class SearchGoogleFree(SearchBase): |
|
|
""" |
|
|
Free Google Search tool that doesn't require API keys. |
|
|
""" |
|
|
|
|
|
def __init__( |
|
|
self, |
|
|
name: str = "GoogleFreeSearch", |
|
|
num_search_pages: Optional[int] = 5, |
|
|
max_content_words: Optional[int] = None, |
|
|
**kwargs |
|
|
): |
|
|
""" |
|
|
Initialize the Free Google Search tool. |
|
|
|
|
|
Args: |
|
|
name (str): Name of the tool |
|
|
num_search_pages (int): Number of search results to retrieve |
|
|
max_content_words (int): Maximum number of words to include in content |
|
|
**kwargs: Additional keyword arguments for parent class initialization |
|
|
""" |
|
|
super().__init__(name=name, num_search_pages=num_search_pages, max_content_words=max_content_words, **kwargs) |
|
|
|
|
|
def search(self, query: str, num_search_pages: int = None, max_content_words: int = None) -> Dict[str, Any]: |
|
|
""" |
|
|
Searches Google for the given query and retrieves content from multiple pages. |
|
|
|
|
|
Args: |
|
|
query (str): The search query. |
|
|
num_search_pages (int): Number of search results to retrieve |
|
|
max_content_words (int): Maximum number of words to include in content, None means no limit |
|
|
|
|
|
Returns: |
|
|
Dict[str, Any]: Contains a list of search results and optional error message. |
|
|
""" |
|
|
|
|
|
num_search_pages = num_search_pages or self.num_search_pages |
|
|
max_content_words = max_content_words or self.max_content_words |
|
|
|
|
|
results = [] |
|
|
try: |
|
|
|
|
|
logger.info(f"Searching Google (Free) for: {query}, num_results={num_search_pages}, max_content_words={max_content_words}") |
|
|
search_results = list(google_f_search(query, num_results=num_search_pages)) |
|
|
if not search_results: |
|
|
return {"results": [], "error": "No search results found."} |
|
|
|
|
|
logger.info(f"Found {len(search_results)} search results") |
|
|
|
|
|
|
|
|
for url in search_results: |
|
|
try: |
|
|
title, content = self._scrape_page(url) |
|
|
if content: |
|
|
|
|
|
display_content = self._truncate_content(content, max_content_words) |
|
|
|
|
|
results.append({ |
|
|
"title": title, |
|
|
"content": display_content, |
|
|
"url": url, |
|
|
}) |
|
|
except Exception as e: |
|
|
logger.warning(f"Error processing URL {url}: {str(e)}") |
|
|
continue |
|
|
|
|
|
return {"results": results, "error": None} |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"Error in free Google search: {str(e)}") |
|
|
return {"results": [], "error": str(e)} |
|
|
|
|
|
|
|
|
class GoogleFreeSearchTool(Tool): |
|
|
name: str = "google_free_search" |
|
|
description: str = "Search Google without requiring an API key and retrieve content from search results" |
|
|
inputs: Dict[str, Dict[str, str]] = { |
|
|
"query": { |
|
|
"type": "string", |
|
|
"description": "The search query to execute on Google" |
|
|
}, |
|
|
"num_search_pages": { |
|
|
"type": "integer", |
|
|
"description": "Number of search results to retrieve. Default: 5" |
|
|
}, |
|
|
"max_content_words": { |
|
|
"type": "integer", |
|
|
"description": "Maximum number of words to include in content per result. None means no limit. Default: None" |
|
|
} |
|
|
} |
|
|
required: Optional[List[str]] = ["query"] |
|
|
|
|
|
def __init__(self, search_google_free: SearchGoogleFree = None): |
|
|
super().__init__() |
|
|
self.search_google_free = search_google_free |
|
|
|
|
|
def __call__(self, query: str, num_search_pages: int = None, max_content_words: int = None) -> Dict[str, Any]: |
|
|
"""Execute Google free search using the SearchGoogleFree instance.""" |
|
|
if not self.search_google_free: |
|
|
raise RuntimeError("Google free search instance not initialized") |
|
|
|
|
|
try: |
|
|
return self.search_google_free.search(query, num_search_pages, max_content_words) |
|
|
except Exception as e: |
|
|
return {"results": [], "error": f"Error executing Google free search: {str(e)}"} |
|
|
|
|
|
|
|
|
class GoogleFreeSearchToolkit(Toolkit): |
|
|
def __init__( |
|
|
self, |
|
|
name: str = "GoogleFreeSearchToolkit", |
|
|
num_search_pages: Optional[int] = 5, |
|
|
max_content_words: Optional[int] = None, |
|
|
**kwargs |
|
|
): |
|
|
|
|
|
search_google_free = SearchGoogleFree( |
|
|
name="GoogleFreeSearch", |
|
|
num_search_pages=num_search_pages, |
|
|
max_content_words=max_content_words, |
|
|
**kwargs |
|
|
) |
|
|
|
|
|
|
|
|
tools = [ |
|
|
GoogleFreeSearchTool(search_google_free=search_google_free) |
|
|
] |
|
|
|
|
|
|
|
|
super().__init__(name=name, tools=tools) |
|
|
|
|
|
|
|
|
self.search_google_free = search_google_free |
|
|
|
|
|
|
|
|
|