Skip to content

Latest commit

 

History

33 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

Predicto — Real-Time Emotion-Aware Music Recommendation Platform

React Vite React Router Sass MediaPipe Node.js Express MongoDB Redis JWT ImageKit


Predicto is a full-stack web application that turns a user's live facial expression into a mood-aware music playlist. The browser accesses the device camera, feeds the video stream into a MediaPipe Face Landmarker model running in VIDEO mode, and continuously extracts facial blendshape scores — numeric signals for smile intensity, jaw openness, brow movement, and frown depth. Those raw signals are evaluated against explicit threshold rules to classify the current expression into one of six application-level emotional states. The detected state is mapped to a supported mood category, which becomes the query parameter for a backend music request.

The backend is a Node.js / Express 5 REST API that authenticates users with JWT tokens delivered as HTTP-only cookies, stores user accounts and song metadata in MongoDB via Mongoose, writes revoked tokens to Redis on logout, and orchestrates uploaded audio through a media-processing pipeline before persisting assets in ImageKit. The pipeline reads embedded ID3 tags, extracts any embedded album artwork, uploads audio and poster separately, normalizes the track title, and saves the resulting song record with its mood category. Authenticated users who land on the detection or music pages are served mood-matched songs that stream directly from ImageKit CDN URLs into an in-browser audio player with full playback controls.


📑 Table of Contents


🌟 Overview

Predicto sits at the intersection of browser-based computer vision and music discovery. Rather than asking a user to self-report a mood, Predicto observes it through the camera in real time. MediaPipe performs sub-second facial landmark and blendshape inference directly in the browser, the application layer classifies the resulting signals into an emotional state, and that state is translated into one of five supported mood categories. A credentialed API request fetches the corresponding playlist from the backend, and the user immediately enters an interactive music experience — all within a cohesive, visually polished single-page application.

The project demonstrates a complete engineering story: real-time vision inference in the browser → application-level emotion classification → authenticated REST API → mood-filtered data retrieval → cloud media delivery → interactive audio player. Every layer — frontend architecture, routing protection, backend controllers, data modeling, upload processing, and media storage — is implemented from scratch without abstraction shortcuts.


✨ Core Capabilities

🎥 Real-Time Emotion Detection

When a user navigates to the detection page (a protected route), the browser requests camera access via the MediaDevices API. The live video stream is assigned to an HTML video element and fed into MediaPipe Face Landmarker running in VIDEO mode with blendshape output enabled. An animationFrame-driven inference loop continuously calls detectForVideo against the current video timestamp, extracts the blendshape score map from the first detected face, and evaluates those scores through a classification function. The resulting emotion label updates in real time on screen. When the component unmounts, all active animation frames are cancelled and every camera track is explicitly stopped, releasing the hardware resource.

🧠 Emotion-to-Mood Classification

The classification layer reads five groups of blendshape signals from the MediaPipe output:

Signal Group Blendshapes Sampled
Smile intensity mouthSmileLeft, mouthSmileRight (max of pair)
Jaw openness jawOpen
Brow raised browOuterUpLeft, browOuterUpRight (max of pair)
Brow pressed down browDownLeft, browDownRight (max of pair)
Frown depth mouthFrownLeft, mouthFrownRight (max of pair)

These numeric scores (0–1) are evaluated against explicit threshold rules in a priority-ordered chain:

Detected Emotion Primary Conditions
😁 Very Happy Smile > 0.75 and Jaw > 0.30
😊 Happy Smile > 0.45
😲 Surprise Jaw > 0.50 and Brow raised > 0.38
😠 Angry Brow down > 0.45 and Frown > 0.30
😢 Sad Frown > 0.0045
😐 Neutral Default fallback

A separate mapping layer then converts each emotional state string into one of five supported mood category keysvery happy, happy, surprised, sad, neutral — that serve as the query parameter to the backend. "Angry" and "Surprise" both route to the surprised music bucket, reflecting the application's music-category taxonomy rather than a one-to-one psychological mapping.

🎵 Mood-Aware Music Discovery

Once an emotion is detected and its mood key resolved, the user triggers a navigation event that carries the mood key as a URL search parameter. The music page reads that parameter, calls the authenticated song API with the mood value, and receives an ordered array of song records from the backend. Each record contains a track title, an audio CDN URL, and a poster CDN URL. The full playlist renders immediately into the player interface, with the first track auto-selected and ready to play.

🎧 Interactive Music Player

