From 614cb5642090b336899e3d2d8182d3893decb2e1 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 5 Jan 2026 00:05:56 +0100 Subject: [PATCH] feat: Add configurable DDGS backend selection with UI support (#20366) * init * Update WebSearch.svelte * reorder --- backend/open_webui/config.py | 6 ++++ backend/open_webui/main.py | 2 ++ .../open_webui/retrieval/web/duckduckgo.py | 4 ++- backend/open_webui/routers/retrieval.py | 4 +++ .../admin/Settings/WebSearch.svelte | 30 +++++++++++++++++++ 5 files changed, 45 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index a18b0612f..b56ad0552 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -3193,6 +3193,12 @@ SERPLY_API_KEY = PersistentConfig( os.getenv("SERPLY_API_KEY", ""), ) +DDGS_BACKEND = PersistentConfig( + "DDGS_BACKEND", + "rag.web.search.ddgs_backend", + os.getenv("DDGS_BACKEND", "auto"), +) + JINA_API_KEY = PersistentConfig( "JINA_API_KEY", "rag.web.search.jina_api_key", diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 37a6589fe..6a1d79e72 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -312,6 +312,7 @@ from open_webui.config import ( YACY_PASSWORD, SERPER_API_KEY, SERPLY_API_KEY, + DDGS_BACKEND, SERPSTACK_API_KEY, SERPSTACK_HTTPS, TAVILY_API_KEY, @@ -969,6 +970,7 @@ app.state.config.SERPSTACK_API_KEY = SERPSTACK_API_KEY app.state.config.SERPSTACK_HTTPS = SERPSTACK_HTTPS app.state.config.SERPER_API_KEY = SERPER_API_KEY app.state.config.SERPLY_API_KEY = SERPLY_API_KEY +app.state.config.DDGS_BACKEND = DDGS_BACKEND app.state.config.TAVILY_API_KEY = TAVILY_API_KEY app.state.config.SEARCHAPI_API_KEY = SEARCHAPI_API_KEY app.state.config.SEARCHAPI_ENGINE = SEARCHAPI_ENGINE diff --git a/backend/open_webui/retrieval/web/duckduckgo.py b/backend/open_webui/retrieval/web/duckduckgo.py index 0303b4e30..7528418cd 100644 --- a/backend/open_webui/retrieval/web/duckduckgo.py +++ b/backend/open_webui/retrieval/web/duckduckgo.py @@ -13,12 +13,14 @@ def search_duckduckgo( count: int, filter_list: Optional[list[str]] = None, concurrent_requests: Optional[int] = None, + backend: Optional[str] = "auto", ) -> list[SearchResult]: """ Search using DuckDuckGo's Search API and return the results as a list of SearchResult objects. Args: query (str): The query to search for count (int): The number of results to return + backend (str): The search backend to use (auto, duckduckgo, google, brave, etc.) Returns: list[SearchResult]: A list of search results @@ -32,7 +34,7 @@ def search_duckduckgo( # Use the ddgs.text() method to perform the search try: search_results = ddgs.text( - query, safesearch="moderate", max_results=count, backend="lite" + query, safesearch="moderate", max_results=count, backend=backend ) except RatelimitException as e: log.error(f"RatelimitException: {e}") diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index cb018471e..2d17e7553 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -543,6 +543,7 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)): "SERPSTACK_HTTPS": request.app.state.config.SERPSTACK_HTTPS, "SERPER_API_KEY": request.app.state.config.SERPER_API_KEY, "SERPLY_API_KEY": request.app.state.config.SERPLY_API_KEY, + "DDGS_BACKEND": request.app.state.config.DDGS_BACKEND, "TAVILY_API_KEY": request.app.state.config.TAVILY_API_KEY, "SEARCHAPI_API_KEY": request.app.state.config.SEARCHAPI_API_KEY, "SEARCHAPI_ENGINE": request.app.state.config.SEARCHAPI_ENGINE, @@ -605,6 +606,7 @@ class WebConfig(BaseModel): SERPSTACK_HTTPS: Optional[bool] = None SERPER_API_KEY: Optional[str] = None SERPLY_API_KEY: Optional[str] = None + DDGS_BACKEND: Optional[str] = None TAVILY_API_KEY: Optional[str] = None SEARCHAPI_API_KEY: Optional[str] = None SEARCHAPI_ENGINE: Optional[str] = None @@ -1097,6 +1099,7 @@ async def update_rag_config( request.app.state.config.SERPSTACK_HTTPS = form_data.web.SERPSTACK_HTTPS request.app.state.config.SERPER_API_KEY = form_data.web.SERPER_API_KEY request.app.state.config.SERPLY_API_KEY = form_data.web.SERPLY_API_KEY + request.app.state.config.DDGS_BACKEND = form_data.web.DDGS_BACKEND request.app.state.config.TAVILY_API_KEY = form_data.web.TAVILY_API_KEY request.app.state.config.SEARCHAPI_API_KEY = form_data.web.SEARCHAPI_API_KEY request.app.state.config.SEARCHAPI_ENGINE = form_data.web.SEARCHAPI_ENGINE @@ -2071,6 +2074,7 @@ def search_web( request.app.state.config.WEB_SEARCH_RESULT_COUNT, request.app.state.config.WEB_SEARCH_DOMAIN_FILTER_LIST, concurrent_requests=request.app.state.config.WEB_SEARCH_CONCURRENT_REQUESTS, + backend=request.app.state.config.DDGS_BACKEND, ) elif engine == "tavily": if request.app.state.config.TAVILY_API_KEY: diff --git a/src/lib/components/admin/Settings/WebSearch.svelte b/src/lib/components/admin/Settings/WebSearch.svelte index 4cbd58115..68a343e5f 100644 --- a/src/lib/components/admin/Settings/WebSearch.svelte +++ b/src/lib/components/admin/Settings/WebSearch.svelte @@ -697,7 +697,37 @@ {/if} + + {#if webConfig.WEB_SEARCH_ENGINE === 'duckduckgo'} +