Skip to content

Recommender

Recommendation engine internals from musicseed-core (musicseed.recommender.*). Production retrieval scores all eligible non-seed tracks in scalar SQL batches and retains an exact, artist-constrained top-k. Only seeds and selected tracks load ORM graphs. Average uses one library scan; frequency uses one per distinct seed and ranks mean scores, then votes, then IDs.

See recommendation resolvers for the full flow and retrieval decisions for measurements and limits.

Scoring

musicseed.recommender.scoring

Scoring primitives for MusicSeed recommendations.

SignalStatus = Literal['observed', 'neutral_missing', 'not_applicable', 'missing', 'mixed', 'unknown'] module-attribute

Availability of one scoring signal.

observed means the component reflects real data; neutral_missing means it fell back to the neutral 0.5 because required data was absent (no sonic vector, unknown popularity or year); not_applicable means the seed profile has no tag basis (empty seed styles or genres), retaining the weighted 0.5. missing labels absent candidate tags whose historical score is zero (not a neutral fallback). mixed aggregates different evidence states; unknown means an older score supplied no availability metadata.

Weights

Bases: BaseModel

Normalized recommendation weights.

Popularity means proximity to the seed popularity, not an absolute boost. Artist diversity is enforced as a selection constraint, not as a score component. Weights are normalized by their sum at scoring time, so absolute values only control relative importance.

SeedProfile

Bases: BaseModel

Aggregated recommendation signals from one or more seed tracks.

ScoreBreakdown

Bases: BaseModel

Component-level score details for explainable service and surface output.

availability describes each component's evidence, not a confidence probability: observed (a real comparison), neutral_missing (neutral fallback), not_applicable (no seed basis), missing (absent candidate tags), mixed (different per-seed evidence states), or unknown (legacy score).

SonicCoverage

Bases: BaseModel

How many scored candidates have a usable (finite, nonzero) sonic vector.

This is candidate-side availability; a missing/unusable seed profile can still make sonic comparisons neutral. Per-track availability explains that distinction. Stored zero vectors do not count as usable coverage.

has_usable_vector(value)

Whether a vector can supply finite, nonzero sonic evidence.

sonic_comparable(left, right)

Both sides must be usable and have matching dimensions.

cosine_similarity(a, b)

Return cosine similarity normalized from [-1, 1] into [0, 1].

Parameters:

Name Type Description Default
a Sequence[float] | ndarray | None

first vector; None or empty means "unknown".

required
b Sequence[float] | ndarray | None

second vector; None or empty means "unknown".

required

Returns:

Type Description
float

The normalized similarity, or the neutral 0.5 when either vector

float

is missing, zero-norm, non-finite, or dimensionally incompatible.

jaccard(left, right)

Return the Jaccard similarity of two tag sets.

Parameters:

Name Type Description Default
left set[str]

first tag set (e.g. seed styles).

required
right set[str]

second tag set (e.g. candidate styles).

required

Returns:

Type Description
float

|left ∩ right| / |left ∪ right|. Returns the neutral 0.5

float

when both sets are empty (no information either way) and 0.0

float

when exactly one side is empty (historical missing-candidate policy,

float

not proof of an observed mismatch).

average_or_none(values)

Return the mean of the non-None values, or None when there are none.

Parameters:

Name Type Description Default
values Iterable[float | int | None]

numbers, any of which may be None.

required

Returns:

Type Description
float | None

The arithmetic mean over the concrete values, or None when every

float | None

value is None.

popularity_value(normalized, spotify)

Project the existing normalized-first/provider-fallback policy to 0-100.

track_popularity_value(track)

Return the best available popularity value on a 0-100 scale.

build_seed_profile(seed_tracks, vectors)

Aggregate one or more seed tracks into a single recommendation profile.

The sonic embedding is the element-wise mean of the seed vectors (None when no seed has a vector); styles and genres are the union across seeds; year and popularity are averaged over the seeds that have them.

Parameters:

Name Type Description Default
seed_tracks Sequence[Track]

