Skip to content

sanikad20/brainlag

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BrainLag — Digital Burnout Detector

A Flutter mobile app that detects digital burnout using real Android Digital Wellbeing data, combining two machine learning models: a manual PyTorch model for instant predictions and a personalised 7-day LSTM (Keras/TensorFlow) that learns each user's own baseline behaviour and flags deviations from it.

Architecture Overview

Flutter App (Android)
  ├── Firebase Auth (Login / Register / Forgot Password / 2FA)
  ├── Manual Mode → PredictionScreen → /predict        (PyTorch, 1–10 scale)
  └── Continuous Monitoring → ContinuousMonitoringScreen
        ├── /predict        (per-day score, for the 7-day chart)
        └── /predict_lstm   (personalised baseline + today, 1–10 scale)

FastAPI Backend
  ├── /register, /login        (SQLite + bcrypt via passlib)
  ├── /predict                 (PyTorch MLP, 14 features)
  └── /predict_lstm            (Keras LSTM, 23 features, 7-day sequence)

Android (Kotlin)
  └── MainActivity.kt → UsageStatsManager
        reads real screen time, app switches, and per-category usage
        (social / work / entertainment / wellness) directly from
        Android's Digital Wellbeing data store

Repository Structure

digital-burnout-detector/
├── Backend/
│   ├── main.py                       FastAPI app — all routes
│   ├── database.py                   SQLAlchemy engine/session
│   ├── models.py                     User table definition
│   ├── users.db                      SQLite database (auto-created)
│   ├── best_burnout_model.pt         Manual PyTorch model weights
│   ├── burnout_scaler.pkl            Scaler for the manual model
│   ├── manual_feature_cols.pkl       14 feature names, manual model
│   ├── burnout_lstm_savedmodel/      Keras LSTM, TensorFlow SavedModel format
│   ├── lstm_scaler.pkl               Scaler for the LSTM model
│   ├── lstm_feature_cols.pkl         23 feature names, LSTM model
│   ├── baseline_stats.pkl            Population-level baseline stats
│   └── app_category_weights.json     Reference: which apps count as social/work/etc.
│
└── flutter_catalog/
    ├── android/app/src/main/kotlin/com/example/flutter_catalog/
    │   └── MainActivity.kt           Reads real UsageStatsManager data
    └── lib/
        ├── main.dart                 App entry point, Firebase init
        ├── welcome_screen.dart
        ├── login_screen.dart         Email/password + Forgot Password + 2FA
        ├── register_screen.dart
        ├── home_screen.dart          Choose Manual or Continuous mode
        ├── prediction_screen.dart    Manual mode — slider inputs → /predict
        ├── continuous_monitoring_consent_screen.dart
        ├── usage_access_setup_screen.dart
        ├── continuous_monitoring_screen.dart   Real data + dual model scores
        ├── usage_service.dart        MethodChannel bridge + baseline math
        ├── api_service.dart          HTTP calls to the FastAPI backend
        └── firebase_options.dart     Auto-generated by FlutterFire CLI

Prerequisites

  • Flutter SDK (3.x) and Android Studio / VS Code with the Flutter extension
  • Python 3.10+
  • A physical Android phone or emulator with Usage Access permission support
  • A Firebase project with Email/Password authentication enabled
  • Both the backend machine and the phone on the same Wi-Fi network

Backend Setup

  1. Navigate to the Backend folder and create a virtual environment.

    cd digital-burnout-detector/Backend
    python3 -m venv venv
    source venv/bin/activate
  2. Install dependencies.

    pip install fastapi uvicorn sqlalchemy passlib[bcrypt] python-multipart
    pip install torch numpy joblib
    pip install tensorflow
  3. Confirm the following files are present in Backend/ before starting the server. If any are missing, retrain using the provided train_lstm_burnout.py script in Google Colab and copy the outputs here.

    best_burnout_model.pt
    burnout_scaler.pkl
    manual_feature_cols.pkl
    burnout_lstm_savedmodel/
    lstm_scaler.pkl
    lstm_feature_cols.pkl
    baseline_stats.pkl
    
  4. Find your machine's local IP address, since the phone will connect to this address rather than localhost.

    hostname -I | awk '{print $1}'
  5. Start the server, binding to all network interfaces so the phone can reach it.

    uvicorn main:app --host 0.0.0.0 --port 8000 --reload
  6. Verify the backend is reachable from the phone's browser by visiting http://YOUR_IP:8000. A successful response looks like {"message": "BrainLag backend running"}. If this fails, check that the phone and computer share the same network and that any firewall allows port 8000.

    sudo ufw allow 8000   # if a firewall is blocking the connection

