CoolFace
Apppublic

DuskAFK/depression-detection

sourceHugging Faceupdated 4mo agoView on Hugging Face
0likes
App README

MindScan — University Mental Health Early Warning Platform

BTech Major Project | Group 124 | Delhi Technological University

MindScan is an end-to-end mental health monitoring system for university students. It combines a fine-tuned DistilBERT transformer with PHQ-9 aligned severity scoring, gradient-based explainability, longitudinal trend tracking, NLP-driven cognitive analysis, and a counselor-facing dashboard — moving far beyond binary classification into a deployable early-warning product. A companion Chrome extension brings analysis to any webpage.


Table of Contents


Overview

The minor project established a binary DistilBERT classifier (depressed / not depressed) trained on Reddit mental health data. The major project extends this into a complete clinical-grade monitoring system across three successive development phases:

CapabilityMinor Projectv3 (Major Project)v4 (AI Features)
OutputBinary (0/1)4-level PHQ-9 severity+ linguistic + domain analysis
ExplainabilityNoneGradient-based word saliency+ word importance heatmap
HistoryNoneSQLite journal, 30-day trend chart+ 90-day heatmap, streak, consistency
AlertsNone4-level rule-based escalation+ crisis resources, box breathing
Mood PredictionNone3-day trajectory forecastsame
NLP AnalysisNoneNoneLinguistic patterns, distortions, domains
AI NarrativeNoneNoneWeekly summary, personalized insights
Counselor ToolsNoneDashboard + flag workflowsame
ExtensionNoneNoneChrome extension (popup + context menu)

System Architecture

[Student Web App / Chrome Extension]
         │  journal entry (text + user_id)
         ▼
[Preprocessing] ── tokenize, truncate (max 128 tokens)
         │
         ▼
[DistilBERT Encoder] ── distilbert-base-uncased, 67M parameters
         │  CLS embedding vector
         ▼
[Classification Head] ── Dropout(0.2) → Linear(768→1) → Sigmoid
         │  probability ∈ [0, 1]
         ▼
[PHQ-9 Severity Mapper] ── 4-class threshold bucketing (0–3)
         │
         ├──► [Gradient Saliency Module] ── word importance scores
         │
         ├──► [AI Analysis Engine (analysis.py)]
         │         ├── Linguistic Pattern Analyzer
         │         ├── Stress Domain Classifier (6 domains)
         │         ├── Cognitive Distortion Detector (7 types, CBT)
         │         ├── Context-aware Journal Prompts
         │         ├── Weekly AI Summary Generator
         │         └── Personalized Insight Engine
         │
         ├──► [Alert Engine] ── rule-based escalation (green/yellow/orange/red)
         │
         ▼
[SQLite Journal Store] ── entries keyed by user_id + timestamp
         │
         ├──► [Trend Analysis] ── 7/14/30-day severity line chart
         ├──► [Trajectory Prediction] ── numpy linear regression, 3-day forecast
         ├──► [Calendar Heatmap] ── 90-day GitHub-style severity calendar
         ├──► [Mood Streak] ── consecutive low-severity days
         └──► [Counselor Dashboard] ── anonymized risk overview, flag/escalate workflow

Features

Student Web App

  • Journal entry input — write daily text, analyzed and saved under a student ID
  • PHQ-9 severity badge — color-coded label (Minimal / Mild / Moderate / Severe) with clinical PHQ-9 score range
  • Confidence score — raw model probability displayed as a percentage
  • Alert banner — contextual message with guidance based on current risk level
  • Word importance heatmap — each word highlighted by its gradient saliency score; red = high influence on the prediction
  • Context-aware journal prompt — AI-generated writing prompt based on recent mood trajectory, refreshed per session
  • Deep Analysis panel — expandable section showing linguistic stats, stress domains, and CBT patterns

AI Analysis Engine (v4)

Linguistic Pattern Analysis

