Spaces:
Running
Running
| """ | |
| Rate limiting for the ResearchRAG API. | |
| Every endpoint here is expensive: a chat turn runs HyDE (2 LLM calls), BM25, a | |
| CPU cross-encoder rerank and a streamed completion; an upload runs the full PDF | |
| pipeline. Without limits a single client can exhaust CPU and burn the user's | |
| LLM quota. | |
| Limits are keyed by authenticated user when a bearer token is present, falling | |
| back to client IP for anonymous routes such as login. That way one user hitting | |
| their limit never throttles everyone behind the same NAT. | |
| """ | |
| from __future__ import annotations | |
| from fastapi import Request | |
| from slowapi import Limiter | |
| from slowapi.util import get_remote_address | |
| def _identify(request: Request) -> str: | |
| """Prefer the token subject; fall back to the peer address.""" | |
| auth = request.headers.get("Authorization", "") | |
| if auth.lower().startswith("bearer "): | |
| token = auth[7:].strip() | |
| if token: | |
| try: | |
| from api.security import decode_access_token | |
| return f"user:{decode_access_token(token)}" | |
| except Exception: | |
| # Invalid/expired token — fall through to IP so the limiter | |
| # never rejects a request for the wrong reason. | |
| pass | |
| return f"ip:{get_remote_address(request)}" | |
| # headers_enabled=False: slowapi's X-RateLimit-* injection requires every | |
| # decorated endpoint to accept a `response: Response` parameter, which would | |
| # leak a transport concern into each handler's signature. Enforcement (and the | |
| # 429 response) is unaffected — only the advisory headers are omitted. | |
| # default_limits is what makes the module docstring true. Without it slowapi | |
| # evaluates an EMPTY limit list for every undecorated route, so /api/ready, | |
| # /auth/logout, /auth/me and the whole documents read surface were unlimited — | |
| # each one touching Chroma or SQLite from a finite threadpool. | |
| limiter = Limiter( | |
| key_func=_identify, | |
| default_limits=["120/minute"], | |
| headers_enabled=False, | |
| ) | |