Coverage for open_webui/retrieval/web/google_pse.py: 16%
29 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
1from __future__ import annotations
3import logging
5from open_webui.retrieval.web.main import SearchResult, get_filtered_results
6from open_webui.utils.session_pool import get_session
8log = logging.getLogger(__name__)
11async def search_google_pse(
12 api_key: str,
13 search_engine_id: str,
14 query: str,
15 count: int,
16 filter_list: list[str] | None = None,
17 referer: str | None = None,
18) -> list[SearchResult]:
19 """Query Google Programmable Search Engine with automatic pagination.
21 The PSE API returns at most 10 results per request, so this function
22 issues multiple requests when ``count > 10``.
23 """
24 url = 'https://www.googleapis.com/customsearch/v1'
25 headers: dict[str, str] = {'Content-Type': 'application/json'}
26 if referer:
27 headers['Referer'] = referer
29 all_items: list[dict] = []
30 start_index = 1 # PSE uses 1-based pagination
32 session = await get_session()
33 remaining = count
34 while remaining > 0:
35 page_size = min(remaining, 10)
36 params = {
37 'cx': search_engine_id,
38 'q': query,
39 'key': api_key,
40 'num': str(page_size),
41 'start': str(start_index),
42 }
44 async with session.get(url, headers=headers, params=params) as response:
45 response.raise_for_status()
46 payload = await response.json()
48 items = payload.get('items', [])
49 if not items:
50 break
52 all_items.extend(items)
53 remaining -= len(items)
54 start_index += 10
56 if filter_list:
57 all_items = get_filtered_results(all_items, filter_list)
59 return [
60 SearchResult(
61 link=item.get('link', ''),
62 title=item.get('title'),
63 snippet=item.get('snippet'),
64 )
65 for item in all_items
66 ]