Clinical pharmacokinetic decision-support platform — Personalised drug-interaction analysis, Monte Carlo uncertainty quantification, and evidence-traceable audit trails. For healthcare professionals only. All outputs are decision support, not medical advice.
AbsorbAI resolves polypharmacy conflicts before they become pharmacokinetic failures. Every analysis runs through a 10-layer clinical engine that:
- Personalises PK parameters to the individual patient (age, weight, renal/hepatic function, CYP enzyme activity)
- Simulates drug concentration over time with a two-compartment model + Monte Carlo uncertainty (100–500 samples)
- Detects drug–drug and drug–food interactions from a merged knowledge graph (45 curated drugs, 170+ DDI/FDI)
- Optimises dosing schedules via Pareto frontier (minimise peak risk, maximise trough efficacy)
- Stress-tests regimens against missed doses, renal impairment, hepatic impairment, and elderly scenarios
- Explains every recommendation with a traversable reasoning chain and immutable audit trail
- Updates patient-specific Bayesian PK posteriors from real lab observations, persisted across server restarts
# 1. Clone and create virtualenv
git clone https://github.com/jeyadev-jd/AbsorbAI.git
cd AbsorbAI
python -m venv venv
venv\Scripts\activate # Windows
# source venv/bin/activate # Linux/macOS
# 2. Install dependencies
pip install -r requirements.txt
# 3. Configure environment
cp .env.example .env # edit SECRET_KEY and DEBUG=true
# 4. Run migrations
python manage.py migrate
# 5. Seed demo users (optional)
python manage.py shell -c "
from core.models import AbsorbUser, Patient
AbsorbUser.objects.create_user(username='doctor@demo.com', email='doctor@demo.com', password='doctor123', role='doctor', first_name='Demo', last_name='Doctor')
u = AbsorbUser.objects.create_user(username='patient@demo.com', email='patient@demo.com', password='patient123', role='patient', first_name='Demo', last_name='Patient', patient_key='demo')
Patient.objects.get_or_create(patient_key='demo', defaults={'name':'Demo Patient','age':35,'weight':70,'height':170,'sex':'M'})
"
# 6. Start server
python manage.py runserver
# Visit http://127.0.0.1:8000Demo credentials
| Role | Password | |
|---|---|---|
| Doctor | doctor@demo.com | doctor123 |
| Patient | patient@demo.com | patient123 |
| Layer | Module | What it does |
|---|---|---|
| 0 | input_validator.py |
Data quality scoring, confidence-weighted Monte Carlo scaling |
| 1 | biological_twin.py |
Patient physiological personalisation (CrCl, Child-Pugh, CYP activity) |
| 2 | pk_pd_engine.py |
Two-compartment PK + Bliss/Loewe multi-drug interaction |
| 3 | knowledge_graph.py |
NetworkX causal pharmacology graph — drugs, enzymes, transporters |
| 4 | uncertainty_engine.py |
Monte Carlo credible intervals, Bayesian posterior updating |
| 5 | optimizer.py |
Pareto-optimal dosing schedule optimisation |
| 6 | adversarial_engine.py |
Missed-dose, double-dose, renal/hepatic stress tests |
| 7 | explainability.py |
Step-by-step reasoning chain + immutable compliance audit log |
| 8 | gemma_engine.py |
Evidence-based prescription suggestions (13 condition families) |
| 9 | orchestrator.py |
Bayesian PK update from lab observations, DB-persisted posteriors |
FHIRAdapterparses inbound FHIRBundleresources (Patient,MedicationRequest,Observation,AllergyIntolerance) into the internalpatient_profile/prescriptionsshape the engine consumesFHIRMapperconverts engine output back to FHIR —DetectedIssueper safety violation,RiskAssessmentper PK result,GuidanceResponse— wrapped in a responseBundle- 4 endpoints under
/fhir/(see API Reference); every response carriesContent-Type: application/fhir+jsonplus the samedecision_support_onlydisclaimer as the native JSON API - Async variant (
/fhir/analyze/async/) enqueues a Celery job and returns a pollablerun_id
absorbai_project/celery.pyboots the Celery app; tasks incore/tasks.pyrun_hifi_analysis— after every synchronous analyze call (n=100), re-runs at n=500 in the background and refreshes the cached result in placerun_full_analysis_async— full async run backed by anEngineRunDB row, polled via/api/engine/run/<id>/- Falls back gracefully without a worker: the synchronous n=100 path still returns normally; only the hi-fi refresh and async jobs no-op
- JWT authentication — HttpOnly cookie, role-based access control (
doctor/patient) - Email-format validation on signup + login — regex-enforced server-side
- Rate limiting — per-IP sliding window (60 req/60 s, configurable)
- CORS — django-cors-headers with origin allowlist
- Input validation — negative doses rejected (400), bad patient profile rejected (400), all boundaries checked
- 3-layer disclaimer enforcement — engine level + API level + UI modal gate
- Concentration-vs-time curve with therapeutic window shading
- Monte Carlo AUC/Cmax histogram (5th/50th/95th percentiles)
- Pareto frontier scatter — click a point to change the schedule
- NetworkX knowledge graph rendered as force-directed graph
- Adversarial stress-test grid with fragility badge
- Layer-by-layer progress indicator during analysis
- Step-by-step reasoning chain timeline
- Counterfactual risk contribution bars
- Risk Priority Queue — patients sorted by interaction severity
- Prescribe — drug search with auto-populated instructions, DDI check on add
- AI Suggest — evidence-augmented prescription suggestions by diagnosis
- Interaction Matrix — drug–nutrient DDI/FDI table sorted by severity, click for full evidence citation
- PK Impact — pharmacokinetic summary + counterfactual risk contribution
- Override — clinical override with mandatory justification
- Audit Trail — searchable compliance timeline, full engine trace per recommendation
- Today's medication schedule with dietary separation timings
- Risk summary widget
- Medication list with food effect warnings
- Dietary profile editor
- Dose logging with adherence score
- Language selector: English, Hindi, Tamil, Telugu, Bengali, Marathi, Kannada
- Accessibility mode: Standard, Voice Mode, Large Font
Patient Profile + Prescriptions
│
▼
[Layer 0] Input Validator ← data_confidence score, mc_multiplier
│
▼
[Layer 1] Biological Twin ← personalise PK params per patient physiology
│
▼
[Layer 2] PK/PD Engine ← 2-compartment ODE, Monte Carlo, DDI
│
▼
[Layer 3] Knowledge Graph ← NetworkX causal graph, merged DDI/FDI
│
▼
[Layer 4] Uncertainty Engine ← credible intervals, Bayesian update
│
▼
[Layer 5] Optimizer ← Pareto-optimal schedules (up to 10)
│
▼
[Layer 6] Adversarial Engine ← stress scenarios, counterfactuals
│
▼
[Layer 7] Explainability ← reasoning chain, audit log
│
▼
[Layer 8] Gemma Suggestions ← evidence-based Rx (13 condition families)
│
▼
[Layer 9] Bayesian Update ← real lab obs → updated PK priors (DB-persisted)
│
▼
Result JSON { decision_support_only: true, disclaimer, pk_results,
safety_violations, pareto_solutions, audit_entry_id }
AbsorbAI/
├── absorbai_project/
│ ├── settings.py # CORS, rate limiting, structured logging, startup checks
│ ├── celery.py # Celery app entry point
│ └── urls.py
│
├── core/
│ ├── views.py # 24 API endpoints, JWT auth, role-based access
│ ├── middleware.py # RateLimitMiddleware — per-IP sliding window
│ ├── models.py # AbsorbUser, Patient, PKPrior, AdherenceEvent, EngineRun, AuditEntry
│ ├── tasks.py # Celery tasks — async hi-fi engine runs
│ ├── tests.py # 61 tests — auth, JWT, validation, engine, audit, roles
│ ├── urls.py # 12 API routes + signup
│ │
│ ├── fhir/
│ │ ├── adapter.py # FHIRAdapter (FHIR→internal) + FHIRMapper (internal→FHIR)
│ │ └── views.py # FHIR R4 endpoints (4 routes)
│ │
│ ├── templates/
│ │ └── index.html # Single-page app (~2400 lines, vanilla JS)
│ │
│ ├── static/
│ │ ├── js/engine-viz.js # 8 engine visualisation functions
│ │ └── css/engine-viz.css
│ │
│ ├── drugdb/
│ │ ├── drug_data.py # ~45 drugs, hand-curated with clinical metadata
│ │ └── ddi_database.py # 113 DDI + 20 FDI from OpenFDA
│ │
│ └── engine/
│ ├── orchestrator.py # Layer coordinator, Bayesian persist/restore
│ ├── input_validator.py # Layer 0
│ ├── biological_twin.py # Layer 1
│ ├── pk_pd_engine.py # Layer 2
│ ├── knowledge_graph.py # Layer 3
│ ├── uncertainty_engine.py # Layer 4
│ ├── optimizer.py # Layer 5
│ ├── adversarial_engine.py # Layer 6
│ ├── explainability.py # Layer 7
│ └── gemma_engine.py # Layer 8
│
├── requirements.txt
├── build_ddi_database.py # OpenFDA → ddi_database.py pipeline
└── manage.py
All responses include { "decision_support_only": true, "disclaimer": "..." }.
All engine endpoints require Authorization: Bearer <token> via absorb_jwt cookie.
| Method | Path | Roles | Description |
|---|---|---|---|
| POST | /api/login/ |
— | JWT login → absorb_jwt HttpOnly cookie |
| POST | /api/signup/ |
— | Register new account (patient or doctor) |
| POST | /api/logout/ |
— | Clear cookie |
| Method | Path | Roles | Description |
|---|---|---|---|
| POST | /api/engine/analyze/ |
doctor | Full 10-layer PK/PD analysis |
| POST | /api/engine/observation/ |
doctor | Bayesian update from lab value |
| POST | /api/engine/suggestions/ |
doctor | Evidence-based prescription suggestions |
| GET | /api/engine/audit/ |
doctor | ?patient_id= — audit trail (last 50) |
| GET | /api/engine/run/<id>/ |
doctor | Engine run status |
| Method | Path | Roles | Description |
|---|---|---|---|
| GET | /api/patient/profile/ |
patient, doctor | ?patient_key= — biological twin profile |
| POST | /api/patient/profile/update/ |
doctor | Update physiological parameters |
| Method | Path | Roles | Description |
|---|---|---|---|
| GET | /api/drugs/search/ |
patient, doctor | ?q=&detail=true — autocomplete + clinical metadata |
| GET | /api/drugs/interactions/ |
patient, doctor | ?drug= — merged DDI + FDI |
| Method | Path | Roles | Description |
|---|---|---|---|
| POST | /api/adherence/log/ |
patient, doctor | Log dose event (taken/skipped/late) |
| GET | /api/adherence/history/ |
patient, doctor | ?patient_key= — adherence score + breakdown |
| Method | Path | Description |
|---|---|---|
| POST | /fhir/analyze/ |
FHIR Bundle in → full 10-layer analysis → FHIR Bundle out |
| POST | /fhir/analyze/async/ |
Same, enqueued as Celery job → {run_id} |
| GET | /fhir/patient/<patient_id>/ |
AbsorbAI Patient row → FHIR Patient resource |
| POST | /fhir/observation/ |
FHIR Observation (lab/drug level) → Bayesian PK update |
Analyze request body:
{
"patient_id": "ananya",
"patient_profile": {
"age": 42, "weight": 68, "height": 165, "sex": "F",
"serum_creatinine": 0.9, "child_pugh_score": 5,
"cyp3a4_activity": 1.0, "cyp2c9_activity": 0.6
},
"prescriptions": [
{ "drug_name": "warfarin", "dose_mg": 5, "frequency_per_day": 1,
"start_time_hr": 8, "bioavailability": 0.93 }
],
"dietary_factors": ["grapefruit", "vitamin_k"]
}Hand-curated (core/drugdb/drug_data.py) — ~45 drugs across 12 classes:
anticoagulants · antihypertensives · antidiabetics · thyroid · antiepileptics · antibiotics · statins · antidepressants · antiarrhythmics · immunosuppressants · cardiac glycosides · oncology
Each entry: mechanism, food effects, monitoring requirements, therapeutic range, contraindications, primary CYP enzyme, narrow-TI flag.
Auto-generated (core/drugdb/ddi_database.py) — built by build_ddi_database.py:
| Source | Pairs |
|---|---|
| OpenFDA Drug Labels (NLP regex) | 102 DDI |
| OpenFDA FAERS (co-occurrence) | 11 DDI |
| Curated FDI | 20 FDI |
| Total | 113 DDI + 20 FDI |
Evidence-based keyword alias matching across 13 condition families:
| Diagnosis keywords | Suggested drugs |
|---|---|
| hypertension / htn / blood pressure | Amlodipine, Lisinopril |
| diabetes / t2dm / hyperglycemia | Metformin, Empagliflozin |
| afib / atrial fibrillation | Warfarin, Apixaban |
| dry cough / ace inhibitor cough | Amlodipine, Losartan |
| arrhythmia / palpitations | Bisoprolol, Amiodarone |
| depression / mdd | Sertraline |
| high cholesterol / statin / ldl | Atorvastatin |
| gerd / acid reflux / heartburn | Omeprazole |
| nausea | Ondansetron, Metoclopramide |
| osteoporosis | Alendronate |
| anemia / iron deficiency | Ferrous Sulfate |
| migraine | Sumatriptan |
| asthma | Salbutamol |
| copd | Tiotropium |
Optional Gemma 1.5B via Ollama for natural-language enhancement — falls back to deterministic templates (clinical accuracy identical).
ollama pull gemma3:1b && ollama serve- Engine — every
analyze_patient_regimen()result:decision_support_only: true+ full text - API —
_dsr()helper injects disclaimer into every JSON response - UI — session-gated modal + checkbox required before dashboard access
confidence = (mandatory_present / 4) × 0.75 + (optional_present / 8) × 0.25 − penalties
mc_multiplier = 1.0 + (1.0 − confidence) × 2.0 # more samples when data thin
unc_scale = 1.0 + (1.0 − confidence) × 1.5 # wider PK distributions
SHA256 key from (patient_id, prescriptions, dietary_factors) · 10-min TTL · 200-key LRU · invalidated on adherence log event.
python manage.py test core --verbosity=261 tests covering:
- Auth: login success/failure, missing fields, empty email, logout
- JWT protection: all 12 endpoints reject unauthenticated requests (401)
- Validation: negative dose → 400, bad profile type → 400, unknown patient → 404
- Engine: single drug analysis, audit entry creation, engine run
- Drug search: autocomplete, detail, interactions
- Suggestions: hypertension, diabetes, unknown fallback, aliases (htn, high blood pressure)
- Adherence: log, audit creation, history
- Audit: responds correctly, persists after analysis
- Role protection: patient cannot access doctor endpoints
| Env var | Default | Description |
|---|---|---|
SECRET_KEY |
— | Required in production |
DEBUG |
false |
Enable Django debug mode |
ALLOWED_HOSTS |
localhost,127.0.0.1 |
Comma-separated |
DATABASE_URL |
— | Postgres URL (falls back to SQLite) |
REDIS_URL |
redis://localhost:6379/0 |
Cache + Celery broker |
CORS_ALLOWED_ORIGINS |
http://localhost:8000,... |
Comma-separated |
RATE_LIMIT_REQUESTS |
60 |
Requests per window |
RATE_LIMIT_WINDOW |
60 |
Window in seconds |
ENGINE_VERSION |
1.0.0 |
Stamped on every audit entry |
- Email / phone verification on signup
- HTTPS + production WSGI (gunicorn + nginx)
- EHR/FHIR integration (HL7 FHIR R4 —
core/fhir/, Patient/MedicationRequest/Observation in, DetectedIssue/RiskAssessment out) - Paediatric PK population parameters
- PDF export of audit trail and PK report
- Bulk patient import (CSV)
- Real-time dose alerts (WebSocket)
- HIPAA field-level encryption (PII at rest)
- GDPR data deletion and portability endpoints
- Continuous sensor integration — Layer 9 generic observation schema
| Name | Role | |
|---|---|---|
| Jeyadev | jeyadev2006@gmail.com | Lead developer |
| Vimochini | vvimochini@gmail.com | Contributor |
Contributions welcome — open an issue or PR.
- In-memory rate limiter — resets on server restart; use Redis in production
- RxNorm DNS — structured DDI lookup fails in some networks; OpenFDA fallback used
- Adult PK params — paediatric use flagged + uncertainty widened, but population params are adult-derived
- No HTTPS — dev server only; production requires WSGI + TLS
- FHIR coverage is partial —
core/fhir/handlesPatient,MedicationRequest,Observation,AllergyIntolerancein andDetectedIssue/RiskAssessment/GuidanceResponseout; noMedicationStatement,Encounter, subscriptions, or bulk export - Celery requires a running worker + Redis — without one, hi-fi background refresh and async FHIR jobs silently no-op; only the synchronous n=100 path is guaranteed
MIT — see LICENSE.
AbsorbAI is not approved as a medical device. Do not use as a substitute for clinical judgment. A licensed healthcare professional must review all recommendations before any clinical action is taken.
Jeyadev R · AI/ML Engineer & Full-Stack Developer · Chennai, India
- Portfolio: jeyadev.dev
- GitHub: @jeyadev-jd
- LinkedIn: r-jeyadev
If this project is useful to you, a ⭐ on the repo helps others find it.






