Instructions to use desert-ant-labs/toxic with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LiteRT
How to use desert-ant-labs/toxic with LiteRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
# No code snippets available yet for this library.
# To use this model, check the repository files and the library's documentation.
# Want to help? PRs adding snippets are welcome at:
# https://github.com/huggingface/huggingface.jsToxic
Catch hate speech before it posts.
On-device hate-speech triage for European languages.
| Platforms | iOS, macOS, tvOS, visionOS, Android, Linux, Windows, Browser, Node |
| Languages | 35 |
| Weights | v0.2.2 |
| Demo | https://desertant.com/models/toxic/ |
| Status | Beta |
Install
Swift (requirements)
.package(url: "https://github.com/Desert-Ant-Labs/desert-ant-core.git", from: "4.3.0")
Then add the Toxic product to your target.
Kotlin (requirements)
implementation("ai.desertant:toxic:4.3.0")
JavaScript (requirements)
npm i @desert-ant-labs/toxic @litertjs/core # browser
npm i @desert-ant-labs/toxic # Node, prebuilt native core
Usage
Swift
import Toxic
let toxic = Toxic()
let result = try await toxic.analyze(comment)
if result.isToxic { holdForReview(result.content, result.targets) }
result.score(.hateful) // 0...1
result.flagged // the heads at or above their thresholds
The text goes in as written: no lower-casing, no stripping. Canceling the calling task stops the analysis and throws CancellationError. On Apple platforms every op of the graph runs on the Neural Engine; the SDK tokenizes and looks the tokens' rows up itself and feeds the graph embeddings. Pass computeUnits: to Toxic(directory:computeUnits:) to change the units.
Kotlin
import ai.desertant.toxic.Toxic
import ai.desertant.toxic.Options
Toxic(context).use { toxic ->
val result = toxic.analyze(comment)
if (result.isToxic) holdForReview(result.content, result.targets)
}
JavaScript
import { Toxic } from "@desert-ant-labs/toxic"; // browser
// import { Toxic } from "@desert-ant-labs/toxic/native"; // server-side Node
const toxic = await Toxic.load();
const { isToxic, scores, content, targets } = await toxic.analyze(comment);
toxic.dispose();
What comes back
Every SDK returns the same analysis:
| Field | |
|---|---|
scores |
Every head's probability in 0...1: HATEFUL, ABUSIVE, THREAT, and the eight target heads RACE, RELIGION, NATIONAL_ETHNIC_ORIGIN, SEXUAL_ORIENTATION, GENDER, DISABILITY, AGE, OTHER. |
thresholds |
The threshold each head was judged at. |
flagged |
The heads at or above their thresholds, content and target heads alike. |
content |
The content heads that fired: what the text does. HATEFUL is incitement to hatred or violence against a group, ABUSIVE insulting or degrading language, aimed or not, THREAT a threat of violence. |
targets |
The target heads that fired, highest score first: which group a hateful text is about. Read them when HATEFUL fired. |
isToxic |
Whether a content head fired. |
Toxic is a triage signal for human review or a stricter check, not a verdict: it reacts to hateful words whether a text uses them or quotes them, and the line between hate and merely offensive text is soft.
Options
| Option | Default | |
|---|---|---|
thresholds |
the model's | A label to the threshold that replaces the model's default for that head. The defaults ship with the model, chosen on validation text (Toxic.defaultThresholds() in Swift). Raise a threshold to flag less, lower it to flag more. |
Long texts
The graph reads 128 tokens at a time, about 80 words. A longer text is read in overlapping windows, and each head keeps its highest score over them, so a long text's score is its worst window's.
Loading the model
The SDK downloads the weights from Hugging Face on first use and caches them. See model downloads and caching.
Measured quality
ROC-AUC per head on public sets the model was not trained on, scored at the precision of the shipped weights. ROC-AUC is the chance that the model scores a text carrying the label above a text that does not: 0.5 is a coin toss and 1.0 is a perfect ranking. It does not depend on the threshold, so it describes the scores themselves.
| Benchmark | Languages | Texts | Hateful | Abusive | Threat |
|---|---|---|---|---|---|
| RTP-LX | 38 | 42,016 | 0.786 | 0.809 | 0.805 |
| TextDetox multilingual toxicity | 15 | 71,374 | 0.823 | ||
| Aya red-teaming | 8 | 7,419 | 0.779 | 0.742 | 0.640 |
| OpenAI moderation evaluation set | en | 1,680 | 0.917 | 0.900 | 0.902 |
| ToxiGen, annotated | en | 9,900 | 0.902 | ||
| ToxicChat | en | 5,083 | 0.863 | 0.774 | |
| ALIA-es, human test set | es | 3,000 | 0.797 | ||
| News-RO-Offense | ro | 4,053 | 0.775 | 0.852 |
A blank cell means the set has no label for that head, or too few texts with it to score.
Performance
Through the SDK: one short text per call, the median of 50 calls, model load excluded. SDK 4.3.0.
| Device | Runtime | Per text |
|---|---|---|
| MacBook Pro M5 Pro | Core ML | 1.6 ms |
| iPhone 16 Pro | Core ML | 2.0 ms |
| Mac mini M1 | Core ML | 2.7 ms |
| MacBook Pro 16 M1 Max | Core ML | 2.9 ms |
| Linux, x86-64 | LiteRT, CPU | 8.6 ms |
| Galaxy S26, Exynos 2600 | LiteRT, CPU | 17 ms |
| Windows, AMD Ryzen AI 300 | LiteRT, CPU | 20 ms |
| Windows, Intel Core Ultra 200V | LiteRT, CPU | 47 ms |
Files
| File | Format | Size | Contents |
|---|---|---|---|
coreml-mixed/toxic.mlmodelc |
Compiled Core ML, the layers 8-bit | 43MB | The graph on Apple platforms, every op on the Neural Engine (used by the Swift SDK) |
litert-mixed/toxic.tflite |
LiteRT, the layers 8-bit | 44MB | The graph on Android, Linux, Windows, Node, and the web (downloaded on demand by the Kotlin and JavaScript SDKs) |
coreml-mixed/toxic_meta.json, litert-mixed/toxic_meta.json |
JSON | 2KB | The graph's input and output names, the heads in output order, the table's and the tokenizer's shapes, the default thresholds |
toxic_table.bin |
The embedding table as the SDK reads it, 4-bit | 50MB | The rows the SDK looks a text's tokens up in and feeds the graph, shared by both runtimes |
toxic_tokenizer.bin |
The tokenizer as the SDK reads it | 9.4MB | The pieces, the merges and the added tokens of the encoder's tokenizer, shared by both runtimes |
License
Desert Ant Labs Source-Available License. Free for most apps, and a commercial license is required at scale. Full terms are at the link. Licensing: licensing@desertant.com.
Third-party notices for the weights: THIRD_PARTY_NOTICES.md.
Citation
@software{toxic_2026,
title = {Toxic: On-device hate-speech triage for European languages},
author = {Desert Ant Labs},
year = {2026},
url = {https://huggingface.co/desert-ant-labs/toxic},
}
© 2026 Desert Ant Labs · https://desertant.com
- Downloads last month
- 243