Skip to content

Commit 0733695

Browse files
feat: add candidate filtering by watched items and genre whitelist
1 parent 390d69c commit 0733695

File tree

1 file changed

+41
-19
lines changed

1 file changed

+41
-19
lines changed

app/services/recommendation/engine.py

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,37 @@ def _apply_diversification(self, pool: list, targets: dict, max_results: int) ->
594594

595595
return result
596596

597+
def _filter_candidates_by_watched_and_genres(
598+
self, candidates: list[dict], watched_tmdb: set[int], whitelist: set[int], existing_ids: set[int] | None = None
599+
) -> list[dict]:
600+
"""
601+
Filter candidates by watched items and genre whitelist.
602+
603+
Args:
604+
candidates: List of candidate items to filter
605+
watched_tmdb: Set of watched TMDB IDs to exclude
606+
whitelist: Set of preferred genre IDs
607+
existing_ids: Optional set of IDs to exclude (for deduplication)
608+
609+
Returns:
610+
Filtered list of candidates
611+
"""
612+
filtered = []
613+
existing = existing_ids or set()
614+
615+
for it in candidates:
616+
item_id = it.get("id")
617+
if not item_id or item_id in existing:
618+
continue
619+
if item_id in watched_tmdb:
620+
continue
621+
if not RecommendationFiltering.passes_top_genre_whitelist(it.get("genre_ids"), whitelist):
622+
continue
623+
filtered.append(it)
624+
existing.add(item_id)
625+
626+
return filtered
627+
597628
async def get_recommendations_for_theme(self, theme_id: str, content_type: str, limit: int = 20) -> list[dict]:
598629
"""Parse theme and fetch recommendations with strict filtering."""
599630
params = {}
@@ -667,13 +698,7 @@ async def get_recommendations_for_theme(self, theme_id: str, content_type: str,
667698
)
668699

669700
# Initial filter
670-
filtered = []
671-
for it in candidates:
672-
if it.get("id") in watched_tmdb:
673-
continue
674-
if not RecommendationFiltering.passes_top_genre_whitelist(it.get("genre_ids"), whitelist):
675-
continue
676-
filtered.append(it)
701+
filtered = self._filter_candidates_by_watched_and_genres(candidates, watched_tmdb, whitelist)
677702

678703
# If we still don't have enough candidates, fetch more pages
679704
max_page_fetched = max(pages_to_fetch) if pages_to_fetch else 0
@@ -688,21 +713,18 @@ async def get_recommendations_for_theme(self, theme_id: str, content_type: str,
688713
self.tmdb_service.get_discover(content_type, page=p, **params) for p in additional_pages
689714
]
690715
additional_results = await asyncio.gather(*additional_tasks, return_exceptions=True)
691-
# Track already processed IDs to avoid duplicates
692-
existing_ids = {it.get("id") for it in filtered}
716+
# Collect new candidates from additional pages
717+
new_candidates = []
693718
for res in additional_results:
694719
if isinstance(res, Exception):
695720
continue
696-
for it in res.get("results", []):
697-
item_id = it.get("id")
698-
if not item_id or item_id in existing_ids:
699-
continue
700-
if item_id in watched_tmdb:
701-
continue
702-
if not RecommendationFiltering.passes_top_genre_whitelist(it.get("genre_ids"), whitelist):
703-
continue
704-
filtered.append(it)
705-
existing_ids.add(item_id)
721+
new_candidates.extend(res.get("results", []))
722+
# Filter new candidates, excluding already processed ones
723+
existing_ids = {it.get("id") for it in filtered}
724+
additional_filtered = self._filter_candidates_by_watched_and_genres(
725+
new_candidates, watched_tmdb, whitelist, existing_ids
726+
)
727+
filtered.extend(additional_filtered)
706728
except Exception as e:
707729
logger.warning(f"Failed to fetch additional pages: {e}")
708730

0 commit comments

Comments
 (0)