diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index 75b4b6d284..bb9a762f38 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1271,6 +1271,8 @@ SOUGOU_API_SK = os.getenv('SOUGOU_API_SK', '') TAVILY_API_KEY = os.getenv('TAVILY_API_KEY', '') +OLOSTEP_API_KEY = os.getenv('OLOSTEP_API_KEY', '') + TAVILY_EXTRACT_DEPTH = os.getenv('TAVILY_EXTRACT_DEPTH', 'basic') PLAYWRIGHT_WS_URL = os.getenv('PLAYWRIGHT_WS_URL', '') @@ -2989,6 +2991,7 @@ DEFAULT_CONFIG = { 'web.search.sougou_api_sid': SOUGOU_API_SID, 'web.search.sougou_api_sk': SOUGOU_API_SK, 'web.search.tavily_api_key': TAVILY_API_KEY, + 'web.search.olostep_api_key': OLOSTEP_API_KEY, 'web.search.tavily_extract_depth': TAVILY_EXTRACT_DEPTH, 'web.loader.playwright_ws_url': PLAYWRIGHT_WS_URL, 'web.loader.playwright_timeout': PLAYWRIGHT_TIMEOUT, diff --git a/backend/open_webui/retrieval/web/olostep.py b/backend/open_webui/retrieval/web/olostep.py new file mode 100644 index 0000000000..338b03d650 --- /dev/null +++ b/backend/open_webui/retrieval/web/olostep.py @@ -0,0 +1,59 @@ +from __future__ import annotations + +import logging + +import requests +from open_webui.retrieval.web.main import SearchResult, get_filtered_results + +log = logging.getLogger(__name__) + +OLOSTEP_SEARCH_URL = "https://api.olostep.com/v1/searches" + + +def search_olostep( + api_key: str, + query: str, + count: int, + filter_list: list[str] | None = None, +) -> list[SearchResult]: + """Search using Olostep's Search API and return the results as a list of + SearchResult objects. + + Args: + api_key (str): An Olostep API key + query (str): The query to search for + count (int): The maximum number of results to return + filter_list (list[str] | None): Optional domain filter list + + Returns: + A list of SearchResult objects. + """ + headers = { + "Content-Type": "application/json", + "Authorization": f"Bearer {api_key}", + } + data = {"query": query, "limit": count} + + response = requests.post( + OLOSTEP_SEARCH_URL, + headers=headers, + json=data, + timeout=count * 3 + 10, + ) + response.raise_for_status() + + json_response = response.json() + + results = (json_response.get("result") or {}).get("links") or [] + if filter_list: + results = get_filtered_results(results, filter_list) + + return [ + SearchResult( + link=result["url"], + title=result.get("title", ""), + snippet=result.get("description"), + ) + for result in results[:count] + if result.get("url") + ] diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index 9023c8b634..e8db4b8848 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -115,6 +115,7 @@ from open_webui.retrieval.web.serply import search_serply from open_webui.retrieval.web.serpstack import search_serpstack from open_webui.retrieval.web.sougou import search_sougou from open_webui.retrieval.web.tavily import search_tavily +from open_webui.retrieval.web.olostep import search_olostep from open_webui.retrieval.web.utils import get_web_loader from open_webui.retrieval.web.yacy import search_yacy from open_webui.retrieval.web.yandex import search_yandex @@ -384,6 +385,7 @@ RETRIEVAL_CONFIG_KEYS = { 'SOUGOU_API_SID': 'web.search.sougou_api_sid', 'SOUGOU_API_SK': 'web.search.sougou_api_sk', 'TAVILY_API_KEY': 'web.search.tavily_api_key', + 'OLOSTEP_API_KEY': 'web.search.olostep_api_key', 'TAVILY_EXTRACT_DEPTH': 'web.search.tavily_extract_depth', 'TEXT_SPLITTER': 'rag.text_splitter', 'TIKA_SERVER_URL': 'rag.tika_server_url', @@ -2628,6 +2630,17 @@ async def search_web(request: Request, engine: str, query: str, user=None) -> li ) else: raise Exception('No TAVILY_API_KEY found in environment variables') + elif engine == "olostep": + if config.OLOSTEP_API_KEY: + return await asyncio.to_thread( + search_olostep, + config.OLOSTEP_API_KEY, + query, + config.WEB_SEARCH_RESULT_COUNT, + config.WEB_SEARCH_DOMAIN_FILTER_LIST, + ) + else: + raise Exception("No OLOSTEP_API_KEY found in environment variables") elif engine == 'exa': if config.EXA_API_KEY: return await asyncio.to_thread( diff --git a/src/lib/components/admin/Settings/WebSearch.svelte b/src/lib/components/admin/Settings/WebSearch.svelte index e257620e58..890da2f03d 100644 --- a/src/lib/components/admin/Settings/WebSearch.svelte +++ b/src/lib/components/admin/Settings/WebSearch.svelte @@ -47,7 +47,8 @@ 'yandex', 'youcom', 'linkup', - 'openserp' + 'openserp', + 'olostep' ]; let webLoaderEngines = ['playwright', 'firecrawl', 'tavily', 'microsoft_web_iq', 'external']; @@ -572,6 +573,20 @@ /> + {:else if webConfig.WEB_SEARCH_ENGINE === 'olostep'} +
+
+
+ {$i18n.t('Olostep API Key')} +
+ + +
+
{:else if webConfig.WEB_SEARCH_ENGINE === 'searchapi'}