Remove MusicBrainz/YT verification (async greenlet conflict), use direct YouTube Music search links

This commit is contained in:
root
2026-03-31 16:14:42 -05:00
parent a0d9f1f9d9
commit 99ca2ff7cc
2 changed files with 13 additions and 57 deletions

View File

@@ -188,7 +188,7 @@ Already in their library (do NOT recommend these):
{disliked_instruction} {disliked_instruction}
{exclude_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 - "title": song title
- "artist": artist name - "artist": artist name
- "album": album name (if known) - "album": album name (if known)
@@ -218,48 +218,7 @@ Return ONLY the JSON array, no other text."""
except json.JSONDecodeError: except json.JSONDecodeError:
return [], remaining return [], remaining
# Verify recommendations exist using MusicBrainz, get YouTube Music links # Save to DB with 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
recommendations = [] recommendations = []
for rec in recs_data: for rec in recs_data:
if len(recommendations) >= count: if len(recommendations) >= count:
@@ -269,23 +228,18 @@ Return ONLY the JSON array, no other text."""
title = rec.get("title", "Unknown") title = rec.get("title", "Unknown")
reason = rec.get("reason", "") reason = rec.get("reason", "")
# Verify on MusicBrainz + get YouTube link (sync, run in thread) youtube_url = f"https://music.youtube.com/search?q={quote_plus(f'{artist} {title}')}"
verified = await asyncio.to_thread(verify_and_link, artist, title)
if not verified:
continue # Song doesn't exist — AI hallucinated it
r = Recommendation( r = Recommendation(
user_id=user.id, user_id=user.id,
playlist_id=playlist_id, playlist_id=playlist_id,
title=verified["title"], title=title,
artist=verified["artist"], artist=artist,
album=verified.get("album") or rec.get("album"), album=rec.get("album"),
image_url=verified.get("image_url"),
reason=reason, reason=reason,
score=rec.get("score"), score=rec.get("score"),
query=query, query=query,
youtube_url=verified["youtube_url"], youtube_url=youtube_url,
) )
db.add(r) db.add(r)
recommendations.append(r) recommendations.append(r)

View File

@@ -69,7 +69,7 @@ export default function Discover() {
const response = await generateRecommendations( const response = await generateRecommendations(
selectedPlaylist || undefined, selectedPlaylist || undefined,
query.trim() || undefined, query.trim() || undefined,
bandcampMode, false,
mode, mode,
adventurousness, adventurousness,
excludeGenres.trim() || undefined, excludeGenres.trim() || undefined,
@@ -78,14 +78,16 @@ export default function Discover() {
const recs = response.recommendations || [] const recs = response.recommendations || []
setResults(recs) setResults(recs)
setRemaining(response.remaining_this_week ?? null) 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 // Scroll to results after render
if (recs.length > 0) { if (recs.length > 0) {
setTimeout(() => resultsRef.current?.scrollIntoView({ behavior: 'smooth' }), 100) setTimeout(() => resultsRef.current?.scrollIntoView({ behavior: 'smooth' }), 100)
} }
} catch (err: any) { } catch (err: any) {
setError( const msg = err.response?.data?.detail || err.message || 'Unknown error'
err.response?.data?.detail || 'Failed to generate recommendations. Please try again.' setError(`Error: ${msg} (status: ${err.response?.status || 'none'})`)
)
} finally { } finally {
setDiscovering(false) setDiscovering(false)
} }