the resolved seed tracks.

required
vectors SonicVectors

the query-time Plex sonic vector store.

required

Returns:

Type Description
SeedProfile

The aggregated seed profile used for candidate generation and

SeedProfile

scoring.

popularity_proximity(seed_popularity, candidate_popularity)

Score how close a candidate's popularity is to the seed's.

Popularity is a proximity signal, not an absolute boost: a candidate at the seed's popularity scores 1.0, and the score decays linearly to 0.0 at 100 popularity points of distance (the full 0-100 scale).

Parameters:

Name Type Description Default
seed_popularity float | None

seed popularity on a 0-100 scale, or None.

required
candidate_popularity float | None

candidate popularity on a 0-100 scale, or None.

required

Returns:

Type Description
float

Proximity in [0, 1], or the neutral 0.5 when either side is

float

unknown.

era_proximity(seed_year, candidate_year)

Score how close a candidate's release year is to the seed's.

Same-year releases score 1.0; the score decays linearly to 0.0 at 50 years of distance.

Parameters:

Name Type Description Default
seed_year int | None

seed release year, or None.

required
candidate_year int | None

candidate release year, or None.

required

Returns:

Type Description
float

Proximity in [0, 1], or the neutral 0.5 when either side is

float

unknown.

novelty_score(play_count)

Score a candidate's novelty from its local play count.

Never-played tracks score 1.0; the score decays as 1 / (1 + 0.2 * plays), so 5 plays yields ~0.5 and 20 plays ~0.2.

Parameters:

Name Type Description Default
play_count int | None

local play count; None is treated as 0.

required

Returns:

Type Description
float

Novelty in (0, 1].

calculate_score(candidate, seed, weights, vectors)

Score one candidate against a seed profile on all six signals.

Components lie in [0, 1]. Missing sonic/popularity/year uses neutral 0.5. Absent seed tags also use 0.5; absent candidate tags with a tagged seed keep the historical score of zero, explicitly labelled missing rather than an observed mismatch. The total is the weighted mean of the components.

Parameters:

Name Type Description Default
candidate Track

the track to score.

required
seed SeedProfile

the aggregated seed profile.

required
weights Weights

per-signal weights.

required
vectors SonicVectors

the query-time Plex sonic vector store.

required

Returns:

Type Description
ScoreBreakdown

The total score plus every component score for explainability.

score_signals(*, candidate_styles, candidate_genres, play_count, candidate_vector, candidate_popularity, candidate_year, seed, weights)

Score scalar facts without an ORM graph; shared with calculate_score.

Component formulas, availability and normalization are identical for the streaming and ORM adapters. No scoring policy is changed by retrieval.

Eligible retrieval and constrained selection

musicseed.recommender.retrieval

Exact constrained top-k scoring of streamed scalar metadata, without ORM graphs.

ScoredTrack dataclass

Only selected IDs, artist identity and explanations survive the scalar scan.

rank property

Rank by score, frequency vote count where relevant, then lower local ID.

ConstrainedTopK

Exact streaming top-k under a per-artist cap, with O(limit) retained scores.

An incoming track displaces the worst from its artist if that group is full; otherwise it displaces the global worst if the selection is full. This is the exchange rule for a cardinality-truncated partition constraint and is equivalent to globally sorting then applying the same artist cap.

__init__(limit, artist_max)

Start an empty constrained selection with positive limits.

add(record)

Consider one distinct candidate; evicted score objects are not retained.

results()

Return the exact selected set in deterministic descending rank order.

score_eligible_tracks(session, seed, vectors, *, limit, weights, year_min=None, year_max=None, max_tracks_per_artist=3, min_score=None, exclude_ids=None)

Filter years, exclude all seeds, score scalar batches and retain exact top-k.

No candidate budget truncates eligibility. SQL reads only scoring columns, stats and tag names. Seeds are excluded before tags/scoring/selection, using membership rather than an unbounded SQL IN list. The caller materializes only the final selected tracks. No artist/album/mood/history graphs are read.

