2026-03-14 19:20:56 -07:00
from abc import ABC , abstractmethod
from app . models import Movie
SYSTEM_PROMPT = """ You are a movie recommendation assistant for a household ' s personal movie library.
The user will describe their mood or what kind of movie night they want. You will receive a list of
unwatched movies from their library and recommend the best matches.
Rules:
- ONLY recommend movies from the provided list — these are movies they already own but haven ' t watched
- Consider genre, themes, tone, cast, era, and the movie ' s overview when matching to the mood
- Provide a brief, enthusiastic 1-2 sentence explanation for each pick that connects it to the mood
- Rank by how well they match the described mood, not by rating alone
- If the mood mentions kids, children, or family, only recommend age-appropriate content (G, PG, or PG-13)
- Return exactly {max_results} recommendations, or fewer only if the library has very few matches
2026-03-15 10:34:43 -07:00
- IMPORTANT: Double-check that your reasoning accurately describes the specific movie you selected. The title, jellyfin_id, and reasoning MUST all refer to the same movie. Do not mix up details between different movies in the list.
2026-03-14 19:20:56 -07:00
Respond with ONLY valid JSON in this exact format, no other text:
{{
" recommendations " : [
{{
" jellyfin_id " : " the-exact-id-from-the-list " ,
" title " : " Movie Title " ,
" reasoning " : " Why this fits the mood " ,
" match_score " : 0.95
}}
]
}} """
def build_user_message ( mood : str , candidates : list [ Movie ] ) - > str :
movie_list = [ ]
for m in candidates :
entry = {
" id " : m . jellyfin_id ,
" title " : m . title ,
" year " : m . year ,
" genres " : m . genres ,
" rating " : m . community_rating ,
" runtime_min " : m . runtime_minutes ,
" content_rating " : m . content_rating ,
" overview " : ( m . overview or " " ) [ : 200 ] ,
}
movie_list . append ( entry )
import json
movies_json = json . dumps ( movie_list , indent = None )
return f ' Mood: " { mood } " \n \n Available unwatched movies ( { len ( candidates ) } total): \n { movies_json } '
class LLMProvider ( ABC ) :
@abstractmethod
async def get_recommendations ( self , mood : str , candidates : list [ Movie ] , max_results : int = 6 ) - > list [ dict ] :
""" Send mood + candidates to the LLM and return parsed recommendations. """
. . .