eumora-api / PRODUCT_SPEC.md
VivDubs's picture
feat: update README and product specification; enhance sarcasm detection and emotion classification details
0c0288d
|
Raw
History Blame Contribute Delete
9.53 kB
# EUMORA β€” Product Feature Specification
**Version 1.0 | May 2026 | Status: In Development**
---
## 1. What EUMORA Does
EUMORA is a **lyric-to-song recommendation engine**. A user provides a piece of text β€” song lyrics, a mood description, a sentence β€” and EUMORA:
1. **Classifies the emotional content** of the text using a fine-tuned DeBERTa-v3-Base transformer model
2. **Maps that emotion** to a set of Spotify audio feature targets (valence, energy, danceability, tempo, mode)
3. **Queries the Spotify Recommendations API** with those targets to find real songs matching the emotional fingerprint
4. **Returns a ranked list of track recommendations** with per-feature match justification
---
## 2. Spotify Audio Features β€” What We Can and Can't Map
Spotify's `/v1/audio-features` and `/v1/recommendations` use the following fields. Our emotion classifier
operates on text only, so mappability depends on whether emotion correlates with that feature:
| Spotify Field | Type | Range | Can We Map? | Reasoning |
|--------------------|--------------|----------------|-------------|-----------|
| `valence` | float | 0.0 – 1.0 | βœ… Yes | Directly correlates with positive/negative emotion |
| `energy` | float | 0.0 – 1.0 | βœ… Yes | High for joy/anger/surprise, low for sadness/neutral |
| `danceability` | float | 0.0 – 1.0 | βœ… Yes | High for joy/love/surprise, low for sadness/fear |
| `tempo` | float (BPM) | ~50 – 200 | βœ… Yes | Fast for joy/anger, slow for sadness/fear |
| `mode` | int | 0 (minor) / 1 (major) | βœ… Yes | Joy/love β†’ major; sadness/anger/fear β†’ minor |
| `loudness` | float (dB) | -60 – 0 | ⚠️ Partial | Anger/joy β†’ louder; sadness/neutral β†’ quieter |
| `speechiness` | float | 0.0 – 1.0 | ⚠️ Partial | Sarcasm/anger skew slightly higher; not strongly correlated |
| `acousticness` | float | 0.0 – 1.0 | ❌ No | Depends on instrumentation, not text emotion |
| `instrumentalness` | float | 0.0 – 1.0 | ❌ No | Depends on vocal presence, not text content |
| `liveness` | float | 0.0 – 1.0 | ❌ No | Live vs. studio recording β€” unrelated to emotion |
| `key` | int | 0 – 11 (Pitch) | ❌ No | Musical key β€” no emotion mapping |
| `time_signature` | int | 3 – 7 | ❌ No | Rhythmic metre β€” no emotion mapping |
| `duration_ms` | int | ms | ❌ No | Song length β€” unrelated |
**Summary**: We can confidently map 5 features (`valence`, `energy`, `danceability`, `tempo`, `mode`),
partially use 2 more (`loudness`, `speechiness`), and skip the remaining 6.
---
## 3. Emotion β†’ Spotify Feature Targets
These are the numeric ranges passed as `target_*` parameters to `/v1/recommendations`.
Where the classifier returns a **full probability distribution**, the top-2 emotions are
**blended by their probabilities** (weighted average) for a more nuanced query.
| Emotion | `target_valence` | `target_energy` | `target_danceability` | `target_tempo` (BPM) | `target_mode` | `seed_genres` |
|-----------|-----------------|-----------------|----------------------|---------------------|---------------|--------------------------|
| joy | 0.85 | 0.82 | 0.80 | 128 | 1 (major) | pop, dance |
| love | 0.75 | 0.52 | 0.62 | 96 | 1 (major) | romance, r-n-b |
| sadness | 0.18 | 0.28 | 0.32 | 72 | 0 (minor) | sad, indie, acoustic |
| anger | 0.18 | 0.88 | 0.58 | 148 | 0 (minor) | metal, hard-rock |
| fear | 0.22 | 0.52 | 0.38 | 88 | 0 (minor) | ambient, dark |
| surprise | 0.62 | 0.80 | 0.70 | 138 | 1 (major) | pop, electronic |
| neutral | 0.50 | 0.38 | 0.50 | 100 | 1 (major) | chill, study |
| sarcasm | 0.45 | 0.60 | 0.55 | 110 | 0 (minor) | alternative, indie |
### Blended Query Example
Input: *"I'm excited but kind of scared"*
β†’ Classifier: 52% surprise + 35% fear
β†’ Blended targets:
- `target_valence` = (0.52 Γ— 0.62) + (0.35 Γ— 0.22) = 0.40
- `target_energy` = (0.52 Γ— 0.80) + (0.35 Γ— 0.52) = 0.60
- `target_tempo` = (0.52 Γ— 138) + (0.35 Γ— 88) = 103 BPM
---
## 4. Core System Components
### 4.1 Emotion Classifier (`src/predict.py`)
- **Model**: DeBERTa-v3-Base fine-tuned on ~59k samples (GoEmotions + dair-ai/emotion)
- **Output**: 8 emotion classes β€” `sadness`, `joy`, `love`, `anger`, `fear`, `surprise`, `neutral`, `sarcasm`
- **Sarcasm handling**: Bayesian prior adjustment (`target_sarcasm_prior`) corrects training-domain bias
- **Output format**: Primary emotion + full probability distribution + confidence score + music context
- **Current accuracy**: ~65.6% weighted F1 on validation; 95%+ on unambiguous direct expressions
### 4.2 Emotion β†’ Feature Mapper (`src/spotify.py` β€” to be built)
- Converts classifier output to numeric Spotify `target_*` parameters
- Implements probability-weighted blending across top-2 emotions
- Expands confidence score into `min_*/max_*` constraint windows:
- High confidence (>0.75) β†’ tight window (Β±0.08 around target)
- Medium confidence (0.45–0.75) β†’ medium window (Β±0.15)
- Low confidence (<0.45) β†’ wide window (Β±0.25), broader genre seeds
### 4.3 Spotify Integration (`src/spotify.py` β€” to be built)
**Endpoints used:**
- `GET /v1/recommendations` β€” Core call with `target_valence`, `target_energy`, `target_danceability`,
`target_tempo`, `target_mode`, `seed_genres`, `limit`
- `GET /v1/audio-features/{id}` β€” Fetch actual features of returned tracks for match scoring
- `GET /v1/search` β€” Optional seed track lookup by title/artist
**Authentication**: OAuth 2.0 Client Credentials flow (no user login needed for recommendations)
### 4.4 Recommendation Ranker (`src/spotify.py` β€” to be built)
After Spotify returns candidates, EUMORA re-ranks using:
- **Feature distance score**: Euclidean distance across [`valence`, `energy`, `danceability`, `tempo_norm`]
between the emotion target vector and each track's actual audio features
- **Diversity filter**: Max 2 tracks per artist in top-10
- **Output**: Ordered list of tracks with per-track match score (0–100)
---
## 5. Data Flow (End-to-End)
```
User Input: "City lights blur as I'm driving through the night"
↓
[ EmotionPredictor β€” src/predict.py ]
DeBERTa-v3-Base β†’ 8-class softmax β†’ sarcasm calibration
↓
{ emotion: "fear", confidence: 0.54, probabilities: {fear: 0.54, anger: 0.23, ...} }
↓
[ Feature Mapper β€” src/spotify.py ]
Blend top-2 emotions (fear Γ— 0.54 + anger Γ— 0.23, normalised)
β†’ { target_valence: 0.19, target_energy: 0.73, target_danceability: 0.46,
target_tempo: 122, target_mode: 0, seed_genres: ["dark", "hard-rock"] }
↓
[ Spotify Recommendations API ]
GET /v1/recommendations?target_valence=0.19&target_energy=0.73&limit=20&seed_genres=dark,hard-rock
↓
20 raw candidate tracks (with audio_features fetched per track)
↓
[ Ranker β€” src/spotify.py ]
Euclidean distance scoring + artist diversity filter
↓
Top 10 tracks with match scores + Spotify links
↓
User Output (CLI / future: UI)
```
---
## 6. CLI Interface
| Command | What it does |
|---|---|
| `python main.py predict "text"` | Emotion only (existing) |
| `python main.py recommend "text"` | Full pipeline β†’ Spotify tracks *(to be added)* |
| `python main.py recommend "text" --limit 5` | Top 5 recommendations |
| `python main.py recommend "text" --genre rock` | Override seed genre |
| `python main.py recommend "text" --no-blend` | Use top-1 emotion only, no blending |
---
## 7. What It Does NOT Do (Phase 1 Scope)
- Does not map `acousticness`, `instrumentalness`, `liveness`, `key`, `time_signature` β€” no text-to-audio model for these
- Does not personalize based on user listening history (no user OAuth)
- Does not analyze audio files or waveforms (text-only)
- Does not stream or play music directly
- Does not guarantee sarcasm accuracy β€” calibration mitigates it
---
## 8. Planned Extensions (Phase 2+)
| Feature | Phase | Description |
|---|---|---|
| User preference learning | 2 | OAuth login; bias toward user's top genres/artists |
| Audio file analysis | 3 | Upload a recording; extract features via librosa |
| Acousticness/instrumentalness mapping | 3 | Infer from audio+lyrics combined model |
| Multimodal fusion | 4 | Combine lyrics emotion + audio features |
| Web UI | 5 | Browser interface with Spotify 30s clip previews |
| Playlist generation | 5 | Multi-text input β†’ coherent 10-track playlist |
---
## 9. New Dependencies
| Library | Version | Role |
|---|---|---|
| `spotipy` | `>=2.23.0` | Spotify Web API client β€” handles OAuth + all endpoint calls |
Add to `requirements.txt`:
```
spotipy>=2.23.0
```