Spaces:
Running
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 | |
| ```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/<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 || 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 | |
| <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 | |
| ```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/<id>` | 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 | | |