A safety-aware Flask application that combines symptom-pattern classification with a locally hosted, fine-tuned Llama 2 medical chatbot.
Warning
This repository is an educational and research demonstration. It does not provide medical diagnosis, triage, prescriptions, or treatment advice. Its models have not been clinically validated or approved as medical devices.
This project brings two machine-learning experiences into one professional Flask application:
- a Random Forest classifier that compares selected symptoms with patterns in a bundled demonstration dataset and returns three ranked condition labels;
- a conversational assistant powered by
younesgu/medical_chatbot, Younes Guendoul's QLoRA fine-tuned Llama 2 adapter.
The chatbot was fine-tuned by Younes on approximately 275K real
patient–doctor conversations that he collected, cleaned, and converted to
Llama 2 instruction format. The published
medicalQALlama2
dataset viewer currently reports approximately 276K training rows.
Suggested GitHub description: Safety-aware Flask app combining a Random Forest symptom explorer with a locally hosted Llama 2 medical chatbot fine-tuned on 275K patient–doctor conversations.
- Responsive, accessible symptom-search and chatbot interface.
- 131 normalized symptom features and 41 demonstration condition labels.
- Three ranked classifier matches with careful score interpretation.
- Local PEFT inference using Younes Guendoul's medical Llama 2 adapter.
- Conversation-aware prompts using the Llama 2
[INST]format used in training. - Lazy model loading: the 7B base model is not downloaded during app startup.
- Configurable CPU, CUDA, and optional 4-bit inference modes.
- Emergency-language handoff and blocking of individualized medication requests.
- No default persistence of symptoms, prompts, or generated responses.
- Payload validation, safe DOM rendering, security headers, tests, CI, and Docker.
- Historical prototype artifacts retained in isolation and never loaded at runtime.
| Component | Details |
|---|---|
| Chatbot adapter | younesgu/medical_chatbot |
| Base model | NousResearch/Llama-2-7b-chat-hf |
| Fine-tuning method | QLoRA / PEFT LoRA (r=64, alpha=16, q_proj and v_proj) |
| Training data | younesgu/medicalQALlama2 |
| Training scale | Approximately 275K patient–doctor conversations |
| Prompt format | <s>[INST] patient question [/INST] doctor-style answer |
| Intended use | Education, research, and non-clinical prototyping |
The Hub model is a PEFT adapter, not a standalone 7B checkpoint. At runtime,
AutoPeftModelForCausalLM loads the Llama 2 base model and applies Younes's LoRA
weights. This is why the first request requires a network connection and enough
disk space for both repositories.
flowchart TD
A[Browser interface] --> B[Flask application]
B --> C[Symptom validation]
C --> D[Random Forest classifier]
D --> E[Three ranked patterns]
B --> F[Safety gates]
F --> G[Llama 2 base + Younes's PEFT adapter]
The classifier and chatbot run locally in the application process. User prompts are not sent to a hosted inference API.
- Python 3.10, 3.11, 3.12, or 3.13
pip- Internet access for the first Hugging Face model download
- Sufficient disk and memory for a Llama 2 7B model
Python 3.11 is recommended. CPU inference is supported but can be very slow and requires substantial system RAM. A CUDA-capable GPU with 4-bit loading is the recommended interactive setup.
py -3.11 -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
python app.pyIf PowerShell blocks activation for the current session:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
.\.venv\Scripts\Activate.ps1python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
python app.pyOpen http://127.0.0.1:5000. The symptom classifier trains at startup. The chatbot downloads and loads only when the first non-blocked chat question is submitted; that first response can take several minutes.
If the machine cannot host a 7B model, the symptom explorer can still run:
python -m pip install -r requirements-core.txtSet MEDICAL_CHATBOT_ENABLED=0 in .env. Chat requests will then report that
the chatbot is disabled instead of silently using a different model.
Install the optional quantization runtime:
python -m pip install -r requirements-gpu.txtThen configure:
MEDICAL_CHATBOT_DEVICE=cuda
MEDICAL_CHATBOT_QUANTIZATION=4bitYour PyTorch installation must match the CUDA version installed on the host.
See the official PyTorch selector if
the default wheel does not detect the GPU. The app fails with a clear 503
response if CUDA or bitsandbytes is requested but unavailable.
Copy .env.example to .env and adjust only what is needed:
| Variable | Default | Purpose |
|---|---|---|
MEDICAL_CHATBOT_ENABLED |
1 |
Enable local chatbot inference |
MEDICAL_CHATBOT_MODEL_ID |
younesgu/medical_chatbot |
PEFT adapter repository |
MEDICAL_CHATBOT_DEVICE |
auto |
auto, cpu, or cuda |
MEDICAL_CHATBOT_QUANTIZATION |
none |
none or CUDA 4bit |
MEDICAL_CHATBOT_MAX_INPUT_TOKENS |
1536 |
Maximum prompt context |
MEDICAL_CHATBOT_MAX_NEW_TOKENS |
256 |
Maximum generated tokens |
MEDICAL_CHATBOT_TEMPERATURE |
0.2 |
Sampling temperature; 0 is deterministic |
MEDICAL_CHATBOT_TOP_P |
0.9 |
Nucleus-sampling threshold |
HF_TOKEN |
empty | Optional Hugging Face access token |
The published adapter and dataset are public, so HF_TOKEN is normally not
required. Never commit a token or populated .env file.
| Method | Endpoint | Purpose |
|---|---|---|
GET |
/ |
Search symptoms and open the chatbot |
POST |
/predict |
Return three ranked symptom patterns |
POST |
/api/chat |
Generate a safety-guarded local chatbot response |
GET |
/api/chat/status |
Report chatbot configuration and load state |
GET |
/health |
Report application and model metadata |
Example chat request:
{
"message": "What are common causes of a headache?",
"history": [
{"role": "user", "content": "Hello"},
{"role": "assistant", "content": "How can I help?"}
]
}History is limited to three complete user/assistant turns. Messages are limited
to 1,000 characters and rendered in the browser using textContent.
.
├── app.py # Development entry point
├── src/medical_diagnosis/
│ ├── predictor.py # Dataset repair, training, and inference
│ ├── chatbot.py # Lazy PEFT loading and local generation
│ ├── assistant.py # Safety gates and reviewed fallback logic
│ ├── web.py # App factory, routes, and headers
│ ├── resources/ # Classifier CSV and reviewed guidance
│ ├── static/ # Responsive styles and JavaScript
│ └── templates/ # Accessible Jinja templates
├── tests/ # Unit and route tests; no model download
├── scripts/evaluate.py # Deduplicated classifier evaluation
├── docs/ # Classifier/chatbot cards and security notes
├── notebooks/ # Original model exploration
├── contracts/ # Isolated hash-only audit example
├── legacy/ # Non-runtime historical artifacts
├── Dockerfile
├── pyproject.toml
└── requirements*.txt
The original CSV contains 4,920 records, 132 raw symptom columns, and 41 labels.
An audit found 4,616 exact duplicate records, one duplicate feature column, and
three malformed feature names. The production loader derives the schema from
the CSV, repairs the headers, merges fluid_overload, strips target whitespace,
and trains on 304 unique records across 131 features.
Run the reproducible, deduplicated evaluation:
python scripts/evaluate.pySee docs/MODEL_CARD.md. Offline classifier scores are not
evidence of clinical validity.
python -m pip install -r requirements-dev.txt
python -m ruff check .
python -m pytestTests inject a deterministic fake generator, so they validate prompt formatting, history handling, safety gates, routes, schema repair, and prediction behavior without downloading the Llama 2 model.
docker build -t medical-symptom-explorer .
docker run --rm -p 8000:8000 medical-symptom-explorerOpen http://127.0.0.1:8000. The container intentionally runs one Gunicorn worker so the 7B model is not duplicated in memory. Mount a persistent Hugging Face cache for repeated deployments and pass GPU access explicitly when using CUDA.
- Emergency expressions bypass generation and display an emergency-services handoff.
- Requests for a prescription, dose, or instruction to start/stop medication are blocked before reaching the model.
- A system prompt enforces educational scope, uncertainty, and clinician referral.
- The app does not write prompts, symptoms, or generated messages to a database.
- Model downloads contact Hugging Face, but chat content remains in local memory.
- Generated answers can be incomplete, biased, outdated, or factually wrong.
- Training conversations can contain noisy, sensitive, or unsafe source language.
- Keyword safeguards are limited and are not a clinical safety system.
- No output should be used for real diagnosis, triage, or treatment decisions.
Read docs/CHATBOT_MODEL_CARD.md and
docs/SECURITY.md before deployment. Any real health use
requires clinical, legal, privacy, and security review.
The original Keras intent chatbot and version-sensitive scikit-learn pickle are
retained under legacy/ for project history. They are not loaded by
the application. The active conversational model is the Hugging Face PEFT
adapter documented above.