Three evidence-based linguistic signals extracted from every entry:

  • Absolutist words — rate of extreme all-or-nothing terms (always, never, completely, nothing, everyone, etc.) per 100 words. Elevated rates (≥2.5%) are associated with depressive and anxious ideation (Al-Mosaiwi & Johnstone, 2018). Displayed with warning/alert thresholds.
  • Negation density — rate of negation words (not, never, no, cannot, hardly, etc.) per 100 words. Rates ≥4% flagged as elevated.
  • First-person singular focus — rate of i, me, my, myself per 100 words, a marker of self-focused rumination.
  • Word count — entry length indicator.
Stress Domain Classification

Each entry is classified into up to 3 of 6 life-stress domains based on keyword co-occurrence:

DomainExample keywords
Academicexam, assignment, grades, deadline, professor, study
Sociallonely, friends, rejected, isolated, relationship, ignored
Familyparents, home, fight, disappoint, expectations, pressure
Healthsick, pain, tired, sleep, eating, energy, hospital
Financialmoney, debt, fees, afford, rent, expenses, scholarship
Existentialpurpose, meaning, future, worthless, identity, belong

A radar chart (Chart.js) shows normalized intensity across all 6 domains for each entry.

Cognitive Distortion Detection (CBT)

Seven CBT cognitive distortion patterns are detected via regex, displayed with clinical descriptions and therapist-style reframes:

DistortionDescription
All-or-Nothing ThinkingViewing situations in absolute black/white terms
CatastrophizingAssuming the worst-case outcome will happen
Mind ReadingAssuming you know what others think
Emotional ReasoningTreating emotions as objective facts
Should StatementsRigid rules about how things "must" be
PersonalizationBlaming yourself for external events
OvergeneralizationDrawing broad conclusions from a single event

Each detected distortion shows its name, a description, and a CBT reframe — a concrete alternative way to interpret the thought. Distortions are displayed in a collapsible accordion.

Crisis Resources & Box Breathing

For Moderate/Severe entries (orange/red alert), a Crisis Support Resources panel is automatically shown with India-specific helplines:

  • iCall — TISS Counselling: 9152987821
  • Vandrevala Foundation: 1860-2662-345 (24/7)
  • DTU Counselling Cell: imentor@dtu.ac.in
  • NIMHANS Helpline: 080-46110007

An integrated box breathing exercise (4-4-4-4 seconds: inhale → hold → exhale → hold) with animated CSS ring provides an in-browser grounding tool accessible without leaving the app.


History & Longitudinal Insights

Trend Chart

Line chart with three overlaid datasets over 7/14/30 days:

  • ML model probability (raw)
  • PHQ-9 severity score (0–3)
  • 3-day predicted trajectory (dashed line, numpy linear regression)
90-Day Calendar Heatmap

GitHub-style severity heatmap showing 90 days of entries as a grid of colored cells. Empty days are gray; filled cells use the severity color scale (green → yellow → orange → red). Renders client-side in pure JavaScript from the calendar dict returned by the history API.

Weekly AI Summary

AI-generated narrative paragraph summarizing the past 7 days of entries: dominant themes, trajectory direction, domain patterns, and a forward-looking note. Generated server-side in analysis.py → generate_weekly_summary(). Displayed in a collapsible card.

Personalized Insights

Up to 4 plain-English observations generated from longitudinal patterns, for example:

  • "Your entries this week show academic stress peaking around mid-week."
  • "Entries with social domain keywords tend to have higher severity scores."
  • "You've maintained a 5-day low-severity streak — that's notable."
Day-of-Week Pattern

Bar chart showing average severity by day of week, identifying whether certain days (e.g., Mondays, exam weeks) correlate with mood dips.

Domain Frequency Bar List

Horizontal bar list showing how often each stress domain appeared across all entries, ranked by frequency.

Mood Streak & Consistency
  • Mood streak — consecutive calendar days with severity ≤ Mild (green badge, shown in badge on Chrome extension)
  • Consistency — percentage of days with at least one journal entry over the past 30 days
  • Entry count — total entries in the selected window
Peer Comparison Insight

A percentile statement comparing the current entry's severity against all entries in the database for context (e.g., "This entry is in the top 20% lowest-severity entries you've logged").


Counselor Dashboard

