Skip to content

Commit ed55206

Browse files
refactor: update profile constants and enhance recommendation logic
1 parent 3bea071 commit ed55206

File tree

4 files changed

+194
-156
lines changed

4 files changed

+194
-156
lines changed

app/services/profile/constants.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,14 @@
4848
FREQUENCY_MULTIPLIER_LOG_FACTOR: Final[float] = 0.1 # Subtle boost
4949

5050
# Top Picks Caps (diversity constraints)
51-
TOP_PICKS_RECENCY_CAP: Final[float] = 0.10 # Max 10% recent items (from trending/popular)
52-
TOP_PICKS_GENRE_CAP: Final[float] = 0.40 # Max 40% per genre
51+
TOP_PICKS_RECENCY_CAP: Final[float] = 0.15 # Max 15% recent items (from trending/popular)
52+
TOP_PICKS_GENRE_CAP: Final[float] = 0.50 # Max 50% per genre
5353
TOP_PICKS_CREATOR_CAP: Final[int] = 3 # Max 3 items per creator (director/actor)
54-
TOP_PICKS_ERA_CAP: Final[float] = 0.40 # Max 40% per era
55-
TOP_PICKS_MIN_VOTE_COUNT: Final[int] = 500 # Minimum vote count for quality
56-
TOP_PICKS_MIN_RATING: Final[float] = 7.5 # Minimum weighted rating for quality
54+
TOP_PICKS_ERA_CAP: Final[float] = 0.50 # Max 50% per era
55+
TOP_PICKS_MIN_VOTE_COUNT: Final[int] = 250 # Lower noise filter
56+
TOP_PICKS_MIN_RATING: Final[float] = 7.2 # Minimum weighted rating
57+
58+
MAXIMUM_POPULARITY_SCORE: Final[float] = 15
5759

5860
# Genre whitelist limit (top N genres)
5961
GENRE_WHITELIST_LIMIT: Final[int] = 7

app/services/profile/sampling.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def sample_items(
6969
if not (it.get("_is_loved") or it.get("_is_liked") or it.get("_id") in added_item_ids)
7070
]
7171

72-
# Always include strong signal items: Loved/Liked: 45%, Added: 20%
72+
# Always include strong signal items: Loved/Liked: 30%, Added: 20%
7373
strong_signal_items = loved_liked_items[: int(max_items * 0.45)] + added_items[: int(max_items * 0.20)]
7474
strong_signal_scored = [self.scoring_service.process_item(it) for it in strong_signal_items]
7575

app/services/recommendation/scoring.py

Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from typing import Any
55

66
from app.core.constants import DEFAULT_MINIMUM_RATING_FOR_THEME_BASED_MOVIE, DEFAULT_MINIMUM_RATING_FOR_THEME_BASED_TV
7+
from app.services.profile.constants import MAXIMUM_POPULARITY_SCORE
78

89

910
class RecommendationScoring:
@@ -91,31 +92,21 @@ def m_raw(year: int | None) -> float:
9192
return m_raw, alpha
9293

9394
@staticmethod
94-
def apply_quality_adjustments(score: float, wr: float, vote_count: int, is_ranked: bool, is_fresh: bool) -> float:
95-
"""Apply multiplicative adjustments based on item quality and source."""
96-
q_mult = 1.0
97-
if vote_count < 50:
98-
q_mult *= 0.75
99-
elif vote_count < 150:
100-
q_mult *= 0.90
101-
102-
if wr < 5.5:
103-
q_mult *= 0.5
104-
elif wr < 6.0:
105-
q_mult *= 0.7
106-
elif wr >= 7.0 and vote_count >= 500:
107-
q_mult *= 1.10
108-
109-
if is_ranked:
110-
if wr >= 6.5 and vote_count >= 200:
111-
q_mult *= 1.25
112-
elif wr >= 6.0 and vote_count >= 100:
113-
q_mult *= 1.10
114-
115-
if is_fresh and wr >= 7.0 and vote_count >= 300:
116-
q_mult *= 1.10
117-
118-
return score * q_mult
95+
def apply_quality_adjustments(
96+
score: float, wr: float, vote_count: int, popularity: float, is_ranked: bool, is_fresh: bool
97+
) -> float:
98+
"""Apply simple quality boost for high-confidence items only."""
99+
# Simplified: only boost proven high-quality items, no penalties
100+
# Trust the weighted rating formula to handle low vote counts naturally
101+
if vote_count >= 1000 and wr >= 7.5 and popularity <= MAXIMUM_POPULARITY_SCORE:
102+
# Proven gem: high confidence, high quality
103+
return score * 1.10
104+
elif vote_count >= 500 and wr >= 7.0 and popularity <= MAXIMUM_POPULARITY_SCORE:
105+
# Good confidence and quality
106+
return score * 1.05
107+
108+
# Everything else: trust the base scoring
109+
return score
119110

120111
@staticmethod
121112
def calculate_final_score(
@@ -158,13 +149,14 @@ def calculate_final_score(
158149
)
159150
quality_score = RecommendationScoring.normalize(wr)
160151

161-
# Apply quality adjustments
152+
# Simple weighted combination: profile match is primary, quality ensures no bad items
153+
base_score = (profile_score * 0.70) + (quality_score * 0.30)
154+
155+
# light boost for high-confidence items (no penalties!)
162156
vote_count = item.get("vote_count", 0)
163-
adjusted_profile_score = RecommendationScoring.apply_quality_adjustments(
164-
profile_score, wr, vote_count, is_ranked=is_ranked, is_fresh=is_fresh
157+
popularity = item.get("popularity", 0)
158+
final_score = RecommendationScoring.apply_quality_adjustments(
159+
base_score, wr, vote_count, popularity, is_ranked=is_ranked, is_fresh=is_fresh
165160
)
166161

167-
# Combined score: profile similarity (with quality adjustments) + quality
168-
final_score = (adjusted_profile_score * 0.6) + (quality_score * 0.4)
169-
170162
return final_score

0 commit comments

Comments
 (0)