Playlist

musicseed.recommender.playlist

Playlist recommendation orchestration.

RecommendMethod = Literal['average', 'frequency'] module-attribute

Seed aggregation strategies: "average" scores every eligible track against the seeds' mean profile in one scan; "frequency" gathers per-seed votes and ranks by their average score with vote count as a tiebreaker.

Recommendation

Bases: BaseModel

One recommended track with its score breakdown and candidate sources.

resolve_seed_tracks(session, *, seed_texts=None, seed_ids=None)

Resolve seed IDs and seed text queries into loaded Track objects.

Text seeds accept "Artist - Title" or a bare title; exact case-insensitive matches win, otherwise a substring search must narrow to exactly one track. Results are deduplicated, preserving input order.

Parameters:

Name Type Description Default
session Session

open database session.

required
seed_texts Sequence[str] | None

seed tracks as text queries.

None
seed_ids Sequence[int] | None

seed tracks by local database id.

None

Returns:

Type Description
list[Track]

The resolved seed tracks with artist, album, tags, and stats eagerly

list[Track]

loaded.

Raises:

Type Description
ValueError

when a seed id or text matches no track, a text seed is ambiguous (multiple matches), or no seeds were given at all.

recommend_from_profile(session, seed_profile, vectors, *, limit, weights, year_min=None, year_max=None, max_tracks_per_artist=3, min_score=None, exclude_ids=None)

Score eligible scalar facts and materialize only the selected ORM tracks.

recommend_frequency(session, seed_tracks, *, limit, per_seed_limit=30, weights, year_min=None, year_max=None, max_tracks_per_artist=3, min_score=None, vectors, exclude_ids=None)

Recommend tracks voted for by multiple individual seed tracks.

Each seed is used as its own single-track profile to score all eligible candidates; every seed (and any exclude_ids) is excluded up front, and one vector-cache snapshot is reused across seeds. This costs one scalar scan per seed; prefer average mode for large seed sets. A candidate's score is the average of its per-seed scores across every seed that recommended it (its "votes"); results are ranked by that average score, with vote count as a tiebreaker, so limit cuts at the highest-scoring candidates. Each recommendation's sources lists the voting seed ids.

Parameters:

Name Type Description Default
session Session

open database session.

required
seed_tracks list[Track]

resolved seed tracks, each used as an individual seed.

required
limit int

maximum number of recommendations to return.

required
per_seed_limit int

candidates gathered per seed.

30
weights Weights

signal weights.

required
year_min int | None

only recommend tracks released in this year or later.

None
year_max int | None

only recommend tracks released in this year or earlier.

None
max_tracks_per_artist int

artist diversity cap applied during selection.

3
min_score float | None

drop recommendations with a total score below this value.

None
vectors SonicVectors

Plex sonic vectors to score against.

required
exclude_ids set[int] | None

additional track ids to exclude before per-seed budgets; seed track ids are always excluded.

None

Returns:

Type Description
list[Recommendation]

Aggregated recommendations, best first, and the sonic coverage of the

SonicCoverage

candidate pool (identical for every per-seed scan).

recommend_tracks(session, *, seed_texts=None, seed_ids=None, limit=50, method='average', per_seed_limit=30, weights=None, year_min=None, year_max=None, max_tracks_per_artist=3, min_score=None, vectors=None)

Score every eligible non-seed track and return the exact constrained top-k.

Resolve seeds, filter years, stream scalar scoring facts, and retain the best limit under the artist cap and score threshold. method="average" (the default) aggregates the seeds into one mean profile and scores in a single scan; method="frequency" scores each seed individually and ranks by per-seed vote average with vote count as a tiebreaker. This is equivalent to globally sorting by score then local ID, but loads ORM graphs only for seeds and selected tracks. No source budget can omit an eligible candidate. Average-populate uses this same pipeline.

Parameters:

Name Type Description Default
session Session

open database session.

required
seed_texts Sequence[str] | None

seed tracks as text queries (see resolve_seed_tracks).

