Spaces:
Sleeping
Sleeping
File size: 18,394 Bytes
5a264f5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 | # 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 |
|