Compassionate support for cancer patients in Sri Lanka.
Ayu is a mental health and cancer support platform built for Sri Lankan patients. It combines an AI-powered chatbot, mood tracking, medication reminders, doctor consultations, and video recommendations into a single mobile app ,backed by two FastAPI services, a Next.js doctor dashboard, and a Next.js admin dashboard.
Tested on Pixel 9 Pro XL · Flutter 3.41.5
It also includes Articles (read health articles published by admins).
Next.js web app used by oncologists to manage their patients and appointments.
- Overview stats - total patients, upcoming appointments, and completed sessions at a glance
- Calendar - monthly view of all scheduled appointments
- Appointment timeline - chronological list of upcoming consultations with patient details
- Appointment details - view intake notes, add clinical notes, upload prescriptions and documentation, and start Zoom call
- Past appointments - searchable history of completed sessions
- Patient profile - full patient record including mood stats, journal summary, and medication list
Next.js web app for platform administrators.
- Patient management - browse all registered patients and view individual profiles
- Doctor management - add, view, and manage doctor accounts
- Articles - create, edit, and publish health articles for the patient community
- Community feed - create posts and moderate the community feed
- Moderation - review and action flagged community content
- Documents - manage platform-level documents and resources
- Logs - view system and audit logs
- Edit profile - update admin account details
| Layer | Technology |
|---|---|
| Mobile | Flutter 3.41.5 · Dart |
| Main backend | FastAPI 0.129.0 · Python 3.10 · Uvicorn |
| Admin backend | FastAPI · Python 3.10 (no Docker) |
| AI / ML | Gemini 2.5 Flash Lite · ChromaDB · FastEmbed all-MiniLM-L6-v2 · Scikit-learn · XGBoost |
| LLM (video queries) | Ollama gemma4:e4b-it-q8_0 |
| Infrastructure | Nginx NJS · Docker Compose · Redis 7 |
| Auth | Firebase Auth · Firestore |
| Media | Cloudinary · Firebase Storage |
| Video calls | Zoom OAuth |
| Dashboards | Next.js 16 · React 19 · Tailwind CSS 4 · TypeScript 5 |
ayu/
├── backend/ # Main FastAPI backend (3 Docker replicas)
├── backend-admin/ # Admin FastAPI backend (local only, no Docker)
├── frontend/
│ ├── mobile/ # Flutter patient app
│ └── web/
│ ├── doctor-dashboard/ # Next.js doctor dashboard
│ └── admin-dashboard/ # Next.js admin dashboard
├── nginx/ # Nginx config + NJS uid-hash module
├── models/ # ML model .pkl files
├── data/ # Knowledge base + ChromaDB (not in git see below)
├── notebooks/ # Jupyter notebooks for model training and experimentation
│ ├── Sentiment Analysis.ipynb
│ ├── Chatbot.ipynb
│ └── Video Recommendation.ipynb
└── docker-compose.yml
data/ is not tracked in git because it contains large dataset files. You need to provide:
data/cancer_knowledge_base.json- the RAG knowledge base used by the chatbot. This is a JSON file containing curated cancer-related information. You can build it from your own sources or request it from the team.data/chroma_db/- do not create this manually. ChromaDB builds it automatically on first startup fromcancer_knowledge_base.json
If you are setting up a fresh environment, the minimum you need is cancer_knowledge_base.json. Without it the chatbot will fail to initialise.
| Tool | Version |
|---|---|
| Docker + Docker Compose | 24.x / v2 |
| Python | 3.10 |
| Node.js | 18+ |
| Flutter + Dart SDK | 3.41.5 |
Get a Firebase service account key from Firebase Console, Project Settings, Service accounts, Generate new private key and place it in:
backend/firebase-adminsdk.json
backend-admin/serviceAccountKey.json
Download google-services.json from Firebase Console, Project Settings, Your apps, Android and place it at:
frontend/mobile/android/app/google-services.json
The main backend runs as 3 replicas behind Nginx with a shared Redis instance.
Before starting, ensure these exist:
backend/.envbackend/firebase-adminsdk.jsonmodels/-bnb_model.pkl,lr_model.pkl,xgb_model.pkl,vectorizer.pkl,label_encoder.pkldata/cancer_knowledge_base.json- FastEmbed
all-MiniLM-L6-v2model cached locally - Docker runs withHF_HUB_OFFLINE=1so the model must be cached before the container starts or the chatbot will fail to initialise
data/chroma_db/ does not need to exist beforehand - it is created automatically on first startup.
docker compose up --build # build and start
docker compose up --build -d # run in background
docker compose logs -f # stream all logs
docker compose logs -f backend1 # logs from one replica
docker compose down # stop
docker compose down -v # stop and clear Redis dataAPI available at http://localhost/api. First startup takes a few minutes while ML models load and ChromaDB builds its index.
The admin backend has no Docker setup therefore run it locally (see below).
cd backend
python -m venv venv
venv\Scripts\activate
pip install -r requirements.txt
uvicorn main:app --reload --port 8000Add to backend/.env when running without Docker:
REDIS_URL=redis://localhost:6379/0cd backend-admin
python -m venv venv
venv\Scripts\activate
pip install -r requirements.txt
uvicorn main:app --reload --port 8001cd frontend/web/doctor-dashboard
npm install
npm run dev # http://localhost:3000cd frontend/web/admin-dashboard
npm install
npm run dev -- -p 3001 # http://localhost:3001cd frontend/mobile
flutter pub get
flutter runAPP_NAME=AYU Backend API
API_PREFIX=/api
CORS_ORIGINS=["http://localhost:3000","http://127.0.0.1:3000"]
FIREBASE_CREDENTIALS_PATH=firebase-adminsdk.json
FIREBASE_PROJECT_ID=your-project-id
FIREBASE_STORAGE_BUCKET=your-project-id.firebasestorage.app
CLOUDINARY_URL=cloudinary://api_key:api_secret@cloud_name
CLOUDINARY_CLOUD_NAME=your-cloud-name
CLOUDINARY_API_KEY=your-api-key
CLOUDINARY_API_SECRET=your-api-secret
GEMINI_API_KEY=your-gemini-api-key
OLLAMA_HOST=https://your-ollama-host
OLLAMA_CF_CLIENT_ID=your-cloudflare-access-client-id
OLLAMA_CF_CLIENT_SECRET=your-cloudflare-access-client-secret
MODEL=gemma4:e4b-it-q8_0
YOUTUBE_API_KEY=your-youtube-api-key
HF_TOKEN=your-hf-token
ZOOM_ACCOUNT_ID=your-zoom-account-id
ZOOM_CLIENT_ID=your-zoom-client-id
ZOOM_CLIENT_SECRET=your-zoom-client-secret
SENDGRID_API_KEY=your-sendgrid-api-key
SENDGRID_FROM_EMAIL=your-sender-email
ZOOM_USER_ID=your-zoom-user-id
# Optional path overrides (defaults shown)
MODEL_DIR=../models
CHROMA_DB_DIR=../data/chroma_db
KNOWLEDGE_BASE_PATH=../data/cancer_knowledge_base.jsonSENDGRID_API_KEY=your-sendgrid-api-key
SENDGRID_FROM_EMAIL=your-sender-email
APP_BASE_URL=http://localhost:3001Both the chatbot and the video recommendation service support Gemini and Ollama as interchangeable providers. Switch between them in one of two ways, no other code changes needed:
- Edit the defaults directly in
backend/app/core/config.py - Or add the variables to
backend/.envto override the defaults at runtime (the.envvalue takes priority)
| Variable | Options | Default |
|---|---|---|
CHATBOT_PROVIDER |
gemini or ollama |
gemini |
VIDEO_PROVIDER |
gemini or ollama |
ollama |
MODEL |
any Ollama model name | gemma4:e4b-it-q8_0 |
Using Gemini for everything (no Ollama required):
CHATBOT_PROVIDER=gemini
VIDEO_PROVIDER=gemini
GEMINI_API_KEY=your-gemini-api-keyUsing Ollama for everything:
CHATBOT_PROVIDER=ollama
VIDEO_PROVIDER=ollama
OLLAMA_HOST=https://your-ollama-host
MODEL=gemma4:e4b-it-q8_0The backend validates these settings at startup and will exit with a clear error if a required key is missing for the selected provider.
| Component | Version |
|---|---|
| Python (both backends) | 3.10 |
| FastAPI | 0.129.0 |
| Uvicorn | 0.41.0 |
| Pydantic | 2.12.5 |
| Flutter / Dart SDK | 3.41.5 |
| Next.js (doctor dashboard) | 16.1.7 |
| Next.js (admin dashboard) | 16.2.1 |
| React | 19.2.x |
| Tailwind CSS | ^4 |
| TypeScript | ^5 |
| Redis | redis:7-alpine |
|
RividuPesara |
AizaAshaf |
RumethW |
TashiAMFernando |
MethmiDeSilva |