BREATHE / SETUP.md
tannuiscoding's picture
added app.py
5a264f5

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 torch line in requirements.txt with:

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 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

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)

# 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 torch line in requirements.txt with:

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