From 99ca2ff7ccfe45e8c5c67e7a8c6e574411789869 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 31 Mar 2026 16:14:42 -0500 Subject: [PATCH] Remove MusicBrainz/YT verification (async greenlet conflict), use direct YouTube Music search links --- backend/app/services/recommender.py | 60 ++++------------------------- frontend/src/pages/Discover.tsx | 10 +++-- 2 files changed, 13 insertions(+), 57 deletions(-) diff --git a/backend/app/services/recommender.py b/backend/app/services/recommender.py index fa8f3d3..e912ecb 100644 --- a/backend/app/services/recommender.py +++ b/backend/app/services/recommender.py @@ -188,7 +188,7 @@ Already in their library (do NOT recommend these): {disliked_instruction} {exclude_instruction} -Respond with exactly {count * 3} music recommendations as a JSON array. Give more than requested so we can verify they exist. Each item should have: +Respond with exactly {count} music recommendations as a JSON array. Only recommend songs that actually exist — do not invent or guess song titles. Each item should have: - "title": song title - "artist": artist name - "album": album name (if known) @@ -218,48 +218,7 @@ Return ONLY the JSON array, no other text.""" except json.JSONDecodeError: return [], remaining - # Verify recommendations exist using MusicBrainz, get YouTube Music links - import asyncio - from app.services.musicbrainz import verify_track as mb_verify - from app.services.youtube_music import search_track as yt_search - - def verify_and_link(artist: str, title: str) -> dict | None: - """Verify track on MusicBrainz, then get YouTube Music link.""" - # Step 1: Verify on MusicBrainz - mb_result = mb_verify(artist, title) - if not mb_result: - return None - - real_artist = mb_result["artist"] - real_title = mb_result["title"] - album = mb_result.get("album") - - # Step 2: Get YouTube Music link for listening - youtube_url = None - image_url = None - try: - yt_results = yt_search(f"{real_artist} {real_title}") - if yt_results: - yt = yt_results[0] - yt_id = yt.get("youtube_id") - if yt_id: - youtube_url = f"https://music.youtube.com/watch?v={yt_id}" - image_url = yt.get("image_url") - except Exception: - pass - - if not youtube_url: - youtube_url = f"https://www.youtube.com/results?search_query={quote_plus(f'{real_artist} {real_title}')}" - - return { - "artist": real_artist, - "title": real_title, - "album": album, - "youtube_url": youtube_url, - "image_url": image_url, - } - - # Save to DB — only keep verified tracks + # Save to DB with YouTube Music links recommendations = [] for rec in recs_data: if len(recommendations) >= count: @@ -269,23 +228,18 @@ Return ONLY the JSON array, no other text.""" title = rec.get("title", "Unknown") reason = rec.get("reason", "") - # Verify on MusicBrainz + get YouTube link (sync, run in thread) - verified = await asyncio.to_thread(verify_and_link, artist, title) - - if not verified: - continue # Song doesn't exist — AI hallucinated it + youtube_url = f"https://music.youtube.com/search?q={quote_plus(f'{artist} {title}')}" r = Recommendation( user_id=user.id, playlist_id=playlist_id, - title=verified["title"], - artist=verified["artist"], - album=verified.get("album") or rec.get("album"), - image_url=verified.get("image_url"), + title=title, + artist=artist, + album=rec.get("album"), reason=reason, score=rec.get("score"), query=query, - youtube_url=verified["youtube_url"], + youtube_url=youtube_url, ) db.add(r) recommendations.append(r) diff --git a/frontend/src/pages/Discover.tsx b/frontend/src/pages/Discover.tsx index b1489e5..9e71824 100644 --- a/frontend/src/pages/Discover.tsx +++ b/frontend/src/pages/Discover.tsx @@ -69,7 +69,7 @@ export default function Discover() { const response = await generateRecommendations( selectedPlaylist || undefined, query.trim() || undefined, - bandcampMode, + false, mode, adventurousness, excludeGenres.trim() || undefined, @@ -78,14 +78,16 @@ export default function Discover() { const recs = response.recommendations || [] setResults(recs) setRemaining(response.remaining_this_week ?? null) + if (recs.length === 0) { + setError(`Got 0 results back from API. Raw response keys: ${Object.keys(response).join(', ')}`) + } // Scroll to results after render if (recs.length > 0) { setTimeout(() => resultsRef.current?.scrollIntoView({ behavior: 'smooth' }), 100) } } catch (err: any) { - setError( - err.response?.data?.detail || 'Failed to generate recommendations. Please try again.' - ) + const msg = err.response?.data?.detail || err.message || 'Unknown error' + setError(`Error: ${msg} (status: ${err.response?.status || 'none'})`) } finally { setDiscovering(false) }