A production-oriented FastAPI service that exposes two independently mounted applications: an Items demo API and an NSFW image classification API backed by a SigLIP-based model from Hugging Face. The gateway adds CORS, a root discovery endpoint, and a lightweight health check suitable for orchestrators and load balancers.
| Capability | Description |
|---|---|
| Gateway | Single ASGI application (app.py) mounting sub-apps under /api/items and /api/nsfw. |
| Items API | Minimal in-memory catalog demo (main.py): welcome route and list endpoint. |
| NSFW API | Image moderation-style classification using Ateeqq/nsfw-image-detection with lazy model loading (nsfw_api.py). |
| Observability | GET /health returns { "status": "healthy" } for probes; Docker image includes a curl-based HEALTHCHECK. |
flowchart TB
Client[Clients]
GW[Combined API app.py]
Items[Items sub-app /api/items]
NSFW[NSFW sub-app /api/nsfw]
HF[Hugging Face model cache]
Keys[api_keys.txt]
Client --> GW
GW --> Items
GW --> NSFW
NSFW --> HF
NSFW --> Keys
mount preserves each sub-application’s own routes and OpenAPI metadata under its prefix.runtime.txt).python3.12 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
Development (auto-reload):
python app.py
or explicitly:
uvicorn app:app --host 0.0.0.0 --port 8000 --reload
Production-style (matches container command—multiple workers):
gunicorn --bind 0.0.0.0:8000 --workers 4 --worker-class uvicorn.workers.UvicornWorker app:app
curl -s http://127.0.0.1:8000/health
curl -s http://127.0.0.1:8000/
Detection endpoints require an X-API-Key header. Valid keys are loaded from api_keys.txt (one key per line). If the file is absent at startup, a default key is created—replace it before any untrusted exposure.
Administrative routes under /api/nsfw/admin/keys/* accept JSON bodies { "key": "<value>", "admin_secret": "<secret>" }. The admin secret is defined in code as ADMIN_SECRET in nsfw_api.py; override this pattern for production (for example via environment variables and a secrets manager).
The gateway enables permissive CORS (allow_origins=["*"]). Tighten origins when deploying to a known front-end or API consumer.
Base URL shown as http://127.0.0.1:8000; substitute your host and scheme in deployment.
| Method | Path | Purpose |
|---|---|---|
GET | / | Service metadata and links to mounted APIs |
GET | /health | Liveness / readiness-style health payload |
/api/items)Mounted from main.py. Paths below are relative to the mount (full paths include /api/items).
| Method | Path | Purpose |
|---|---|---|
GET | / | Welcome message |
GET | /items | Returns the in-memory list of items (initially empty) |
/api/nsfw)Mounted from nsfw_api.py. All detection and admin routes below require authentication as described in each section.
Detection (require header X-API-Key: <your-key>):
| Method | Path | Purpose |
|---|---|---|
GET | / | Service metadata and route index |
POST | /detect/upload | Multipart upload of an image file (file field) |
POST | /detect/url | JSON body { "image_url": "https://..." } |
Administration (JSON body includes admin_secret; see Configuration):
| Method | Path | Purpose |
|---|---|---|
POST | /admin/keys/add | Register a new API key |
POST | /admin/keys/remove | Revoke an API key |
POST | /admin/keys/list | List configured keys |
Successful classification returns a JSON object of the form:
{
"predicted_class_id": 2,
"predicted_class_label": "safe_normal",
"confidence_scores": {
"graphically_violent": 0.0001,
"nudity_pornography": 0.0002,
"safe_normal": 0.9997
}
}
Label strings and score keys come from the model’s id2label mapping and may evolve with the upstream checkpoint.
FastAPI exposes OpenAPI-powered UIs on each application:
Use the NSFW Swagger UI to exercise X-API-Key and request bodies interactively.
curl -s -X POST 'http://127.0.0.1:8000/api/nsfw/detect/url' \
-H 'Content-Type: application/json' \
-H 'X-API-Key: YOUR_API_KEY' \
-d '{"image_url": "https://example.com/image.jpg"}'
curl -s -X POST 'http://127.0.0.1:8000/api/nsfw/detect/upload' \
-H 'accept: application/json' \
-H 'X-API-Key: YOUR_API_KEY' \
-F 'file=@/path/to/image.jpg'
curl -s 'http://127.0.0.1:8000/api/items/items'
The repository includes a Dockerfile that:
requirements.txtDockerfile CMD)HEALTHCHECK against http://localhost:8000/healthBuild and run locally:
docker build -t combined-api .
docker run --rm -p 8000:8000 combined-api
CI/CD workflows under .github/workflows/ automate image build and deployment to Azure Container Registry for the main branch when secrets are configured.
--workers.detect/url uses requests.get without custom SSRF controls—deploy behind a trusted network or add outbound filtering if that matches your threat model.| Path | Role |
|---|---|
app.py | Gateway application, CORS, mounts |
main.py | Items sub-application |
nsfw_api.py | NSFW sub-application, model wrapper, API keys |
nsfw.py | Standalone script-style demo of the model (not the HTTP API) |
requirements.txt | Python dependencies |
runtime.txt | Python version pin for platforms that consume it |
Dockerfile | Container image definition |
For schemas, status codes, and request validation details, rely on the generated OpenAPI documents linked above.
A production-oriented FastAPI service that exposes two independently mounted applications: an Items demo API and an NSFW image classification API backed by a SigLIP-based model from Hugging Face. The gateway adds CORS, a root discovery endpoint, and a lightweight health check suitable for orchestrators and load balancers.
| Capability | Description |
|---|---|
| Gateway | Single ASGI application (app.py) mounting sub-apps under /api/items and /api/nsfw. |
| Items API | Minimal in-memory catalog demo (main.py): welcome route and list endpoint. |
| NSFW API | Image moderation-style classification using Ateeqq/nsfw-image-detection with lazy model loading (nsfw_api.py). |
| Observability | GET /health returns { "status": "healthy" } for probes; Docker image includes a curl-based HEALTHCHECK. |
flowchart TB
Client[Clients]
GW[Combined API app.py]
Items[Items sub-app /api/items]
NSFW[NSFW sub-app /api/nsfw]
HF[Hugging Face model cache]
Keys[api_keys.txt]
Client --> GW
GW --> Items
GW --> NSFW
NSFW --> HF
NSFW --> Keys
mount preserves each sub-application’s own routes and OpenAPI metadata under its prefix.runtime.txt).python3.12 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
Development (auto-reload):
python app.py
or explicitly:
uvicorn app:app --host 0.0.0.0 --port 8000 --reload
Production-style (matches container command—multiple workers):
gunicorn --bind 0.0.0.0:8000 --workers 4 --worker-class uvicorn.workers.UvicornWorker app:app
curl -s http://127.0.0.1:8000/health
curl -s http://127.0.0.1:8000/
Detection endpoints require an X-API-Key header. Valid keys are loaded from api_keys.txt (one key per line). If the file is absent at startup, a default key is created—replace it before any untrusted exposure.
Administrative routes under /api/nsfw/admin/keys/* accept JSON bodies { "key": "<value>", "admin_secret": "<secret>" }. The admin secret is defined in code as ADMIN_SECRET in nsfw_api.py; override this pattern for production (for example via environment variables and a secrets manager).
The gateway enables permissive CORS (allow_origins=["*"]). Tighten origins when deploying to a known front-end or API consumer.
Base URL shown as http://127.0.0.1:8000; substitute your host and scheme in deployment.
| Method | Path | Purpose |
|---|---|---|
GET | / | Service metadata and links to mounted APIs |
GET | /health | Liveness / readiness-style health payload |
/api/items)Mounted from main.py. Paths below are relative to the mount (full paths include /api/items).
| Method | Path | Purpose |
|---|---|---|
GET | / | Welcome message |
GET | /items | Returns the in-memory list of items (initially empty) |
/api/nsfw)Mounted from nsfw_api.py. All detection and admin routes below require authentication as described in each section.
Detection (require header X-API-Key: <your-key>):
| Method | Path | Purpose |
|---|---|---|
GET | / | Service metadata and route index |
POST | /detect/upload | Multipart upload of an image file (file field) |
POST | /detect/url | JSON body { "image_url": "https://..." } |
Administration (JSON body includes admin_secret; see Configuration):
| Method | Path | Purpose |
|---|---|---|
POST | /admin/keys/add | Register a new API key |
POST | /admin/keys/remove | Revoke an API key |
POST | /admin/keys/list | List configured keys |
Successful classification returns a JSON object of the form:
{
"predicted_class_id": 2,
"predicted_class_label": "safe_normal",
"confidence_scores": {
"graphically_violent": 0.0001,
"nudity_pornography": 0.0002,
"safe_normal": 0.9997
}
}
Label strings and score keys come from the model’s id2label mapping and may evolve with the upstream checkpoint.
FastAPI exposes OpenAPI-powered UIs on each application:
Use the NSFW Swagger UI to exercise X-API-Key and request bodies interactively.
curl -s -X POST 'http://127.0.0.1:8000/api/nsfw/detect/url' \
-H 'Content-Type: application/json' \
-H 'X-API-Key: YOUR_API_KEY' \
-d '{"image_url": "https://example.com/image.jpg"}'
curl -s -X POST 'http://127.0.0.1:8000/api/nsfw/detect/upload' \
-H 'accept: application/json' \
-H 'X-API-Key: YOUR_API_KEY' \
-F 'file=@/path/to/image.jpg'
curl -s 'http://127.0.0.1:8000/api/items/items'
The repository includes a Dockerfile that:
requirements.txtDockerfile CMD)HEALTHCHECK against http://localhost:8000/healthBuild and run locally:
docker build -t combined-api .
docker run --rm -p 8000:8000 combined-api
CI/CD workflows under .github/workflows/ automate image build and deployment to Azure Container Registry for the main branch when secrets are configured.
--workers.detect/url uses requests.get without custom SSRF controls—deploy behind a trusted network or add outbound filtering if that matches your threat model.| Path | Role |
|---|---|
app.py | Gateway application, CORS, mounts |
main.py | Items sub-application |
nsfw_api.py | NSFW sub-application, model wrapper, API keys |
nsfw.py | Standalone script-style demo of the model (not the HTTP API) |
requirements.txt | Python dependencies |
runtime.txt | Python version pin for platforms that consume it |
Dockerfile | Container image definition |
For schemas, status codes, and request validation details, rely on the generated OpenAPI documents linked above.