Add adaptive recommendations

master
Felix Stupp 2 years ago
parent 5b875a6e05
commit d6d65574bd
Signed by: zocker
GPG Key ID: 93E1BD26F6B02FB7

@ -72,6 +72,16 @@ from entertainment_decider.extras import remove_common_trails
T = TypeVar("T")
def adapt_score_list(
base: Optional[PreferenceScore] = None,
tag_points_mapping: Dict[int, int] = {},
) -> PreferenceScore:
o = base or PreferenceScore()
for tag_id, points in tag_points_mapping.items():
o = o.adapt_score(Tag[tag_id], points, on_hierachy=False)
return o
####
# Logging Config
####
@ -239,6 +249,14 @@ setup_custom_tables()
Pony(flask_app)
####
# Settings helpers
####
PREFERENCES_SCORE_NAME = "score_adapt"
####
# Return filters
####
@ -694,6 +712,70 @@ def recommend_on_media(media_id: int) -> ResponseReturnValue:
)
@flask_app.route("/recommendations/adaptive")
def recommend_adaptive() -> ResponseReturnValue:
score_adapt = request.args.get("score_adapt", default=2, type=int)
max_length = request.args.get("max_length", default=0, type=int)
preferences = request.cookies.get(
key=PREFERENCES_SCORE_NAME,
default=PreferenceScore(),
type=PreferenceScore.from_base64,
) * (1 if score_adapt > 0 else -1 if score_adapt < 0 else 0)
preference_list = generate_preference_list(
object_gen=lambda: get_all_considered(
order_by="elem.release_date DESC",
filter_by=f"(length - progress) <= {max_length * 60}"
if max_length
else "true",
),
score_adapt=score_adapt,
base=preferences,
limit=32,
)
resp = make_response(
render_template(
"recommendations_adaptive.htm",
max_length=max_length,
score_adapt=score_adapt,
preferences=preferences,
media_list=preference_list,
)
)
return resp
def cookies_rating(negative: bool) -> ResponseReturnValue:
media_id = request.form.get("media_id", default=None, type=str)
element = MediaElement.get(id=media_id) if media_id else None
if element is None:
return "Not found", 404
preferences = request.cookies.get(
key=PREFERENCES_SCORE_NAME,
default=PreferenceScore(),
type=PreferenceScore.from_base64,
).adapt_score(element, score=3 if negative else -3)
resp = redirect_back_or_okay()
resp.set_cookie(PREFERENCES_SCORE_NAME, preferences.to_base64())
return resp
@flask_app.route("/cookies/rating/positive", methods=["POST"])
def cookies_rating_positive() -> ResponseReturnValue:
return cookies_rating(False)
@flask_app.route("/cookies/rating/negative", methods=["POST"])
def cookies_rating_negative() -> ResponseReturnValue:
return cookies_rating(True)
@flask_app.route("/cookies/rating/reset", methods=["POST"])
def cookies_rating_reset() -> ResponseReturnValue:
resp = redirect_back_or_okay()
resp.delete_cookie(key=PREFERENCES_SCORE_NAME)
return resp
@flask_app.route("/api/refresh/collections", methods=["POST"])
def refresh_collections() -> ResponseReturnValue:
collection_ids = set[int](

@ -391,6 +391,7 @@
{% macro _sidebar() %}
<div class="sidebar-box">
<a class="sidebar-button button" href="/recommendations/adaptive">Adaptive</a>
<a class="sidebar-button button" href="/recommendations/short_filler">Small Fillers</a>
<a class="sidebar-button button" href="/recommendations/series_episode">Series Episode</a>
<a class="sidebar-button button" href="/recommendations/movie_like">Movie Like</a>
@ -432,6 +433,7 @@
{% macro media_thumbnail_buttons(
element,
show_fragment=True,
show_rating=False
) %}
{% set api_uri = "/api/media/" + element.id|string %}
{% set fragment = ("media_element_" + element.id|string) if show_fragment else None %}
@ -446,6 +448,10 @@
{{ as_play_link(element, symbol='&#9655;') }}
{{ post_form(api_uri, "ignored", "true", "&#10005;"|safe, fragment) }}
{% endif %}
{% if show_rating %}
{{ post_form("/cookies/rating/positive", "media_id", element.id|string, "+", fragment) }}
{{ post_form("/cookies/rating/negative", "media_id", element.id|string, "-", fragment) }}
{% endif %}
{% endmacro %}
{% macro link_position_marker(link, prefix=false) -%}
@ -465,6 +471,7 @@
check_considered=True,
is_considered=True,
link_collection=True,
show_rating=False,
title=None,
) %}
{% set element = link.element if link else element %}
@ -505,7 +512,7 @@
{%- endif -%}
"></div>
<div class="button_list">
{{ media_thumbnail_buttons(element) }}
{{ media_thumbnail_buttons(element, show_rating=show_rating) }}
</div>
{% if caller is defined %}
<div class="additional_info">
@ -539,6 +546,7 @@
links=None,
check_considered=True,
link_collection=True,
show_rating=False,
titles=None,
) %}
{%- set l = elements or links -%}
@ -552,6 +560,7 @@
check_considered=False,
is_considered=considered[elem.id] if check_considered else True,
link_collection=link_collection,
show_rating=show_rating,
title=titles[loop.index0] if titles else None,
) }}
{% endfor %}

@ -0,0 +1,43 @@
{% import "macros.htm" as macros %}
<!DOCTYPE html>
<html>
{% set title = "Adaptive Recommendations" %}
<head>
<meta charset="utf-8"/>
<title>{{ title }}</title>
{{ macros.shared_style() }}
</head>
<body>
{{ macros.body_header() }}
<h1>{{ title }}</h1>
<form class="form-single-button" method="get" action="/recommendations/adaptive">
<label>
<span>Max Length:</span>
<input type="number" name="max_length" min="0" size="4" value="{{ max_length or '' }}"/>
<span>min</span>
</label>
<label>
<span>Score Adapt:</span>
<input type="number" name="score_adapt" min="-5" step="1" max="5" size="2" value="{{ score_adapt or 1 }}"/>
</label>
<button type="submit">Search</button>
</form>
<form class="form-single-button" method="post" action="/cookies/rating/reset">
{{ macros.hidden_redirect_back(fragment=fragment) }}
<button type="submit">Reset</button>
</form>
<div>
<span>Preferences:</span>
<ul>
{% for tag, score in preferences.points.items() %}
<li>{{ tag.title }}: {{ score }}</li>
{% endfor %}
</ul>
</div>
{{ macros.media_thumbnail_list(
elements=media_list,
check_considered=False,
show_rating=True,
) }}
</body>
</html>
Loading…
Cancel
Save