Source code for evidence_fetcher.api
"""Public Python API."""
from __future__ import annotations
from evidence_fetcher._http import SearchHttpClient, UrlLibSearchHttpClient
from evidence_fetcher._providers.brave import BraveSearchProvider
from evidence_fetcher.models import Evidence, _canonical_url_key
from evidence_fetcher.ranking import EvidenceRanker, TfidfEvidenceRanker
[docs]
def fetch_evidence(
query: str,
*,
limit: int = 10,
http_client: SearchHttpClient | None = None,
ranker: EvidenceRanker | None = None,
) -> list[Evidence]:
"""Fetch normalized, deduplicated evidence for a search query.
The first vertical slice uses Brave Search. Provider-specific request and
response handling remain internal; callers receive only normalized
:class:`Evidence` values.
"""
normalized_query = query.strip()
if not normalized_query:
raise ValueError("query must not be empty")
if limit < 1:
raise ValueError("limit must be at least 1")
client = http_client if http_client is not None else UrlLibSearchHttpClient()
provider = BraveSearchProvider(client)
candidates = _deduplicate(
provider.search(normalized_query, limit=limit),
limit=limit,
)
evidence_ranker = ranker if ranker is not None else TfidfEvidenceRanker()
return evidence_ranker.rank(normalized_query, candidates)[:limit]
def _deduplicate(results: list[Evidence], *, limit: int) -> list[Evidence]:
seen_urls: set[str] = set()
deduplicated: list[Evidence] = []
for result in results:
key = _canonical_url_key(result.url)
if key in seen_urls:
continue
seen_urls.add(key)
deduplicated.append(result)
if len(deduplicated) >= limit:
break
return deduplicated