recommendations: open user recommendations to all users.
* Open recommendations to all users (not just gold). * Show recommendations on all posts (not just posts after 2017). * Allow users to browse recommendations for other users. * Increase number of recommended posts returned. * Change endpoints to /recommended_posts?user_id=1234 and /recommended_posts?post_id=1234 and add json/xml support.
This commit is contained in:
@@ -1,23 +1,18 @@
|
||||
class RecommendedPostsController < ApplicationController
|
||||
before_action :member_only
|
||||
respond_to :html
|
||||
respond_to :html, :json, :xml, :js
|
||||
|
||||
def show
|
||||
@posts = load_posts()
|
||||
@max_recommendations = params.fetch(:max_recommendations, 100).to_i.clamp(0, 1000)
|
||||
|
||||
if request.xhr?
|
||||
render partial: "show", layout: false
|
||||
if params[:user_id].present?
|
||||
@recs = RecommenderService.recommend_for_user(params[:user_id], @max_recommendations)
|
||||
elsif params[:post_id].present?
|
||||
@recs = RecommenderService.recommend_for_post(params[:post_id], @max_recommendations)
|
||||
else
|
||||
@recs = []
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_posts
|
||||
if params[:context] == "post"
|
||||
@posts = RecommenderService.recommend(post_id: params[:post_id].to_i)
|
||||
|
||||
elsif params[:context] == "user"
|
||||
@posts = RecommenderService.recommend(user_id: CurrentUser.id)
|
||||
end
|
||||
@posts = @recs.map { |rec| rec[:post] }
|
||||
respond_with(@recs)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,6 +9,7 @@ let Post = {};
|
||||
Post.pending_update_count = 0;
|
||||
Post.SWIPE_THRESHOLD = 60;
|
||||
Post.SWIPE_VELOCITY = 0.6;
|
||||
Post.MAX_RECOMMENDATIONS = 27; // 3 rows of 9 posts at 1920x1080.
|
||||
|
||||
Post.initialize_all = function() {
|
||||
|
||||
@@ -433,9 +434,7 @@ Post.initialize_post_sections = function() {
|
||||
$("#comments").hide();
|
||||
$("#edit").hide();
|
||||
$("#recommended").show();
|
||||
$.get("/recommended_posts", {context: "post", post_id: Utility.meta("post-id")}, function(data) {
|
||||
$("#recommended").html(data);
|
||||
});
|
||||
$.get("/recommended_posts.js", { post_id: Utility.meta("post-id"), max_recommendations: Post.MAX_RECOMMENDATIONS });
|
||||
} else {
|
||||
$("#edit").hide();
|
||||
$("#comments").hide();
|
||||
|
||||
40
app/logical/recommender_service.rb
Normal file
40
app/logical/recommender_service.rb
Normal file
@@ -0,0 +1,40 @@
|
||||
module RecommenderService
|
||||
module_function
|
||||
|
||||
MIN_POST_FAVS = 5
|
||||
MIN_USER_FAVS = 50
|
||||
CACHE_LIFETIME = 4.hours
|
||||
|
||||
def enabled?
|
||||
Danbooru.config.recommender_server.present?
|
||||
end
|
||||
|
||||
def available_for_post?(post)
|
||||
enabled? && post.fav_count > MIN_POST_FAVS
|
||||
end
|
||||
|
||||
def available_for_user?(user)
|
||||
enabled? && user.favorite_count > MIN_USER_FAVS
|
||||
end
|
||||
|
||||
def recommend_for_user(user_id, limit = 50)
|
||||
body, status = HttpartyCache.get("#{Danbooru.config.recommender_server}/recommend/#{user_id}", params: { limit: limit }, expiry: CACHE_LIFETIME)
|
||||
return [] if status != 200
|
||||
|
||||
process_recs(body)
|
||||
end
|
||||
|
||||
def recommend_for_post(post_id, limit = 50)
|
||||
body, status = HttpartyCache.get("#{Danbooru.config.recommender_server}/similar/#{post_id}", params: { limit: limit }, expiry: CACHE_LIFETIME)
|
||||
return [] if status != 200
|
||||
|
||||
process_recs(body).reject { |rec| rec[:post].id == post_id }
|
||||
end
|
||||
|
||||
def process_recs(recs)
|
||||
recs = JSON.parse(recs).to_h
|
||||
recs = Post.where(id: recs.keys).map { |post| { score: recs[post.id], post: post } }
|
||||
recs = recs.sort_by { |rec| -rec[:score] }
|
||||
recs
|
||||
end
|
||||
end
|
||||
@@ -1,62 +0,0 @@
|
||||
module RecommenderService
|
||||
extend self
|
||||
|
||||
SCORE_THRESHOLD = 5
|
||||
|
||||
def enabled?
|
||||
Danbooru.config.recommender_server.present?
|
||||
end
|
||||
|
||||
def available_for_post?(post)
|
||||
return true if Rails.env.development?
|
||||
|
||||
enabled? && post.created_at > Date.civil(2017, 1, 1) && post.fav_count >= SCORE_THRESHOLD
|
||||
end
|
||||
|
||||
def available_for_user?
|
||||
enabled? && CurrentUser.is_gold?
|
||||
end
|
||||
|
||||
def recommend_for_user(user_id)
|
||||
ids = Cache.get("rsu:#{user_id}", 1.hour) do
|
||||
resp = HTTParty.get(
|
||||
"#{Danbooru.config.recommender_server}/recommend/#{user_id}",
|
||||
Danbooru.config.httparty_options.merge(
|
||||
basic_auth: {
|
||||
username: "danbooru",
|
||||
password: Danbooru.config.recommender_key
|
||||
}
|
||||
)
|
||||
)
|
||||
JSON.parse(resp.body)
|
||||
end
|
||||
Post.find(ids.map(&:first))
|
||||
end
|
||||
|
||||
def recommend_for_post(post_id)
|
||||
ids = Cache.get("rss:#{post_id}", 1.hour) do
|
||||
resp = HTTParty.get(
|
||||
"#{Danbooru.config.recommender_server}/similar/#{post_id}",
|
||||
Danbooru.config.httparty_options.merge(
|
||||
basic_auth: {
|
||||
username: "danbooru",
|
||||
password: Danbooru.config.recommender_key
|
||||
}
|
||||
)
|
||||
)
|
||||
JSON.parse(resp.body)
|
||||
end
|
||||
if ids.is_a?(Hash) # error state
|
||||
return []
|
||||
end
|
||||
Post.find(ids.reject {|x| x[0] == post_id}.map(&:first))
|
||||
end
|
||||
|
||||
def recommend(post_id: nil, user_id: nil)
|
||||
if post_id
|
||||
recommend_for_post(post_id)
|
||||
elsif user_id
|
||||
recommend_for_user(user_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,8 +2,8 @@
|
||||
<%= subnav_link_to "Listing", posts_path %>
|
||||
<%= subnav_link_to "Upload", new_upload_path %>
|
||||
<%= subnav_link_to "Hot", posts_path(:tags => "order:rank", :d => "1") %>
|
||||
<% if RecommenderService.available_for_user? %>
|
||||
<%= subnav_link_to "Recommended", recommended_posts_path(context: "user") %>
|
||||
<% if RecommenderService.available_for_user?(CurrentUser.user) %>
|
||||
<%= subnav_link_to "Recommended", recommended_posts_path(user_id: CurrentUser.id) %>
|
||||
<% end %>
|
||||
<% unless CurrentUser.is_anonymous? %>
|
||||
<%= subnav_link_to "Favorites", posts_path(tags: "ordfav:#{CurrentUser.user.name}") %>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div id="a-show">
|
||||
<h1>Recommended Posts</h1>
|
||||
|
||||
<p>Based on your favorites, you may enjoy these posts. Favorite more to get more accurate results. These recommendations update every hour.</p>
|
||||
<p>Based on your favorites, you may enjoy these posts. Favorite more posts to get more accurate results. These recommendations update every few hours.</p>
|
||||
|
||||
<%= render "posts/partials/common/inline_blacklist" %>
|
||||
<%= render partial: "show" %>
|
||||
|
||||
1
app/views/recommended_posts/show.js.erb
Normal file
1
app/views/recommended_posts/show.js.erb
Normal file
@@ -0,0 +1 @@
|
||||
$("#recommended").html("<%= j render "recommended_posts/show" %>");
|
||||
Reference in New Issue
Block a user