A FastAPI service that detects toxicity, hate speech, spam, and harmful content across multiple languages (English, Hindi, Arabic) using Hugging Face transformer models.
Python
0
13 commits
updated Apr 26, 2026
A FastAPI-powered content moderation service that detects toxicity and harmful content across English, Hindi, and Arabic using Hugging Face transformer models. Features language-aware threshold calibration to handle cross-lingual bias in multilingual NLP models.
/docsdocker-compose up┌──────────────┐ ┌──────────────┐ ┌───────────────────────┐
│ Client │────▶│ FastAPI │────▶│ DistilBERT │
│ (Streamlit/ │ │ Backend │ │ Multilingual │
│ curl/app) │◀────│ :8000 │◀────│ Toxicity Model │
└──────────────┘ └──────┬───────┘ └───────────────────────┘
│
┌──────▼───────┐
│ Language │
│ Detection │
│ (langdetect)│
└──────────────┘
Request flow: Text input → Language detection → Text sanitisation → Tokenization → Model inference → Sigmoid → Language-aware thresholding → Structured JSON response
git clone https://github.com/SonaliBalekundri/multilingual-content-moderator.git
cd multilingual-content-moderator
docker-compose up --build
Then open:
Prerequisites: Python 3.12, pip
git clone https://github.com/SonaliBalekundri/multilingual-content-moderator.git
cd multilingual-content-moderator
python -m venv venv
source venv/bin/activate # Windows: .\venv\Scripts\Activate
pip install -r requirements.txt
# Terminal 1: Run API
uvicorn app.main:app --reload --port 8000
# Terminal 2: Run Dashboard
streamlit run streamlit_app.py
First request will take ~30 seconds (model download + loading). Subsequent requests: 16–40ms.
pytest tests/test_moderator.py -v
# Performance benchmarks (API must be running)
python tests/test_performance.py
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/moderate | Moderate a single text |
| POST | /api/v1/moderate/batch | Moderate up to 100 texts |
| GET | /api/v1/languages | List supported languages |
| GET | /api/v1/categories | List moderation categories |
| GET | /api/v1/health | Health check with model status |
Example request:
curl -X POST http://localhost:8000/api/v1/moderate \
-H "Content-Type: application/json" \
-d '{"text": "You are a disgusting person"}'
Example response:
{
"text": "You are a disgusting person",
"language": "en",
"verdict": "toxic",
"categories": {
"toxic": {"score": 0.9301, "flagged": true},
"not_toxic": {"score": 0.1017, "flagged": false}
},
"confidence": 0.9301,
"processing_time_ms": 40.03,
"threshold_used": 0.5,
"warnings": []
}
See API_DOCS.md for full documentation with all endpoints, examples, and error handling.
The interactive dashboard provides:
Model: citizenlab/distilbert-base-multilingual-cased-toxicity
| Metric | English | Hindi | Arabic | Overall |
|---|---|---|---|---|
| Threshold | 0.50 | 0.15 | 0.20 | — |
| Benchmark Accuracy | — | — | — | 91.7% (11/12) |
Performance (CPU):
| Metric | Value |
|---|---|
| Single request latency | 16–40ms |
| Batch (50 texts) throughput | 14.6 texts/sec |
| Model load time | ~2.3 seconds |
The same toxic content scores differently across languages due to training data bias:
"You are stupid" → EN score: 0.93 (easily caught at 0.50)
"तुम बेवकूफ हो" → HI score: 0.42 (missed at 0.50, caught at 0.15)
"أنت غبي" → AR score: 0.34 (missed at 0.50, caught at 0.20)
Without per-language thresholds, Hindi and Arabic toxic content goes undetected. This is the key insight from our model evaluation.
Two models were evaluated during Week 1:
| Model | Accuracy | Key Issue |
|---|---|---|
unitary/multilingual-toxic-xlm-roberta | 50% | Inverted scores — clean text scored higher than toxic |
citizenlab/distilbert-base-multilingual-cased-toxicity | 91.7% | Selected — correct score separation with calibrated thresholds |
| Layer | Technologies |
|---|---|
| ML/AI | PyTorch (CPU), Hugging Face Transformers (DistilBERT multilingual), langdetect |
| Backend | FastAPI, Pydantic, Uvicorn |
| Frontend | Streamlit, Plotly |
| Infrastructure | Docker, Docker Compose, WSL 2 |
| Testing | pytest (31 tests), FastAPI TestClient |
| Utilities | pandas, matplotlib, requests |
multilingual-content-moderator/
├── app/
│ ├── main.py # FastAPI application entry point
│ ├── config.py # Settings, thresholds, language aliases
│ ├── api/
│ │ └── routes.py # API endpoint handlers
│ ├── models/
│ │ └── moderator.py # ML model wrapper (ContentModerator)
│ ├── schemas/
│ │ └── moderation.py # Pydantic request/response models
│ └── utils/
│ └── language.py # Language detection + alias mapping
├── tests/
│ ├── test_moderator.py # 31 tests (language, model, API)
│ └── test_performance.py # Performance benchmarking script
├── streamlit_app.py # Interactive dashboard
├── docs/
│ └── demo.mp4 # Demo recording
├── API_DOCS.md # Full API documentation
├── Dockerfile # Multi-stage container build (CPU-only PyTorch)
├── docker-compose.yml # API + Streamlit orchestration
├── .dockerignore # Exclude venv, .git, __pycache__ from image
└── requirements.txt # Python dependencies
MIT
A FastAPI service that detects toxicity, hate speech, spam, and harmful content across multiple languages (English, Hindi, Arabic) using Hugging Face transformer models.
Python
0
13 commits
updated Apr 26, 2026
A FastAPI-powered content moderation service that detects toxicity and harmful content across English, Hindi, and Arabic using Hugging Face transformer models. Features language-aware threshold calibration to handle cross-lingual bias in multilingual NLP models.
/docsdocker-compose up┌──────────────┐ ┌──────────────┐ ┌───────────────────────┐
│ Client │────▶│ FastAPI │────▶│ DistilBERT │
│ (Streamlit/ │ │ Backend │ │ Multilingual │
│ curl/app) │◀────│ :8000 │◀────│ Toxicity Model │
└──────────────┘ └──────┬───────┘ └───────────────────────┘
│
┌──────▼───────┐
│ Language │
│ Detection │
│ (langdetect)│
└──────────────┘
Request flow: Text input → Language detection → Text sanitisation → Tokenization → Model inference → Sigmoid → Language-aware thresholding → Structured JSON response
git clone https://github.com/SonaliBalekundri/multilingual-content-moderator.git
cd multilingual-content-moderator
docker-compose up --build
Then open:
Prerequisites: Python 3.12, pip
git clone https://github.com/SonaliBalekundri/multilingual-content-moderator.git
cd multilingual-content-moderator
python -m venv venv
source venv/bin/activate # Windows: .\venv\Scripts\Activate
pip install -r requirements.txt
# Terminal 1: Run API
uvicorn app.main:app --reload --port 8000
# Terminal 2: Run Dashboard
streamlit run streamlit_app.py
First request will take ~30 seconds (model download + loading). Subsequent requests: 16–40ms.
pytest tests/test_moderator.py -v
# Performance benchmarks (API must be running)
python tests/test_performance.py
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/moderate | Moderate a single text |
| POST | /api/v1/moderate/batch | Moderate up to 100 texts |
| GET | /api/v1/languages | List supported languages |
| GET | /api/v1/categories | List moderation categories |
| GET | /api/v1/health | Health check with model status |
Example request:
curl -X POST http://localhost:8000/api/v1/moderate \
-H "Content-Type: application/json" \
-d '{"text": "You are a disgusting person"}'
Example response:
{
"text": "You are a disgusting person",
"language": "en",
"verdict": "toxic",
"categories": {
"toxic": {"score": 0.9301, "flagged": true},
"not_toxic": {"score": 0.1017, "flagged": false}
},
"confidence": 0.9301,
"processing_time_ms": 40.03,
"threshold_used": 0.5,
"warnings": []
}
See API_DOCS.md for full documentation with all endpoints, examples, and error handling.
The interactive dashboard provides:
Model: citizenlab/distilbert-base-multilingual-cased-toxicity
| Metric | English | Hindi | Arabic | Overall |
|---|---|---|---|---|
| Threshold | 0.50 | 0.15 | 0.20 | — |
| Benchmark Accuracy | — | — | — | 91.7% (11/12) |
Performance (CPU):
| Metric | Value |
|---|---|
| Single request latency | 16–40ms |
| Batch (50 texts) throughput | 14.6 texts/sec |
| Model load time | ~2.3 seconds |
The same toxic content scores differently across languages due to training data bias:
"You are stupid" → EN score: 0.93 (easily caught at 0.50)
"तुम बेवकूफ हो" → HI score: 0.42 (missed at 0.50, caught at 0.15)
"أنت غبي" → AR score: 0.34 (missed at 0.50, caught at 0.20)
Without per-language thresholds, Hindi and Arabic toxic content goes undetected. This is the key insight from our model evaluation.
Two models were evaluated during Week 1:
| Model | Accuracy | Key Issue |
|---|---|---|
unitary/multilingual-toxic-xlm-roberta | 50% | Inverted scores — clean text scored higher than toxic |
citizenlab/distilbert-base-multilingual-cased-toxicity | 91.7% | Selected — correct score separation with calibrated thresholds |
| Layer | Technologies |
|---|---|
| ML/AI | PyTorch (CPU), Hugging Face Transformers (DistilBERT multilingual), langdetect |
| Backend | FastAPI, Pydantic, Uvicorn |
| Frontend | Streamlit, Plotly |
| Infrastructure | Docker, Docker Compose, WSL 2 |
| Testing | pytest (31 tests), FastAPI TestClient |
| Utilities | pandas, matplotlib, requests |
multilingual-content-moderator/
├── app/
│ ├── main.py # FastAPI application entry point
│ ├── config.py # Settings, thresholds, language aliases
│ ├── api/
│ │ └── routes.py # API endpoint handlers
│ ├── models/
│ │ └── moderator.py # ML model wrapper (ContentModerator)
│ ├── schemas/
│ │ └── moderation.py # Pydantic request/response models
│ └── utils/
│ └── language.py # Language detection + alias mapping
├── tests/
│ ├── test_moderator.py # 31 tests (language, model, API)
│ └── test_performance.py # Performance benchmarking script
├── streamlit_app.py # Interactive dashboard
├── docs/
│ └── demo.mp4 # Demo recording
├── API_DOCS.md # Full API documentation
├── Dockerfile # Multi-stage container build (CPU-only PyTorch)
├── docker-compose.yml # API + Streamlit orchestration
├── .dockerignore # Exclude venv, .git, __pycache__ from image
└── requirements.txt # Python dependencies
MIT