None
seed_ids Sequence[int] | None

seed tracks by local database id.

None
limit int

maximum number of recommendations to select.

50
method RecommendMethod

"average" or "frequency" (see RecommendMethod).

'average'
per_seed_limit int

candidates gathered per seed ("frequency" method only).

30
weights Weights | None

signal weights; defaults to Weights().

None
year_min int | None

only recommend tracks released in this year or later.

None
year_max int | None

only recommend tracks released in this year or earlier.

None
max_tracks_per_artist int

artist diversity cap applied during selection.

3
min_score float | None

drop recommendations with a total score below this value.

None
vectors SonicVectors | None

Plex sonic vectors to score against; defaults to the default context's cached vectors.

None

Returns:

Type Description
list[Track]

(seed_tracks, selected, sonic_coverage) where sonic_coverage

list[Recommendation]

reports how many candidate tracks had a real Plex sonic vector.

Raises:

Type Description
ValueError

if limit or max_tracks_per_artist is not positive, if method is unknown, if per_seed_limit is not positive in frequency mode, or if the seeds cannot be resolved.

Populate

musicseed.recommender.populate

Recommendation strategies for populating an existing playlist.

PopulateMethod = Literal['average', 'frequency'] module-attribute

Playlist populate strategies: "average" scores against the playlist's mean profile; "frequency" aggregates per-track votes.

populate_average(session, playlist_track_ids, *, limit, weights=None, year_min=None, year_max=None, max_tracks_per_artist=3, min_score=None, vectors=None)

Recommend tracks against the mean sonic/metadata profile of a playlist.

Tracks already in the playlist are excluded automatically because they are the seed set, and recommend_tracks never returns seed tracks.

Parameters:

Name Type Description Default
session Session

open database session.

required
playlist_track_ids list[int]

local ids of the playlist's tracks, used as seeds.

required
limit int

maximum number of recommendations to return.

required
weights Weights | None

signal weights; defaults to Weights().

None
year_min int | None

only recommend tracks released in this year or later.

None
year_max int | None

only recommend tracks released in this year or earlier.

None
max_tracks_per_artist int

artist diversity cap applied during selection.

3
min_score float | None

drop recommendations with a total score below this value.

None
vectors SonicVectors | None

Plex sonic vectors to score against; defaults to the default context's cached vectors.

None

Returns:

Type Description
list[Recommendation]

Scored recommendations, best first.

populate_frequency(session, playlist_track_ids, *, limit, per_seed_limit=30, weights=None, year_min=None, year_max=None, max_tracks_per_artist=3, min_score=None, vectors=None)

Recommend tracks voted for by multiple individual playlist tracks.

Each distinct playlist track is used as its own single-track seed to score all eligible candidates. The entire playlist is excluded before per-seed vote budgets, and one vector-cache snapshot is reused for the request. This costs one scalar scan per seed; prefer average mode for large playlists. A candidate's score is the average of its per-seed scores across every seed that recommended it (its "votes"); results are ranked by that average score, with vote count as a tiebreaker, so --limit cuts at the highest-scoring candidates. This avoids a literal set-intersection across seeds, which collapses to empty once a playlist has more than a handful of tracks.

Parameters:

Name Type Description Default
session Session

open database session.

required
playlist_track_ids list[int]

local ids of the playlist's tracks, each used as an individual seed.

required
limit int

maximum number of recommendations to return.

required
per_seed_limit int

candidates gathered per playlist track.

30
weights Weights | None

signal weights; defaults to Weights().

None
year_min int | None

only recommend tracks released in this year or later.

None
year_max int | None

only recommend tracks released in this year or earlier.

None
max_tracks_per_artist int

artist diversity cap applied during selection.

3
min_score float | None

drop recommendations with a total score below this value.

None
vectors SonicVectors | None

Plex sonic vectors to score against; defaults to the default context's cached vectors.

None

Returns:

Type Description
list[Recommendation]

Aggregated recommendations, best first; each recommendation's

list[Recommendation]

sources lists the seed track ids that voted for it.

populate_playlist_recommendations(session, playlist_track_ids, *, method='average', limit=10, per_seed_limit=30, weights=None, year_min=None, year_max=None, max_tracks_per_artist=3, min_score=None, vectors=None)

Dispatch to the requested populate strategy.

Parameters:

Name Type Description Default
session Session

open database session.

required
playlist_track_ids list[int]

local ids of the playlist's tracks.

required
method PopulateMethod

"average" or "frequency" (see PopulateMethod).

'average'
limit int

maximum number of recommendations to return.

10
per_seed_limit int

candidates gathered per playlist track ("frequency" method only).

30
weights Weights | None

signal weights; defaults to Weights().

None
year_min int | None

only recommend tracks released in this year or later.

None
year_max int | None

only recommend tracks released in this year or earlier.

None
max_tracks_per_artist int

artist diversity cap applied during selection.

3
min_score float | None

drop recommendations with a total score below this value.

None
vectors SonicVectors | None

Plex sonic vectors to score against; defaults to the default context's cached vectors.

None

Returns:

Type Description
list[Recommendation]

Scored recommendations, best first.

Raises:

Type Description
ValueError

if method is not a known populate strategy.

Historical candidate pool

build_candidate_pool is retained for offline baseline comparisons. It is not used as the production retrieval path or as a fallback.

musicseed.recommender.candidates

Historical bounded-retrieval reference for offline evaluation and benchmarks.

Production uses retrieval.score_eligible_tracks. The original source budgets (including their known omissions) stay here as an explicit comparator, not a fallback or alternate user-facing retrieval mode.

CandidatePool

Bases: BaseModel

Merged candidate IDs and the signal sources that produced each candidate.

track_ids property

All distinct candidate track ids in the pool.

add(track_id, source, seed_ids)

Record that source produced track_id as a candidate.

Seed tracks are silently skipped — seeds are never their own candidates.

Parameters:

Name Type Description Default
track_id int

local id of the candidate track.

required
source str

name of the signal source (e.g. "sonic", "genre").

required
seed_ids set[int]

ids of the seed tracks to exclude.

required

add_many(track_ids, source, seed_ids)

Record several candidate ids from one source (see add).

Parameters:

Name Type Description Default
track_ids list[int]

local ids of the candidate tracks.

required
source str

name of the signal source that produced them.

required
seed_ids set[int]

ids of the seed tracks to exclude.

required

sources_for(track_id)

Return the sorted source names that produced a candidate.

Parameters:

Name Type Description Default
track_id int

local id of the candidate track.

required

Returns:

Type Description
list[str]

Sorted source names, or an empty list for an unknown id.

build_candidate_pool(session, seed, vectors, *, limit, year_min=None, year_max=None)

Build the historical bounded pool for diagnostics, not production selection.

Each signal contributes its own bounded query (capped at max(limit * 4, 50) ids) so the pool is a generous superset that the scorer later trims — sources are only included when the seed profile has data for them:

  • sonic — nearest neighbors of the seed embedding in Plex's vectors (ranked in memory, restricted to the year window before ranking),
  • genre / style — tracks sharing any seed genre/style,
  • era — tracks closest to the seed year,
  • popularity — tracks closest to the seed popularity,
  • novelty — least-played tracks first (always included).

The year window filters every source before its limit is applied, so a narrow window searches within the window rather than truncating after the fact. Seed tracks are excluded by CandidatePool.add.

Parameters:

Name Type Description Default
session Session

open database session.

required
seed SeedProfile

the aggregated seed profile.

required
vectors SonicVectors

the query-time Plex sonic vector store.

required
limit int

requested number of final recommendations; per-source queries are bounded to a multiple of this.

required
year_min int | None

only consider tracks released in this year or later.

None
year_max int | None

only consider tracks released in this year or earlier.

None

Returns:

Type Description
CandidatePool

The merged candidate pool, recording which sources produced each

CandidatePool

candidate.