MudassserRasool/nfsw

Python

0

34 commits

updated May 10, 2026

See the code

README

Combined API

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.


Table of contents


Overview

CapabilityDescription
GatewaySingle ASGI application (app.py) mounting sub-apps under /api/items and /api/nsfw.
Items APIMinimal in-memory catalog demo (main.py): welcome route and list endpoint.
NSFW APIImage moderation-style classification using Ateeqq/nsfw-image-detection with lazy model loading (nsfw_api.py).
ObservabilityGET /health returns { "status": "healthy" } for probes; Docker image includes a curl-based HEALTHCHECK.

Architecture

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
  • Mounting: FastAPI mount preserves each sub-application’s own routes and OpenAPI metadata under its prefix.
  • NSFW inference: First request to an NSFW endpoint triggers download/load of the transformers model and processor; subsequent requests reuse the in-memory model.

Requirements

  • Python: 3.12 (see runtime.txt).
  • Hardware: CPU inference is supported; GPU will accelerate PyTorch if available. Plan memory for PyTorch, transformers, and (under multi-worker process models) per-worker model copies—see Operational notes.
  • Network: NSFW URL detection fetches remote images via HTTP(S); the Hugging Face model is pulled on first use.

Quick start

python3.12 -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -r requirements.txt

2. Run the application

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

3. Verify

curl -s http://127.0.0.1:8000/health
curl -s http://127.0.0.1:8000/

Configuration

NSFW API keys

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).

CORS

The gateway enables permissive CORS (allow_origins=["*"]). Tighten origins when deploying to a known front-end or API consumer.


API surface

Base URL shown as http://127.0.0.1:8000; substitute your host and scheme in deployment.

Gateway

MethodPathPurpose
GET/Service metadata and links to mounted APIs
GET/healthLiveness / readiness-style health payload

Items API (/api/items)

Mounted from main.py. Paths below are relative to the mount (full paths include /api/items).

MethodPathPurpose
GET/Welcome message
GET/itemsReturns the in-memory list of items (initially empty)

NSFW API (/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>):

MethodPathPurpose
GET/Service metadata and route index
POST/detect/uploadMultipart upload of an image file (file field)
POST/detect/urlJSON body { "image_url": "https://..." }

Administration (JSON body includes admin_secret; see Configuration):

MethodPathPurpose
POST/admin/keys/addRegister a new API key
POST/admin/keys/removeRevoke an API key
POST/admin/keys/listList configured keys

Detection response shape

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.


Interactive documentation

FastAPI exposes OpenAPI-powered UIs on each application:

Use the NSFW Swagger UI to exercise X-API-Key and request bodies interactively.


Examples

NSFW: classify from a URL

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"}'

NSFW: upload a file

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'

Items: list catalog

curl -s 'http://127.0.0.1:8000/api/items/items'

Container deployment

The repository includes a Dockerfile that:

  • Uses Python 3.12 slim base image
  • Installs dependencies from requirements.txt
  • Exposes port 8000
  • Runs Gunicorn with Uvicorn workers (see Dockerfile CMD)
  • Defines a HEALTHCHECK against http://localhost:8000/health

Build 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.


Operational notes

  • Cold start: The first NSFW request pays the cost of downloading and loading the Hugging Face model; allow higher timeouts during rollout.
  • Memory: Default Gunicorn configuration uses four workers. Each worker process may load its own copy of the PyTorch model—size RAM accordingly or reduce --workers.
  • Disk: Transformers caches models under the default Hugging Face cache directory; ensure sufficient space and permissions in container images.
  • URL fetching: detect/url uses requests.get without custom SSRF controls—deploy behind a trusted network or add outbound filtering if that matches your threat model.

Security considerations

  • Rotate default API keys and admin secrets before production use; prefer environment-driven configuration over committed literals.
  • Treat NSFW scores as assistive signals, not sole grounds for automated enforcement; validate labels and calibration for your jurisdiction and use case.
  • Restrict CORS and consider rate limiting and request size limits at the edge when exposing upload endpoints.

Repository layout (reference)

PathRole
app.pyGateway application, CORS, mounts
main.pyItems sub-application
nsfw_api.pyNSFW sub-application, model wrapper, API keys
nsfw.pyStandalone script-style demo of the model (not the HTTP API)
requirements.txtPython dependencies
runtime.txtPython version pin for platforms that consume it
DockerfileContainer image definition

For schemas, status codes, and request validation details, rely on the generated OpenAPI documents linked above.

MudassserRasool/nfsw

Python

0

34 commits

updated May 10, 2026

See the code

README

Combined API

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.


Table of contents


Overview

CapabilityDescription
GatewaySingle ASGI application (app.py) mounting sub-apps under /api/items and /api/nsfw.
Items APIMinimal in-memory catalog demo (main.py): welcome route and list endpoint.
NSFW APIImage moderation-style classification using Ateeqq/nsfw-image-detection with lazy model loading (nsfw_api.py).
ObservabilityGET /health returns { "status": "healthy" } for probes; Docker image includes a curl-based HEALTHCHECK.

Architecture

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
  • Mounting: FastAPI mount preserves each sub-application’s own routes and OpenAPI metadata under its prefix.
  • NSFW inference: First request to an NSFW endpoint triggers download/load of the transformers model and processor; subsequent requests reuse the in-memory model.

Requirements

  • Python: 3.12 (see runtime.txt).
  • Hardware: CPU inference is supported; GPU will accelerate PyTorch if available. Plan memory for PyTorch, transformers, and (under multi-worker process models) per-worker model copies—see Operational notes.
  • Network: NSFW URL detection fetches remote images via HTTP(S); the Hugging Face model is pulled on first use.

Quick start

python3.12 -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -r requirements.txt

2. Run the application

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

3. Verify

curl -s http://127.0.0.1:8000/health
curl -s http://127.0.0.1:8000/

Configuration

NSFW API keys

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).

CORS

The gateway enables permissive CORS (allow_origins=["*"]). Tighten origins when deploying to a known front-end or API consumer.


API surface

Base URL shown as http://127.0.0.1:8000; substitute your host and scheme in deployment.

Gateway

MethodPathPurpose
GET/Service metadata and links to mounted APIs
GET/healthLiveness / readiness-style health payload

Items API (/api/items)

Mounted from main.py. Paths below are relative to the mount (full paths include /api/items).

MethodPathPurpose
GET/Welcome message
GET/itemsReturns the in-memory list of items (initially empty)

NSFW API (/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>):

MethodPathPurpose
GET/Service metadata and route index
POST/detect/uploadMultipart upload of an image file (file field)
POST/detect/urlJSON body { "image_url": "https://..." }

Administration (JSON body includes admin_secret; see Configuration):

MethodPathPurpose
POST/admin/keys/addRegister a new API key
POST/admin/keys/removeRevoke an API key
POST/admin/keys/listList configured keys

Detection response shape

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.


Interactive documentation

FastAPI exposes OpenAPI-powered UIs on each application:

Use the NSFW Swagger UI to exercise X-API-Key and request bodies interactively.


Examples

NSFW: classify from a URL

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"}'

NSFW: upload a file

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'

Items: list catalog

curl -s 'http://127.0.0.1:8000/api/items/items'

Container deployment

The repository includes a Dockerfile that:

  • Uses Python 3.12 slim base image
  • Installs dependencies from requirements.txt
  • Exposes port 8000
  • Runs Gunicorn with Uvicorn workers (see Dockerfile CMD)
  • Defines a HEALTHCHECK against http://localhost:8000/health

Build 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.


Operational notes

  • Cold start: The first NSFW request pays the cost of downloading and loading the Hugging Face model; allow higher timeouts during rollout.
  • Memory: Default Gunicorn configuration uses four workers. Each worker process may load its own copy of the PyTorch model—size RAM accordingly or reduce --workers.
  • Disk: Transformers caches models under the default Hugging Face cache directory; ensure sufficient space and permissions in container images.
  • URL fetching: detect/url uses requests.get without custom SSRF controls—deploy behind a trusted network or add outbound filtering if that matches your threat model.

Security considerations

  • Rotate default API keys and admin secrets before production use; prefer environment-driven configuration over committed literals.
  • Treat NSFW scores as assistive signals, not sole grounds for automated enforcement; validate labels and calibration for your jurisdiction and use case.
  • Restrict CORS and consider rate limiting and request size limits at the edge when exposing upload endpoints.

Repository layout (reference)

PathRole
app.pyGateway application, CORS, mounts
main.pyItems sub-application
nsfw_api.pyNSFW sub-application, model wrapper, API keys
nsfw.pyStandalone script-style demo of the model (not the HTTP API)
requirements.txtPython dependencies
runtime.txtPython version pin for platforms that consume it
DockerfileContainer image definition

For schemas, status codes, and request validation details, rely on the generated OpenAPI documents linked above.