- Add maturity/ service (FastAPI + Falconsai/nsfw_image_detection ViT classifier)
- /analyze (URL) and /analyze/file (multipart upload) endpoints
- Normalized response: maturity_label, confidence, score, labels,
action_hint (safe/review/flag_high), advisory, threshold_used,
analysis_time_ms, model, source
- Configurable thresholds via MATURITY_THRESHOLD_MATURE / MATURITY_THRESHOLD_REVIEW
- Reuses common/image_io for URL validation and file-size enforcement
- Explicit 502/503 errors on failure — no silent safe fallback
- Per-request structured logging (score, label, threshold path, elapsed ms)
- Update gateway/main.py
- MATURITY_URL + MATURITY_ENABLED env vars
- POST /analyze/maturity and POST /analyze/maturity/file endpoints
- /health includes maturity service status
- _assert_maturity_enabled() guard for clean 503 when disabled
- All existing endpoints untouched (additive change)
- Update docker-compose.yml
- Add maturity service with healthcheck (start_period: 90s)
- Gateway environment: MATURITY_URL, MATURITY_ENABLED
- Gateway depends_on: maturity (service_healthy)
- Update README.md and USAGE.md
- Document maturity service, env vars, curl examples,
full response schema table, action_hint logic, failure guidance
154 lines
4.3 KiB
YAML
154 lines
4.3 KiB
YAML
services:
|
|
gateway:
|
|
build:
|
|
context: .
|
|
dockerfile: gateway/Dockerfile
|
|
ports:
|
|
- "8003:8000"
|
|
env_file:
|
|
- .env
|
|
environment:
|
|
- CLIP_URL=http://clip:8000
|
|
- BLIP_URL=http://blip:8000
|
|
- YOLO_URL=http://yolo:8000
|
|
- QDRANT_SVC_URL=http://qdrant-svc:8000
|
|
- CARD_RENDERER_URL=http://card-renderer:8000
|
|
- MATURITY_URL=http://maturity:8000
|
|
- MATURITY_ENABLED=true
|
|
- API_KEY=${API_KEY}
|
|
- VISION_TIMEOUT=300
|
|
- MAX_IMAGE_BYTES=52428800
|
|
depends_on:
|
|
clip:
|
|
condition: service_healthy
|
|
blip:
|
|
condition: service_healthy
|
|
yolo:
|
|
condition: service_healthy
|
|
qdrant-svc:
|
|
condition: service_healthy
|
|
card-renderer:
|
|
condition: service_healthy
|
|
maturity:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=5).read()"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 20s
|
|
|
|
card-renderer:
|
|
build:
|
|
context: .
|
|
dockerfile: card-renderer/Dockerfile
|
|
environment:
|
|
- CARD_DEFAULT_FONT=/app/assets/fonts/Inter-Regular.ttf
|
|
- CARD_BOLD_FONT=/app/assets/fonts/Inter-Bold.ttf
|
|
- CARD_LOGO_PATH=/app/assets/logo.png
|
|
- CARD_MAX_IMAGE_BYTES=52428800
|
|
- CARD_DEFAULT_OUTPUT=webp
|
|
- CARD_DEFAULT_QUALITY=90
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=5).read()"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 20s
|
|
|
|
qdrant:
|
|
image: qdrant/qdrant:latest
|
|
ports:
|
|
- "6333:6333"
|
|
volumes:
|
|
- ./data/qdrant:/qdrant/storage
|
|
environment:
|
|
- QDRANT__SERVICE__GRPC_PORT=6334
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "bash -c ':> /dev/tcp/127.0.0.1/6333' || exit 1"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 5
|
|
start_period: 15s
|
|
|
|
qdrant-svc:
|
|
build:
|
|
context: .
|
|
dockerfile: qdrant/Dockerfile
|
|
environment:
|
|
- QDRANT_HOST=qdrant
|
|
- QDRANT_PORT=6333
|
|
- CLIP_URL=http://clip:8000
|
|
- COLLECTION_NAME=images
|
|
- VECTOR_DIM=512
|
|
- SEARCH_HNSW_EF=128
|
|
depends_on:
|
|
qdrant:
|
|
condition: service_healthy
|
|
clip:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=5).read()"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 20s
|
|
|
|
clip:
|
|
build:
|
|
context: .
|
|
dockerfile: clip/Dockerfile
|
|
environment:
|
|
- MODEL_NAME=ViT-B-32
|
|
- MODEL_PRETRAINED=openai
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=5).read()"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 5
|
|
start_period: 60s
|
|
|
|
blip:
|
|
build:
|
|
context: .
|
|
dockerfile: blip/Dockerfile
|
|
environment:
|
|
- BLIP_MODEL=Salesforce/blip-image-captioning-base
|
|
#- BLIP_MODEL=Salesforce/blip-image-captioning-small
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=5).read()"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 5
|
|
start_period: 90s
|
|
|
|
yolo:
|
|
build:
|
|
context: .
|
|
dockerfile: yolo/Dockerfile
|
|
environment:
|
|
- YOLO_MODEL=yolov8n.pt
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=5).read()"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 5
|
|
start_period: 60s
|
|
|
|
maturity:
|
|
build:
|
|
context: .
|
|
dockerfile: maturity/Dockerfile
|
|
environment:
|
|
- MATURITY_MODEL=${MATURITY_MODEL:-Falconsai/nsfw_image_detection}
|
|
- MATURITY_THRESHOLD_MATURE=${MATURITY_THRESHOLD_MATURE:-0.80}
|
|
- MATURITY_THRESHOLD_REVIEW=${MATURITY_THRESHOLD_REVIEW:-0.60}
|
|
- MAX_IMAGE_BYTES=52428800
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=5).read()"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 5
|
|
start_period: 90s
|
|
|