Medical Anamnesis Chatbot with NLP (Chatbot PUSTU)
Production-ready medical chatbot achieving 92.61% intent classification accuracy using Multinomial Naive Bayes for Indonesian Puskesmas healthcare anamnesis workflow. Automated training data generation via Gemini Flash 2.0 API with custom NLP preprocessing pipeline built from scratch.
Role
Full Stack Developer & NLP Engineer
Client
Academic Project - Natural Language Processing Course
Team
2-person Team
Timeline
5 month • 2025

Skills & Tools
Skills Applied
Tools & Software
Challenges
Building production NLP system for Indonesian medical terminology without external Indonesian NLP libraries. Generating high-quality balanced training data across 14 intent classes with medical domain vocabulary. Implementing stateful 14-stage dialog management with context-aware entity extraction and smart prefilling algorithm.
Solutions
Automated training data generation using Gemini Flash 2.0 with custom prompt engineering for Indonesian medical context (14,000 samples). Built NLP preprocessing pipeline from scratch with custom slang normalization (94 mappings) and stopword filtering (93 words). Implemented dictionary-based NER system using regex patterns and context-aware extraction without external NLP libraries. Hybrid prediction combining ML model outputs with keyword boosting (0.90-0.95 confidence thresholds).
Impact
Successfully streamlined patient anamnesis workflow for Indonesian Puskesmas healthcare workers. Achieved production-grade 92.61% accuracy on medical intent classification. 24/7 cloud deployment enables immediate adoption without infrastructure requirements. Demonstrates feasibility of building domain-specific NLP systems for low-resource languages using LLM-powered data generation and classical ML techniques.
Project Overview
Chatbot PUSTU is a full-stack medical anamnesis chatbot for Indonesian Puskesmas (community health centers). Built for a Natural Language Processing course, it uses Multinomial Naive Bayes with TF-IDF vectorization to reach 92.61% intent classification accuracy across 14 Indonesian medical intent classes — covering the full pipeline from LLM-powered data generation to a custom NER system, stateful dialog management, and 24/7 cloud deployment.
Healthcare Problem
Indonesian Puskesmas struggle with slow, inconsistent patient anamnesis: 15+ minutes of manual history-taking per patient, non-standardized records, and a lack of robust Indonesian medical NLP tooling — all while small clinics cannot afford commercial EMR systems.
Technical Architecture
Three-tier system with an ML-powered backend:
- Frontend (Vercel) — Next.js 16 + TypeScript chat UI with conversation history, dark/light mode, and client-side PDF export.
- Backend (Railway) — Flask + Gunicorn serving intent classification, entity extraction, dialog state, and smart prefilling.
- ML pipeline — Multinomial Naive Bayes (alpha=0.1) over TF-IDF features (5,000 features, 1–2 n-grams), custom preprocessing, and dictionary-based NER (97 symptoms, 23 body locations) with hybrid keyword boosting.
Training Data Generation (Gemini Flash 2.0)
With no existing Indonesian medical anamnesis dataset, I generated 14,000 balanced samples (1,000 each across 14 intents) using Gemini Flash 2.0 with prompt engineering tuned for colloquial Indonesian medical language — total cost roughly $3.50 on the free tier.
The 14 intents span the full interview: chief complaint, accompanying symptoms, duration, location, severity, medical history, medications, allergies, and risk factors, plus conversational intents (greeting, thanks, confirmation, denial, unclear).
NLP Preprocessing (Built From Scratch)
Because Indonesian NLP libraries lack medical vocabulary and slang handling, I built a custom pipeline: lowercasing, punctuation removal, tokenization, slang normalization (94 mappings, e.g. gak → tidak, udah → sudah), and stopword filtering (93 words).
Example: "Dok saya batuk gak sembuh-sembuh udah 3 hari" becomes "batuk tidak sembuh sudah 3 hari".
Custom Named Entity Recognition
With no pre-trained Indonesian medical NER available, entities are extracted via dictionary and regex matching: a 97-type symptom dictionary (with synonyms), 23 body locations, and 3 severity levels. Duration extraction uses context keywords (sudah, sejak, selama, sekitar) to avoid false positives — "batuk sudah 3 hari" is captured while "umur saya 28 tahun" is correctly rejected.
NER validation (500-sample manual test):
| Entity Type | Precision | Recall | F1-Score |
|---|---|---|---|
| Symptoms | 94.2% | 87.3% | 90.6% |
| Body Locations | 96.1% | 89.7% | 92.8% |
| Duration | 92.5% | 88.1% | 90.2% |
| Severity | 89.3% | 85.6% | 87.4% |
Intent Classification
Naive Bayes was chosen for sub-10ms inference, roughly 2s training on 14K samples, native handling of sparse TF-IDF features, and interpretable probabilistic outputs for confidence thresholding.
Test set (2,800 samples): 92.61% accuracy with 93% macro precision, recall, and F1. Strongest intents reach 98% F1 (greeting, medication history, unclear); weakest are chief complaint (84%, confused with accompanying symptoms) and severity (89%, ambiguous keywords).
A hybrid layer boosts ML predictions with keyword evidence (0.90–0.95 confidence thresholds), lifting effective accuracy to roughly 94%.
Dialog Management
A 14-stage stateful interview runs from greeting and demographics through complaint, symptoms, duration, location, severity, history, medications, allergies, and risk factors to a final summary. A smart prefilling algorithm auto-fills later stages when a user volunteers information early — "sakit kepala parah sudah 3 hari di bagian kanan" fills symptom, severity, duration, and location at once, cutting average interview time by roughly 30%.
Deployment
The backend runs on Railway (Python 3.10, Gunicorn, models loaded in memory); the frontend on Vercel (global CDN, Next.js 16 / React 19). Both use automatic HTTPS with 24/7 availability.
Key Takeaways
- LLM-generated data is a cost-effective substitute for manual annotation in low-resource domains (roughly $3.50 vs $1,000+).
- Domain-specific dictionaries beat generic Indonesian NLP libraries for medical NER (90%+ F1, no training).
- Classical ML (Naive Bayes + TF-IDF) still delivers production accuracy with roughly 100x faster inference than BERT and zero GPU cost.
- Hybrid prediction and confidence thresholding reduce error rate and enable graceful "ask for clarification" fallbacks.
Live Demo: pustu-anamnesis-chatbot.vercel.app · Source: GitHub Repository · Course: Natural Language Processing, Hasanuddin University, 2025
Project Metrics
92.61% intent classification accuracy on 2,800 test samples
14,000 balanced training samples generated via Gemini Flash 2.0 API
97 symptom types + 23 body locations in custom NER system
14-stage stateful dialog management with smart prefilling
94 slang mappings + 93 stopwords in custom preprocessing pipeline
24/7 cloud deployment (Railway + Vercel)
Credits & Acknowledgments
Gemini Flash 2.0 API by Google for training data generation
Scikit-learn library for Multinomial Naive Bayes classifier
Flask web framework for REST API backend
Next.js 16 with TypeScript for modern frontend
Project Tags
Related Projects
View all projects →
Aspect-Based Sentiment Analysis on Financial News
Fine-tuned RoBERTa-base model for aspect-based sentiment analysis on 10,686 financial news headlines achieving 86.67% accuracy on entity-level sentiment classification with comprehensive handling of severe class imbalance through weighted loss and regularization techniques.

Urban Complaint Pattern Mining on NYC 311 Data (21M+ Records)
End-to-end data mining of 21.3M NYC 311 service requests, discovering a six-complaint 'interior maintenance syndrome' validated against 11M independent housing inspection records. Buildings with the full syndrome show 12-44x higher verified violation rates, holding across building-size strata and a prior time window designed to rule out administrative circularity.

MyFriends - Emergency SOS & Contact Management App
Production-ready emergency SOS app with multi-layered persistent notification system (foreground + background + 60 scheduled alarms), real-time location sharing, and comprehensive contact management using Flutter and Firebase.
