Sign inSign up

fkde/bouncer

By fkde

•Updated 2 months ago

Image
0

406

fkde/bouncer repository overview

⁠Bouncer 🛡️

The doorman for your uploads. A self-hosted service that checks whether an uploaded image is safe to accept — primarily to keep nudity / sexual content off your server. Runs a local LLM via Ollama, needs no GPU, and is a single container.

Send it an image → get a verdict:

{ "allowed": true, "block": false, "confidence": 0.94, "reason": "..." }

⁠How it works

Two stages, which is what makes small local models reliable here:

  1. Describe — a vision model turns the image into neutral, factual text.
  2. Decide — a text model reads that text and returns { allowed, reason, confidence }.

Low confidence → uncertain (flag for review). Everything is fail-closed: on any error, timeout, or overload the answer is "don't accept".

⁠Tags

TagBuild
latest, X.Y.ZCPU-only, slim (~380 MB). Runs anywhere.
X.Y.Z-gpuIncludes NVIDIA CUDA runners. Run with --gpus all + nvidia-container-toolkit.

⁠Quick start

docker run -d --name bouncer --restart unless-stopped \
  -p 8080:8080 -v bouncer-models:/root/.ollama \
  -e DESCRIBER_MODEL=gemma4:e2b -e DECISION_MODEL=gemma4:e2b \
  fkde/bouncer:latest
  • The -v volume persists pulled models across restarts.
  • First start pulls the model (a few minutes). The container reports healthy only once the download is done and it can classify — watch with docker ps (STATUS column) or curl localhost:8080/healthz.
  • Then: demo UI on http://localhost:8080⁠, API at POST /classify.

⁠Using the API

# file upload
curl -s -F [email protected] http://localhost:8080/classify

# or JSON base64
curl -s -X POST http://localhost:8080/classify \
  -H 'Content-Type: application/json' \
  -d '{"image_base64":"'"$(base64 -i photo.jpg)"'"}'

Integrate fail-closed: accept the upload only when block === false. Every other case — rejected, uncertain, error, 503 (queue full → retry) — means do not accept.

⁠Configuration (env vars)

VariableDefaultMeaning
DESCRIBER_MODELgemma4:e2bStage 1 vision model (must support images).
DECISION_MODELgemma4:e2bStage 2 text model. Same tag = fastest.
THRESHOLD0.8Below this confidence → uncertain.
TEMPERATURE00 = most deterministic.
MAX_DIM1536Downscale longest edge before inference.
CLASSIFY_CONCURRENCY1Images processed at once (CPU: keep 1).
QUEUE_MAX32Active+waiting cap before 503 backpressure.
OLLAMA_URLinternalPoint at an external Ollama (e.g. a GPU host).

Pull more models anytime:

docker exec bouncer pull-model.sh gemma4:e4b

⁠Endpoints

EndpointPurpose
POST /classifyClassify an image (multipart image or JSON image_base64).
GET /healthz200 once ready (models pulled), else 503. Used by the healthcheck.
GET /api/healthRich status: ready, model count, queue depth.
GET /Demo UI.

⁠GPU (NVIDIA)

docker run -d --name bouncer --restart unless-stopped --gpus all \
  -p 8080:8080 -v bouncer-models:/root/.ollama \
  -e DESCRIBER_MODEL=gemma4:e2b -e DECISION_MODEL=gemma4:e2b \
  fkde/bouncer:latest-gpu

⁠Notes

  • Local only — images and models stay on your machine; no cloud calls.
  • Not a substitute for human review — model confidence is imperfectly calibrated; treat uncertain as "needs a look".
  • Full docs & source: https://github.com/fkde/bouncer⁠

Tag summary

Content type

Image

Digest

sha256:1d77be2ab…

Size

126.8 MB

Last updated

2 months ago

docker pull fkde/bouncer