mirror of
https://github.com/andrewyng/openworker.git
synced 2026-09-04 16:42:35 +00:00
OpenWorker: initial import
Imported from andrewyng/aisuite@1b4bbf303e (contents of its platform/ directory, hoisted to the repo root). Development history prior to this commit lives in that repository. Co-authored-by: Devika <devikaverma11@gmail.com>
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
"""Web search providers — a keyless default + pluggable third-party services.
|
||||
|
||||
`duckduckgo` works with no API key (our "starting version of our own"). `tavily` and `brave`
|
||||
give better results but need a key (configured via the SecretStore / env). All providers
|
||||
return a uniform `list[SearchResult]`; the heavy client libs are lazy-imported.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
||||
_TIMEOUT = 20.0
|
||||
|
||||
|
||||
@dataclass
|
||||
class SearchResult:
|
||||
title: str
|
||||
url: str
|
||||
snippet: str
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {"title": self.title, "url": self.url, "snippet": self.snippet}
|
||||
|
||||
|
||||
class WebSearchProvider(ABC):
|
||||
name: str = "base"
|
||||
requires_key: bool = False
|
||||
|
||||
@abstractmethod
|
||||
def search(self, query: str, max_results: int = 5) -> list[SearchResult]: ...
|
||||
|
||||
|
||||
class DuckDuckGoProvider(WebSearchProvider):
|
||||
"""Keyless default via the `ddgs` library."""
|
||||
|
||||
name = "duckduckgo"
|
||||
requires_key = False
|
||||
|
||||
def search(self, query: str, max_results: int = 5) -> list[SearchResult]:
|
||||
from ddgs import DDGS
|
||||
|
||||
rows = DDGS().text(query, max_results=max_results) or []
|
||||
return [
|
||||
SearchResult(
|
||||
title=r.get("title", ""),
|
||||
url=r.get("href", "") or r.get("url", ""),
|
||||
snippet=r.get("body", "") or r.get("snippet", ""),
|
||||
)
|
||||
for r in rows
|
||||
]
|
||||
|
||||
|
||||
class TavilyProvider(WebSearchProvider):
|
||||
name = "tavily"
|
||||
requires_key = True
|
||||
|
||||
def __init__(self, api_key: str) -> None:
|
||||
self.api_key = api_key
|
||||
|
||||
def search(self, query: str, max_results: int = 5) -> list[SearchResult]:
|
||||
import httpx
|
||||
|
||||
resp = httpx.post(
|
||||
"https://api.tavily.com/search",
|
||||
json={"api_key": self.api_key, "query": query, "max_results": max_results},
|
||||
timeout=_TIMEOUT,
|
||||
)
|
||||
data = resp.json()
|
||||
return [
|
||||
SearchResult(
|
||||
title=r.get("title", ""),
|
||||
url=r.get("url", ""),
|
||||
snippet=r.get("content", ""),
|
||||
)
|
||||
for r in data.get("results", [])
|
||||
]
|
||||
|
||||
|
||||
class BraveProvider(WebSearchProvider):
|
||||
name = "brave"
|
||||
requires_key = True
|
||||
|
||||
def __init__(self, api_key: str) -> None:
|
||||
self.api_key = api_key
|
||||
|
||||
def search(self, query: str, max_results: int = 5) -> list[SearchResult]:
|
||||
import httpx
|
||||
|
||||
resp = httpx.get(
|
||||
"https://api.search.brave.com/res/v1/web/search",
|
||||
headers={
|
||||
"X-Subscription-Token": self.api_key,
|
||||
"Accept": "application/json",
|
||||
},
|
||||
params={"q": query, "count": max_results},
|
||||
timeout=_TIMEOUT,
|
||||
)
|
||||
data = resp.json()
|
||||
return [
|
||||
SearchResult(
|
||||
title=r.get("title", ""),
|
||||
url=r.get("url", ""),
|
||||
snippet=r.get("description", ""),
|
||||
)
|
||||
for r in (data.get("web", {}) or {}).get("results", [])
|
||||
]
|
||||
|
||||
|
||||
_PROVIDERS = {
|
||||
"duckduckgo": DuckDuckGoProvider,
|
||||
"tavily": TavilyProvider,
|
||||
"brave": BraveProvider,
|
||||
}
|
||||
|
||||
|
||||
def build_provider(name: str, api_key: Optional[str] = None) -> WebSearchProvider:
|
||||
cls = _PROVIDERS.get(name, DuckDuckGoProvider)
|
||||
if cls.requires_key:
|
||||
if not api_key:
|
||||
raise ValueError(f"web search provider '{name}' needs an API key")
|
||||
return cls(api_key) # type: ignore[call-arg]
|
||||
return cls() # type: ignore[call-arg]
|
||||
|
||||
|
||||
def provider_names() -> list[str]:
|
||||
return list(_PROVIDERS)
|
||||
Reference in New Issue
Block a user