diff --git a/config/__init__.py b/config/__init__.py index 2dcc824..4962922 100644 --- a/config/__init__.py +++ b/config/__init__.py @@ -53,10 +53,15 @@ def load_config(): }) # Default values if missing - + # Default values if missing if 'ollama' not in config: config['ollama'] = {'model': 'llama3'} - + + # Search config + if 'search' not in config: config['search'] = {} + config['search']['provider'] = os.getenv('SEARCH_PROVIDER', config['search'].get('provider', 'duckduckgo')) + config['search']['tavily_api_key'] = os.getenv('TAVILY_API_KEY', config['search'].get('tavily_api_key', '')) + return config except FileNotFoundError: logging.error(f"Configuration file {CONFIG_FILE} not found.") diff --git a/config/config.yaml.example b/config/config.yaml.example index 5766c15..4ddbf39 100644 --- a/config/config.yaml.example +++ b/config/config.yaml.example @@ -40,6 +40,10 @@ email: # ssl: true # enabled: true +search: + provider: "duckduckgo" # duckduckgo or tavily + tavily_api_key: "" # Required when provider is tavily + servers: - name: "Local System" type: "local" diff --git a/env.example b/env.example index 0b3d562..333d03b 100644 --- a/env.example +++ b/env.example @@ -1,4 +1,6 @@ TELEGRAM_BOT_TOKEN= TELEGRAM_CHAT_ID= GBYTE_ERP_URL="" -API_KEY=secret-agent-key \ No newline at end of file +API_KEY=secret-agent-key +SEARCH_PROVIDER=duckduckgo # duckduckgo or tavily +TAVILY_API_KEY= # Required when SEARCH_PROVIDER=tavily diff --git a/requirements.txt b/requirements.txt index a1dec54..21a9c1a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -27,6 +27,7 @@ pyyaml dateparser pytz ddgs +tavily-python youtube-transcript-api python-dateutil playwright diff --git a/tools/web_search.py b/tools/web_search.py index 94737ec..7cf2621 100644 --- a/tools/web_search.py +++ b/tools/web_search.py @@ -2,19 +2,20 @@ Web Search Tool — Search the web and summarize content. """ import logging +import os import re from langchain_core.tools import tool import config as app_config -def perform_web_search(query): +def perform_duckduckgo_search(query): """Performs a DuckDuckGo search.""" from ddgs import DDGS try: results = DDGS().text(query, max_results=5) if not results: return "No results found." - + summary = "" for r in results: summary += f"- [{r['title']}]({r['href']}): {r['body']}\n" @@ -23,6 +24,39 @@ def perform_web_search(query): return f"Error performing search: {e}" +def perform_tavily_search(query): + """Performs a Tavily search.""" + from tavily import TavilyClient + try: + client = TavilyClient() + response = client.search(query=query, max_results=5) + results = response.get("results", []) + if not results: + return "No results found." + + summary = "" + for r in results: + summary += f"- [{r['title']}]({r['url']}): {r.get('content', '')}\n" + return summary + except Exception as e: + return f"Error performing search: {e}" + + +def perform_web_search(query): + """Dispatches search to the configured provider (duckduckgo or tavily).""" + conf = app_config.load_config() + provider = (conf.get("search", {}).get("provider", "duckduckgo") if conf else os.environ.get("SEARCH_PROVIDER", "duckduckgo")).lower() + if provider not in ("duckduckgo", "tavily"): + logging.warning(f'Unknown SEARCH_PROVIDER "{provider}", falling back to duckduckgo') + provider = "duckduckgo" + if provider == "tavily": + tavily_key = conf.get("search", {}).get("tavily_api_key", "") if conf else "" + if tavily_key: + os.environ.setdefault("TAVILY_API_KEY", tavily_key) + return perform_tavily_search(query) + return perform_duckduckgo_search(query) + + def get_youtube_video_id(url): """Extracts YouTube video ID from URL.""" patterns = [