Sborole commited on
Commit
3c64d32
·
verified ·
1 Parent(s): ce0477b

Update tools/WebSearchTool.py

Browse files
Files changed (1) hide show
  1. tools/WebSearchTool.py +47 -29
tools/WebSearchTool.py CHANGED
@@ -6,7 +6,8 @@ class SearxngSearchTool(Tool):
6
  """
7
  A metasearch tool that queries multiple search engines (including Google, Bing, etc.)
8
  through a free, public Searxng instance. This is a robust, keyless alternative
9
- when specific search APIs are overloaded or require payment/keys.
 
10
  """
11
  name = "searxng_search"
12
  description = "Use a free, keyless metasearch engine (Searxng) to query the web for general knowledge and current information when other search tools are unavailable."
@@ -16,12 +17,18 @@ class SearxngSearchTool(Tool):
16
  }
17
  output_type = "string"
18
 
19
- # Note: Using a popular public instance. This may occasionally fail if the instance is down.
20
- DEFAULT_INSTANCE = "https://searx.be/search"
 
 
 
 
 
 
21
 
22
  def forward(self, query: str) -> str:
23
  """
24
- Executes a Searxng search query and formats the top results (up to 3).
25
 
26
  Args:
27
  query: The search term provided by the agent.
@@ -29,7 +36,6 @@ class SearxngSearchTool(Tool):
29
  Returns:
30
  A formatted string of search results, or an error message.
31
  """
32
- print(f"Executing Searxng Search for: '{query}'")
33
 
34
  params = {
35
  "q": query,
@@ -38,32 +44,44 @@ class SearxngSearchTool(Tool):
38
  "pageno": 1,
39
  }
40
 
41
- try:
42
- # Make the API request
43
- response = requests.get(self.DEFAULT_INSTANCE, params=params)
44
- response.raise_for_status()
45
- data = response.json()
46
 
47
- # Extract the search results
48
- items = data.get('results', [])
 
 
 
 
 
 
49
 
50
- if not items:
51
- # Return the specific failure message expected by the agent
52
- return "XX record info: No results found."
53
 
54
- search_results = []
55
- # Process the top 3 results
56
- for i, item in enumerate(items[:3]):
57
- search_results.append(
58
- f"RESULT {i+1}: '{item.get('title', 'N/A')}'\n"
59
- f"CONTENT: {item.get('content', 'No snippet available.')}\n"
60
- f"SOURCE: {item.get('url', 'N/A')}"
61
- )
62
 
63
- # Join the results with a clear separator
64
- return "\n\n---SEPARATOR---\n\n".join(search_results)
 
 
 
 
 
 
65
 
66
- except requests.exceptions.RequestException as e:
67
- return f"Error during Searxng API Request. The instance may be temporarily unavailable: {e}"
68
- except Exception as e:
69
- return f"Error processing Searxng results: {e}"
 
 
 
 
 
 
 
 
 
 
6
  """
7
  A metasearch tool that queries multiple search engines (including Google, Bing, etc.)
8
  through a free, public Searxng instance. This is a robust, keyless alternative
9
+ when specific search APIs are overloaded or require payment/keys. It attempts
10
+ multiple public instances for high resilience against temporary server outages or blocks.
11
  """
12
  name = "searxng_search"
13
  description = "Use a free, keyless metasearch engine (Searxng) to query the web for general knowledge and current information when other search tools are unavailable."
 
17
  }
18
  output_type = "string"
19
 
20
+ # List of popular, generally reliable public instances.
21
+ # The order attempts to prioritize faster or more stable instances first.
22
+ PUBLIC_INSTANCES = [
23
+ "https://searx.be/search", # The original instance
24
+ "https://searx.prvcy.eu/search",
25
+ "https://searx.tieko.co/search",
26
+ "https://searx.baczek.me/search",
27
+ ]
28
 
29
  def forward(self, query: str) -> str:
30
  """
31
+ Executes a Searxng search query, cycling through available instances until one succeeds.
32
 
33
  Args:
34
  query: The search term provided by the agent.
 
36
  Returns:
37
  A formatted string of search results, or an error message.
38
  """
 
39
 
40
  params = {
41
  "q": query,
 
44
  "pageno": 1,
45
  }
46
 
47
+ last_error = ""
 
 
 
 
48
 
49
+ # Loop through each public instance until a successful connection is made
50
+ for instance_url in self.PUBLIC_INSTANCES:
51
+ print(f"Executing Searxng Search for: '{query}' using instance: {instance_url}")
52
+ try:
53
+ # Make the API request
54
+ response = requests.get(instance_url, params=params, timeout=5) # Added timeout
55
+ response.raise_for_status()
56
+ data = response.json()
57
 
58
+ # Extract the search results
59
+ items = data.get('results', [])
 
60
 
61
+ if not items:
62
+ # If the instance worked but returned no results, continue to the next instance
63
+ print(f"Instance {instance_url} returned no results. Trying next instance.")
64
+ continue
 
 
 
 
65
 
66
+ search_results = []
67
+ # Process the top 3 results
68
+ for i, item in enumerate(items[:3]):
69
+ search_results.append(
70
+ f"RESULT {i+1}: '{item.get('title', 'N/A')}'\n"
71
+ f"CONTENT: {item.get('content', 'No snippet available.')}\n"
72
+ f"SOURCE: {item.get('url', 'N/A')}"
73
+ )
74
 
75
+ # If successful, return the results immediately
76
+ return "\n\n---SEPARATOR---\n\n".join(search_results)
77
+
78
+ except requests.exceptions.RequestException as e:
79
+ # Record the error and try the next instance
80
+ last_error = f"Instance {instance_url} failed: {e}"
81
+ print(last_error)
82
+ except Exception as e:
83
+ last_error = f"Error processing Searxng results for {instance_url}: {e}"
84
+ print(last_error)
85
+
86
+ # If the loop finishes without returning, all instances failed.
87
+ return f"XX record info: No results found. All Searxng instances failed. Last error: {last_error}"