Repository navigation
feat(bot): autoplay artist prefer/block preferences - #572
Conversation
- add setArtistFeedback, removeArtistFeedback methods - add getPreferredArtistKeys, getBlockedArtistKeys methods - add getArtistFeedbackSummary for listing user's preferences - store as separate Redis hash with 30d TTL - normalize artist names using cleanAuthor + normalizeText
- update calculateRecommendationScore to accept preferred/blocked artist keys - return -Infinity score for blocked artists (exclude from candidates) - add +0.3 boost for preferred artists - fetch artist preference sets in _replenishQueue - pass artist keys to all candidate collection functions - skip candidates with -Infinity scores
- Add handleAutoplayArtist handler with prefer, block, remove, list subcommands - Integrate with recommendationFeedbackService for artist preference storage - Display preferred/blocked artists with emoji indicators and counts - List subcommand shows all preferred and blocked artists for user
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📜 Recent review details⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
📝 WalkthroughWalkthroughAdds artist-level feedback: new artist subcommand group for /autoplay, RecommendationFeedbackService artist APIs (prefer/block/remove/list) persisted in Redis, and artist-based prefer/block logic wired into queue replenishment and recommendation scoring. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Bot as Autoplay Command
participant Service as Recommendation<br/>Feedback Service
participant Redis as Redis Store
participant Queue as QueueReplenisher
User->>Bot: /autoplay artist prefer {artist}
activate Bot
Bot->>Service: setArtistFeedback(guildId,userId,artist,'prefer')
activate Service
Service->>Service: normalize & validate artist
Service->>Redis: setex music:artist_feedback:{userId} (JSON)
activate Redis
Redis-->>Service: OK
deactivate Redis
Service-->>Bot: success
deactivate Service
Bot-->>User: confirmation embed
deactivate Bot
Note over Bot,Queue: Later: queue refill uses artist feedback
Queue->>Service: getPreferredArtistKeys(userId)
activate Service
Service->>Redis: get music:artist_feedback:{userId}
activate Redis
Redis-->>Service: JSON map
deactivate Redis
Service-->>Queue: Set(preferred)
deactivate Service
Queue->>Queue: collectRecommendationCandidates(..., preferred, blocked)
Queue->>Queue: calculateRecommendationScore(candidate, preferred, blocked)
alt Artist is blocked
Queue->>Queue: return -Infinity (skip)
else Artist is preferred
Queue->>Queue: apply positive boost
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Size Change: 0 B Total Size: 324 kB ℹ️ View Unchanged
|
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/bot/src/utils/music/queueManipulation.ts (2)
809-821:⚠️ Potential issue | 🔴 CriticalGenre candidates need the same blocked-artist guard.
addGenreTrackCandidate()always upserts, even whencalculateRecommendationScore()returns-Infinityfor a blocked artist. That breaks the new “blocked artists are excluded” contract whenever recommendations come fromautoplayGenres.Minimal fix
const rec = calculateRecommendationScore( track, ctx.currentTrack, ctx.recentArtists, ctx.likedTrackKeys, ctx.preferredArtistKeys, ctx.blockedArtistKeys, ctx.autoplayMode, ) + if (rec.score === -Infinity) return upsertScoredCandidate(ctx.candidates, track, { score: rec.score + GENRE_SCORE_BOOST, reason: rec.reason ? `${rec.reason} • ${tag} vibes` : `${tag} vibes`, })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bot/src/utils/music/queueManipulation.ts` around lines 809 - 821, addGenreTrackCandidate currently always calls upsertScoredCandidate even when calculateRecommendationScore returns -Infinity for blocked artists, which violates the blocked-artist exclusion; fix addGenreTrackCandidate (the block around the rec = calculateRecommendationScore and upsertScoredCandidate call) to skip the upsert when rec.score is -Infinity (or otherwise non-finite/represents blocked) so only valid scored candidates are added to ctx.candidates; use the existing calculateRecommendationScore and upsertScoredCandidate symbols to locate and guard the insertion.
731-745:⚠️ Potential issue | 🔴 CriticalBlocked artists still leak through the Last.fm similar-track branch.
This path now passes
blockedArtistKeysintocalculateRecommendationScore(), but unlike the seed and broad-fallback loops it never short-circuits onrec.score === -Infinity. If this branch is the only one producing candidates, a blocked artist can still be selected and queued.Minimal fix
const rec = calculateRecommendationScore( track, currentTrack, recentArtists, likedTrackKeys, preferredArtistKeys, blockedArtistKeys, autoplayMode, ) + if (rec.score === -Infinity) continue upsertScoredCandidate(candidates, track, { score: (rec.score + LASTFM_SCORE_BOOST) * (s.match / 100), reason: rec.reason ? `${rec.reason} • similar to your taste` : 'similar to your taste',🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bot/src/utils/music/queueManipulation.ts` around lines 731 - 745, The Last.fm branch calls calculateRecommendationScore(...) and immediately upserts candidates, allowing blocked artists to leak; change this to skip inserting when calculateRecommendationScore returns rec.score === -Infinity (i.e., treat it as a rejected/blocked track). Specifically, in the block that computes rec via calculateRecommendationScore(track, currentTrack, recentArtists, likedTrackKeys, preferredArtistKeys, blockedArtistKeys, autoplayMode) and then calls upsertScoredCandidate(...), add a guard that if rec.score === -Infinity you do not call upsertScoredCandidate (continue/return from the loop), preserving the existing score/ reason logic (including LASTFM_SCORE_BOOST and s.match multiplier) only for non-rejected rec values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/bot/src/services/musicRecommendation/feedbackService.ts`:
- Around line 224-226: The code reads the whole artist feedback map with
getArtistFeedbackMap, mutates it and writes it back with saveArtistFeedbackMap
which causes lost updates under concurrency; replace that read-modify-write with
an atomic update (either switch to a Redis hash and use HSET with a per-user key
so you can set artistKey directly, or implement a Redis transaction/LUA script
that updates the JSON map atomically and retries on watch failure). Update both
call sites that currently call getArtistFeedbackMap/saveArtistFeedbackMap (the
block around the map[artistKey] = feedback and the other occurrence at lines
~245-247) to use the new atomic setter (or HSET) instead and remove the
non-atomic round-trip.
- Around line 285-299: getArtistFeedbackSummary currently returns normalized
storage keys instead of human-readable artist names; change it to resolve each
artistKey from getArtistFeedbackMap into a display name before pushing to
preferred/blocked. For each artistKey from the map, look up the artist record
(e.g. via an existing lookup like this.getArtistByKey, this.artistStore.get, or
a similar method) and use its display/name field (falling back to artistKey if
no record) when populating the preferred and blocked arrays, then return those
display names. Ensure you only change getArtistFeedbackSummary and keep the
returned shape { preferred: string[]; blocked: string[] } so callers such as the
autoplay command render human-friendly names.
- Around line 214-255: Change setArtistFeedback and removeArtistFeedback to
return a success boolean (Promise<boolean>) instead of void: if
normalizeArtistKey(...) returns falsy immediately return false; after loading
and mutating the map via getArtistFeedbackMap(...) and
saveArtistFeedbackMap(...), return true on success; in each catch block return
false (and still call errorLog with the same context). Use the existing symbols
normalizeArtistKey, getArtistFeedbackMap, and saveArtistFeedbackMap to locate
the logic and ensure callers (e.g., the autoplay command) can await the boolean
result to decide whether to show a success embed.
---
Outside diff comments:
In `@packages/bot/src/utils/music/queueManipulation.ts`:
- Around line 809-821: addGenreTrackCandidate currently always calls
upsertScoredCandidate even when calculateRecommendationScore returns -Infinity
for blocked artists, which violates the blocked-artist exclusion; fix
addGenreTrackCandidate (the block around the rec = calculateRecommendationScore
and upsertScoredCandidate call) to skip the upsert when rec.score is -Infinity
(or otherwise non-finite/represents blocked) so only valid scored candidates are
added to ctx.candidates; use the existing calculateRecommendationScore and
upsertScoredCandidate symbols to locate and guard the insertion.
- Around line 731-745: The Last.fm branch calls
calculateRecommendationScore(...) and immediately upserts candidates, allowing
blocked artists to leak; change this to skip inserting when
calculateRecommendationScore returns rec.score === -Infinity (i.e., treat it as
a rejected/blocked track). Specifically, in the block that computes rec via
calculateRecommendationScore(track, currentTrack, recentArtists, likedTrackKeys,
preferredArtistKeys, blockedArtistKeys, autoplayMode) and then calls
upsertScoredCandidate(...), add a guard that if rec.score === -Infinity you do
not call upsertScoredCandidate (continue/return from the loop), preserving the
existing score/ reason logic (including LASTFM_SCORE_BOOST and s.match
multiplier) only for non-rejected rec values.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 084d5ecd-f075-4791-b3dc-1dad32ba61e9
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (6)
packages/bot/src/functions/music/commands/autoplay.spec.tspackages/bot/src/functions/music/commands/autoplay.tspackages/bot/src/services/musicRecommendation/feedbackService.spec.tspackages/bot/src/services/musicRecommendation/feedbackService.tspackages/bot/src/utils/music/queueManipulation.spec.tspackages/bot/src/utils/music/queueManipulation.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: SonarCloud Scan
- GitHub Check: Quality Gates
- GitHub Check: compressed-size
|
* feat(bot): add artist-level feedback methods to feedbackService - add setArtistFeedback, removeArtistFeedback methods - add getPreferredArtistKeys, getBlockedArtistKeys methods - add getArtistFeedbackSummary for listing user's preferences - store as separate Redis hash with 30d TTL - normalize artist names using cleanAuthor + normalizeText * feat(bot): wire artist preferences into autoplay scoring - update calculateRecommendationScore to accept preferred/blocked artist keys - return -Infinity score for blocked artists (exclude from candidates) - add +0.3 boost for preferred artists - fetch artist preference sets in _replenishQueue - pass artist keys to all candidate collection functions - skip candidates with -Infinity scores * feat: add /autoplay artist subcommand for managing artist preferences - Add handleAutoplayArtist handler with prefer, block, remove, list subcommands - Integrate with recommendationFeedbackService for artist preference storage - Display preferred/blocked artists with emoji indicators and counts - List subcommand shows all preferred and blocked artists for user * test(bot): add artist preference tests for feedback and autoplay * test(bot): add artist key mocks and fix conflict resolution * fix(bot): add missing artist feedback methods and test coverage * test(bot): cover artist handler error paths and default case



Summary
feedbackServicewith artist-level feedback:setArtistFeedback,removeArtistFeedback,getPreferredArtistKeys,getBlockedArtistKeys,getArtistFeedbackSummarycleanAuthor()+ lowercase for consistent matchingcalculateRecommendationScore: blocked artists excluded, preferred get+0.3boost/autoplay artistsubcommand group:prefer,block,remove,listReplaces #571 (rebased onto main after v2.6.91 merge).
Summary by CodeRabbit
New Features
Bug Fixes
Tests