83 lines
1.8 KiB
Python
83 lines
1.8 KiB
Python
"""Pure domain models shared across application boundaries."""
|
|
|
|
from dataclasses import dataclass
|
|
from enum import StrEnum
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Track:
|
|
"""A Spotify track expressed without transport-specific data."""
|
|
|
|
id: str
|
|
uri: str
|
|
title: str
|
|
artists: tuple[str, ...]
|
|
album_name: str
|
|
album_art_url: str | None
|
|
external_url: str | None
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class TrackCandidate:
|
|
"""A title and artist pair proposed for Spotify resolution."""
|
|
|
|
title: str
|
|
artist: str
|
|
|
|
|
|
class Familiarity(StrEnum):
|
|
"""How strongly a request should favor known or unknown music."""
|
|
|
|
FAMILIAR = "familiar"
|
|
MIX = "mix"
|
|
NEW = "new"
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Intent:
|
|
"""Structured interpretation and candidate set for a discovery query."""
|
|
|
|
mood: tuple[str, ...]
|
|
activity: str | None
|
|
era: tuple[str, ...]
|
|
languages: tuple[str, ...]
|
|
genres: tuple[str, ...]
|
|
familiarity: Familiarity
|
|
is_refinement: bool
|
|
intent_summary: str
|
|
candidates: tuple[TrackCandidate, ...]
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class RerankSelection:
|
|
"""One grounded track selected by the recommender."""
|
|
|
|
track_id: str
|
|
justification: str
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class TasteProfile:
|
|
"""Bounded Spotify taste signals collected for one session."""
|
|
|
|
short_term_artists: tuple[str, ...]
|
|
long_term_artists: tuple[str, ...]
|
|
short_term_tracks: tuple[Track, ...]
|
|
long_term_tracks: tuple[Track, ...]
|
|
saved_tracks: tuple[Track, ...]
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class CompressedTasteProfile:
|
|
"""Prompt-ready taste text plus exact known Spotify track identifiers."""
|
|
|
|
text: str
|
|
known_track_ids: frozenset[str]
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class CreatedPlaylist:
|
|
"""The application-owned result of creating a Spotify playlist."""
|
|
|
|
id: str
|
|
url: str
|