A sentence-level propaganda detection system that combines a locally fine-tuned BERT classifier with LLM-based technique labeling and explainability. Propasafe-Hybrid identifies propagandistic sentences in news articles, assigns specific technique labels from a closed 17-technique taxonomy, and generates concise rationales β all while reducing API token usage through a cost-aware pre-filtering stage that forwards only high-likelihood sentences to the LLM.
Built on top of Propasafe, extending it with an explainability module while preserving its offline, privacy-conscious architecture.
π Paper: Propasafe-Hybrid: A Text-Based Hybrid Propaganda Detection Tool β FLAIRS-39, 2026
π€ BERT Model: Download from Figshare
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
β Browser ExtensionββββββΆβ FastAPI Backend ββββββΆβ OpenAI API β
β (Content Script) βββββββ + BERT Model βββββββ (Batch Request)β
βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
- Article Extraction: Raw HTML fetched via
requests, DOM pre-cleaned withlxml(removes modals, ads, navbars), then text extracted viatrafilaturaβreadability-lxmlβnewspaper3kcascade. Text normalized and tokenized via NLTK Punkt (max 400 sentences). - Local BERT Sieve: All sentences scored by fine-tuned BERT model (batched inference)
- Threshold Filter: Only sentences with
bert_score >= 0.5proceed to LLM - Batched LLM Analysis: Flagged sentences sent to OpenAI in a single request
- Technique Labeling: LLM identifies specific propaganda techniques with evidence
- Docker Desktop
- OpenAI API key
- Fine-tuned BERT model (download here) - place in
backend/app/model/best_model.keras
# Set API key
export OPENAI_API_KEY="sk-..."
# Start container
docker compose up --buildBackend runs at http://127.0.0.1:8000
curl http://127.0.0.1:8000/health
# {"ok": true}Primary endpoint. Streams NDJSON progress events.
curl -X POST http://127.0.0.1:8000/extract-and-classify-hybrid \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/article"}' \
--no-bufferResponse (NDJSON stream):
{"event":"extraction_done","sentence_count":42,"title":"Article Title"}
{"event":"bert_done","threshold":0.5,"flagged_count":6,"total_count":42}
{"event":"openai_request_started","flagged_count":6}
{"event":"results","results":[...]}Result object:
{
"sentence": "Original text",
"bert_score": 0.723,
"severity": "mild",
"techniques": ["Loaded Language"],
"evidence": {"Loaded Language": "Uses emotionally charged terms"},
"llm_status": "ok"
}llm_status values:
okβ LLM confirmed β₯1 techniqueemptyβ LLM returned no techniques (sentence still highlighted by BERT)not_runβ BERT score below threshold, LLM not invokederrorβ API call failed
BERT-only endpoint (no LLM). Returns JSON array of scored sentences.
On-demand detailed explanation for a specific sentence.
curl -X POST http://127.0.0.1:8000/explain-sentence \
-H "Content-Type: application/json" \
-d '{"sentence":"...", "techniques":["Loaded Language"]}'| Variable | Default | Description |
|---|---|---|
OPENAI_API_KEY |
required | OpenAI API key |
OPENAI_MODEL |
gpt-5.2-2025-12-11 |
OpenAI model for technique labeling |
PROPAGANDA_THRESHOLD |
0.5 |
BERT score threshold for LLM analysis |
BERT_BATCH_SIZE |
32 |
Batch size for BERT inference |
MAX_SENTENCES |
400 |
Maximum sentences per article |
PROPASAFE_VERBOSITY |
medium |
LLM response detail: low/medium/verbose |
Verbosity detail:
lowβ€20 word evidence,mediumβ€25 words,verboseβ€30 words + explanation up to 120 words.
Set in .env file or pass as environment variable:
# Option 1: Add to .env file
echo "PROPASAFE_VERBOSITY=verbose" >> .env
# Option 2: Pass directly
PROPASAFE_VERBOSITY=verbose docker compose upChrome extension for in-page propaganda highlighting.
- Open
chrome://extensions - Enable Developer Mode
- Load unpacked from
extension/directory
- Real-time sentence highlighting (yellow=mild, red=severe)
- Click highlights for analysis card with:
- BERT score and severity
- Detected techniques
- Evidence snippets
- On-demand detailed explanations
- Popup with pie chart distribution
propasafe-hybrid/
βββ backend/app/
β βββ main.py # FastAPI endpoints, BERT inference
β βββ openai_client.py # LLM batching, structured outputs
βββ extension/
β βββ content-script.js # In-page highlighting
β βββ popup.html/js # Extension popup with Chart.js
β βββ vendor/ # mark.js, chart.js
βββ extractor/
β βββ app.py # Article extraction
βββ Dockerfile
βββ docker-compose.yml
Fine-tuned on propaganda detection dataset. Model file: backend/app/model/best_model.keras
Severity thresholds:
bert_score >= 0.50: Mild (yellow highlight)bert_score >= 0.75: Severe (red highlight)
Supported propaganda techniques (17):
loaded language Β· name calling or labeling Β· repetition Β· exaggeration or minimization Β· doubt Β· appeal to fear/prejudice Β· flag-waving Β· causal oversimplification Β· slogans Β· appeal to authority Β· black-and-white fallacy Β· thought-terminating cliche Β· whataboutism Β· reductio ad hitlerum Β· red herring Β· bandwagon Β· obfuscation/intentional vagueness/confusion
- Thomas Kimmeth β John Jay College of Criminal Justice, CUNY
- Avijit Roy β John Jay College of Criminal Justice, CUNY Β· GitHub Β· Website
- Vivek Sharma β John Jay College of Criminal Justice, CUNY
If you use this work, please cite:
@article{kimmeth2026propasafe,
title={Propasafe-Hybrid: A Text-Based Hybrid Propaganda Detection Tool},
author={Kimmeth, Thomas and Roy, Avijit and Sharma, Vivek},
journal={The International FLAIRS Conference Proceedings},
volume={39},
number={1},
year={2026},
month={May},
doi={10.32473/flairs.39.1.141595},
url={https://journals.flvc.org/FLAIRS/article/view/141595}
}This project is licensed under the MIT License.