ModerationKit
Self-hosted image moderation that runs offline, and corrects a documented bias in the model it depends on.

- score boost correcting a ~3× gender bias
- 2.5×
- detector model, not the 12 MB default
- 104 MB
- framework integrations shipped
- 4
The problem
Every free open-source nudity detector is a thin wrapper around NudeNet behind a single threshold. NudeNet's training data is female-skewed, so male anatomy scores roughly three times lower than the equivalent female detection, and the model will sometimes assert the wrong-gender class over the same region of an image. Wrapping that raw means shipping its false negatives to production. The paid alternatives fix the accuracy by charging per image and requiring you to upload your users' photos to someone else's server.
What I built
Two models behind one verdict. A NudeNet body-part detector — the 104 MB 640m ONNX weights rather than the 12 MB nano model the pip package bundles — provides the annotations, and a Falconsai vision transformer classifies the image as a whole. A composition layer runs both, applies a three-stage correction pipeline, and returns a single ALLOW, REVIEW or BLOCK.
Three delivery surfaces off the same core: a FastAPI service with a /check endpoint and Swagger docs, a Gradio UI for humans, and a batch CLI for folders. Every threshold is an environment variable with a documented default. Docker Compose brings up the API and the UI from one image with a healthcheck, and there are one-command installers for Windows, macOS and Linux.
The README is treated as part of the product. It ships the verdict semantics, a threshold table, paste-ready fail-closed integrations for Express, Next.js App Router, Django and Laravel, an explicit bias notice, and a responsible-use section that refuses the CSAM use case outright and routes operators to PhotoDNA, Thorn and the NCMEC CyberTipline instead.
The hard part
Demoting the model you built on
The correction is three mechanisms applied in a fixed order. Male-class raw scores are multiplied by 2.5 and clamped, because they peak around 0.2–0.4 where the female equivalents peak at 0.7–0.9. A confident face-gender detection — trusted only at or above 0.75, and skipped entirely when both genders appear — suppresses the anatomically contradictory classes. And when two biologically impossible detections overlap at an IoU of 0.5 or more, both are dropped rather than keeping the higher scorer, on the reasoning that a biased detector gives you no principled way to pick the winner.
The decision underneath all three is the one that mattered: the whole-image classifier was promoted to the primary verdict signal and the detector demoted to an annotation source. The detector answers "what specifically is in this image", which is what it is good at; it no longer decides whether the image is a problem, which is what the bias corrupts. The documentation says plainly that this is compensation and not a fix — no amount of post-processing repairs a biased model, and claiming otherwise would be the more dangerous bug.
Outcome
- Public and MIT-licensed, running offline with no per-image cost and no image ever leaving the operator's machine.
- A documented bias-compensation pipeline that raw-NudeNet projects do not have: a 2.5× score boost, a 0.75-gated face suppression, and IoU-based conflict resolution.
- Four paste-ready integrations and nine environment-tunable thresholds, so adopting it is a copy rather than a port.
- A responsible-use section that turns away the one use case the tool must not serve, and names the organisations that should handle it instead.
Screens

The other end of the same scale. The whole-image classifier is the primary signal, so 1.00 against a 0.7 threshold blocks outright. The image that produced this is not shown.

Why that verdict is defensible: the detector classifies each region separately. Only the two explicit rows force a block. The same table on the cover image returns suggestive throughout.

The API an integrator actually adopts: one multipart POST, returning the verdict, both scores and every detection.

The third surface, for moderating a library that already exists rather than a live upload. One folder, one verdict per file, one CSV.
Want something like this built? I take on a small number of projects at a time.