DeepCritical / src /tools /web_search_factory.py
SeasonalFall84's picture
Add TTS on-demand with UI credentials, improve UI layout, and fix References removal
b4f9ff5
raw
history blame
4.53 kB
"""Factory for creating web search tools based on configuration."""
import structlog
from src.tools.base import SearchTool
from src.tools.searchxng_web_search import SearchXNGWebSearchTool
from src.tools.serper_web_search import SerperWebSearchTool
from src.tools.web_search import WebSearchTool
from src.utils.config import settings
from src.utils.exceptions import ConfigurationError
logger = structlog.get_logger()
def create_web_search_tool(provider: str | None = None) -> SearchTool | None:
"""Create a web search tool based on configuration.
Args:
provider: Override provider selection. If None, uses settings.web_search_provider.
Returns:
SearchTool instance, or None if not available/configured
The tool is selected based on provider (or settings.web_search_provider if None):
- "serper": SerperWebSearchTool (requires SERPER_API_KEY)
- "searchxng": SearchXNGWebSearchTool (requires SEARCHXNG_HOST)
- "duckduckgo": WebSearchTool (always available, no API key)
- "brave" or "tavily": Not yet implemented, returns None
- "auto": Auto-detect best available provider (prefers Serper > SearchXNG > DuckDuckGo)
Auto-detection logic (when provider is "auto" or not explicitly set):
1. Try Serper if SERPER_API_KEY is available (best quality - Google search + full content scraping)
2. Try SearchXNG if SEARCHXNG_HOST is available
3. Fall back to DuckDuckGo (always available, but lower quality - snippets only)
"""
provider = provider or settings.web_search_provider
# Auto-detect best available provider if "auto" or if provider is duckduckgo but better options exist
if provider == "auto" or (provider == "duckduckgo" and settings.serper_api_key):
# Prefer Serper if API key is available (better quality)
if settings.serper_api_key:
try:
logger.info(
"Auto-detected Serper web search (SERPER_API_KEY found)",
provider="serper",
)
return SerperWebSearchTool()
except Exception as e:
logger.warning(
"Failed to initialize Serper, falling back",
error=str(e),
)
# Try SearchXNG as second choice
if settings.searchxng_host:
try:
logger.info(
"Auto-detected SearchXNG web search (SEARCHXNG_HOST found)",
provider="searchxng",
)
return SearchXNGWebSearchTool()
except Exception as e:
logger.warning(
"Failed to initialize SearchXNG, falling back",
error=str(e),
)
# Fall back to DuckDuckGo
if provider == "auto":
logger.info(
"Auto-detected DuckDuckGo web search (no API keys found)",
provider="duckduckgo",
)
return WebSearchTool()
try:
if provider == "serper":
if not settings.serper_api_key:
logger.warning(
"Serper provider selected but no API key found",
hint="Set SERPER_API_KEY environment variable",
)
return None
return SerperWebSearchTool()
elif provider == "searchxng":
if not settings.searchxng_host:
logger.warning(
"SearchXNG provider selected but no host found",
hint="Set SEARCHXNG_HOST environment variable",
)
return None
return SearchXNGWebSearchTool()
elif provider == "duckduckgo":
# DuckDuckGo is always available (no API key required)
return WebSearchTool()
elif provider in ("brave", "tavily"):
logger.warning(
f"Web search provider '{provider}' not yet implemented",
hint="Use 'serper', 'searchxng', or 'duckduckgo'",
)
return None
else:
logger.warning(f"Unknown web search provider '{provider}', falling back to DuckDuckGo")
return WebSearchTool()
except ConfigurationError as e:
logger.error("Failed to create web search tool", error=str(e), provider=provider)
return None
except Exception as e:
logger.error("Unexpected error creating web search tool", error=str(e), provider=provider)
return None