Files
movie-night/app/services/llm/base.py
T

55 lines
2.0 KiB
Python
Raw Normal View History

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
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\nAvailable 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."""
...