| import httpx | |
| import asyncio | |
| from typing import List, Dict, Any | |
| DEFAULT_TIMEOUT = 25.0 | |
| async def fetch_json( | |
| url: str, | |
| params: dict = None, | |
| headers: dict = None, | |
| timeout: float = DEFAULT_TIMEOUT, | |
| ) -> dict: | |
| """Fetch JSON from URL with timeout.""" | |
| async with httpx.AsyncClient(timeout=timeout, follow_redirects=True) as client: | |
| try: | |
| r = await client.get(url, params=params, headers=headers or {}) | |
| r.raise_for_status() | |
| return r.json() | |
| except Exception as e: | |
| return {"error": str(e)} | |
| async def fetch_text( | |
| url: str, | |
| params: dict = None, | |
| headers: dict = None, | |
| timeout: float = DEFAULT_TIMEOUT, | |
| ) -> str: | |
| """Fetch raw text/XML from URL with timeout.""" | |
| async with httpx.AsyncClient(timeout=timeout, follow_redirects=True) as client: | |
| try: | |
| r = await client.get(url, params=params, headers=headers or {}) | |
| r.raise_for_status() | |
| return r.text | |
| except Exception as e: | |
| return "" | |
| def normalize_result( | |
| title: str, | |
| authors: list, | |
| year: int, | |
| abstract: str, | |
| doi: str, | |
| pdf_url: str, | |
| source: str, | |
| university: str = None, | |
| citation_count: int = None, | |
| ) -> dict: | |
| """Normalize a search result to common format.""" | |
| return { | |
| "title": title or "N/A", | |
| "authors": authors or [], | |
| "year": year, | |
| "abstract": abstract or "", | |
| "doi": doi or "", | |
| "pdfUrl": pdf_url or "", | |
| "source": source, | |
| "university": university or "", | |
| "citationCount": citation_count, | |
| } | |