Add Qdrant vectorstore service, gateway API-key middleware, docs and .gitignore

This commit is contained in:
2026-03-21 09:16:11 +01:00
parent 8da669c0e1
commit 3b300ab3b4
3 changed files with 19 additions and 2 deletions

View File

@@ -21,7 +21,7 @@ docker compose up -d --build
## Health ## Health
```bash ```bash
curl https://vision.klevze.net/health curl -H "X-API-Key: <your-api-key>" https://vision.klevze.net/health
``` ```
## Universal analyze (ALL) ## Universal analyze (ALL)

View File

@@ -10,6 +10,7 @@ services:
- BLIP_URL=http://blip:8000 - BLIP_URL=http://blip:8000
- YOLO_URL=http://yolo:8000 - YOLO_URL=http://yolo:8000
- QDRANT_SVC_URL=http://qdrant-svc:8000 - QDRANT_SVC_URL=http://qdrant-svc:8000
- API_KEY=please-change-me
- VISION_TIMEOUT=300 - VISION_TIMEOUT=300
- MAX_IMAGE_BYTES=52428800 - MAX_IMAGE_BYTES=52428800
depends_on: depends_on:

View File

@@ -5,7 +5,9 @@ import asyncio
from typing import Any, Dict, Optional from typing import Any, Dict, Optional
import httpx import httpx
from fastapi import FastAPI, HTTPException, UploadFile, File, Form from fastapi import FastAPI, HTTPException, UploadFile, File, Form, Request
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
CLIP_URL = os.getenv("CLIP_URL", "http://clip:8000") CLIP_URL = os.getenv("CLIP_URL", "http://clip:8000")
@@ -14,7 +16,21 @@ YOLO_URL = os.getenv("YOLO_URL", "http://yolo:8000")
QDRANT_SVC_URL = os.getenv("QDRANT_SVC_URL", "http://qdrant-svc:8000") QDRANT_SVC_URL = os.getenv("QDRANT_SVC_URL", "http://qdrant-svc:8000")
VISION_TIMEOUT = float(os.getenv("VISION_TIMEOUT", "20")) VISION_TIMEOUT = float(os.getenv("VISION_TIMEOUT", "20"))
# API key (set via env var `API_KEY`). If not set, gateway will reject requests.
API_KEY = os.getenv("API_KEY")
class APIKeyMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
# allow health and docs endpoints without API key
if request.url.path in ("/health", "/openapi.json", "/docs", "/redoc"):
return await call_next(request)
key = request.headers.get("x-api-key") or request.headers.get("X-API-Key")
if not API_KEY or key != API_KEY:
return JSONResponse(status_code=401, content={"detail": "Unauthorized"})
return await call_next(request)
app = FastAPI(title="Skinbase Vision Gateway", version="1.0.0") app = FastAPI(title="Skinbase Vision Gateway", version="1.0.0")
app.add_middleware(APIKeyMiddleware)
class ClipRequest(BaseModel): class ClipRequest(BaseModel):