61 lines
2.9 KiB
Markdown
61 lines
2.9 KiB
Markdown
# Recommendation & Vibe Specification
|
|
|
|
This document defines the logic for the "Vibe" engine, moving from simple similarity to a continuous, evolving listening experience.
|
|
|
|
## 1. The "Vibe" Concept
|
|
The "Vibe" is an infinite, stateful listening session. Unlike a static playlist, it is a **Rolling Window** that evolves based on user interaction.
|
|
|
|
## 2. Scoring Logic
|
|
|
|
When generating a sequence, every candidate track is assigned a score.
|
|
|
|
$$Score = (W_{genre} \cdot S_{genre}) + (W_{artist} \cdot S_{artist}) + (W_{random} \cdot R)$$
|
|
|
|
### **Scoring Components**
|
|
* **$S_{genre}$ (Genre Match):**
|
|
* Uses hierarchical weights (e.g., `Deep House` (1.0) $\rightarrow$ `House` (0.8) $\rightarrow$ `Electronic` (0.5)).
|
|
* Calculated as the highest weight match between candidate and "Center Track."
|
|
* **$S_{artist}$ (Artist Similarity):**
|
|
* A binary or weighted score based on whether the artist is in the user's "Liked" list or frequent listening history.
|
|
* **$R$ (Randomness/Exploration):**
|
|
* A jitter factor to ensure the queue doesn't feel repetitive.
|
|
|
|
## 3. The Rolling Window Algorithm
|
|
|
|
The backend does not return a fixed list. It returns a **Sequence Chunk**.
|
|
|
|
### **Step-by-Step Generation**
|
|
1. **Identify the Center:** Find the `last_successfully_played_track_id`.
|
|
2. **Candidate Selection:**
|
|
* **Local Pool (80%):** Tracks from the user's library similar to the center track.
|
|
* **Probation Pool (20%):** Tracks from the `recommendation_batch` that have `probation=1`.
|
|
3. **Constraint Application (Batch Rules):**
|
|
* **Diversity Check:** No more than 1 track from the same artist per chunk.
|
|
* **Genre Cap:** No more than 2 tracks from the same genre per chunk.
|
|
4. **Chunking:** Return a sequence of $N$ tracks (e.g., 20).
|
|
|
|
## 4. The "Vibe" Session Lifecycle
|
|
|
|
A "Vibe" is represented by a `recommendation_batch` record.
|
|
|
|
| State | Description |
|
|
| :--- | :--- |
|
|
| **ACTIVE** | The user is currently listening. The stream is being generated. |
|
|
| **RESOLVED** | The session has ended naturally or timed out. |
|
|
| **FAILED** | The session was interrupted by a critical error or manual reset. |
|
|
|
|
### **Transition Logic**
|
|
* **Start:** User clicks "Start Vibe" $\rightarrow$ Create `ACTIVE` batch.
|
|
* **Progress:** User listens $\rightarrow$ Update `last_interaction_at` in the batch.
|
|
* **Termination:**
|
|
* **Natural:** User exits the app $\rightarrow$ Session marked `RESOLVED` after 24h.
|
|
* **Manual:** User ends session $\rightarrow$ Mark `RESOLVED` immediately.
|
|
* **Timeout:** No interaction for 24h $\rightarrow$ Mark `RESOLVED`.
|
|
|
|
## 5. Success/Failure Feedback Loop
|
|
|
|
The engine learns from the `feedback` table:
|
|
* **`action = 'promoted'`:** (High Score) Increase weight of this genre/artist in future seeds.
|
|
* **`action = 'disliked'`:** (Negative Signal) Decrease weight of this genre/artist.
|
|
* **`action = 'skipped'`:** (Transient Negative) Do not adjust long-term weights, but avoid this specific track in the current session window.
|