music_rec_sys: MoodTunes Turns Feelings Into a Playlist, Then Protects the Vibe With Hard-Nosed Feedback
Inside an open-source music recommender that maps language to emotion, uses Rocchio to reshape taste in real time, and encrypts Spotify tokens so personalization does not come at the cost of trust.
- MoodTunes is less interested in finding the perfect song than in preventing a mood break, and that changes the whole recommender design.
- The system turns messy language into a compressed emotional geometry before it ever scores a track.
- Dislikes matter more than likes because the product is trying to steer away from emotional mismatch, not just drift toward taste.
- The repo pairs a surprisingly mature privacy layer with a prototype-scale architecture, which makes the trust story feel as deliberate as the music logic.
Why MoodTunes Cares More About Ruining the Vibe Than Finding the Perfect Song
Most recommenders optimize for relevance. MoodTunes optimizes for continuity. That difference matters because mood is brittle. One off-track recommendation can break the session faster than a mediocre but adjacent one ever could.
The repo’s core belief is simple: negative space is the real control surface. It is easier to keep a playlist emotionally coherent by removing the wrong candidates than by endlessly searching for the perfect one.
| Traditional recommender | MoodTunes |
|---|---|
| Find songs you may like | Keep the current mood intact |
| Positive preference dominates | Negative feedback is weighted harder |
| Success means higher relevance | Success means fewer emotional interruptions |
| Wrong results are tolerated | Wrong results are treated as disruptive |
| User intent is broad | User intent is a narrow vibe boundary |
How Text Becomes a Mood Vector
The translation stack starts with emotion.py. A RoBERTa model classifies the text into 28 emotions, which are then mapped into valence-arousal space. That gives the system a geometry for feelings instead of a single label.
From there, the project collapses those 28 emotions into seven user-facing vibe buckets. That move is smart product design. The model gets to think in detail, while the interface speaks in a smaller emotional vocabulary.
# Conceptual flow from emotion.py
text -> roberta_go_emotions -> 28_emotion_scores
28_emotion_scores -> valence_arousal_point
valence_arousal_point -> vibe_bucket
# Example idea:
# joy + excitement -> high valence, high arousal
# sadness + fatigue -> low valence, low arousal
The Recommender Does Three Things at Once
The scorer is hybrid by design. It blends emotion alignment, preference similarity, and popularity into one final rank. That is a practical concession. Mood alone is not enough to pick tracks, and taste alone is not enough to preserve the session’s emotional target.
The other moving part is Rocchio-style feedback. Seed tracks initialize the profile, likes nudge it toward similar tracks, and dislikes push it away. The repo’s distinctive choice is how hard that push happens.
| Signal | Role in ranking | Behavior in MoodTunes |
|---|---|---|
| Emotion score | Tracks the target vibe | Keeps results aligned to the current mood |
| Preference score | Tracks the user profile | Moves with likes, dislikes, and seed tracks |
| Popularity score | Adds a coarse fallback | Prevents the list from becoming too narrow |
| Rocchio update | Rewrites the profile vector | Uses stronger negative correction than positive reward |
Why the System Favors Dislikes
This is the repo’s boldest product choice: dislikes carry a weight of -4.0 while likes sit at +1.0. That asymmetry is not a bug. It is a statement about what mood products are supposed to do.
If the user is trying to stay in a specific emotional lane, a bad track is more damaging than a good one is helpful. MoodTunes encodes that reality directly. It does not merely learn what the user likes. It learns what would break the session.
| Positive feedback | Negative feedback |
|---|---|
| +1.0 moves the profile closer | +4.0 equivalent push moves it away harder |
| Adds signal | Removes risk |
| Useful for refinement | Crucial for containment |
| Helpful in many recommenders | More important in a vibe-first system |
That logic is why the project feels coherent. The system is not trying to maximize delight in the abstract. It is trying to preserve a fragile emotional boundary.
From Recommendation to Playlist, With Tokens Locked Down
The Spotify layer turns model output into something usable. OAuth handles authorization, encrypted token storage protects credentials, and playlist creation batches track adds so the system can hand off a finished result instead of just a ranked list.
The privacy detail matters because it changes the product story. Encryption is not a decorative security feature here. It is part of the trust contract required for personalized music software.
| Plaintext tokens | Encrypted tokens |
|---|---|
| Readable if the database leaks | Protected by Fernet before storage |
| Easy to misuse | Harder to extract and reuse |
| Fast to implement | More credible for a personalization app |
| Treats security as afterthought | Treats security as part of product design |
Why the Prototype Feels More Mature Than Its Scale Suggests
The stack is small, but it is not sloppy. FastAPI, Pydantic, SQLAlchemy, SQLite, Hugging Face, Parquet, and NumPy fit together into a clean path from ingestion to inference to playlist creation. The repo reads like someone built the boring parts carefully.
That said, the current design is still an in-memory system at heart. It is quick and elegant for a prototype. It will not stay elegant once the catalog and user base grow much larger.
| What works now | What would need to change at scale |
|---|---|
| In-memory vector math | Vector database or retrieval layer |
| Single-user fast iteration | Distributed inference |
| Local Parquet dataset | More robust ingestion and indexing |
| SQLite simplicity | Stronger concurrency and storage strategy |
What Would Have to Change for MoodTunes to Scale
The main ceiling is retrieval. As the song catalog and user activity grow, the current approach will need better indexing, more durable storage, and a way to keep the preference vector responsive without loading everything into memory.
But the idea itself scales well. MoodTunes has a clear product thesis, a legible feedback loop, and a trust layer that matches the intimacy of the use case. That is a strong foundation, even before the infrastructure catches up.





