Coverage for open_webui/retrieval/web/searchapi.py: 28%
21 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 05:07 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 05:07 +0000
1import logging
2from typing import Optional
3from urllib.parse import urlencode
5import requests
6from open_webui.retrieval.web.main import SearchResult, get_filtered_results
8log = logging.getLogger(__name__)
11def search_searchapi(
12 api_key: str,
13 engine: str,
14 query: str,
15 count: int,
16 filter_list: Optional[list[str]] = None,
17) -> list[SearchResult]:
18 """Search using searchapi.io's API and return the results as a list of SearchResult objects.
20 Args:
21 api_key (str): A searchapi.io API key
22 query (str): The query to search for
23 """
24 url = 'https://www.searchapi.io/api/v1/search'
26 engine = engine or 'google'
28 payload = {'engine': engine, 'q': query, 'api_key': api_key}
29 if engine.startswith('google'):
30 payload['link'] = 'resolved'
32 url = f'{url}?{urlencode(payload)}'
33 response = requests.request('GET', url, timeout=30)
34 response.raise_for_status()
36 json_response = response.json()
37 log.debug('results from searchapi search: %s', json_response)
39 # top_stories entries carry no position, so the merged list keeps API order
40 results = [
41 *json_response.get('organic_results', []),
42 *json_response.get('top_stories', []),
43 ]
44 if filter_list:
45 results = get_filtered_results(results, filter_list)
46 return [
47 SearchResult(
48 link=result.get('link', ''),
49 title=result.get('title'),
50 snippet=result.get('snippet'),
51 )
52 for result in results[:count]
53 ]