Files
ThinkStorm/thinkstorm/services/searxng.py
T

80 lines
3.1 KiB
Python

"""
SearXNG Service Adapter
Discovers prior art, candidate sources, and web references via SearXNG JSON API.
"""
import json
import time
import urllib.parse
import urllib.request
import asyncio
from typing import List, Dict, Any, Optional
from .base import BaseServiceAdapter, ServiceHealth
class SearXNGAdapter(BaseServiceAdapter):
def __init__(self, endpoint: str = "https://sx.godno.de"):
super().__init__(service_id="searxng", endpoint=endpoint)
async def check_health(self) -> ServiceHealth:
start = time.time()
try:
url = f"{self.endpoint}/search?format=json&q=ping"
req = urllib.request.Request(
url,
headers={"User-Agent": "ThinkStorm-Orchestrator/0.1"}
)
# Run in executor to avoid blocking async event loop
loop = asyncio.get_running_loop()
def fetch():
with urllib.request.urlopen(req, timeout=8.0) as resp:
return resp.read()
raw = await loop.run_in_executor(None, fetch)
data = json.loads(raw.decode("utf-8"))
elapsed = int((time.time() - start) * 1000)
return ServiceHealth(
service_id=self.service_id,
healthy=True,
endpoint=self.endpoint,
message=f"SearXNG online (returned {len(data.get('results', []))} results)",
response_time_ms=elapsed
)
except Exception as e:
elapsed = int((time.time() - start) * 1000)
return ServiceHealth(
service_id=self.service_id,
healthy=False,
endpoint=self.endpoint,
message=f"SearXNG connection error: {str(e)}",
response_time_ms=elapsed
)
async def search(self, query: str, limit: int = 8) -> List[Dict[str, Any]]:
"""Executes a search query and returns structured results."""
encoded_query = urllib.parse.quote_plus(query)
url = f"{self.endpoint}/search?format=json&q={encoded_query}&language=en"
req = urllib.request.Request(
url,
headers={"User-Agent": "ThinkStorm-Orchestrator/0.1"}
)
loop = asyncio.get_running_loop()
def fetch():
with urllib.request.urlopen(req, timeout=3.0) as resp:
return resp.read()
try:
raw = await asyncio.wait_for(loop.run_in_executor(None, fetch), timeout=3.0)
data = json.loads(raw.decode("utf-8"))
raw_results = data.get("results", [])
results = []
for r in raw_results[:limit]:
results.append({
"title": r.get("title", "Untitled"),
"url": r.get("url", ""),
"content": r.get("content", ""),
"engine": r.get("engine", "searxng"),
"score": r.get("score", 0.0)
})
return results
except Exception as e:
print(f"[SearXNG] Search error for query '{query}': {e}")
return []