|
4 | 4 | from typing import Any |
5 | 5 |
|
6 | 6 | 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 |
7 | 8 |
|
8 | 9 |
|
9 | 10 | class RecommendationScoring: |
@@ -91,31 +92,21 @@ def m_raw(year: int | None) -> float: |
91 | 92 | return m_raw, alpha |
92 | 93 |
|
93 | 94 | @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 |
119 | 110 |
|
120 | 111 | @staticmethod |
121 | 112 | def calculate_final_score( |
@@ -158,13 +149,14 @@ def calculate_final_score( |
158 | 149 | ) |
159 | 150 | quality_score = RecommendationScoring.normalize(wr) |
160 | 151 |
|
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!) |
162 | 156 | 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 |
165 | 160 | ) |
166 | 161 |
|
167 | | - # Combined score: profile similarity (with quality adjustments) + quality |
168 | | - final_score = (adjusted_profile_score * 0.6) + (quality_score * 0.4) |
169 | | - |
170 | 162 | return final_score |
0 commit comments