Skip to content

About

Continual-learning MLOps system for Indonesian sentiment analysis

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

SlangGuard

A continual-learning MLOps system for Indonesian sentiment analysis. When the language in new data changes (drift), the system retrains the model with LoRA + replay, so it learns new slang without forgetting old data.

Status

Done: data pipeline (DVC), baselines, the LoRA + replay method, a prediction API with Docker and CI, the retraining pipeline (drift check, Kaggle GPU, promotion rule, registry, API switch) run end to end on real services, monitoring with Prometheus and Grafana, a public demo, and a separate abusive language flag in the API.

Try it: https://huggingface.co/spaces/amc76/slangguard-demo. The model runs in your browser, so nothing you type is sent anywhere. See docs/design.md for the full design and roadmap.

Tech stack

Modeling

Python PyTorch Hugging Face

Data and experiments

DVC MLflow DagsHub pandas Jupyter Kaggle

Drift and pipeline

Evidently AI Prefect

Serving

FastAPI Pydantic Docker

Quality and tooling

GitHub Actions pytest Ruff uv Git GitHub

Monitoring

Prometheus Grafana

Demo

ONNX JavaScript HTML5 Gradio

Badges are made with shields.io in the style of ileriayo/markdown-badges.

Results

Language change is simulated: four periods, from formal reviews to tweets that are increasingly rewritten with slang. P3 and P4 are not real future language. Mean over 3 seeds, macro-F1 on the test sets of all four periods after the last update:

Method AvgF1 P1 (oldest period) Training time of the last update
Naive fine-tune (new data only) 0.677 0.759 32 s
Full retrain on all data 0.724 0.925 328 s
LoRA + 5% replay 0.725 0.900 29 s

Details and limits: docs/results.md and docs/baselines.md. The trained adapter is on Hugging Face: amc76/slangguard-indobert-lora-replay.

Run the API

You need Docker. The first start downloads the model (about 480 MB, a few minutes), and later starts take seconds.

docker compose up

Then, in another terminal:

curl -X POST localhost:8000/predict -H 'Content-Type: application/json' \
  -d '{"texts": ["makanannya enak banget, pelayanannya ramah", "parah sih, lama banget nunggunya"]}'

The answer has a sentiment label and the three class probabilities for each text, in the same order, and a separate flag for abusive language (abusive and abusive_score), see below. Interactive documentation is at http://localhost:8000/docs, and GET /health shows the model version. Stop with docker compose down. Without Docker: uv run uvicorn src.serving.app:create_default_app --factory.

One sentence takes about 60 ms in Docker on a laptop CPU, and the container uses about 1 GB.

Abusive language flag

Sentiment is not rudeness: "kontol" alone can score as neutral in sentiment. So a second small model (TF-IDF over letter groups and logistic regression, 1.3 MB) flags abusive words, and the API returns it next to the sentiment: "abusive": true, "abusive_score": 1.0. F1 is 0.893 on its own test set. Its first version flagged plain praise like "enak banget", which only showed up when it was checked on this project's own text, and the fix is described in docs/abusive.md. The model is CC BY-NC-SA 4.0 because its data is: amc76/slangguard-abusive. The demo in the browser does not show it yet.

Monitoring

The API reports request counts, latency, the mix of predicted labels and word pieces per word (a live sign that slang is arriving). It is optional and does not start with the API:

docker compose --profile monitoring up    # Grafana at http://localhost:3000, Prometheus at :9090

The Grafana dashboard after traffic from P1 to P4

Details, the metrics and what was measured: docs/monitoring.md.

The demo

The page at https://huggingface.co/spaces/amc76/slangguard-demo loads an 8-bit version of the model into your browser (about 125 MB on the first visit). It is a static page because Gradio Spaces now need a paid plan. How it was built and checked against the Python model: docs/demo.md. To try the model with Gradio on your own computer: PYTHONPATH=. uv run python demo/app.py.

Retraining pipeline

New text is checked for drift with Evidently. If the language changed, a Prefect flow trains a copy of the current model on a Kaggle GPU, compares it with the current one on validation sets, and switches the API only if it passes. How it works, how it was calibrated, and what has been run for real: docs/pipeline.md.

Develop

uv sync                  # all dependencies
uv run ruff check . && uv run ruff format --check . && uv run pytest

Training runs on Kaggle (see notebooks/), and the data is tracked with DVC.

About

Continual-learning MLOps system for Indonesian sentiment analysis

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages