24 / 24Next →
AI-assisted cognitive wellbeing app · BSc final project2026

MindAware

A CBT-inspired mobile app that detects cognitive distortions in a user's own words as they talk with an AI companion. It recognises when they return to a thought they've had before and turns those patterns into insights, using three services and a custom NLP pipeline.

ContextUniversity of Bedfordshire
Year2026
TypeMobile
StatusCompleted
RoleResearch, product design & full-stack / ML engineering
9Distortion types highlighted in the user's text
384-dEmbeddings powering semantic memory
928Backend and frontend test cases
318Human-verified evaluation rows

Project media coming soon

Screenshots and demo videos for this case study will appear here.

Overview

MindAware is a reflective companion, not a diagnostic tool. As users talk through what is on their mind, an NLP service tags nine types of cognitive distortion directly in their text. It notices when they return to a thought they have had before and gently prompts reflection. Over time, an insights dashboard shows recurring themes, mood correlations, emotion trends and tentative core beliefs that the user can confirm or reject.

React NativeExpoTypeScriptExpressPrismapgvectorPythonFastAPIscikit-learnGroq
Challenge

General-purpose LLMs reply to messages, but they don't track how someone thinks over weeks. The system needed explainable pattern detection on sensitive text, long-term semantic memory and firm safety boundaries. It also needed an evaluation method honest enough to show when a classifier isn't good enough.

Approach

An Expo and React Native client talks to an Express 5 and Prisma API on Neon Postgres with pgvector, which calls a stateless FastAPI NLP service. That service pairs an LLM classifier (gpt-oss-120b on Groq, in JSON mode) with a rule-based fallback. It uses MiniLM sentence embeddings for repetition and memory, silhouette-tuned K-Means for themes and a local DistilRoBERTa model for emotion. The API orchestrates each request, persists the results and generates the reply.

Outcome

The result is a complete research prototype: 39 endpoints across three services, 928 passing backend and frontend test cases, a 318-row human-verified evaluation set and full academic documentation.

System architecture
01Mobile clientExpo SDK 54 · React Native · Zustand · Reanimated

Feature modules follow a types → store → service pattern. Chat highlights distortions using character offsets, and the insight dashboards are built with victory-native.

02APIExpress 5 · TypeScript · Prisma 6 · Zod

Handles authentication, AES-256 encryption of messages at rest, the message pipeline, insights, mood, the article library, search and notifications, behind a routes → controllers → services → repositories structure.

03NLP serviceFastAPI · spaCy · sentence-transformers · scikit-learn

Stateless /analyze, /cluster and /embed-backfill endpoints covering distortion tags, repetition scores, safety verdicts, embeddings and emotion.

04DataNeon Postgres · pgvector

Stores 384-dimensional message embeddings and a retrieval (RAG) knowledge base, queried by cosine nearest-neighbour search.

05ModelsGroq gpt-oss-120b · MiniLM · DistilRoBERTa

The hosted LLM handles classification, safety confirmation and replies. Embeddings and emotion run locally on CPU so they use no API tokens.

Engineering decisions
01

One round trip per message

For each message, the API encrypts it, sends it for analysis and stores each distortion with its exact character span. It then searches the user's entire history with pgvector. If at least two earlier messages exceed 0.75 similarity, the reply notes that the user has had this thought before. The system prompt is assembled from those signals, and the client receives the reply, tags, title and memory in a single response. An NLP outage never breaks the chat, because the API falls back to a supportive reply.

02

Crisis detection that fails safe

A cheap keyword pre-filter runs first, so harmless messages never trigger an LLM call. Only a match escalates to an LLM check that separates genuine first-person risk from figurative language. If that check errors, the message is treated as a crisis rather than as safe. A confirmed crisis skips all analysis and switches the reply to a de-escalation prompt with helpline resources.

03

Measure before trusting the model

I built an evaluation harness with 318 labelled rows, including 92 hard negatives, phrases that look like distortions but are negated, quoted or hypothetical. It reports per-type F1 and a hard-negative accuracy score. The keyword baseline reached a macro-F1 of 0.223 and scored zero on inference-heavy types, which was the evidence for switching to an LLM classifier. LLM predictions are cached so runs can resume, and the harness refuses to publish partial results.

04

Privacy by construction

Message content is encrypted with AES-256-CBC using a fresh initialisation vector for every message. Refresh tokens and email codes are stored only as SHA-256 hashes, and logout revokes every session. Google ID tokens are verified on the server. Users can export all their data as JSON or delete their account, which removes everything linked to it.

05

Cost-aware AI

Emotion classification and embeddings run locally, so they cost nothing per call. Core-belief inference runs only once there is enough evidence: at least 15 distortion tags across three or more types in 90 days, with a 24-hour cooldown. The user must confirm each belief, and rejected beliefs are never suggested again.

What I built
01Reflective chat with in-text distortion highlights, a pattern sheet and Socratic reframing questions
02Semantic memory that recognises when the user returns to an earlier thought
03Named recurring themes via silhouette-tuned K-Means, weekly reports and a mood–distortion correlation
04Mindful Reflection mode grounded in a curated 19-source RAG knowledge base
05JWT and Google authentication, email OTP verification, push notifications and data export
06Evaluation tooling plus Jest and Pytest suites across all three services
Next projectINTT Leisure →