Spaces:
Sleeping
Sleeping
Update utils/movies_explanation.py
Browse files- utils/movies_explanation.py +157 -158
utils/movies_explanation.py
CHANGED
|
@@ -1,158 +1,157 @@
|
|
| 1 |
-
|
| 2 |
-
import
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
return f"We recommend \"{title}\" {year_info}, a {primary_genre_for_explanation.lower()} movie for {audience_phrase}."
|
|
|
|
| 1 |
+
import random
|
| 2 |
+
from typing import Dict, List, Any, Optional, Tuple
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
def generate_explanation(user_tags: Dict[str, Any], item: Dict[str, Any]) -> str:
|
| 6 |
+
"""
|
| 7 |
+
Generates a personalized, natural-sounding explanation for a recommended movie.
|
| 8 |
+
|
| 9 |
+
The explanation dynamically combines matched user preferences (genres, mood, audience)
|
| 10 |
+
with movie attributes (title, director, lead actor, era, original genres/moods)
|
| 11 |
+
using varied templates.
|
| 12 |
+
|
| 13 |
+
Args:
|
| 14 |
+
user_tags (Dict[str, Any]): Parsed tags from the user's query (e.g., genres, mood, target_audience).
|
| 15 |
+
item (Dict[str, Any]): The movie record being recommended, including its annotated attributes.
|
| 16 |
+
|
| 17 |
+
Returns:
|
| 18 |
+
str: A generated explanation string in English.
|
| 19 |
+
"""
|
| 20 |
+
# --- Extract and prepare attributes ---
|
| 21 |
+
title = item.get("title", "this captivating movie")
|
| 22 |
+
director = item.get("director", "a talented director").title() if item.get(
|
| 23 |
+
"director") else "a talented director" # Capitalize
|
| 24 |
+
cast = item.get("cast", [])
|
| 25 |
+
lead_actor = cast[0].title() if cast and cast[0] else "a stellar cast" # Capitalize
|
| 26 |
+
|
| 27 |
+
# Ensure default values are used correctly if lists are empty
|
| 28 |
+
genres_item = item.get("genres")
|
| 29 |
+
if not genres_item:
|
| 30 |
+
genres_item = ["drama"] # Default for explanation if missing or empty
|
| 31 |
+
|
| 32 |
+
mood_item = item.get("mood")
|
| 33 |
+
if not mood_item:
|
| 34 |
+
mood_item = ["captivating"] # Default for explanation if missing or empty
|
| 35 |
+
|
| 36 |
+
era_item = item.get("era", "recent")
|
| 37 |
+
audience_item = item.get("target_audience", "adult")
|
| 38 |
+
|
| 39 |
+
# Try to get release_year from release_date if release_year is not directly available
|
| 40 |
+
release_year = item.get("release_year")
|
| 41 |
+
if not release_year:
|
| 42 |
+
try:
|
| 43 |
+
release_year = int(item.get("release_date", "").split("-")[0])
|
| 44 |
+
except (ValueError, IndexError):
|
| 45 |
+
release_year = None
|
| 46 |
+
|
| 47 |
+
year_info = f"({release_year})" if release_year else f"(from the {era_item} era)" # More descriptive year info
|
| 48 |
+
|
| 49 |
+
# --- Identify matched user preferences ---
|
| 50 |
+
user_genres = user_tags.get("genres", [])
|
| 51 |
+
user_moods = user_tags.get("mood", [])
|
| 52 |
+
|
| 53 |
+
matched_genres = sorted(list(set(user_genres) & set(genres_item)))
|
| 54 |
+
matched_moods = sorted(list(set(user_moods) & set(mood_item)))
|
| 55 |
+
|
| 56 |
+
# Prioritize user's preferred genre and mood if matched, otherwise fall back to item's first
|
| 57 |
+
primary_genre_for_explanation = matched_genres[0] if matched_genres else (
|
| 58 |
+
genres_item[0] if genres_item else "general")
|
| 59 |
+
primary_mood_for_explanation = matched_moods[0] if matched_moods else (mood_item[0] if mood_item else "engaging")
|
| 60 |
+
|
| 61 |
+
# --- Construct dynamic phrases ---
|
| 62 |
+
audience_phrase = ""
|
| 63 |
+
if audience_item == "children":
|
| 64 |
+
audience_phrase = "perfect for the whole family"
|
| 65 |
+
elif audience_item == "young_adult":
|
| 66 |
+
audience_phrase = "ideal for teens and young adults"
|
| 67 |
+
else: # adult
|
| 68 |
+
audience_phrase = "recommended for mature audiences"
|
| 69 |
+
|
| 70 |
+
genre_match_phrase = ""
|
| 71 |
+
if matched_genres:
|
| 72 |
+
if len(matched_genres) == 1:
|
| 73 |
+
genre_match_phrase = f"matching your interest in {matched_genres[0].lower()} films"
|
| 74 |
+
else:
|
| 75 |
+
genre_match_phrase = f"matching your interest in {', '.join(matched_genres).lower()} genres"
|
| 76 |
+
|
| 77 |
+
mood_match_phrase = ""
|
| 78 |
+
if matched_moods:
|
| 79 |
+
if len(matched_moods) == 1:
|
| 80 |
+
mood_match_phrase = f"with a distinctly {matched_moods[0].lower()} vibe"
|
| 81 |
+
else:
|
| 82 |
+
mood_match_phrase = f"offering a mix of {', '.join(matched_moods).lower()} moods"
|
| 83 |
+
elif user_tags.get("mood"): # User asked for mood, but no exact match in movie item's direct moods
|
| 84 |
+
# This covers cases where the user asked for a mood, but the movie's annotated moods didn't perfectly overlap
|
| 85 |
+
mood_match_phrase = f"that aligns with your desire for something {', '.join(user_tags['mood']).lower()}"
|
| 86 |
+
|
| 87 |
+
# --- Diverse and intelligent templates ---
|
| 88 |
+
templates = []
|
| 89 |
+
|
| 90 |
+
# High-specificity templates (when both genre and mood match)
|
| 91 |
+
if matched_genres and matched_moods:
|
| 92 |
+
templates.append(
|
| 93 |
+
f"This is a fantastic pick {audience_phrase}: \"{title}\" {year_info}, directed by {director}, is a {primary_genre_for_explanation.lower()} film, especially {primary_mood_for_explanation.lower()} and {genre_match_phrase}."
|
| 94 |
+
)
|
| 95 |
+
templates.append(
|
| 96 |
+
f"We think you'll love \"{title}\" {year_info}. It's a {primary_genre_for_explanation.lower()} movie, exactly what you asked for {mood_match_phrase} and {genre_match_phrase}."
|
| 97 |
+
)
|
| 98 |
+
templates.append(
|
| 99 |
+
f"Join {lead_actor} in \"{title}\" {year_info}, a {primary_genre_for_explanation.lower()} masterpiece by {director} that's both {primary_mood_for_explanation.lower()} and {genre_match_phrase}."
|
| 100 |
+
)
|
| 101 |
+
templates.append(
|
| 102 |
+
f"For a truly {primary_mood_for_explanation.lower()} {primary_genre_for_explanation.lower()} cinematic experience, dive into \"{title}\" {year_info} by {director}."
|
| 103 |
+
)
|
| 104 |
+
|
| 105 |
+
# Medium-specificity templates (when only genre or only mood match)
|
| 106 |
+
if matched_genres and not matched_moods:
|
| 107 |
+
templates.append(
|
| 108 |
+
f"Searching for a {primary_genre_for_explanation.lower()} film? \"{title}\" {year_info}, by {director}, perfectly matches your genre preference."
|
| 109 |
+
)
|
| 110 |
+
templates.append(
|
| 111 |
+
f"This {primary_genre_for_explanation.lower()} movie, \"{title}\" {year_info}, starring {lead_actor}, comes highly recommended {audience_phrase}."
|
| 112 |
+
)
|
| 113 |
+
templates.append(
|
| 114 |
+
f"If you're looking for {primary_genre_for_explanation.lower()} movies, \"{title}\" is a strong choice by {director} {year_info}."
|
| 115 |
+
)
|
| 116 |
+
|
| 117 |
+
if matched_moods and not matched_genres:
|
| 118 |
+
templates.append(
|
| 119 |
+
f"Looking for something {primary_mood_for_explanation.lower()}? \"{title}\" {year_info}, directed by {director}, offers just that experience."
|
| 120 |
+
)
|
| 121 |
+
templates.append(
|
| 122 |
+
f"For a truly {primary_mood_for_explanation.lower()} cinematic journey, don't miss \"{title}\" {year_info}, featuring {lead_actor}."
|
| 123 |
+
)
|
| 124 |
+
templates.append(
|
| 125 |
+
f"This movie, \"{title}\" by {director}, provides a {primary_mood_for_explanation.lower()} escape {audience_phrase}."
|
| 126 |
+
)
|
| 127 |
+
templates.append(
|
| 128 |
+
f"Feeling {primary_mood_for_explanation.lower()}? \"{title}\" {year_info} is a perfect match {audience_phrase}."
|
| 129 |
+
)
|
| 130 |
+
|
| 131 |
+
# General templates (when audience or other general attributes match, or as fallback)
|
| 132 |
+
templates.append(
|
| 133 |
+
f"\"{title}\" {year_info}, directed by {director}, is a {primary_genre_for_explanation.lower()} film that viewers find {primary_mood_for_explanation.lower()}. It's {audience_phrase}."
|
| 134 |
+
)
|
| 135 |
+
templates.append(
|
| 136 |
+
f"A compelling watch {audience_phrase}, \"{title}\" {year_info} offers a {primary_mood_for_explanation.lower()} experience in the {primary_genre_for_explanation.lower()} genre."
|
| 137 |
+
)
|
| 138 |
+
templates.append(
|
| 139 |
+
f"You might enjoy \"{title}\" {year_info} from {director}, a {primary_genre_for_explanation.lower()} story starring {lead_actor} that is {primary_mood_for_explanation.lower()}."
|
| 140 |
+
)
|
| 141 |
+
templates.append(
|
| 142 |
+
f"This {primary_genre_for_explanation.lower()} classic {year_info} by {director} is an {primary_mood_for_explanation.lower()} pick {audience_phrase}."
|
| 143 |
+
)
|
| 144 |
+
templates.append(
|
| 145 |
+
f"Experience {primary_mood_for_explanation.lower()} thrills in “{title}” {year_info}, a {primary_genre_for_explanation.lower()} gem by {director}, {audience_phrase}."
|
| 146 |
+
)
|
| 147 |
+
templates.append(
|
| 148 |
+
f"Discover \"{title}\" {year_info} by {director}, a highly-rated {primary_genre_for_explanation.lower()} film {audience_phrase}."
|
| 149 |
+
)
|
| 150 |
+
|
| 151 |
+
# Filter out empty templates and choose one
|
| 152 |
+
valid_templates = [t for t in templates if t.strip()]
|
| 153 |
+
if valid_templates:
|
| 154 |
+
return random.choice(valid_templates)
|
| 155 |
+
else:
|
| 156 |
+
# Fallback if no specific templates could be formed (should be rare with general templates)
|
| 157 |
+
return f"We recommend \"{title}\" {year_info}, a {primary_genre_for_explanation.lower()} movie for {audience_phrase}."
|
|
|