Compare commits
2 commits
4bd4af703e
...
81cfe9c9d8
| Author | SHA1 | Date | |
|---|---|---|---|
| 81cfe9c9d8 | |||
| 024c1008fb |
1 changed files with 28 additions and 27 deletions
|
|
@ -43,9 +43,8 @@ class Engine:
|
||||||
else:
|
else:
|
||||||
self.state = {
|
self.state = {
|
||||||
'channels': {
|
'channels': {
|
||||||
'globalKeywords': {'locked': False, 'value': 7},
|
'globalKeywords': {'locked': False, 'value': 8},
|
||||||
'userKeywords': {'locked': False, 'value': 7},
|
'userKeywords': {'locked': False, 'value': 8}
|
||||||
'screenings': {'locked': True, 'value': 2}
|
|
||||||
},
|
},
|
||||||
'globalKeywords': {},
|
'globalKeywords': {},
|
||||||
}
|
}
|
||||||
|
|
@ -55,6 +54,11 @@ class Engine:
|
||||||
'nextPlaylist': {'locked': False, 'value': 4},
|
'nextPlaylist': {'locked': False, 'value': 4},
|
||||||
'staySame': {'locked': False, 'value': 8}
|
'staySame': {'locked': False, 'value': 8}
|
||||||
}
|
}
|
||||||
|
if 'userKeywordsWeights' not in self.state:
|
||||||
|
self.state['userKeywordsWeights'] = {
|
||||||
|
'themeTags': {'locked': False, 'value': 0.3},
|
||||||
|
'characterTags': {'locked': False, 'value': 0.7}
|
||||||
|
}
|
||||||
self.update_keywords()
|
self.update_keywords()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
@ -197,12 +201,12 @@ class Engine:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# NOTE for future improvement: vids_exclude element unit could be clip or in/out time pairs, rather than playlist.
|
|
||||||
# The same playlist could be played in the grid view as long as these are differenct clips or separate times.
|
|
||||||
def get_recommendations(self, user, vids_exclude = []):
|
def get_recommendations(self, user, vids_exclude = []):
|
||||||
channels = {k: v.get('value', 0) for k, v in self.state['channels'].items()}
|
channels = {k: v.get('value', 0) for k, v in self.state['channels'].items()}
|
||||||
sliders = {k: v.get('value', 0) for k, v in self.state['globalKeywords'].items()}
|
sliders = {k: v.get('value', 0) for k, v in self.state['globalKeywords'].items()}
|
||||||
gridChange = {k: v.get('value', 0) for k, v in self.state['gridChange'].items()}
|
gridChange = {k: v.get('value', 0) for k, v in self.state['gridChange'].items()}
|
||||||
|
userKeywordsWeights = {k: v.get('value', 1) for k, v in self.state['userKeywordsWeights'].items()}
|
||||||
|
|
||||||
# Exclude playlists from the most recent grid
|
# Exclude playlists from the most recent grid
|
||||||
playlists = copy.deepcopy(self.playlists)
|
playlists = copy.deepcopy(self.playlists)
|
||||||
|
|
@ -211,13 +215,26 @@ class Engine:
|
||||||
if playlist["name"] in vids_exclude:
|
if playlist["name"] in vids_exclude:
|
||||||
playlists.remove(playlist)
|
playlists.remove(playlist)
|
||||||
|
|
||||||
# For each playlist, compute user keyword score
|
# For each playlist, compute user keyword score by theme and character tags
|
||||||
user_keywords = user.get('keywords', {})
|
user_keywords = copy.deepcopy(user.get('keywords', {}))
|
||||||
|
theme_tags = {k.lower():v for k,v in user_keywords.items() if not k.isupper()}
|
||||||
|
character_tags = {k:v for k,v in user_keywords.items() if k.isupper()}
|
||||||
|
# manually modify some of the user keywords to match the playlist tags
|
||||||
|
theme_tags["god"] = theme_tags.get("god - gods",0)
|
||||||
|
theme_tags["visionary"] = theme_tags.get("visionary - enlightenment",0)
|
||||||
|
theme_tags["enlightenment"] = theme_tags.get("visionary - enlightenment",0)
|
||||||
|
character_tags["FEDOR MIKHAILOVICH SOFRONOV"] = character_tags.get("FYODOR MIKHAILOVICH SOFRONOV",0)
|
||||||
|
character_tags["SHKABARNYA OLGA SERGEEVNA"] = character_tags.get("OLGA SERGEEVNA SHKABARNYA",0)
|
||||||
|
character_tags["VICTORIA OLEGOVNA SKITSKAYA"] = character_tags.get("VIKTORIA OLEGOVNA SKITSKAYA",0)
|
||||||
|
|
||||||
score = {}
|
score = {}
|
||||||
for playlist in playlists:
|
for playlist in playlists:
|
||||||
score[playlist['name']] = random.random()
|
score[playlist['name']] = random.random() * 0.001
|
||||||
for tag in [tag for tag in playlist['tags'] if tag in user_keywords]:
|
for tag in playlist['tags']:
|
||||||
score[playlist['name']] += user_keywords[tag]
|
if tag in theme_tags:
|
||||||
|
score[playlist['name']] += theme_tags[tag] * userKeywordsWeights["themeTags"]
|
||||||
|
elif tag in character_tags:
|
||||||
|
score[playlist['name']] += character_tags[tag] * userKeywordsWeights["characterTags"]
|
||||||
# Select highest scoring playlists
|
# Select highest scoring playlists
|
||||||
playlists = sorted(
|
playlists = sorted(
|
||||||
playlists,
|
playlists,
|
||||||
|
|
@ -236,23 +253,7 @@ class Engine:
|
||||||
playlists,
|
playlists,
|
||||||
key=lambda playlist: -score[playlist['name']]
|
key=lambda playlist: -score[playlist['name']]
|
||||||
)
|
)
|
||||||
videos += playlists[:channels['globalKeywords']]
|
videos += playlists[:16 - channels['userKeywords']]
|
||||||
playlists = playlists[channels['globalKeywords']:]
|
|
||||||
# Count products the user has seen
|
|
||||||
count = defaultdict(lambda: 0)
|
|
||||||
for event in user.get('events', []):
|
|
||||||
if event.get('data', {}).get('product'):
|
|
||||||
count[event['data']['product']] += 1
|
|
||||||
# For each product in playlist tags, increment score by count
|
|
||||||
for playlist in playlists:
|
|
||||||
score[playlist['name']] = random.random()
|
|
||||||
for tag in set(playlist['tags']) & set(count):
|
|
||||||
score[playlist['name']] += count[tag]
|
|
||||||
# Select highest scoring playlists
|
|
||||||
videos += sorted(
|
|
||||||
playlists,
|
|
||||||
key=lambda playlist: -score[playlist['name']]
|
|
||||||
)[:16 - channels['userKeywords'] - channels['globalKeywords']]
|
|
||||||
# Shuffle playlists (randomize layout) and shift clips (randomize start)
|
# Shuffle playlists (randomize layout) and shift clips (randomize start)
|
||||||
random.shuffle(videos)
|
random.shuffle(videos)
|
||||||
return [{
|
return [{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue