Browse Source

feat/enh: perplexity search support

Timothy Jaeryang Baek 2 weeks ago
parent
commit
7f411dd5cc

+ 64 - 0
backend/open_webui/retrieval/web/perplexity_search.py

@@ -0,0 +1,64 @@
+import logging
+from typing import Optional, Literal
+import requests
+
+from open_webui.retrieval.web.main import SearchResult, get_filtered_results
+from open_webui.env import SRC_LOG_LEVELS
+
+
+log = logging.getLogger(__name__)
+log.setLevel(SRC_LOG_LEVELS["RAG"])
+
+
+def search_perplexity_search(
+    api_key: str,
+    query: str,
+    count: int,
+    filter_list: Optional[list[str]] = None,
+) -> list[SearchResult]:
+    """Search using Perplexity API and return the results as a list of SearchResult objects.
+
+    Args:
+      api_key (str): A Perplexity API key
+      query (str): The query to search for
+      count (int): Maximum number of results to return
+      filter_list (Optional[list[str]]): List of domains to filter results
+
+    """
+
+    # Handle PersistentConfig object
+    if hasattr(api_key, "__str__"):
+        api_key = str(api_key)
+
+    try:
+        url = "https://api.perplexity.ai/search"
+
+        # Create payload for the API call
+        payload = {
+            "query": query,
+            "max_results": count,
+        }
+
+        headers = {
+            "Authorization": f"Bearer {api_key}",
+            "Content-Type": "application/json",
+        }
+
+        # Make the API request
+        response = requests.request("POST", url, json=payload, headers=headers)
+        # Parse the JSON response
+        json_response = response.json()
+
+        # Extract citations from the response
+        results = json_response.get("results", [])
+
+        return [
+            SearchResult(
+                link=result["url"], title=result["title"], snippet=result["snippet"]
+            )
+            for result in results
+        ]
+
+    except Exception as e:
+        log.error(f"Error searching with Perplexity Search API: {e}")
+        return []

+ 11 - 0
backend/open_webui/routers/retrieval.py

@@ -46,6 +46,7 @@ from open_webui.retrieval.loaders.youtube import YoutubeLoader
 from open_webui.retrieval.web.main import SearchResult
 from open_webui.retrieval.web.utils import get_web_loader
 from open_webui.retrieval.web.ollama import search_ollama_cloud
+from open_webui.retrieval.web.perplexity_search import search_perplexity_search
 from open_webui.retrieval.web.brave import search_brave
 from open_webui.retrieval.web.kagi import search_kagi
 from open_webui.retrieval.web.mojeek import search_mojeek
@@ -1801,6 +1802,16 @@ def search_web(request: Request, engine: str, query: str) -> list[SearchResult]:
             request.app.state.config.WEB_SEARCH_RESULT_COUNT,
             request.app.state.config.WEB_SEARCH_DOMAIN_FILTER_LIST,
         )
+    elif engine == "perplexity_search":
+        if request.app.state.config.PERPLEXITY_API_KEY:
+            return search_perplexity_search(
+                request.app.state.config.PERPLEXITY_API_KEY,
+                query,
+                request.app.state.config.WEB_SEARCH_RESULT_COUNT,
+                request.app.state.config.WEB_SEARCH_DOMAIN_FILTER_LIST,
+            )
+        else:
+            raise Exception("No PERPLEXITY_API_KEY found in environment variables")
     elif engine == "searxng":
         if request.app.state.config.SEARXNG_QUERY_URL:
             return search_searxng(

+ 18 - 0
src/lib/components/admin/Settings/WebSearch.svelte

@@ -14,6 +14,7 @@
 
 	let webSearchEngines = [
 		'ollama_cloud',
+		'perplexity_search',
 		'searxng',
 		'yacy',
 		'google_pse',
@@ -148,6 +149,23 @@
 									</div>
 								</div>
 							</div>
+						{:else if webConfig.WEB_SEARCH_ENGINE === 'perplexity_search'}
+							<div class="mb-2.5 flex w-full flex-col">
+								<div>
+									<div class=" self-center text-xs font-medium mb-1">
+										{$i18n.t('Perplexity API Key')}
+									</div>
+
+									<div class="flex w-full">
+										<div class="flex-1">
+											<SensitiveInput
+												placeholder={$i18n.t('Enter Perplexity API Key')}
+												bind:value={webConfig.PERPLEXITY_API_KEY}
+											/>
+										</div>
+									</div>
+								</div>
+							</div>
 						{:else if webConfig.WEB_SEARCH_ENGINE === 'searxng'}
 							<div class="mb-2.5 flex w-full flex-col">
 								<div>