The music experience delivers a fully functional audio player built with the native HTML <audio> element, managed through React state and refs:

  • Play / Pause toggle with live icon state
  • Previous / Next track navigation with wrap-around
  • Seek bar with real-time scrubbing and timestamp display (M:SS)
  • Duration tracking via onLoadedMetadata and onTimeUpdate events
  • Auto-advance to the next track when the current track ends via onEnded
  • Poster artwork rendered from the ImageKit CDN URL with a graceful fallback to a default poster image
  • Active track highlighting and a live playing indicator in the playlist
  • Glowing poster animation toggled by playing state via a CSS class

🔐 Authentication & Protected Experience

User registration and login are handled by the backend, which issues a short-lived JWT (1-hour expiry) stored as an HTTP-only cookie. On every page load the frontend's AuthContext silently calls the profile endpoint using the cookie; if the token is valid, the user state is hydrated and the session is considered active. If the profile request fails, the user state is set to null.

Protected routes — the emotion detector and the music page — are wrapped by a Protected component that consults the auth context. If the session has not loaded, a loading screen is displayed. If the session is absent, the component redirects to /login using React Router's <Navigate>. Authenticated users proceed directly to the protected experience.

☁️ Media Upload & Storage Pipeline

Administrators can upload audio tracks through an authenticated upload endpoint. The pipeline processes each upload through the following stages:

  1. Multipart reception — Multer accepts the audio file as an in-memory buffer (20 MB limit, no disk writes)
  2. ID3 metadata extractionnode-id3 reads the buffer synchronously and extracts embedded tags including the track title and any embedded image buffer
  3. Parallel cloud upload — the audio buffer and the poster image buffer (when present) are uploaded concurrently to ImageKit using Promise.all, each routed to dedicated folders
  4. Fallback poster — tracks without embedded artwork receive a default poster reference
  5. Title normalization — the extracted ID3 title undergoes multi-step cleaning: BOM stripping, underscore expansion, removal of bitrate and quality suffixes, bracket keyword removal, and whitespace normalization
  6. Metadata persistence — the cleaned title, audio CDN URL, poster CDN URL, and mood category are saved as a new Song document in MongoDB

👁️ Computer Vision Pipeline

The complete vision flow, from hardware to music query:

Camera Stream
    → MediaPipe Face Landmarker (VIDEO mode, 1 face, blendshapes enabled)
    → 52+ Blendshape Category Scores per Frame
    → 5-Group Signal Extraction (smile, jaw, brow-up, brow-down, frown)
    → Priority Threshold Chain → Emotional State Label
    → Mood Key Mapping
    → Backend Music Query

The vision layer runs entirely in the browser — no camera frames are transmitted to the server. MediaPipe's WebAssembly runtime is loaded from the jsDelivr CDN and the Face Landmarker model weights are fetched from Google's MediaPipe model repository on first initialization. The model runs in VIDEO mode, which enables frame-timestamp-based inference optimized for continuous live input rather than single-image processing.

The inference loop is driven by requestAnimationFrame, which ties execution to the display refresh cycle. At each frame, detectForVideo is called with the current performance timestamp. If a face is detected, the first face's blendshape category array is reduced into a score lookup object. The classification function then reads five composite signal values and applies the ordered threshold chain. The result propagates through React state to update the live emotion label and the derived mood display panel.

On component unmount, cancelAnimationFrame halts the inference loop and each camera track is explicitly stopped — preventing the browser's camera-in-use indicator from persisting after the user navigates away.


🔄 Recommendation Flow

The complete path from facial expression to playing music:

1. Detection — MediaPipe processes the live video stream and produces blendshape scores per frame.

2. Classification — Application threshold logic converts blendshape scores into a named emotional state (Very Happy, Happy, Surprise, Angry, Sad, or Neutral).

3. Mood Mapping — A deterministic lookup function converts the emotional state string into one of five supported mood category keys used by the backend.

4. Navigation — The user confirms their mood and navigates to /songsbymood?mood=<key>, carrying the mood as a URL parameter.

5. API Request — The music page reads the mood parameter and calls the authenticated backend song endpoint with it as a query string.

6. Data Retrieval — The Express controller queries MongoDB for all Song documents matching the requested mood category and returns the array.

7. Playback — The returned song records populate the playlist. The first track auto-selects and the full player UI activates.


🏗️ System Architecture