Flutter App Setup

  1. Update the backend address in lib/api_service.dart to match your machine's IP from the previous step.

    const String _baseUrl = 'http://YOUR_IP:8000';
  2. Connect Firebase using the FlutterFire CLI, which generates firebase_options.dart automatically.

    dart pub global activate flutterfire_cli
    flutterfire configure
  3. Install Flutter packages.

    cd ../flutter_catalog
    flutter pub get
  4. Connect a physical device or start an emulator, then run the app.

    flutter run
  5. On first launch, grant Usage Access permission when prompted on the Continuous Monitoring screen. This is required for the app to read Digital Wellbeing data; without it, only Manual Mode will function.

How the Two Models Work Together

The manual model is a small PyTorch MLP trained on 14 hand-entered features (sleep, screen time, social ratio, and so on) and returns a single burnout score from 1 to 10. It powers the Manual Mode sliders screen and also generates the 7-day trend line shown in Continuous Monitoring, since it can score any single day independently.

The LSTM model is different in purpose. It is not simply fed seven days and asked to output a score the way the manual model is. Instead, the backend first computes the user's own mean and standard deviation for screen time, app switches, social ratio, and work ratio from their personal seven-day history. Today's values are then expressed as deviations, specifically deltas and z-scores, against that personal baseline rather than against a fixed population number. The sequence passed into the LSTM consists of six days of context plus today, where today's feature vector is the one built from the personal deviation calculation. This lets the same architecture generalise across users with very different baseline habits, since a heavy user and a light user are each compared only against their own normal.

The dynamic threshold for alerts displayed in the app (the orange dashed line on each chart) is computed client-side in usage_service.dart using percentiles of the user's own seven-day data: the 75th percentile once three or more days exist, and the 80th percentile once a full week of data is available, with fewer than three days falling back to mean plus one standard deviation.

Retraining the LSTM Model

The training script is designed to run in Google Colab and produces synthetic data automatically if no real dataset is supplied, which is useful for getting the pipeline working before real usage logs are available.

  1. Open a new Colab notebook and install the Keras 2 compatibility layer, since recent Colab runtimes default to Keras 3, which is not compatible with the SavedModel loading approach used here.

    !pip install tf_keras -q
  2. Paste the contents of train_lstm_burnout.py into a cell and run it. Training on synthetic data (800 users, 60 days each) takes a few minutes on Colab's default CPU runtime.

  3. Once training finishes, the following files will exist in the Colab file browser. Download each of them, or zip the SavedModel folder first since Colab does not offer a direct download option for folders.

    import shutil
    from google.colab import files
    
    shutil.make_archive("burnout_lstm_savedmodel", "zip", ".", "burnout_lstm_savedmodel")
    files.download("burnout_lstm_savedmodel.zip")
    files.download("lstm_scaler.pkl")
    files.download("lstm_feature_cols.pkl")
    files.download("baseline_stats.pkl")
  4. Extract the zip and copy all four items into Backend/, replacing the previous versions. Restart uvicorn to pick up the new model.

Common Issues

Screen time shown in the app does not match Android's own Digital Wellbeing screen. This is almost always caused by system processes such as the launcher, keyboard, or Google Play Services being counted as foreground usage. The exclusion list in MainActivity.kt should cover the most common OEM launchers and system packages, but device-specific system apps may need to be added to the excludePackages set if discrepancies persist.

Burnout score shows -- on Continuous Monitoring. The LSTM endpoint requires exactly seven full days of prior history before it will return a score; until then the screen falls back to the manual model's per-day score and displays a message indicating how many more days are needed.

/predict_lstm returns a 500 error after retraining. This is typically a Keras version mismatch between the environment that trained the model and the one serving it. The SavedModel format used here avoids most of these issues, but if it recurs, confirm that tf_keras (not bare keras) was used during both training and loading, and that the custom AttentionPool layer is registered identically in both places.

App cannot reach the backend from a physical phone. Confirm the phone and the computer running uvicorn are on the same Wi-Fi network, that uvicorn was started with --host 0.0.0.0 rather than the default 127.0.0.1, and that the IP address in api_service.dart is current, since it can change when reconnecting to Wi-Fi.

Privacy Note

All Digital Wellbeing data is read locally on-device via Android's UsageStatsManager API and is sent to the backend only for the purpose of generating a burnout prediction. No usage data is persisted on the server; it is processed in-memory for each request and discarded. Authentication credentials are hashed with bcrypt before storage and are never sent to the prediction endpoints.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors