Spaces:
Running
BREATHE β Project Setup Guide
Overview
BREATHE is a full-stack stress intelligence web application. After logging in, users land on the Breathe hub β a full-screen activity centre with cards for:
- Stress assessments (psychometric + free-text, ML-powered)
- Gratitude journaling (saved to account)
- Daily to-do list (saved in browser only)
- Guided breathing and relaxation exercises
All stress data is stored in a database and shown on a live dashboard with charts and history.
Project Structure
breathe-app/
βββ app.py # WSGI entry-point
βββ requirements.txt
βββ .env.example # copy β .env and fill in values
βββ .gitignore
βββ backend/
β βββ __init__.py # Flask app factory + DB init
β βββ models/
β β βββ user.py # User ORM (profile fields: avatar, gender, dob, bio, is_anonymous)
β β βββ assessment.py # Assessment ORM
β β βββ gratitude.py # GratitudeEntry ORM
β βββ routes/
β β βββ auth.py # /api/auth/*
β β βββ assessments.py # /api/assessments/*
β β βββ profile.py # /api/profile/*
β β βββ gratitude.py # /api/gratitude/*
β βββ ml/
β βββ ml_engine.py # Psychometric + RoBERTa inference (demo fallback)
βββ frontend/ # React 18 + Vite 5 SPA
β βββ index.html
β βββ vite.config.js # Vite config (proxy /api β Flask :5000)
β βββ package.json
β βββ src/
β βββ main.jsx
β βββ App.jsx # Router + auth guards
β βββ index.css # Global design system
β βββ utils.js # Shared helpers + colour maps
β βββ api/client.js # Fetch wrapper (get/post/put/del)
β βββ context/
β β βββ AuthContext.jsx
β βββ components/
β β βββ Layout.jsx # Sidebar shell
β βββ pages/
β βββ LandingPage.jsx
β βββ AuthPage.jsx
β βββ BreathePage.jsx # Activity hub (post-login home)
β βββ DashboardPage.jsx
β βββ AssessPage.jsx
β βββ HistoryPage.jsx
β βββ ProfilePage.jsx
β βββ GratitudePage.jsx
β βββ TodoPage.jsx
βββ models/
β βββ psychometric/ # .pkl files from notebook
β βββ text/ # roberta-model.pt
βββ instance/
βββ breathe.db # SQLite DB (auto-created)
Prerequisites
| Requirement | Version |
|---|---|
| Python | β₯ 3.10 |
| Node.js | β₯ 18 |
| npm | β₯ 9 |
| pip | β₯ 23 |
| (Optional) NVIDIA GPU + CUDA 12.x | for full RoBERTa inference |
Step-by-Step Setup
1 β Open the project folder
cd breathe-app
2 β Create a Python virtual environment
python -m venv venv
# macOS / Linux
source venv/bin/activate
# Windows PowerShell
venv\Scripts\Activate.ps1
3 β Install Python dependencies
pip install --upgrade pip
pip install -r requirements.txt
GPU note: For GPU-accelerated RoBERTa inference, replace the
torchline inrequirements.txtwith:torch==2.2.2+cu121 --index-url https://download.pytorch.org/whl/cu121
4 β Configure environment variables
cp .env.example .env
Open .env and fill in:
| Variable | What to set |
|---|---|
SECRET_KEY |
Long random string |
DATABASE_URL |
sqlite:///breathe.db (default) or a PostgreSQL URI |
PSYCHO_MODEL_DIR |
Path to folder with trained psychometric .pkl files |
ROBERTA_CKPT |
Path to roberta-model.pt |
Demo mode: If model paths are missing or
torchis not installed, the app runs with rule-based heuristic predictions. All features of the UI still work.
Psychometric model artefacts
Run psychometric notebook.ipynb to produce these files, then set PSYCHO_MODEL_DIR:
base_scaler.pkl final_scaler.pkl le_dict.pkl le_target.pkl
selected_cols.pkl poly.pkl top_num.pkl *_best_model.pkl
RoBERTa checkpoint
ROBERTA_CKPT=/path/to/breathe/text-sentiment/roberta-model.pt
5 β Install frontend dependencies
cd frontend
npm install
cd ..
asdf users: run
asdf set nodejs 20.18.1inside thefrontend/directory first.
6 β Run the development servers
Open two terminal tabs.
Terminal 1 β Flask API (port 5000)
# from breathe-app/
source venv/bin/activate
python app.py
Terminal 2 β React dev server (port 5173)
# from breathe-app/frontend/
npm run dev
Open http://localhost:5173 in your browser.
- After login you land on the Breathe hub (
/app/breathe) - The React dev server proxies all
/api/*requests to Flask on port 5000 automatically - The SQLite database (
instance/breathe.db) is created automatically on first run
7 β (Optional) PostgreSQL
pip install psycopg2-binary
createdb breathe
# Set in .env:
# DATABASE_URL=postgresql://postgres:password@localhost:5432/breathe
Database Migrations
The app uses db.create_all() on startup to create new tables. If you add columns to an
existing table (e.g. upgrading from an older version), run the migration script manually:
source venv/bin/activate
python3 - <<'EOF'
import sqlite3, os
conn = sqlite3.connect('instance/breathe.db')
cur = conn.cursor()
# Example: add profile columns if missing
cur.execute("PRAGMA table_info(users)")
existing = {row[1] for row in cur.fetchall()}
new_cols = {
"avatar": "TEXT", "gender": "VARCHAR(32)",
"working_status": "VARCHAR(64)", "dob": "VARCHAR(10)",
"bio": "VARCHAR(500)", "is_anonymous": "BOOLEAN DEFAULT 0",
}
for col, t in new_cols.items():
if col not in existing:
cur.execute(f"ALTER TABLE users ADD COLUMN {col} {t}")
conn.commit(); conn.close(); print('done')
EOF
Running in Production
1 β Build the React frontend
cd frontend
npm run build
cd ..
Outputs a static bundle to frontend/dist/. Flask auto-detects and serves it.
2 β Start the Flask server
source venv/bin/activate
gunicorn "app:app" \
--workers 2 \
--bind 0.0.0.0:5000 \
--timeout 120
Set FLASK_DEBUG=false and a strong SECRET_KEY in .env before deploying.
API Reference
Auth
| Method | Path | Description |
|---|---|---|
| POST | /api/auth/signup |
Create account (username, email, password) |
| POST | /api/auth/login |
Log in (email or username, password) |
| POST | /api/auth/logout |
Log out |
| GET | /api/auth/me |
Current user |
Assessments
| Method | Path | Description |
|---|---|---|
| POST | /api/assessments |
Submit assessment |
| GET | /api/assessments |
List (paginated ?page=1&per_page=20) |
| GET | /api/assessments/<id> |
Single assessment |
| GET | /api/assessments/summary |
Dashboard summary + timeline |
Profile
| Method | Path | Description |
|---|---|---|
| GET | /api/profile |
Get current profile |
| PUT | /api/profile |
Update bio, gender, working_status, dob, is_anonymous |
| POST | /api/profile/avatar |
Upload/remove avatar (base64 data-url, max 2 MB) |
Gratitude Journal
| Method | Path | Description |
|---|---|---|
| POST | /api/gratitude |
Save entry (items[], content, mood) |
| GET | /api/gratitude |
List entries (?page=1) |
| DELETE | /api/gratitude/<id> |
Delete entry |
Page Routes
| URL | Page | Auth |
|---|---|---|
/ |
Landing page | Public |
/auth |
Login / Signup | Public |
/app/breathe |
Breathe hub (post-login home) | Protected |
/app/dashboard |
Stress dashboard | Protected |
/app/assess |
New assessment | Protected |
/app/history |
Assessment history | Protected |
/app/profile |
User profile | Protected |
/app/gratitude |
Gratitude journal | Protected |
/app/todo |
Daily to-do list | Protected |
Stress Level Mapping
| Level | Score Range | Colour |
|---|---|---|
| Minimal | 0.00 β 0.20 | π’ Green |
| Mild | 0.20 β 0.40 | π‘ Light green |
| Moderate | 0.40 β 0.60 | π Yellow |
| Severe | 0.60 β 0.80 | π΄ Orange |
| Critical | 0.80 β 1.00 | π¨ Red |
Troubleshooting
| Problem | Fix |
|---|---|
No version is set for nodejs |
Run asdf set nodejs 20.18.1 in frontend/ |
| Blank page in browser | Make sure Flask is running on port 5000 |
| CORS errors | Add http://localhost:5173 to CORS_ORIGINS in .env |
ModuleNotFoundError: torch |
pip install torch or use demo mode |
FileNotFoundError: base_scaler.pkl |
Set PSYCHO_MODEL_DIR in .env |
| HTTP 500 on login after upgrade | Run the DB migration script above to add new columns |
| Port 5000 in use | Set PORT=5001 in .env and update vite.config.js proxy target |
| Database locked (SQLite) | Use PostgreSQL for multi-worker deployments |
Project Structure
breathe-app/
βββ app.py # WSGI entry-point
βββ requirements.txt
βββ .env.example # copy β .env and fill in values
βββ .gitignore
βββ backend/
β βββ __init__.py # Flask app factory + DB init
β βββ models/
β β βββ user.py # User ORM model
β β βββ assessment.py # Assessment ORM model
β βββ routes/
β β βββ auth.py # /api/auth/* endpoints
β β βββ assessments.py # /api/assessments/* endpoints
β βββ ml/
β βββ ml_engine.py # Psychometric + RoBERTa inference
βββ frontend/ # React + Vite SPA
β βββ index.html # Vite HTML shell
β βββ vite.config.js # Vite config (proxy /api β Flask)
β βββ package.json
β βββ src/
β βββ main.jsx
β βββ App.jsx # Router + auth guards
β βββ index.css # Global design system
β βββ utils.js # Shared helpers + colour maps
β βββ api/client.js # Fetch wrapper
β βββ context/
β β βββ AuthContext.jsx
β βββ components/
β β βββ Layout.jsx # Sidebar shell
β βββ pages/
β βββ AuthPage.jsx # Login / Signup
β βββ DashboardPage.jsx # Charts + stats
β βββ AssessPage.jsx # Sliders + gauge
β βββ HistoryPage.jsx # Paginated history
βββ models/
β βββ psychometric/ # .pkl files from notebook
β βββ text/ # roberta-model.pt
βββ instance/
βββ breathe.db # SQLite DB (auto-created)
Prerequisites
| Requirement | Version |
|---|---|
| Python | β₯ 3.10 |
| npm | β₯ 9 |
| Git | any |
| (Optional) NVIDIA GPU + CUDA 12.x | for full RoBERTa inference |
Step-by-Step Setup
1 β Clone / open the project
cd breathe-app
2 β Create a virtual environment
python -m venv venv
# macOS / Linux
source venv/bin/activate
# Windows PowerShell
venv\Scripts\Activate.ps1
3 β Install Python dependencies
pip install --upgrade pip
pip install -r requirements.txt
GPU note: For GPU-accelerated RoBERTa inference, replace the
torchline inrequirements.txtwith:torch==2.2.2+cu121 --index-url https://download.pytorch.org/whl/cu121
4 β Configure environment variables
cp .env.example .env
Open .env in any editor and fill in:
| Variable | What to set |
|---|---|
SECRET_KEY |
Long random string (see comment in file) |
DATABASE_URL |
SQLite default works out of the box. For Postgres: postgresql://user:pass@host/db |
PSYCHO_MODEL_DIR |
Absolute path to the directory containing your trained psychometric model .pkl files (output of psychometric notebook.ipynb) |
ROBERTA_CKPT |
Absolute path to roberta-model.pt (found in text-sentiment/) |
Generating the psychometric model artefacts
The psychometric notebook saves these files into SAVE_DIR (/kaggle/working/saved_models by default):
base_scaler.pkl
final_scaler.pkl
le_dict.pkl
le_target.pkl
selected_cols.pkl
poly.pkl
top_num.pkl
<model>_best_model.pkl (e.g. lightgbm_best_model.pkl)
Download them from Kaggle β paste into any local folder β set PSYCHO_MODEL_DIR to that folder.
Using the RoBERTa checkpoint
The file text-sentiment/roberta-model.pt is already in the workspace.
Set ROBERTA_CKPT to its full path:
ROBERTA_CKPT=/Users/you/Downloads/breathe/text-sentiment/roberta-model.pt
Demo mode: If you omit or leave either path blank, the app runs in Demo mode β a rule-based heuristic engine. All features of the UI work; only the ML predictions are approximate.
5 β Install frontend dependencies
cd frontend
npm install
cd ..
If you use asdf to manage Node versions, first run:
asdf set nodejs 20.18.1 # or whichever version is installed
6 β Run the development servers
The app requires two processes running at the same time β open two terminal tabs.
Terminal 1 β Flask API (port 5000)
# from breathe-app/
source venv/bin/activate # Windows: venv\Scripts\Activate.ps1
python app.py
Terminal 2 β React dev server (port 5173)
# from breathe-app/frontend/
npm run dev
Then open http://localhost:5173 in your browser.
The React dev server proxies all
/api/*requests to Flask on port 5000 automatically β no extra config needed.
The database (instance/breathe.db) is created automatically by Flask on first run.
7 β (Optional) PostgreSQL setup
# Install psycopg2
pip install psycopg2-binary
# Create database
createdb breathe
# Set in .env:
DATABASE_URL=postgresql://postgres:password@localhost:5432/breathe
Running in Production
1 β Build the React frontend
cd frontend
npm run build
cd ..
This outputs a fully static bundle to frontend/dist/. Flask automatically detects and serves it β no separate Node process needed in production.
2 β Start the Flask server
source venv/bin/activate
gunicorn "app:app" \
--workers 2 \
--bind 0.0.0.0:5000 \
--timeout 120
Set FLASK_DEBUG=false and a strong SECRET_KEY in .env before deploying.
For HTTPS, put Nginx or Caddy in front as a reverse proxy.
API Reference
All endpoints return JSON.
Auth
| Method | Path | Description |
|---|---|---|
| POST | /api/auth/signup |
Create account (username, email, password) |
| POST | /api/auth/login |
Log in (email or username, password) |
| POST | /api/auth/logout |
Log out |
| GET | /api/auth/me |
Get current user |
Assessments
| Method | Path | Description |
|---|---|---|
| POST | /api/assessments |
Submit assessment (psychometric JSON + text note) |
| GET | /api/assessments |
List assessments (paginated: ?page=1&per_page=20) |
| GET | /api/assessments/<id> |
Get single assessment |
| GET | /api/assessments/summary |
Dashboard summary + timeline |
Example POST body
{
"psychometric": {
"Sleep_Duration": 6.5,
"Sleep_Quality": 2,
"Work_Hours": 11,
"Physical_Activity": 0.5,
"Screen_Time": 8,
"Travel_Time": 1.5,
"Social_Interactions": 2,
"Caffeine_Intake": 4,
"Alcohol_Intake": 0,
"Blood_Pressure": 125,
"Cholesterol_Level": 200,
"Blood_Sugar_Level": 95,
"Gender": "Female",
"Occupation": "Working Professional",
"Smoking_Status": "Non-Smoker",
"Diet_Quality": "Average"
},
"text_note": "I've been feeling overwhelmed with deadlines lately and can't stop overthinking at night."
}
Example response
{
"message": "Assessment saved",
"prediction": {
"psycho_label": "High",
"psycho_score": 0.8241,
"text_label": "Stress",
"text_score": 0.4512,
"fused_label": "Severe",
"fused_score": 0.6376,
"modality_used": "both"
},
"assessment": { "id": 7, "created_at": "2026-05-02T14:32:00", ... }
}
Stress Level Mapping
| Level | Score Range | Colour |
|---|---|---|
| Minimal | 0.00 β 0.20 | π’ Green |
| Mild | 0.20 β 0.40 | π‘ Light green |
| Moderate | 0.40 β 0.60 | π Yellow |
| Severe | 0.60 β 0.80 | π΄ Orange |
| Critical | 0.80 β 1.00 | π¨ Red |
Troubleshooting
| Problem | Fix |
|---|---|
No version is set for nodejs |
Run asdf set nodejs 20.18.1 in the frontend/ directory |
| React dev server shows blank page | Make sure Flask is running on port 5000 (the Vite proxy needs it) |
CORS errors in browser console |
Ensure CORS_ORIGINS in .env includes http://localhost:5173 |
ModuleNotFoundError: torch |
Run pip install torch or install the CUDA wheel |
FileNotFoundError: base_scaler.pkl |
Set PSYCHO_MODEL_DIR correctly in .env |
RoBERTa weights not found |
App falls back to demo mode β set ROBERTA_CKPT |
Port 5000 in use |
Change PORT=5001 in .env and update vite.config.js proxy target |
| Database locked (SQLite) | Only one worker at a time with SQLite; use Postgres for multi-worker |
Tech Stack
| Layer | Technology |
|---|---|
| Backend | Python 3.10+, Flask 3, SQLAlchemy |
| Database | SQLite (dev) / PostgreSQL (prod) |
| Auth | Server-side sessions + Werkzeug password hashing |
| ML β Tabular | LightGBM / CatBoost / XGBoost / Stacking ensemble |
| ML β Text | RoBERTa-base fine-tuned on mental-health dataset |
| ML β Fusion | Weighted probability fusion β 5-class output |
| Frontend | React 18, Vite 5, React Router v6, Recharts 2 |