"""Compress Spotify taste signals for prompts and known-track filtering.""" from app.domain.models import CompressedTasteProfile, TasteProfile, Track def compress_taste_profile(profile: TasteProfile) -> CompressedTasteProfile: """Build compact prompt text and the complete known track identifier set.""" # No genre section on purpose: Spotify deprecated the artist genres # field for new apps, so there is no reliable genre source left in the # API. Artist and track names are the genre evidence the model reads. sections = ( _line("Short-term top artists", profile.short_term_artists), _line("Long-term top artists", profile.long_term_artists), _line("Short-term top tracks", _track_labels(profile.short_term_tracks)), _line("Long-term top tracks", _track_labels(profile.long_term_tracks)), _line("Saved-track sample", _track_labels(profile.saved_tracks)), ) known_tracks = (*profile.short_term_tracks, *profile.long_term_tracks, *profile.saved_tracks) return CompressedTasteProfile( text="\n".join(sections), known_track_ids=frozenset(track.id for track in known_tracks), ) def _track_labels(tracks: tuple[Track, ...]) -> tuple[str, ...]: return tuple(f"{track.title} by {', '.join(track.artists)}" for track in tracks) def _line(label: str, values: tuple[str, ...]) -> str: rendered_values = "; ".join(values) if values else "none" return f"{label}: {rendered_values}"