FastAPI + Celery + Next.js + Postgres/Redis app with company monitoring, source collection, LLM-based change analysis, enrichment, and account security (Turnstile, escalating lockout, email verification).
43 lines
1.4 KiB
Python
43 lines
1.4 KiB
Python
"""Brave Search API provider. A fixed, trusted, first-party integration
|
|
endpoint (like Twilio/Resend) - calls httpx directly rather than through
|
|
`safe_fetch`, which exists specifically to guard arbitrary/user-supplied
|
|
collector targets, not our own known-safe API integrations."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import httpx
|
|
|
|
from app.core.config import Settings
|
|
from app.search.base import SearchResult
|
|
|
|
_API_URL = "https://api.search.brave.com/res/v1/web/search"
|
|
|
|
|
|
class BraveSearchProvider:
|
|
provider_name = "brave"
|
|
|
|
def __init__(self, settings: Settings) -> None:
|
|
self._settings = settings
|
|
|
|
async def search(self, query: str, *, count: int = 5) -> list[SearchResult]:
|
|
async with httpx.AsyncClient(timeout=15) as client:
|
|
response = await client.get(
|
|
_API_URL,
|
|
params={"q": query, "count": count},
|
|
headers={
|
|
"Accept": "application/json",
|
|
"X-Subscription-Token": self._settings.brave_search_api_key,
|
|
},
|
|
)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
results = data.get("web", {}).get("results", [])
|
|
return [
|
|
SearchResult(
|
|
title=r.get("title", ""),
|
|
url=r.get("url", ""),
|
|
snippet=r.get("description", ""),
|
|
)
|
|
for r in results[:count]
|
|
]
|