Skip to content

Recommender

Recommendation engine internals from musicseed-core (musicseed.recommender.*): candidate generation, scoring, playlist selection, and recommender-population helpers.

Scoring

musicseed.recommender.scoring

Scoring primitives for MusicSeed recommendations.

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 CLI output.

SonicCoverage

Bases: BaseModel

How many scored candidates actually had a Plex sonic vector.

A candidate without a vector scores a neutral 0.5 on the sonic dimension, indistinguishable from a genuine mid-similarity match. Surfacing this count lets a caller tell a flattened dimension from real coverage.

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 or has zero norm.

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 (known 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.

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.

Each signal produces a component in [0, 1]; signals with missing data (no sonic vector, unknown popularity/year, empty tag sets on both sides) contribute the neutral 0.5 rather than zero, so missing data neither rewards nor punishes a candidate. The total is the weighted mean of the components — weights are normalized by their sum, so absolute weight values only control relative importance.

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.

Candidates

musicseed.recommender.candidates

Candidate generation for multi-signal recommendations.

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 a candidate pool from all available recommendation signals.

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; the year window is still applied in SQL),
  • 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.

Playlist

musicseed.recommender.playlist

Playlist recommendation orchestration.

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_tracks(session, *, seed_texts=None, seed_ids=None, limit=50, weights=None, year_min=None, year_max=None, max_tracks_per_artist=3, min_score=None)

Generate recommendations using multi-source candidates and constrained selection.

Pipeline: resolve the seeds, aggregate them into a SeedProfile, build a multi-source candidate pool, score every candidate against the profile, then select greedily in descending total score. Selection enforces the artist diversity constraint — at most max_tracks_per_artist tracks per artist — and stops at limit tracks or at the first candidate below min_score. Seed tracks are never recommended.

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
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

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, 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)

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

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)

Recommend tracks voted for by multiple individual playlist tracks.

Each playlist track is used as its own single-track seed to gather candidates. 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

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)

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

Returns:

Type Description
list[Recommendation]

Scored recommendations, best first.

Raises:

Type Description
ValueError

if method is not a known populate strategy.