badminton001 commited on
Commit
3def472
·
verified ·
1 Parent(s): b3b9fca

Update utils/movies_explanation.py

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