THR3SHR
Local FastAPI + React workflow that threshes a media dump into destination bins β anime/GIF/video tagging, review, and folder migration (ML-Danbooru / WD taggers).
Β© 2026 Dinamush β software under MIT; brand, UI creative materials, and curated docs under CC BY 4.0. Third-party model owners are credited in ATTRIBUTION.md.
This repo includes:
- Tag vocabulary (
tags.csv) - FastAPI backend for scan β tag β review β migrate
- React SPA with sectioned settings, run dashboard, and review table
- Multi-model inference via
dghs-imgutils(ML-Danbooru ONNX and WD14 taggers)
ONNX weights are not stored in this git tree (too large for GitHub). They are downloaded into the Hugging Face Hub cache on first use. See Model weights for direct links.
What The Web UI Does
- Settings β paths, tagger model, thresholds, workers; sticky unsaved save bar
- Tag selection β search chips from
tags.csv(auto-persisted) - Preview scan β eligible image counts before starting a run
- Run dashboard β status, totals, failed/review counts, progress bar, cancel
- Review table β preview, primary (or βneeds reviewβ), secondary suggestions, global top-5 tags, final tag, approve/migrate
Tagger Models
Choose in Settings (persisted in SQLite as tagger_model):
| Setting value | Backend call | Notes |
|---|---|---|
wd_swinv2_v3 (default) |
get_wd14_tags(..., model_name="SwinV2_v3") |
Recommended accuracy baseline |
wd_eva02_large |
get_wd14_tags(..., model_name="EVA02_Large") |
Larger / slower WD tagger |
ml_danbooru |
get_mldanbooru_tags(..., threshold=0.0, size=448) |
Original ML-Danbooru path |
Related settings:
confidence_threshold(default0.6) β assignment gate for selected tagswd_general_threshold(default0.35) β WD14 general-tag cutoff at inference (WD models only)max_inference_workers(default2) β keep low; ORT session is serialized under a lockforce_cpu_inferenceβ force CPU path
Classification Rules
- Scores are produced for the whole vocabulary (model-dependent).
- Folder assignment ranks only user-selected tags that map to
tags.csv. - Empty scores β failed / needs review.
- Best selected score < noise floor
max(0.15, confidence_threshold * 0.5)β no primary (weak noise winner discarded; kept as secondary suggestion). - Best selected score < confidence_threshold` β no primary; suggestion in secondary.
- Review payload always includes global top-5 tags so mis-assignments are diagnosable.
- Each run stores
tagger_modelfor provenance.
Quick Start
1) Create Python environment and install backend dependencies
cd /path/to/thr3shr
python3 -m venv .venv
. .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r backend/requirements.txt
2) Start backend API (port 8000)
cd /path/to/thr3shr/backend
../.venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload
Health check:
curl http://127.0.0.1:8000/health
3) Start frontend Web UI (port 5173)
cd /path/to/thr3shr/frontend
npm install
npm run dev
Open http://localhost:5173.
Frontend Offline Mode
The frontend falls back to local mock mode when the backend is unreachable. Preview/migration are mock-only in that mode.
Review Workflow
- Set root repository (unsorted images) and categories root (destination folders β not
tags.csv) - Pick a tagger model and thresholds β Save settings
- Optionally Preview scan
- Select destination tags β Start run
- Watch the run dashboard; cancel if needed
- Review: primary / secondary / global tops β approve β migrate (
copyormove)
Supported And Ignored Files
- Supported image extensions:
.jpg,.jpeg,.jfif,.png,.bmp,.webp,.tiff - Extensionless / odd extensions are included when PIL can decode them
- By default ignored:
.gifand common video formats - Optional experimental media: quality-filtered multi-frame sampling with presence pooling (require β₯2 corroborating frames; tagged budget up to 48; black/blank frames rejected) when enabled in settings
GPU Acceleration
Inference uses ONNX Runtime CUDA when the pip CUDA/cuDNN wheels are installed and discoverable.
pip install -r backend/requirements.txt
# includes: onnxruntime-gpu[cuda,cudnn]==1.26.0
On Windows the API prepends site-packages/nvidia/*/bin to the DLL search path before creating sessions. Without that, ORT may list CUDA then fall back to CPU on the first Conv.
CUDA usability is independent of which tagger model is selected; both ML-Danbooru and WD14 share the ORT runtime path.
Verify GPU is actually usable
curl http://127.0.0.1:8000/health/providers
curl http://127.0.0.1:8000/api/providers
Look for "cuda_usable": true, "likely_device": "gpu", and active_providers containing CUDAExecutionProvider. Listing CUDA alone is not enough. The providers payload also echoes the active tagger_model.
Runtime controls
Settings UI values are mirrored into env knobs used by the run executor:
MAX_INFERENCE_WORKERS(default2, clamped1..16)FORCE_CPU_INFERENCE=trueINFERENCE_MODE=batch|single(defaultsinglein practice for imgutils; batch falls back to per-image)INFERENCE_BATCH_SIZE(default1, clamped1..64)QUEUE_SHUFFLE_ENABLED=true|false(defaulttrue)QUEUE_SHUFFLE_SEED=<int>(defaultrun_id)
Examples:
# CPU-safe baseline
FORCE_CPU_INFERENCE=true MAX_INFERENCE_WORKERS=1 ../.venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload
# Conservative GPU (recommended)
MAX_INFERENCE_WORKERS=2 ../.venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload
API Surface (High Level)
GET /healthGET /health/providersGET /api/providersGET/PUT /api/settingsβ includestagger_model,wd_general_threshold,selected_tags, workers, etc.GET /api/tagsGET /api/scan/previewβ discovery stats without inferencePOST /api/runs/startGET /api/runs/{run_id}/statusβ includestagger_model, progress telemetryPOST /api/runs/{run_id}/cancelGET /api/runs/{run_id}/itemsβ includesglobal_top_tags, secondary suggestionsPATCH /api/items/{item_id}GET /api/items/{item_id}/previewGET /api/items/{item_id}/scoresPOST /api/runs/{run_id}/batchPOST /api/runs/{run_id}/migrate
Tests
cd backend
../.venv/bin/python -m pytest tests -q
Model weights
Tagger ONNX files are pulled automatically via huggingface_hub on first inference. Hosted copies (not in this repo):
| Setting value | Weights / labels | Size note |
|---|---|---|
wd_swinv2_v3 (default) |
SmilingWolf/wd-swinv2-tagger-v3 Β· mirror deepghs/wd14_tagger_with_embeddings (β¦/model.onnx) |
~hundreds of MB |
wd_eva02_large |
SmilingWolf/wd-eva02-large-tagger-v3 Β· same deepghs mirror path | larger / slower |
ml_danbooru |
deepghs/ml-danbooru-onnx (ml_caformer_m36_dec-5-97527.onnx) Β· tags deepghs/imgutils-models (mldanbooru/mldanbooru_tags.csv) |
ONNX + CSV |
Cache location (typical): ~/.cache/huggingface/hub/.
License and attribution
| What | Owner | License |
|---|---|---|
| THR3SHR source code | Dinamush | MIT |
| THR3SHR brand, creative docs, curated taxonomies | Dinamush | CC BY 4.0 |
| WD / ML-Danbooru / style / optional VLM weights | Upstream authors (SmilingWolf, deepghs, bartowski, porntech, β¦) | See ATTRIBUTION.md |
Model weights are not shipped in this repository. Preserve LICENSE, CREATIVE_COMMONS.md, and ATTRIBUTION.md when redistributing.
Remotes
| Remote | URL |
|---|---|
origin (Hugging Face Hub) |
https://huggingface.co/Dinamus/thr3shr |
github |
https://github.com/Dinamush/thr3shr |
git push origin main # Hugging Face
git push github main # GitHub
The Gradio app.py entry in the YAML front matter is a legacy Space config; the primary workflow documented here is the FastAPI + React app.