Access at /counselor.

  • Summary cards: total students, count by risk level (Severe / Moderate / Mild / Minimal)
  • Student table sorted by risk: student ID, risk badge, latest severity, 7-day SVG sparkline, entry count, last active date
  • Flag & intervention workflow: counselors can flag students for follow-up, set status (flagged / contacted / resolved), add private notes, and log contact attempts — all stored in SQLite
  • Color legend explaining each alert level

Chrome Extension

A Manifest V3 Chrome extension companion for MindScan. Available in /extension/.

Features

Popup (toolbar icon):

  • Analyze tab — text input with character counter, Ctrl+Enter shortcut, full result view (severity badge, confidence, word heatmap, deep analysis panel)
  • History tab — recent entries with severity badges, 7-day mini trend chart
  • Settings sheet — server URL (supports localhost, Docker, HuggingFace Spaces), user ID, connection test

Context menu integration:

  • Select any text on any webpage → right-click → "Analyze with MindScan"
  • Opens the extension popup (Chrome 127+) or a floating analysis window (older Chrome), pre-filled with the selected text and auto-analyzed
  • Source hostname shown above the input so you know where the text came from

Badge:

  • Extension icon badge shows mood streak (5d) if ≥3 consecutive low-severity days, or a dot () otherwise
  • Badge background color mirrors the latest entry's severity (green/yellow/orange/red)
  • Refreshed after every analysis

Side panel / floating window:

  • Full-featured analysis view used as fallback when openPopup() is unavailable
  • Includes radar chart (Chart.js bundled locally — no CDN), distortion accordion, crisis panel
Technical notes
ItemDetail
Manifest versionV3 (service worker, no background page)
Chart.jsBundled locally as chart.umd.min.js — extension CSP blocks CDN scripts
Context menu → popupUses chrome.action.openPopup() (Chrome 127+) with windows.create() fallback
Pending text handoffchrome.storage.local with retry polling (8 × 250ms) for cross-context reliability
Server configConfigurable URL supports localhost, Docker, or HuggingFace Spaces deployment

PHQ-9 Severity Mapping

The model outputs a probability p ∈ [0, 1] representing the likelihood of depressive language. This is mapped to PHQ-9 aligned severity levels:

Probability RangeSeverityPHQ-9 Score EquivalentColor
0.00 – 0.25Minimal0 – 4Green
0.25 – 0.50Mild5 – 9Yellow
0.50 – 0.75Moderate10 – 14Orange
0.75 – 1.00Severe15 – 27Red
The PHQ-9 (Patient Health Questionnaire-9) is the clinical standard for depression screening used globally by medical practitioners. Mapping to its scale makes the system's output directly interpretable by counselors without requiring ML expertise.

Explainability — Word Importance

MindScan uses input-gradient saliency to explain each prediction. This is more principled than attention-weight visualization (which has known limitations per Jain & Wallace, 2019).

