DuskAFK/depression-detection
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
- System Architecture
- Features
- Student Web App
- AI Analysis Engine (v4)
- History & Longitudinal Insights
- Counselor Dashboard
- Chrome Extension
- PHQ-9 Severity Mapping
- Explainability — Word Importance
- Linguistic Pattern Analysis
- Cognitive Distortion Detection
- Stress Domain Classification
- Alert Escalation Logic
- Mood Trajectory Prediction
- Counselor Intervention Workflow
- API Reference
- Running Locally
- Chrome Extension Setup
- Project Structure
- Model Details
- Comparison with Baselines
- Team
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:
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 workflowFeatures
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,myselfper 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:
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:
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
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:
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:
- Extract word embeddings from DistilBERT's embedding layer (before position encoding)
- Detach and re-attach as a leaf tensor with
requires_grad=True - Run a full forward pass and compute
sigmoid(logit).backward() - The L2 norm of the gradient at each token position gives its importance score
- Subword tokens (e.g.,
hope+##less→hopeless) are merged and scores averaged - 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:
- Name — CBT category name
- Description — plain-language explanation of the thinking pattern
- 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:
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:
- Gives students a forward-looking signal — "your scores are trending down"
- 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 tracking —
flagged→contacted→resolvedpipeline - 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:
{
"text": "I feel completely hopeless and worthless",
"user_id": "2K22/CO/327",
"save": true
}Response:
{
"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?"
}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:
{
"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."
}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+
# 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 --reloadOpen 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:
docker build -t mindscan .
docker run -p 8000:8000 mindscanChrome Extension Setup
- Open Chrome and navigate to
chrome://extensions - Enable Developer mode (top-right toggle)
- Click Load unpacked and select the
extension/directory - 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:
- Select any text on any webpage
- Right-click → Analyze with MindScan
- The popup opens pre-filled with the selected text and analyzes automatically
- 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.pngKey source locations:
Model Details
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
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
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.
