Improve album search normalization and fallback logic
Enhanced normalization by using _matching_engine when available for both search input and database values. Improved album search by considering artist name variations and deduplicating results. Added a fallback mechanism to search all albums by artist to address SQL accent sensitivity issues, increasing robustness in album matching.
This commit is contained in:
parent
c6a9db234a
commit
8620b52709
1 changed files with 61 additions and 8 deletions
|
|
@ -1271,8 +1271,12 @@ class MusicDatabase:
|
||||||
from unidecode import unidecode
|
from unidecode import unidecode
|
||||||
|
|
||||||
# Normalize search terms
|
# Normalize search terms
|
||||||
title_norm = unidecode(title).lower() if title else ""
|
if _matching_engine:
|
||||||
artist_norm = unidecode(artist).lower() if artist else ""
|
title_norm = _matching_engine.normalize_string(title) if title else ""
|
||||||
|
artist_norm = _matching_engine.normalize_string(artist) if artist else ""
|
||||||
|
else:
|
||||||
|
title_norm = unidecode(title).lower() if title else ""
|
||||||
|
artist_norm = unidecode(artist).lower() if artist else ""
|
||||||
|
|
||||||
# Try searching with normalized versions
|
# Try searching with normalized versions
|
||||||
where_conditions = []
|
where_conditions = []
|
||||||
|
|
@ -1312,8 +1316,13 @@ class MusicDatabase:
|
||||||
# Filter results with proper Unicode normalization
|
# Filter results with proper Unicode normalization
|
||||||
filtered_tracks = []
|
filtered_tracks = []
|
||||||
for row in rows:
|
for row in rows:
|
||||||
db_title_norm = unidecode(row['title'].lower()) if row['title'] else ""
|
|
||||||
db_artist_norm = unidecode(row['artist_name'].lower()) if row['artist_name'] else ""
|
if _matching_engine:
|
||||||
|
db_title_norm = _matching_engine.normalize_string(row['title']) if row['title'] else ""
|
||||||
|
db_artist_norm = _matching_engine.normalize_string(row['artist_name']) if row['artist_name'] else ""
|
||||||
|
else:
|
||||||
|
db_title_norm = unidecode(row['title'].lower()) if row['title'] else ""
|
||||||
|
db_artist_norm = unidecode(row['artist_name'].lower()) if row['artist_name'] else ""
|
||||||
|
|
||||||
title_matches = not title or title_norm in db_title_norm
|
title_matches = not title or title_norm in db_title_norm
|
||||||
artist_matches = not artist or artist_norm in db_artist_norm
|
artist_matches = not artist or artist_norm in db_artist_norm
|
||||||
|
|
@ -1707,7 +1716,16 @@ class MusicDatabase:
|
||||||
|
|
||||||
for variation in title_variations:
|
for variation in title_variations:
|
||||||
# Search for this variation
|
# Search for this variation
|
||||||
albums = self.search_albums(title=variation, artist=artist, limit=10, server_source=server_source)
|
albums = []
|
||||||
|
artist_variations = self._get_artist_variations(artist)
|
||||||
|
for artist_variation in artist_variations:
|
||||||
|
found = self.search_albums(title=variation, artist=artist_variation, limit=10, server_source=server_source)
|
||||||
|
# Deduplicate by ID
|
||||||
|
existing_ids = {a.id for a in albums}
|
||||||
|
for album in found:
|
||||||
|
if album.id not in existing_ids:
|
||||||
|
albums.append(album)
|
||||||
|
existing_ids.add(album.id)
|
||||||
|
|
||||||
if albums:
|
if albums:
|
||||||
logger.debug(f"📀 Found {len(albums)} albums for variation '{variation}'")
|
logger.debug(f"📀 Found {len(albums)} albums for variation '{variation}'")
|
||||||
|
|
@ -1728,9 +1746,44 @@ class MusicDatabase:
|
||||||
if best_match and best_confidence >= confidence_threshold:
|
if best_match and best_confidence >= confidence_threshold:
|
||||||
logger.debug(f"✅ Edition match found: '{title}' -> '{best_match.title}' (confidence: {best_confidence:.3f})")
|
logger.debug(f"✅ Edition match found: '{title}' -> '{best_match.title}' (confidence: {best_confidence:.3f})")
|
||||||
return best_match, best_confidence
|
return best_match, best_confidence
|
||||||
else:
|
|
||||||
logger.debug(f"❌ No confident edition match for '{title}' (best: {best_confidence:.3f}, threshold: {confidence_threshold})")
|
# Fallback: Check ALL albums by this artist (resolves SQL accent sensitivity issues #101)
|
||||||
return None, best_confidence
|
# If we haven't found a match yet, fetch broader list from artist and double check
|
||||||
|
if best_confidence < confidence_threshold:
|
||||||
|
logger.debug(f"⚠️ specific title search failed, trying broad artist search fallback for '{artist}'")
|
||||||
|
try:
|
||||||
|
# Get ALL albums by this artist (limit 100 to be safe)
|
||||||
|
# This bypasses SQL 'LIKE' limitations for diacritics (e.g. 'ă' vs 'a')
|
||||||
|
# And relies on Python-side normalization in _calculate_album_confidence
|
||||||
|
artist_albums = []
|
||||||
|
artist_variations = self._get_artist_variations(artist)
|
||||||
|
for artist_var in artist_variations:
|
||||||
|
found_albums = self.search_albums(title="", artist=artist_var, limit=100, server_source=server_source)
|
||||||
|
# Deduplicate
|
||||||
|
existing_ids = {a.id for a in artist_albums}
|
||||||
|
for album in found_albums:
|
||||||
|
if album.id not in existing_ids:
|
||||||
|
artist_albums.append(album)
|
||||||
|
existing_ids.add(album.id)
|
||||||
|
|
||||||
|
if artist_albums:
|
||||||
|
logger.debug(f" Found {len(artist_albums)} total albums for artist fallback")
|
||||||
|
|
||||||
|
for album in artist_albums:
|
||||||
|
confidence = self._calculate_album_confidence(title, artist, album, expected_track_count)
|
||||||
|
if confidence > best_confidence:
|
||||||
|
best_confidence = confidence
|
||||||
|
best_match = album
|
||||||
|
logger.debug(f" 🎯 Fallback match: '{album.title}' confidence: {confidence:.3f}")
|
||||||
|
except Exception as fallback_error:
|
||||||
|
logger.warning(f"Fallback artist search failed: {fallback_error}")
|
||||||
|
|
||||||
|
if best_match and best_confidence >= confidence_threshold:
|
||||||
|
logger.debug(f"✅ Fallback match succeeded: '{title}' -> '{best_match.title}' (confidence: {best_confidence:.3f})")
|
||||||
|
return best_match, best_confidence
|
||||||
|
|
||||||
|
logger.debug(f"❌ No confident edition match for '{title}' (best: {best_confidence:.3f}, threshold: {confidence_threshold})")
|
||||||
|
return None, best_confidence
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error in edition-aware album matching for '{title}' by '{artist}': {e}")
|
logger.error(f"Error in edition-aware album matching for '{title}' by '{artist}': {e}")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue