SurfSense/surfsense_backend/app/capabilities/web/discover/executor.py

42 lines
1.7 KiB
Python

"""``web.discover`` executor: route a query to the first configured search provider."""
from __future__ import annotations
from collections.abc import Sequence
from app.capabilities.core import Executor
from app.capabilities.web.discover.providers.base import DiscoverProvider
from app.capabilities.web.discover.schemas import DiscoverInput, DiscoverOutput
class NoDiscoverProviderError(RuntimeError):
"""Raised when no search provider is configured (no platform key/host set)."""
def build_discover_executor(
providers: Sequence[DiscoverProvider] | None = None,
) -> Executor:
"""Bind the executor to a provider set (defaults to the real env-keyed providers)."""
registry = list(providers) if providers is not None else _default_providers()
async def execute(payload: DiscoverInput) -> DiscoverOutput:
provider = next((p for p in registry if p.is_available()), None)
if provider is None:
raise NoDiscoverProviderError(
"web.discover has no configured search provider "
"(set a SearXNG host or a Linkup/Baidu key)."
)
hits = await provider.search(payload.query, payload.top_k)
# Enforce the verb's documented cap here, once, for every provider:
# some backends (e.g. SearXNG) treat `top_k` as a hint and over-return.
return DiscoverOutput(hits=hits[: payload.top_k])
return execute
def _default_providers() -> list[DiscoverProvider]:
from app.capabilities.web.discover.providers.baidu import BaiduProvider
from app.capabilities.web.discover.providers.linkup import LinkupProvider
from app.capabilities.web.discover.providers.searxng import SearxngProvider
return [SearxngProvider(), LinkupProvider(), BaiduProvider()]