Layer Responsibility Technologies
Presentation Interactive web experience React 19, Vite 7, Sass
Routing Client-side navigation and protected routes React Router 7
Computer Vision Facial expression inference from live camera MediaPipe Tasks Vision
State / Context Authentication session and song playback state React Context API
API Communication Frontend-to-backend requests with credentials Axios
API Layer Authentication and music REST endpoints Node.js, Express 5
Authentication Stateless session tokens and access control JWT, HTTP-only cookies, bcrypt
Data Layer Persistent user accounts and song metadata MongoDB, Mongoose
Session Revocation Logout token blacklist storage Redis via ioredis
Upload Processing Multipart audio handling and metadata extraction Multer, node-id3
Media Storage Audio and poster asset hosting and CDN delivery ImageKit

💻 Frontend Architecture

The frontend is organized into four feature-scoped domains, each encapsulating its own components, pages, hooks, services, and styles. This structure enforces clear boundaries between distinct product areas and avoids shared-logic entanglement.

Feature Domains

Auth — Handles user registration and login pages, the Protected route wrapper, the useAuth custom hook that abstracts login/register/logout actions, the AuthContext provider that maintains global session state across the application, and a dedicated Axios API layer for authentication endpoints. All HTTP requests include credentials so cookies are transparently transmitted.

Expression — Owns the emotion detection page, the live video display component, and the emotion.js utility module that encapsulates the full MediaPipe initialization, detection loop, classification logic, and cleanup sequence. Keeping this logic outside the React component tree makes the vision pipeline self-contained and cleanly separable from rendering concerns.

Home — Contains the marketing landing page with hero section, step-by-step flow, feature showcase, and emotion grid. Also houses the songCatalog.js domain module — the single source of truth for the moodCatalog array and the getMoodKeyFromEmotion mapping function shared across the Expression and Song features.

Song — Manages the mood-matched music page, the useSong hook that wraps song fetching, the SongContext provider for cross-component song state, and the song API service. The music player is fully self-contained within the page component, managing audio state, playback controls, track selection, and progress tracking locally.

Shared Infrastructure

  • Global Sass (main.scss) establishes base reset, typography, scrollbar theming in electric violet, and smooth scroll behaviour
  • Design tokens (_variables.scss) define the full color palette — deep navy #0D1B2A, electric violet #9D4EDD, crimson #BF092F — alongside spacing, radius, and transition values
  • Sass mixins (_mixins.scss) provide reusable patterns: glass() for glassmorphism cards, gradient-text() for violet-to-crimson headline gradients, glow() for radial aura effects, and flex shorthand helpers
  • Route-level protection is implemented through a Protected component that reads auth loading state before rendering guarded content, preventing flash-of-unauthorized-content on page load

⚙️ Backend Architecture

The backend follows a layered architecture with strict separation between routing, controller logic, middleware, data modeling, service abstraction, and configuration.

Route Layer — Two Express routers handle all application traffic. The auth router exposes public registration and login endpoints alongside token-protected profile and logout handlers. The song router applies the verifyToken authentication middleware globally at the router level, ensuring every song endpoint — retrieval and upload — requires a valid session.

Controller Layer — Auth and song controllers contain all business logic. The auth controller handles user lookup, bcrypt comparison, JWT signing, cookie management, and Redis blacklist writes on logout. The song controller orchestrates the full upload pipeline — ID3 extraction, concurrent ImageKit uploads, title cleaning, and MongoDB persistence — as well as mood-filtered song retrieval.

Middleware Layer — The verifyToken middleware extracts the JWT from the request cookie, verifies it against the application secret, and attaches the decoded payload to the request object. The upload middleware configures Multer with in-memory storage and a 20 MB file size cap.

Model Layer — Mongoose schemas define the User model (username, email, hashed password with select: false) and the Song model (title, audio URL, poster URL, mood with an enum constraint). Both models enforce runtime validation.

Service Layer — A dedicated storage.service.js module abstracts all interaction with the ImageKit SDK. Controllers call this service without any direct SDK dependency, keeping the upload orchestration decoupled from the storage provider.

Configuration Layer — Separate config modules initialize the Mongoose connection and the ioredis Redis client, each with connection event logging and error handling.


🗄️ Data Architecture

User

The User document stores the account identity required for authentication: a unique username, a unique email address, and a bcrypt-hashed password. The password field is excluded from default query projections (select: false) and must be explicitly requested during login verification — preventing accidental password exposure in profile or listing responses.

Song

The Song document stores everything needed to render and play a track: a cleaned, human-readable title; a direct audio URL pointing to the ImageKit CDN; a poster URL pointing to the extracted album artwork or the default fallback; and a mood category field constrained to the application's supported values (neutral, happy, sad, surprised, very happy, or an empty string for uncategorized). The mood field's enum constraint enforces data integrity at the database layer, preventing invalid categories from being inserted.


