Files
zeekay 74110d03f8 chat-rag-api: add Qdrant (hanzoai/vector) backend
Extracted from the deployed chat-rag-api:0.7.8-hanzo image; adds a Qdrant
vector store targeting hanzoai/vector as a drop-in for pgvector.

- app/services/vector_store/qdrant_vector.py: QdrantVector(QdrantVectorStore)
  with the id helpers (get_all_ids/get_filtered_ids/get_documents_by_ids),
  delete-by-file_id, and the route's Mongo-style file_id filter translated to
  native Qdrant filters. file_id stored in payload metadata (unique point ids).
- factory.get_vector_store: mode='qdrant' (lazy import; pg/atlas deploys
  unaffected).
- config: VectorDBType.QDRANT + QDRANT_URL/QDRANT_API_KEY/QDRANT_DISTANCE/
  EMBEDDINGS_DIM(1536) + construction branch.
- health: qdrant_health_check (client.get_collections()).
- requirements: langchain-qdrant==0.2.0, qdrant-client==1.12.1.

Verified: pytest tests/test_qdrant_vector.py (4 tests) against in-memory
Qdrant; factory builds QdrantVector with all route methods present.
2026-06-23 21:47:45 -07:00

57 lines
1.9 KiB
Python

# app/middleware.py
import os
import jwt
from jwt import PyJWTError
from fastapi import Request
from datetime import datetime, timezone
from fastapi.responses import JSONResponse
from app.config import logger
async def security_middleware(request: Request, call_next):
async def next_middleware_call():
return await call_next(request)
if request.url.path in {"/docs", "/openapi.json", "/health"}:
return await next_middleware_call()
jwt_secret = os.getenv("JWT_SECRET")
if not jwt_secret:
logger.warn("JWT_SECRET not found in environment variables")
return await next_middleware_call()
authorization = request.headers.get("Authorization")
if not authorization or not authorization.startswith("Bearer "):
logger.info(
f"Unauthorized request with missing or invalid Authorization header to: {request.url.path}"
)
return JSONResponse(
status_code=401,
content={"detail": "Missing or invalid Authorization header"},
)
token = authorization.split(" ")[1]
try:
payload = jwt.decode(token, jwt_secret, algorithms=["HS256"])
exp_timestamp = payload.get("exp")
if exp_timestamp and datetime.now(tz=timezone.utc) > datetime.fromtimestamp(
exp_timestamp, tz=timezone.utc
):
logger.info(
f"Unauthorized request with expired token to: {request.url.path}"
)
return JSONResponse(
status_code=401, content={"detail": "Token has expired"}
)
request.state.user = payload
logger.debug(f"{request.url.path} - {payload}")
except PyJWTError as e:
logger.info(
f"Unauthorized request with invalid token to: {request.url.path}, reason: {str(e)}"
)
return JSONResponse(
status_code=401, content={"detail": f"Invalid token: {str(e)}"}
)
return await next_middleware_call()