How it works:

  1. 1.Extract word embeddings from DistilBERT's embedding layer (before position encoding)
  2. 2.Detach and re-attach as a leaf tensor with requires_grad=True
  3. 3.Run a full forward pass and compute sigmoid(logit).backward()
  4. 4.The L2 norm of the gradient at each token position gives its importance score
  5. 5.Subword tokens (e.g., hope + ##lesshopeless) are merged and scores averaged
  6. 6.Scores are normalized to [0, 1] and visualized as a color heatmap

High-scoring words are highlighted in red; low-scoring words remain blue-tinted. This allows a counselor to see which phrases drove the prediction, making the system a decision-support tool rather than a black box.


Linguistic Pattern Analysis

Based on peer-reviewed NLP research on depression markers in natural language:

Absolutist thinking (Al-Mosaiwi & Johnstone, 2018) — An analysis of 63 online mental health communities found that absolutist word usage was significantly elevated in depression and anxiety communities vs. control groups. MindScan measures absolutist word rate per 100 words and flags entries above 2.5% (warning) and 5% (alert).

Negation density — High negation rates in personal writing correlate with negative affect and avoidance-focused thinking. Flagged at ≥4% (warning) and ≥8% (alert).

First-person singular focus — Elevated I/me/my usage is a known marker of self-focused ruminative thinking, associated with depression and anxiety.

All three metrics are displayed as chips in the Deep Analysis panel with color coding matching their clinical thresholds.


Cognitive Distortion Detection

Cognitive distortions are systematic thinking errors identified in Cognitive Behavioral Therapy (CBT). MindScan detects them using pattern-matched regular expressions tuned to natural language.

For each detected distortion the UI shows:

  1. 1.Name — CBT category name
  2. 2.Description — plain-language explanation of the thinking pattern
  3. 3.Reframe — a therapist-style alternative perspective

This transforms the app from a passive detector into a light CBT psychoeducation tool, giving students immediate, actionable framing.


Stress Domain Classification

The 6-domain classifier uses keyword co-occurrence scoring across domain-specific vocabulary lists. Each domain score is normalized to [0, 1] relative to the highest-scoring domain in the entry. Domains with score > 0.15 are returned as active.

The radar chart plots all 6 scores simultaneously, making multi-domain stress visible at a glance. Aggregated across all entries in the history view, domain frequencies are shown as a ranked bar list so students can identify their primary stressors over time.


Alert Escalation Logic

Alert levels are computed rule-based on top of the ML severity score:

ConditionAlert LevelGuidance Shown
Severity = MinimalGreenNo significant signals
Severity = MildYellowConsider a mental health break; self-care
Severity = ModerateOrangeConsider speaking with a counselor
Severity = SevereOrangeReach out for support
Severity = Severe + high-risk keywordRedImmediate support recommended
Severity ≥ Moderate (orange/red)Crisis resources panel shown automatically

High-risk keywords checked: suicide, suicidal, kill myself, end my life, self-harm, no reason to live, want to die, rather be dead, feel hopeless, worthless, can't go on, give up on life, disappear forever


Mood Trajectory Prediction

When a student has at least 3 journal entries, MindScan fits a linear regression (NumPy polyfit) on their severity scores over time and projects the next 3 days. The forecast is overlaid as a dashed line on the trend chart.

This serves two purposes:

  1. 1.Gives students a forward-looking signal — "your scores are trending down"
  2. 2.Allows counselors to identify students on a worsening trajectory before they reach crisis severity

The trajectory label (Improving, Stable, Worsening) is included in the API response and displayed in the history view.


Counselor Intervention Workflow

The counselor dashboard at /counselor provides more than passive monitoring:

  • Flag for follow-up — mark a student for active monitoring
  • Status trackingflaggedcontactedresolved pipeline
  • Private notes — counselors can log observations not visible to the student
  • Contact log — timestamps and notes for each counselor contact attempt

All counselor actions are stored in a separate counselor_flags table in SQLite, keeping student journal data and counselor records cleanly separated.


API Reference

POST /predict

Analyze a text entry and optionally save it to the journal.

Request body:

json
{
  "text": "I feel completely hopeless and worthless",
  "user_id": "2K22/CO/327",
  "save": true
}

Response:

json
{
  "prob": 0.8531,
  "severity_score": 3,
  "severity_label": "Severe",
  "alert_level": "red",
  "words": ["i", "feel", "completely", "hopeless", "and", "worthless"],
  "word_scores": [0.38, 0.54, 0.50, 1.0, 0.43, 0.49],
  "linguistic_patterns": {
    "absolutist_rate": 3.2,
    "negation_rate": 2.1,
    "first_person_rate": 14.5,
    "word_count": 8
  },
  "stress_domains": ["Existential", "Social"],
  "domain_scores": {
    "Academic": 0.0, "Social": 0.62, "Family": 0.1,
    "Health": 0.0, "Financial": 0.0, "Existential": 1.0
  },
  "cognitive_distortions": [
    {
      "name": "All-or-Nothing Thinking",
      "description": "Viewing situations in absolute black-and-white terms.",
      "reframe": "Are there any partial successes or gray areas being overlooked?",
      "color": "#f87171"
    }
  ],
  "journal_prompt": "What's one small thing that felt manageable today, even briefly?"
}
FieldDescription
probRaw model probability (0–1)
severity_scoreInteger 0–3 (Minimal to Severe)
severity_labelHuman-readable severity level
alert_levelgreen / yellow / orange / red
wordsTokenized words (subwords merged)
word_scoresGradient saliency score per word, normalized to [0, 1]
linguistic_patternsAbsolutist rate, negation rate, 1st-person rate, word count
stress_domainsTop active stress domain names (up to 3)
domain_scoresNormalized 0–1 scores for all 6 domains
cognitive_distortionsList of detected CBT distortions with descriptions and reframes
journal_promptContext-aware writing prompt for the next session

GET /api/history/{user_id}

Retrieve saved entries and longitudinal analytics for a student.

Query params: days (default: 30)

Example: GET /api/history/2K22CO327?days=30

Response:

json
{
  "user_id": "2K22CO327",
  "entries": [...],
  "trajectory": "Improving",
  "mood_streak": 5,
  "consistency_pct": 73,
  "calendar": {
    "2026-05-01": 1,
    "2026-05-02": 2
  },
  "weekly_summary": "This week showed a mix of academic and social stressors...",
  "personalized_insights": [
    "Your entries on Mondays tend to show higher severity scores.",
    "Academic stress has appeared in 60% of your entries this week."
  ],
  "domain_breakdown": {"Academic": 5, "Social": 3, "Family": 1, ...},
  "domain_colors": {"Academic": "#38bdf8", ...},
  "day_pattern": {"Monday": 2.1, "Tuesday": 1.3, ...},
  "has_day_pattern": true,
  "journal_prompt": "What has been the biggest source of energy for you this week?",
  "comparison_insight": "This entry is in the top 25% lowest-severity entries you've logged."
}
FieldDescription
entriesArray of journal entries with severity, probability, alert level, timestamp
trajectoryImproving / Stable / Worsening based on linear regression
mood_streakConsecutive days with severity ≤ 1 (Mild)
consistency_pct% of days in window with at least one entry
calendarDict of {date: avg_severity} for 90 days (used for heatmap)
weekly_summaryAI narrative summary of the past 7 days
personalized_insightsList of plain-English longitudinal observations
domain_breakdownDomain name → entry count across all history
day_patternDay-of-week → average severity score
journal_promptContext-aware prompt based on trajectory
comparison_insightPercentile comparison against own history

GET /counselor

Renders the counselor dashboard (HTML). Shows all students with entries in the past 30 days, sorted by risk level.


Running Locally

Prerequisites: Python 3.10+

bash
# 1. Clone and enter the project
git clone <repo-url>
cd depression-detection

# 2. Create a virtual environment
python3 -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate

# 3. Install dependencies
pip install -r requirements.txt

# 4. Start the server
uvicorn app:app --reload

Open http://127.0.0.1:8000 in your browser.

The model weights (~265 MB) are downloaded automatically from Google Drive on first run. Subsequent starts load from the local models/best_model.pt cache.

Docker:

bash
docker build -t mindscan .
docker run -p 8000:8000 mindscan

Chrome Extension Setup

  1. 1.Open Chrome and navigate to chrome://extensions
  2. 2.Enable Developer mode (top-right toggle)
  3. 3.Click Load unpacked and select the extension/ directory
  4. 4.The MindScan icon appears in the Chrome toolbar

Configuration:

  • Click the extension icon → Settings (gear icon)
  • Set Server URL to match your backend:
  • Local: http://localhost:8000
  • Docker: http://localhost:8000
  • HuggingFace Spaces: your Space URL
  • Set a User ID to link extension entries with your web app history
  • Click Test Connection to verify

Using the context menu:

  1. 1.Select any text on any webpage
  2. 2.Right-click → Analyze with MindScan
  3. 3.The popup opens pre-filled with the selected text and analyzes automatically
  4. 4.The source hostname is shown so you know where the text came from
Requires Chrome 127+ for automatic popup opening. On older Chrome, a floating analysis window opens instead.

Project Structure

depression-detection/
├── app.py                  # FastAPI app — routes, model loading, inference, CORS
├── analysis.py             # AI analysis engine — linguistic, domains, distortions, insights
├── db.py                   # SQLite journal — init, save, query, calendar, streak
├── requirements.txt        # Python dependencies
├── Dockerfile              # Container definition
├── models/
│   └── best_model.pt       # Fine-tuned checkpoint (auto-downloaded)
├── templates/
│   ├── index.html          # Student app — Analyze + History tabs (v4 full UI)
│   └── counselor.html      # Counselor dashboard
└── extension/
    ├── manifest.json       # Chrome Extension Manifest V3
    ├── background.js       # Service worker — context menu, badge refresh
    ├── popup.html          # Extension popup layout
    ├── popup.js            # Popup logic — analyze, history, settings
    ├── popup.css           # Popup styles
    ├── side_panel.html     # Floating analysis window (context menu fallback)
    ├── side_panel.js       # Side panel logic — full result rendering
    ├── side_panel.css      # Side panel styles
    ├── chart.umd.min.js    # Chart.js 4.4.0 (bundled locally — CSP compliance)
    └── icons/
        ├── icon16.png
        ├── icon32.png
        ├── icon48.png
        └── icon128.png

Key source locations:

ConcernLocation
Severity mappingapp.pyget_severity()
Gradient saliencyapp.pyrun_inference_with_importance()
Alert logicapp.pyget_alert_level()
Subword mergingapp.pymerge_subwords()
Linguistic analysisanalysis.pyanalyze_linguistic_patterns()
Domain classifieranalysis.pyclassify_stress_domains(), score_stress_domains()
Distortion detectoranalysis.pydetect_cognitive_distortions()
Weekly AI summaryanalysis.pygenerate_weekly_summary()
Personalized insightsanalysis.pygenerate_personalized_insights()
Journal promptsanalysis.pyget_journal_prompt()
Calendar heatmap datadb.pyget_calendar_data()
Mood streakdb.pyget_mood_streak()
Calendar heatmap rendertemplates/index.htmlrenderCalendar()
Trend + trajectory charttemplates/index.htmlrenderChart()
Counselor sparklinesapp.py_sparkline_svg()
Extension context menuextension/background.js
Extension result renderingextension/popup.js, extension/side_panel.js

Model Details

PropertyValue
Base modeldistilbert-base-uncased
TaskBinary sequence classification
Training dataReddit mental health subreddits
Classification headDropout(0.2) → Linear(768 → 1) → Sigmoid
Inference deviceCPU
Max sequence length128 tokens (predict), 64 tokens (saliency pass)
Parameters~67M (DistilBERT) + 769 (head)

The fine-tuned checkpoint stores separate encoder and head state dicts. At startup, the encoder's parameters are frozen (requires_grad_(False)) so that gradient computation during the saliency pass is scoped only to the input embedding leaf tensor — keeping inference efficient.


Comparison with Baselines

SystemAccuracyF1PHQ-9ExplainabilityLongitudinalNLP AnalysisExtension
Logistic Regression (BoW)~72%~70%NoNoNoNoNo
LSTM~79%~77%NoNoNoNoNo
BERT (full, fine-tuned)~88%~87%NoNoNoNoNo
DistilBERT binary (minor)~87%~86%NoNoNoNoNo
MindScan v3~87%~86%YesYesYesNoNo
MindScan v4~87%~86%YesYesYesYesYes
MindScan's improvement over the minor project is not in raw accuracy — the same underlying model is used. The contribution is in clinical utility: PHQ-9 aligned severity, gradient explainability, longitudinal monitoring, NLP-grounded cognitive analysis using CBT frameworks, and a deployable companion extension that brings the tool to any web context.

Team

BTech Computer Engineering — Delhi Technological University Group 124

NameRoll Number
Kushagra Goel2K22/CO/256
Piyush Kumar2K22/CO/327

MindScan is a screening tool, not a clinical diagnosis. All predictions should be interpreted alongside professional clinical assessment. For persistent distress, please consult a qualified mental health professional.