feat(recommendations): collect demographics and advance age cohorts
ci / ts / ts (packages + web) (push) Successful in 3m19s
ci / db / db (push) Successful in 53s
ci / module boundaries / boundaries (push) Successful in 7s
ci / api / api (push) Successful in 51s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m3s
ci / recommender / recommender (push) Failing after 16s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m15s
ci / ts / ts (packages + web) (push) Successful in 3m19s
ci / db / db (push) Successful in 53s
ci / module boundaries / boundaries (push) Successful in 7s
ci / api / api (push) Successful in 51s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m3s
ci / recommender / recommender (push) Failing after 16s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m15s
This commit is contained in:
1 parent
e158558da3
commit
fff91c446b
24 files changed
+778
-324
No files matched your search
@@ -161,6 +161,9 @@ def load_profile(conn: psycopg.Connection[Any], user_id: str) -> Profile:
|
||||
).fetchone()
|
||||
if row and row[3] and len(scores) < ONBOARDING_UNTIL:
|
||||
apply_onboarding(conn, scores, row[3])
|
||||
apply_demographics(conn, scores, row[3], user_id)
|
||||
for tid in disliked:
|
||||
scores.pop(tid, None)
|
||||
exploration = float(row[0]) if row else 0.15
|
||||
taste_cf = parse_vector(row[1]) if row else None
|
||||
bandit = {str(k): [float(x) for x in v] for k, v in (row[2] or {}).items()} if row else {}
|
||||
@@ -212,6 +215,35 @@ def apply_onboarding(conn: psycopg.Connection[Any], scores: dict[str, float], ch
|
||||
scores.setdefault(tid, v)
|
||||
|
||||
|
||||
def apply_demographics(
|
||||
conn: psycopg.Connection[Any], scores: dict[str, float], choice: dict[str, Any], user_id: str
|
||||
) -> None:
|
||||
"""A weak cold-start prior from actual likes of peers, without assumed musical stereotypes."""
|
||||
gender, age = choice.get("gender"), choice.get("age_group")
|
||||
if not gender and not age:
|
||||
return
|
||||
rows = conn.execute(
|
||||
"""
|
||||
WITH own AS (
|
||||
SELECT onboarding FROM user_profiles_rec WHERE user_id = %s
|
||||
), peers AS (
|
||||
SELECT p.user_id FROM user_profiles_rec p JOIN users u ON u.id = p.user_id, own
|
||||
WHERE p.user_id <> %s AND NOT u.is_blocked
|
||||
AND (%s::text IS NULL OR p.onboarding->>'gender' = %s)
|
||||
AND (%s::text IS NULL OR rec_age_group(p.onboarding) = rec_age_group(own.onboarding))
|
||||
)
|
||||
SELECT r.track_id::text, count(DISTINCT r.user_id) AS fans
|
||||
FROM track_reactions r JOIN peers p ON p.user_id = r.user_id
|
||||
WHERE r.reaction = 'like'
|
||||
GROUP BY r.track_id HAVING count(DISTINCT r.user_id) >= 2
|
||||
ORDER BY fans DESC, r.track_id LIMIT %s
|
||||
""",
|
||||
(user_id, user_id, gender, gender, age, ONBOARDING_LIMIT),
|
||||
)
|
||||
for tid, fans in rows:
|
||||
scores.setdefault(tid, min(0.25, 0.05 * fans))
|
||||
|
||||
|
||||
def seed_tracks(conn: psycopg.Connection[Any], seed_type: str, seed_id: str) -> list[str]:
|
||||
"""Треки, от которых запущена волна: трек, альбом или исполнитель."""
|
||||
queries = {
|
||||
|
||||
Reference in new issue
Block a user