An image classification API for NSFW content, with HTTP and gRPC interfaces. One Go binary uses ONNX Runtime to classify photos and anime, detect explicit regions, and combine the results. Optional Tesseract OCR detects words in images.
Run the CPU image:
docker run -e APP_ENV=web -p 4000:4000 m1chl/nsfw-sherlockMake sure that the service responds:
curl http://localhost:4000/pingThe image includes the models and OCR support. It supports Linux amd64 and arm64. Docker Hub and GHCR publish the same images.
For gRPC, set APP_ENV=grpc. The default interface is HTTP.
All image endpoints accept this JSON request:
{"base64":"<base64-encoded image>","filename":"image.jpg"}| HTTP endpoint | Response |
|---|---|
GET /ping |
Service status |
POST /pic/check |
nsfwPic and nsfwText flags |
POST /pic/labels |
Probabilities for drawings, hentai, neutral, porn, and sexy |
POST /pic/analyze |
Full analysis, model scores, region detections, and elapsed time |
Example response from /pic/check:
{"status":"ok","message":"success","nsfwText":false,"nsfwPic":false}The full analysis includes a verdict (sfw, suggestive, or explicit) and an nsfw score.
Errors use {"errorMessage":"...","status":"FAIL","hasError":true}.
The gRPC service exposes Detect, DetectLabels, and Analyze.
The service definition contains the request and response types.
Install an NVIDIA driver compatible with CUDA 12.9 and the NVIDIA Container Toolkit. Then run the CUDA image:
docker run --gpus all -p 4000:4000 m1chl/nsfw-sherlock:v1.0.4-cudaThis image supports Linux amd64. It includes ONNX Runtime 1.29.0, CUDA 12, and cuDNN.
ORT_DEVICE_ID selects the GPU index, with 0 as the default.
Install ROCm and a MIGraphX-enabled ONNX Runtime 1.29.0 shared library.
Set ORT_PROVIDER=rocm.
Point ORT_LIB to that library.
Keep the provider libraries beside it.
Add the ROCm dependencies to the library search path.
The rocm value is an alias for migraphx. The Go binding requires ORT API 29.
Older runtimes are incompatible. This project does not publish an AMD image.
The MIGraphX guide describes the runtime build.
If the selected provider is unavailable, the service stops at startup. Unsupported operators can still use the CPU. GPU inference remains untested on physical NVIDIA or AMD hardware.
| Variable | Default | Purpose |
|---|---|---|
APP_ENV |
web |
HTTP (web) or gRPC (grpc). http is a deprecated alias. |
PORT |
4000 |
Service port |
NSFW_PROFILE |
balanced |
Model profile |
ORT_PROVIDER |
cpu |
cpu, cuda, or migraphx. rocm aliases migraphx. |
ORT_DEVICE_ID |
0 |
GPU index |
OCR_ENABLED |
true |
Text detection. Requires a build with OCR support. |
Paths, limits, and logging
| Variable | Default | Purpose |
|---|---|---|
MODELS_DIR |
./assets/models |
Model directory |
MANIFEST |
models/manifest.json |
Model manifest |
ORT_LIB |
Auto-detected | ONNX Runtime shared library path |
BAD_WORDS_FILE |
Auto-detected | OCR word list. Uses an embedded list as a fallback. |
MAX_IMAGE_BYTES |
20971520 (20 MiB) |
Maximum image size |
MAX_IMAGE_PIXELS |
50000000 |
Maximum decoded pixel count |
SESSION_POOL_SIZE |
2 |
Sessions per model |
NSFW_ALLOW_DEGRADED |
false |
Allow startup after a required model fails to load. |
LOG_LEVEL |
info |
debug, info, warn, or error |
LOG_FORMAT |
text |
text or json |
Docker images supply the model and runtime paths. They use JSON logs.
| Profile | Photo model | Anime model | Region detector |
|---|---|---|---|
balanced (default) |
Freepik EVA02 | CaFormer | NudeNet 320px |
max |
Freepik EVA02 | CaFormer | NudeNet 640px |
fast |
Freepik EVA02 | MobileNetV3 | NudeNet 320px |
compat |
ViT5 with five legacy labels | None | None |
Requirements: Go 1.27, a C compiler, Python 3, and curl. The runtime download supports Linux amd64, Linux arm64, and macOS arm64.
Download the source, runtime, and models. Then build the binary. Run the binary:
git clone https://github.com/M1chlCZ/nsfw_sherlock
cd nsfw_sherlock
scripts/fetch-models.sh --ort-only
scripts/fetch-models.sh
go build .
./nsfw_sherlockThe download script uses pinned SHA-256 digests for the runtime and models.
The engine also compares each model digest with the manifest at startup.
This source build excludes OCR and always reports nsfwText: false.
For OCR support, install Tesseract, Leptonica, their development libraries, and the English language data. Then build with the OCR tag:
go build -tags ocr .OCR_ENABLED=false also disables text detection.
Run the tests and lint checks:
go test ./... -count=1 -race
go test -tags ocr ./... -count=1 -race
golangci-lint run
golangci-lint run --build-tags ocr
PARITY_REQUIRE=1 go test ./engine -run TestParityThe OCR tests require Tesseract. The parity tests require the models and ONNX Runtime.
CI also runs go vet, govulncheck, and a Docker smoke test.
Release jobs require successful CI checks before they publish images.
The lint configuration adapts the Golden config.
Model tools: manifest · download · export · parity fixtures · benchmark.
Stub generation uses make proto.
The code uses AGPL-3.0. Model licenses apply separately.
| Model | License |
|---|---|
| Freepik photo classifier | MIT |
| deepghs anime classifiers | MIT |
| NudeNet region detectors | AGPL-3.0 |
| ViT5 compatibility classifier | CC-BY-NC-ND-4.0 |
Review the model licenses before commercial use.
The compat model has non-commercial and no-derivatives restrictions.
Review its license before you export or redistribute it.
Runtime: onnxruntime_go. OCR: gosseract and Tesseract.