🔐 Security & Session Management

Mechanism Implementation
Password hashing bcrypt with a cost factor of 10
Authentication tokens JSON Web Tokens signed with an application secret, 1-hour expiry
Token transport HTTP-only cookies; secure flag enabled in production
Route protection (frontend) Protected component blocks unauthenticated access and redirects to /login
Route protection (backend) verifyToken middleware applied globally to all song routes and private auth routes
CORS policy Credentials-enabled CORS with an explicit allowlist of frontend origins
Session revocation On logout, the token is written to Redis with a matching 1-hour TTL as a revocation record
Upload size limiting Multer enforces a 20 MB maximum per uploaded file

Accuracy note on Redis: The verifyToken middleware validates the JWT signature and expiry but does not currently query the Redis blacklist on each incoming request. Redis is written to during logout, providing a persistent revocation record. Extending the middleware to consult the blacklist per request would enable true immediate token invalidation — a natural future enhancement.


☁️ Media Architecture

Audio and artwork travel through a multi-stage pipeline before reaching the database:

Multipart Upload (≤ 20 MB)
    → Multer memory storage  (buffer only, no disk writes)
    → node-id3 reads ID3 tags synchronously from the buffer
         ├── Track title extracted
         └── Embedded image buffer extracted (when present)
    → Parallel Promise.all upload to ImageKit:
         ├── Audio buffer  →  ImageKit /Predicto/songs/
         └── Poster buffer →  ImageKit /Predicto/posters/
              (fallback: default poster reference if no embedded art)
    → CDN URLs returned from ImageKit
    → Title normalization applied:
         strips BOM / zero-width characters
         expands underscores to spaces
         removes bitrate / quality suffixes (MP3, 320K, kbps)
         removes media-type bracket keywords (Official Video, Lyrical, HD)
         collapses repeated delimiters, trims edges
    → Song document persisted in MongoDB:
         { title (cleaned), url, posterUrl, mood }

At playback time, audio streams directly from ImageKit's CDN to the browser — the backend is not in the media streaming path. This keeps backend load minimal and leverages ImageKit's global delivery infrastructure for audio delivery.


🛠️ Tech Stack

Domain Technology Role
Frontend Framework React 19 Component-driven interactive UI
Build Tool Vite 7 Frontend bundling and development server
Routing React Router 7 Client-side navigation and protected-route logic
Styling Sass Modular design system with variables, mixins, and feature-scoped stylesheets
Computer Vision MediaPipe Tasks Vision 0.10 Face Landmarker model, VIDEO-mode blendshape inference
HTTP Client Axios API communication with credential-forwarding
Backend Runtime Node.js Server-side JavaScript runtime
API Framework Express 5 REST API with router-level middleware
Database MongoDB Document storage for users and songs
ODM Mongoose 9 Schema validation, data modeling, and query layer
Cache / Revocation Redis via ioredis 5 Token revocation blacklist storage
Authentication JWT (jsonwebtoken 9) Stateless identity assertions
Password Security bcrypt 6 Adaptive password hashing
Upload Handling Multer 2 Multipart form data processing with memory storage
Metadata Processing node-id3 0.2 ID3 tag and embedded artwork extraction from audio buffers
Media Storage ImageKit (Node.js SDK 7) Audio and poster CDN hosting and delivery
Typography Google Fonts — Outfit, Inter Display and body typefaces

💡 Engineering Highlights

Browser-based computer vision without a backend roundtrip. MediaPipe runs as a WebAssembly module in the browser. Each inference frame processes the camera stream locally, producing blendshape scores in real time without sending any image data to the server.

Continuous animation-frame inference loop. The detection cycle is tied to requestAnimationFrame rather than a polling interval, aligning inference with the display refresh rate and avoiding unnecessary CPU work between frames.

Five-signal, threshold-based expression classification. Rather than treating MediaPipe's output as a black box label, the application reads raw blendshape scores and applies an explicit, readable priority chain. The logic is transparent, auditable, and adjustable without any model retraining.

Feature-oriented React architecture. Each product domain — Auth, Expression, Home, Song — owns its own components, pages, hooks, services, and styles. There are no monolithic files or sprawling shared directories. Each feature composes its own context, custom hook, and API module.

Layered backend with service abstraction. Controllers, routes, middleware, models, services, and configuration are separated into distinct layers. The storage.service.js module abstracts the ImageKit SDK entirely; swapping storage providers would require changes in exactly one file.

