Feature: Mood Session - Real-time Emotion Blending & Goal-Oriented Playlists (Match / Boost / Calm)
#11 opened on Aug 17, 2025
Repository metrics
- Stars
- (80 stars)
- PR merge metrics
- (PR metrics pending)
Description
Summary
Introduce a Mood Session mode that continuously fuses multimodal emotions (text / speech / facial) into a single blended mood vector and generates a dynamic Spotify playlist aligned to a user-selected goal:
- Match my mood,
- Boost (increase energy/valence), or
- Calm (decrease energy/tempo).
The session adapts in real time to incoming signals and user feedback (like/skip), updating track choices and crossfading smoothly.
Motivation
- Current flow is single-shot: detect → recommend. Users often want continuous, adaptive music as their mood shifts.
- Goal framing (Match/Boost/Calm) supports emotion regulation, not just reflection—improving engagement and session length.
- Real-time feedback (skips/likes) gives learning signals to improve recs and evaluate model quality.
Goals
- Start/Stop Mood Session with a goal selector (Match/Boost/Calm).
- Multimodal blend: fuse text/speech/facial scores into one mood vector (e.g., arousal/valence + discrete labels).
- Adaptive playlist: pick tracks by Spotify audio features (valence, energy, tempo, danceability) + genres; refresh as the mood updates.
- Realtime updates: react to new detections and user actions (like/skip/seek) within the session.
- Crossfade and smooth transitions; maintain a small look-ahead queue.
- Privacy controls: clear camera/mic consent; local preview of raw signals; easy pause.
- Telemetry: session metrics, regulation success (mood delta), skips/likes, latency.
Non-Goals (for this issue):
- Long-term personalization models, collaborative filtering across users, social features.
User Stories
- As a user, I can select Match/Boost/Calm and start a session that updates songs as my mood changes.
- As a user, I can see why a track was picked (e.g., “high valence & medium energy to boost your mood”).
- As a user, I can like/skip tracks to influence upcoming recommendations.
- As a privacy-aware user, I can pause camera/mic at any time and keep running with text-only.
Acceptance Criteria
- Start/Stop controls visible on Home and Results pages; goal toggle persists per session.
- Multimodal detections update a blended mood vector at ≤1s p95 from receipt → fusion.
- Next track selection occurs in ≤1.5s p95 after a new mood signal or skip.
- Queue maintains ≥3 upcoming tracks; crossfade between tracks without audible gaps.
- Explain-why tooltip available for each track (surface key audio features + goal).
- Mobile parity: start/stop, goal selection, likes/skips; microphone/camera permissions handled natively.
- If no camera/mic consent, session runs with available modalities (degraded state shown).
- A11y: keyboard navigable controls, ARIA labels, focus states.
UX Notes
- Session Bar (sticky): [● live] Current mood badge → goal chip (Match/Boost/Calm) → Like/Skip → Pause input → End Session.
- Now Playing Card: album art, reason “why”, mood + audio features mini-pill (valence↑, energy→, tempo→).
- Settings: sliders for tempo/energy bounds and explicit content toggle.
API (Django REST — proposed)
Align with existing URL conventions; adjust names as needed.
POST /api/session/start
body: { userId, goal: "match"|"boost"|"calm", modalities: {text?:bool,speech?:bool,face?:bool} }
POST /api/session/stop
body: { sessionId }
POST /api/session/signal
body: { sessionId, signal: { modality:"text"|"speech"|"face", scores:{ valence:number, arousal:number, label:string }, ts?:string } }
GET /api/session/next
query: sessionId
# returns next track(s), queue state, rationale
POST /api/session/feedback
body: { sessionId, trackId, action:"like"|"skip"|"played", positionMs?:number }
GET /api/session/state
query: sessionId
# returns blended mood vector, goal, queue, last update
Response example (/api/session/next):
{
"tracks": [
{
"trackId": "spotify:track:123",
"title": "Sunrise Drive",
"artist": "Night Parade",
"features": { "valence": 0.78, "energy": 0.62, "tempo": 118 },
"rationale": "Boost: higher valence than current mood, moderate energy for smooth transition",
"previewUrl": "https://p.scdn.co/mp3-preview/..."
}
],
"queueSize": 4,
"blendedMood": { "valence": 0.41, "arousal": 0.55, "label": "melancholic" }
}
Blending & Ranking (AI/ML)
-
Fusion: weighted average over normalized modality confidence (dropout-robust; if a modality is missing, re-normalize).
-
Goal transform:
- Match: minimize distance to current mood.
- Boost: target ↑valence (+Δ), cap energy to user preference.
- Calm: target ↓arousal/tempo, maintain moderate valence.
-
Retrieval: filter candidate tracks by Spotify audio features & user constraints → rank by (goal distance + popularity penalty + freshness).
-
Online learning: update per-user short-term weights from likes/skips within session scope.
Data Model (MongoDB examples)
sessions:{ _id, userId, goal, active, blendedMood{valence,arousal,label}, modalities, createdAt, updatedAt }session_events:{ sessionId, type: "signal"|"feedback"|"track_play", payload, ts }user_prefs:{ userId, bounds:{tempo:[min,max], energy:[min,max]}, explicitAllowed:bool }
Privacy & Security
- Explicit consent prompts for mic/camera; store consent state locally, not on server.
- Allow “text-only” mode.
- Rate-limit
/signaland/feedbackto prevent abuse. - Never store raw audio/video; only derived scores + timestamps.
Performance
- Keep an in-memory candidate pool per session for fast re-ranking.
- Redis cache for common seed sets (per goal).
- Pre-fetch next track’s preview and metadata; crossfade via frontend audio element or Spotify SDK bridge where possible.
Analytics / Metrics
Events:
session_start{goal, modalities}session_signal{modality, latencyMs}session_track_recommended{trackId, features, goal}session_feedback{action, trackId}KPIs:- Avg session duration, tracks per session, skip rate, mood regulation delta (target vs actual after N tracks), p95 recommendation latency.
Rollout Plan
- Phase 1: Backend session lifecycle + fusion + basic ranking; web UI; likes/skip.
- Phase 2: Crossfade, queue look-ahead, explanations; mobile parity.
- Phase 3: Personalization (short-term learning), advanced settings, A/B for goal transforms.
Tasks
Backend (Django/DRF)
- Define
sessions&session_eventscollections/models. - Implement
/session/*endpoints + auth + rate limits. - Integrate Spotify features search (valence/energy/tempo/danceability).
- Fusion & goal transform logic; candidate pool + re-ranker.
- Unit/integration tests; load test p95 targets.
AI/ML
- Normalize modality outputs; confidence weighting & dropout handling.
- Map discrete labels ↔ (valence, arousal).
- Online feedback updates (lightweight, session-scoped).
- Quality dashboards (regulation delta, skip correlation).
Frontend (React)
- Session bar + goal toggle; Now Playing card; explanations tooltip.
- Queue UI, crossfade, error/empty states, a11y.
- Permissions prompts & degraded-mode banners.
- Analytics events.
Mobile (React Native/Expo)
- Start/stop, goal selector, likes/skip; mic/camera permissions.
- Lightweight queue UI; background audio constraints documented.
Infra/CI
- Feature flag
mood_session_enabled. - Redis for candidate caching; observability dashboards.
Docs
- README + openapi.yaml updates (new endpoints).
- Privacy/permissions notes, troubleshooting.
Open Questions
- Default fusion weights per modality? (propose equal weights, confidence-scaled)
- Should Boost target both valence and energy by default, or only valence?
- Minimum track preview length before allowing a skip to count as a negative signal?
- Spotify SDK vs. web audio for crossfade (licensing & platform differences)?