Whitepaper
Docs
Sign In
Function
Function
pipe
v0.1.1
Perplexity Sonar Deep Research for OpenRouter
Function ID
perplexity_sonar_deep_research_for_openrouter
Creator
@simplenerd
Downloads
98+
Handling OpenRouter Sonar Deep Research Citations
Get
README
No README available
Function Code
Show
""" title: OpenRouter Sonar Deep Research Citations Manifold Pipe author: simplenerd authors_url: https://github.com/open-webui funding_url: https://github.com/open-webui version: 0.1.1 license: MIT # Acknowledgments # This function is adapted from Perplexity Citations Manifold Pipe v0.2.1. # Special thanks to flynnoct, nikolaskn, justinh-rahb, and moblangeois # For more details, visit: https://openwebui.com/f/agrimmailio/perplexity_citations_manifold """ from pydantic import BaseModel, Field from typing import Union, Generator import requests from urllib.parse import urlparse import json import time from open_webui.utils.misc import pop_system_message class Pipe: class Valves(BaseModel): NAME_PREFIX: str = Field( default="Perplexity/", description="The prefix applied before the model names.", ) OPENROUTER_API_BASE_URL: str = Field( default="https://openrouter.ai/api/v1", description="The base URL for OpenRouter API endpoints.", ) OPENROUTER_API_KEY: str = Field( default="", description="Required API key to access OpenRouter services.", ) def __init__(self): self.type = "manifold" self.valves = self.Valves() def pipes(self): return [ { "id": "sonar-deep-research", "name": f"{self.valves.NAME_PREFIX}Sonar Deep Research", }, ] def extract_domain(self, url: str) -> str: """Extract domain from URL.""" try: return urlparse(url).netloc except Exception: return url def format_citations(self, citations: list) -> str: """Format citations in markdown.""" if not citations: return "" citations_list = [ f"[\\[{i+1}\\] {self.extract_domain(url)}]({url})" for i, url in enumerate(citations) ] return "\n\n**References:**\n" + "\n".join(citations_list) def stream_response( self, url: str, headers: dict, payload: dict ) -> Generator[str, None, None]: try: with requests.post( url, headers=headers, json=payload, stream=True, timeout=(3.05, 60) ) as response: if response.status_code != 200: raise Exception( f"HTTP Error {response.status_code}: {response.text}" ) citations = None # Iterate over each streamed line for line in response.iter_lines(): if line: line = line.decode("utf-8") # Lines typically start with "data: " if line.startswith("data: "): try: data = json.loads(line[6:]) # Capture citations on first occurrence if citations is None and "citations" in data: citations = data["citations"] # Yield incremental answer content if available if "choices" in data and data["choices"]: delta = data["choices"][0].get("delta", {}) delta_content = delta.get("content", "") if delta_content: yield delta_content time.sleep(0.01) except json.JSONDecodeError: print(f"Failed to parse JSON: {line}") except KeyError as e: print(f"Unexpected data structure: {e}") # At the end of the stream, if citations were received, yield the formatted references if citations: yield self.format_citations(citations) except requests.exceptions.RequestException as e: print(f"Request failed: {e}") yield f"Error: Request failed: {e}" except Exception as e: print(f"General error in stream_response method: {e}") yield f"Error: {e}" def pipe( self, body: dict, __user__: dict ) -> Union[str, Generator[str, None, None]]: print(f"pipe:{__name__}") if not self.valves.OPENROUTER_API_KEY: raise Exception("OPENROUTER_API_KEY not provided in the valves.") headers = { "Authorization": f"Bearer {self.valves.OPENROUTER_API_KEY}", "Content-Type": "application/json", "accept": "application/json", } system_message, messages = pop_system_message(body.get("messages", [])) system_prompt = "You are a helpful assistant." if system_message is not None: system_prompt = system_message["content"] payload = { "model": "perplexity/sonar-deep-research", "messages": [{"role": "system", "content": system_prompt}, *messages], "stream": True, "return_citations": True, "return_images": True, } print(payload) url = f"{self.valves.OPENROUTER_API_BASE_URL}/chat/completions" return self.stream_response(url, headers, payload)