Parallel media uploads. When an audio file contains embedded artwork, the audio buffer and poster buffer are uploaded to ImageKit concurrently via Promise.all rather than sequentially — reducing total upload latency without adding complexity.

ID3 metadata pipeline with title normalization. Rather than requiring manual metadata entry, the upload endpoint reads embedded ID3 tags from the audio buffer, recovers the track title and any embedded album art, then applies a multi-step normalization pass to produce clean, human-readable display titles free of encoding artifacts and quality-suffix noise.

Redis-backed revocation storage. Logout writes the current token to Redis with a TTL matching the token's original expiry, providing a persistent revocation record that survives server restarts within the token lifetime.

Credentialed Axios instances. Both the auth and song API modules create Axios instances with withCredentials: true, ensuring cookies are forwarded on every request without manual header management at each call site.

Sass design system. The UI is styled through a structured Sass architecture: global base styles, a color token file defining the full deep-navy / electric-violet / crimson palette, a mixin file providing reusable glassmorphism, gradient-text, glow-aura, and flex utilities, and feature-scoped stylesheets that consume those tokens consistently.


🎨 Product Experience

User journey:

DiscoverAuthenticateEnable CameraLive DetectionMood ResolvedFetch PlaylistPlay Music

The landing page presents Predicto through a multi-section layout: an animated hero with floating emotion tags, a four-step "how it works" walkthrough, a feature showcase with a blendshape confidence visualization mockup, an emotion recognition grid, and a call-to-action banner — all rendered in the application's signature dark visual language.

Visual identity at a glance:

Element Implementation
Base canvas Deep navy #0D1B2A
Primary accent Electric violet #9D4EDD (scrollbar, badges, glow orbs, gradient)
CTA accent Crimson #BF092F (buttons, gradient counterpoint)
Cards Glassmorphism — backdrop-filter: blur(), translucent navy borders
Background depth Large animated radial orbs in violet and teal
Texture CSS grid overlay for subtle HUD-inspired visual layer
Active player poster Glows and pulses via playing-state CSS class
Camera feed Mirrored (scaleX(-1)) for natural selfie orientation
Headings Outfit (700–800 weight)
Body text Inter (400–600 weight)
Gradient headlines Crimson-to-violet on hero and feature headings

📱 Responsive Design

The application adapts its layout across desktop, tablet, and mobile breakpoints through media queries embedded in each feature's Sass stylesheet.

The detection page switches from a two-column grid (camera stage left, mood panel right) to a single stacked column at 992 px and below, with adjusted padding to maintain usability on smaller screens.

The music player page condenses its layout into a single column on narrower viewports, with the poster, controls, and progress bar remaining fully accessible and touch-friendly.

The authentication pages use a split-panel layout on desktop — brand panel left, form right — and collapse to a single centred card on mobile, replacing the brand panel with a compact header inside the form card.

The navigation bar maintains its logo, link group, and CTA layout across standard breakpoints.


🔮 Future Roadmap

The following areas represent natural extensions of the current architecture, not existing features:

  • Redis blacklist enforcement at request time — extending verifyToken to query the Redis blacklist on each protected request, enabling true immediate token invalidation after logout
  • Refresh token rotation — short-lived access tokens paired with longer-lived refresh tokens to allow session extension without re-login
  • Richer mood taxonomy — expanding beyond five mood buckets with more granular emotional states and corresponding song categories
  • Confidence-weighted track selection — using blendshape score magnitude to influence playlist weighting rather than purely categorical lookup
  • Multi-frame averaging — aggregating blendshape scores across consecutive frames to increase classification stability and reduce single-frame noise
  • Per-user play history — storing playback events to surface personalization signals within a mood category
  • Admin song management dashboard — a protected interface for uploading, tagging, and reviewing the music catalog
  • Analytics layer — tracking mood detection frequency, track play duration, and mood-shift patterns
  • Accessibility enhancements — keyboard-navigable player controls, screen reader announcements for emotion state changes, and reduced-motion alternatives for animated backgrounds

👨‍💻 Author

Raza — Full-Stack Engineer

Built Predicto as a portfolio project demonstrating the integration of browser-based computer vision, real-time inference, full-stack authentication, cloud media processing, and a polished interactive product experience.

🌐 Live deployment referenced at predicto.skramizraza.tech


Predicto — where your face picks the playlist.

React MediaPipe MongoDB Redis ImageKit

About

Real-time computer-vision music platform using MediaPipe facial blendshape inference to classify user mood and drive mood-aware music discovery through a full-stack React, Express, and MongoDB architecture.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages