Sborole commited on
Commit
66c107d
·
verified ·
1 Parent(s): ed05be0

Update tools/WebSearchTool.py

Browse files
Files changed (1) hide show
  1. tools/WebSearchTool.py +55 -54
tools/WebSearchTool.py CHANGED
@@ -1,19 +1,16 @@
1
- import os
2
  from smolagents import Tool
3
- # We use googleapiclient for the official Google Custom Search API
4
- from googleapiclient.discovery import build
5
 
6
- class GoogleSearchTool(Tool):
7
  """
8
- A tool to perform web search Google searches using the Custom Search Engine (CSE) API.
9
- Use this tool first to get the necessary information for calculation or further tools.
 
10
  """
11
- # Use a descriptive name to guide the agent
12
- name = "google_search"
13
- # Reverting to a proper, concise tool description.
14
- description = "Use Google to find current information and general knowledge. Returns a snippet and URL."
15
-
16
- # Define the required input structure for the agent framework
17
  inputs = {
18
  "query": {"type": "string", "description": "The search term to look up."}
19
  }
@@ -21,59 +18,63 @@ class GoogleSearchTool(Tool):
21
 
22
  def __init__(self, **kwargs):
23
  super().__init__(**kwargs)
24
-
25
- # Retrieve credentials from environment variables
26
- # NOTE: This requires GOOGLE_API_KEY (the developer key) and GOOGLE_CSE_ID (the ID of your search engine)
27
- self.api_key = os.getenv("GOOGLE_API_KEY")
28
- self.cse_id = os.getenv("GOOGLE_CSE_ID")
29
-
30
- # Check for mandatory credentials
31
- if not self.api_key or not self.cse_id:
32
- raise ValueError("GOOGLE_API_KEY or GOOGLE_CSE_ID secret not found. Check environment variables.")
33
-
34
- # Initialize the Google Custom Search service
35
- # 'customsearch' is the API name, 'v1' is the version
36
- self.service = build(
37
- "customsearch", "v1", developerKey=self.api_key
38
- )
39
 
40
  def forward(self, query: str) -> str:
41
  """
42
- Executes a Google search query and formats the top results (up to 3).
43
-
44
  Args:
45
  query: The search term provided by the agent.
46
-
47
  Returns:
48
- A formatted string of search results, or an error message.
49
  """
50
- print(f"Executing Google search for: '{query}'")
51
- try:
52
- # Execute the search request for up to 3 results
53
- res = self.service.cse().list(
54
- q=query,
55
- cx=self.cse_id,
56
- num=3
57
- ).execute()
58
 
59
- items = res.get('items', [])
 
 
 
 
60
 
61
- if not items:
62
- # Return the specific failure message expected by the agent
63
- return "XX record info: No results found."
 
 
 
 
 
 
 
64
 
65
- search_results = []
66
- for i, item in enumerate(items):
67
- # Formatting the output for clarity (Title, Content, Source URL)
68
- search_results.append(
69
- f"RESULT {i+1}: '{item.get('title')}'\n"
70
- f"CONTENT: {item.get('snippet')}\n"
71
- f"SOURCE: {item.get('link')}"
 
 
 
 
 
72
  )
73
 
74
- # Join the results with a clear separator
75
- return "\n\n---SEPARATOR---\n\n".join(search_results)
76
 
 
 
77
  except Exception as e:
78
- # Provide an informative error message upon API failure
79
- return f"Error during Google Search API call: {e}"
 
1
+ import requests
2
  from smolagents import Tool
3
+ import json
 
4
 
5
+ class DuckDuckGoSearchTool(Tool):
6
  """
7
+ A keyless web search tool using the DuckDuckGo Instant Answer API.
8
+ This is a final fallback option when other robust search APIs are unavailable.
9
+ It primarily returns a single, instant answer or the top result snippet.
10
  """
11
+ name = "duckduckgo_search"
12
+ description = "Use the DuckDuckGo API to fetch instant answers or the top search snippet for general knowledge questions. This tool is quick but may not provide multiple detailed results."
13
+
 
 
 
14
  inputs = {
15
  "query": {"type": "string", "description": "The search term to look up."}
16
  }
 
18
 
19
  def __init__(self, **kwargs):
20
  super().__init__(**kwargs)
21
+ # DuckDuckGo API endpoint for instant answers (format=json, no_html, skip_disambig)
22
+ self.endpoint = "https://api.duckduckgo.com/"
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
  def forward(self, query: str) -> str:
25
  """
26
+ Executes a DuckDuckGo Instant Answer query.
27
+
28
  Args:
29
  query: The search term provided by the agent.
30
+
31
  Returns:
32
+ A formatted string containing the instant answer or top result.
33
  """
34
+ print(f"Executing DuckDuckGo Search for: '{query}'")
35
+
36
+ params = {
37
+ "q": query,
38
+ "format": "json",
39
+ "no_html": "1", # Ensure content is plain text
40
+ "skip_disambig": "1" # Skip pages that offer multiple results
41
+ }
42
 
43
+ try:
44
+ # Make the API request
45
+ response = requests.get(self.endpoint, params=params, timeout=10)
46
+ response.raise_for_status()
47
+ data = response.json()
48
 
49
+ # 1. Prioritize the Instant Answer (a direct, concise answer)
50
+ instant_answer = data.get('AbstractText')
51
+ instant_source = data.get('AbstractURL')
52
+
53
+ if instant_answer and instant_source:
54
+ return (
55
+ f"RESULT 1 (Instant Answer): '{query}'\n"
56
+ f"CONTENT: {instant_answer}\n"
57
+ f"SOURCE: {instant_source}"
58
+ )
59
 
60
+ # 2. Fallback to the top result snippet if no instant answer is found
61
+ related_topics = data.get('RelatedTopics', [])
62
+ if related_topics and isinstance(related_topics[0], dict):
63
+ # We expect the first related topic to be the main search result snippet
64
+ top_topic = related_topics[0]
65
+ text = top_topic.get('Text', 'No snippet available.')
66
+ url = top_topic.get('FirstURL', 'N/A')
67
+
68
+ return (
69
+ f"RESULT 1 (Top Snippet): '{query}'\n"
70
+ f"CONTENT: {text}\n"
71
+ f"SOURCE: {url}"
72
  )
73
 
74
+ # If nothing useful is found:
75
+ return "XX record info: No results found."
76
 
77
+ except requests.exceptions.RequestException as e:
78
+ return f"Error during DuckDuckGo Search API Request: {e}"
79
  except Exception as e:
80
+ return f"Error processing DuckDuckGo results: {e}"