Spaces:
Configuration error
Configuration error
dfk-text-classifier
A Modal deployment of aitf-komdigi/KomdigiITS-8B-DFK-TextClassification β a fine-tuned 8.9B Mistral3 model served as a GPU-backed FastAPI endpoint for Indonesian social media content analysis.
The model classifies content into DFK categories (Disinformasi, Fitnah, Kebencian) and can also summarize text in Bahasa Indonesia.
Features
- DFK classification β detects disinformation, slander, and hate speech from structured social media post metadata
- Summarization mode β summarizes Indonesian text using the base model's general capability (no classification bias)
- Multi-trial MTLA voting β runs N generation trials, scores each via logit-based confidence (K=10 tokens), then majority-votes the result
- Greedy mode β
temperature: 0with single trial for fastest deterministic inference - CPU memory snapshot β model weights snapshotted after first load for faster cold start on subsequent requests
- JSON sanitizer β middleware that fixes copy-pasted text containing literal newline characters inside JSON strings
Setup
pip install modal
modal setup
If the HF repo is private, create a Modal secret:
modal secret create huggingface-secret HF_TOKEN=hf_your_token_here
Then add secrets=[modal.Secret.from_name("huggingface-secret")] to @app.cls(...) in modal_dfk_v3.py.
Commands
# Dev server (hot-reload, temporary endpoint URL printed to console)
modal serve modal_dfk_v3.py
# Production deploy
modal deploy modal_dfk_v3.py
# Stream logs
modal app logs dfk-text-classification-v3
API
Endpoint: POST https://gghafar--dfk-text-classification-v3-dfkmodel-serve.modal.run
DFK Classification
{
"ringkasan": "Summary of the social media post",
"klaim": "Claim made in the post",
"fakta": "Verified fact for comparison",
"image_url": "https://...",
"max_new_tokens": 128,
"temperature": 0.0,
"num_trials": 3
}
Response:
{
"label": "DISINFORMASI",
"label_key": "disinformasi",
"description": "Informasi yang menyesatkan",
"confidence": 97.7,
"consistency": "3/3",
"ambiguous": false,
"reasoning": "...",
"method": "Unsloth LogitsScore K=10, N=3",
"trials": [
{ "trial": 1, "label": "DISINFORMASI", "confidence": 97.7, "reasoning": "..." },
{ "trial": 2, "label": "DISINFORMASI", "confidence": 97.7, "reasoning": "..." },
{ "trial": 3, "label": "DISINFORMASI", "confidence": 97.7, "reasoning": "..." }
]
}
Summarization
{
"text": "Teks yang ingin diringkas...",
"temperature": 0.3
}
Response:
{
"summary": "Ringkasan teks...",
"original_length": 668,
"summary_length": 312
}
Classification Input Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
ringkasan |
string | yes | β | Summary/context of the social media post |
klaim |
string | yes | β | The specific claim or statement to classify |
fakta |
string | yes | β | Verified fact(s) to compare the claim against |
image_url |
string | no | null | Optional image URL for additional context |
max_new_tokens |
int | no | 128 | Max tokens to generate (32β1024) |
temperature |
float | no | 0.0 | Sampling temperature. 0 = greedy. If > 0 and num_trials > 1, enables MTLA voting |
num_trials |
int | no | 3 | Number of generation trials for voting (1β10). Auto-raises temperature to 0.3 when temperature: 0 and num_trials > 1 |
DFK Labels
| Label | Description |
|---|---|
Fakta |
Content consistent with verified facts |
Disinformasi |
Misleading or inaccurate information |
Fitnah |
Serious accusations without verifiable evidence |
Ujaran Kebencian |
Content attacking or degrading individuals/groups |
Non-DFK |
Content outside DFK categories |
Architecture
File: modal_dfk_v3.py
| Component | Description |
|---|---|
DFKModel |
Modal class on L4 GPU. Loads model via @modal.enter(snap=True), builds FastAPI routes via @modal.enter() (always fresh, never stale from snapshot). |
POST /classify |
Structured DFK classification with MTLA multi-trial voting. |
POST /summarize |
Indonesian text summarization using a summarization system prompt. |
_mtla_confidence |
Computes logit-based confidence score from first K generated token probabilities. |
_parse_output |
Extracts [LABEL], [CONFIDENCE], and [REASONING] blocks from raw model output. |
| HF Volume cache | modal.Volume named dfk-8b-cache persists downloaded weights across cold starts. |
Model loading flow:
snap=Trueβ downloads weights (cached in Volume), loads model + tokenizer via UnslothFastLanguageModel.from_pretrainedin bfloat16 β snapshot takensnap=False(default@modal.enter) β rebuilds FastAPI app with fresh endpoint handlers so code changes take effect immediately after every redeploy
Generation Parameters
| Parameter | Default | Description |
|---|---|---|
max_new_tokens |
128 | Maximum tokens to generate |
temperature |
0.0 | 0 = greedy (single trial). > 0 = sampling with MTLA voting |
num_trials |
3 | Number of parallel generation trials for majority voting |
repetition_penalty |
1.05 | Penalizes repeated tokens (hardcoded) |
Infrastructure
| Setting | Value |
|---|---|
| GPU | NVIDIA L4 (24 GB VRAM) |
| CPU | 4 vCPU |
| Memory | 24 GB RAM |
| Timeout | 600s |
| Scale-down | 300s idle |
| Precision | bfloat16 (full size, no quantization) |
| Snapshot | CPU memory snapshot enabled |
| Model | aitf-komdigi/KomdigiITS-8B-DFK-TextClassification |
| Parameters | 8.9B |