# 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 ```bash cd breathe-app ``` ### 2 — Create a Python virtual environment ```bash python -m venv venv # macOS / Linux source venv/bin/activate # Windows PowerShell venv\Scripts\Activate.ps1 ``` ### 3 — Install Python dependencies ```bash pip install --upgrade pip pip install -r requirements.txt ``` > **GPU note:** For GPU-accelerated RoBERTa inference, replace the `torch` line in > `requirements.txt` with: > ``` > torch==2.2.2+cu121 --index-url https://download.pytorch.org/whl/cu121 > ``` ### 4 — Configure environment variables ```bash 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 `torch` is 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 ```bash cd frontend npm install cd .. ``` > **asdf users:** run `asdf set nodejs 20.18.1` inside the `frontend/` directory first. ### 6 — Run the development servers Open **two terminal tabs**. **Terminal 1 — Flask API (port 5000)** ```bash # from breathe-app/ source venv/bin/activate python app.py ``` **Terminal 2 — React dev server (port 5173)** ```bash # 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 ```bash 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: ```bash 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 ```bash cd frontend npm run build cd .. ``` Outputs a static bundle to `frontend/dist/`. Flask auto-detects and serves it. ### 2 — Start the Flask server ```bash 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/` | 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/` | 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 || Node.js | ≥ 18 | | npm | ≥ 9 || pip | ≥ 23 | | Git | any | | (Optional) NVIDIA GPU + CUDA 12.x | for full RoBERTa inference | --- ## Step-by-Step Setup ### 1 — Clone / open the project ```bash cd breathe-app ``` ### 2 — Create a virtual environment ```bash python -m venv venv # macOS / Linux source venv/bin/activate # Windows PowerShell venv\Scripts\Activate.ps1 ``` ### 3 — Install Python dependencies ```bash pip install --upgrade pip pip install -r requirements.txt ``` > **GPU note:** For GPU-accelerated RoBERTa inference, replace the `torch` line in > `requirements.txt` with: > ``` > torch==2.2.2+cu121 --index-url https://download.pytorch.org/whl/cu121 > ``` ### 4 — Configure environment variables ```bash 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 _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 ```bash cd frontend npm install cd .. ``` > If you use **asdf** to manage Node versions, first run: > ```bash > 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)** ```bash # from breathe-app/ source venv/bin/activate # Windows: venv\Scripts\Activate.ps1 python app.py ``` **Terminal 2 — React dev server (port 5173)** ```bash # 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 ```bash # 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 ```bash 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 ```bash 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/` | Get single assessment | | GET | `/api/assessments/summary` | Dashboard summary + timeline | #### Example POST body ```json { "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 ```json { "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 |