Files
danbooru/app/logical/recommender_service.rb
evazion 054ac51d47 policies: remove current request from context.
This refactors Pundit policies to only rely on the current user, not on
the current user and the current HTTP request. In retrospect, it was a
bad idea to include the current request in the Pundit context. It bleeds
out everywhere and there are many contexts (in tests and models) where
we only have the current user, not the current request. The previous
commit got rid of the only two places where we used it.
2021-01-17 00:57:59 -06:00

70 lines
2.4 KiB
Ruby

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, tags: nil, limit: 50)
response = Danbooru::Http.cache(CACHE_LIFETIME).get("#{Danbooru.config.recommender_server}/recommend/#{user.id}", params: { limit: limit })
return [] if response.status != 200
process_recs(response.parse, tags: tags, uploader: user, favoriter: user)
end
def recommend_for_post(post, tags: nil, limit: 50)
response = Danbooru::Http.cache(CACHE_LIFETIME).get("#{Danbooru.config.recommender_server}/similar/#{post.id}", params: { limit: limit })
return [] if response.status != 200
process_recs(response.parse, post: post, tags: tags)
end
def process_recs(recs, post: nil, uploader: nil, favoriter: nil, tags: nil)
posts = Post.where(id: recs.map(&:first))
posts = posts.where.not(id: post.id) if post
posts = posts.where.not(uploader_id: uploader.id) if uploader
posts = posts.where.not(id: favoriter.favorites.select(:post_id)) if favoriter
posts = posts.where(id: Post.user_tag_match(tags).reorder(nil).select(:id)) if tags.present?
id_to_score = recs.to_h
recs = posts.map { |post| { score: id_to_score[post.id], post: post } }
recs = recs.sort_by { |rec| -rec[:score] }
recs
end
def search(params)
if params[:user_name].present?
user = User.find_by_name(params[:user_name])
elsif params[:user_id].present?
user = User.find(params[:user_id])
elsif params[:post_id].present?
post = Post.find(params[:post_id])
end
if user.present?
raise User::PrivilegeError unless Pundit.policy!(CurrentUser.user, user).can_see_favorites?
max_recommendations = params.fetch(:max_recommendations, user.favorite_count + 500).to_i.clamp(0, 50000)
recs = RecommenderService.recommend_for_user(user, tags: params[:post_tags_match], limit: max_recommendations)
elsif post.present?
max_recommendations = params.fetch(:max_recommendations, 100).to_i.clamp(0, 1000)
recs = RecommenderService.recommend_for_post(post, tags: params[:post_tags_match], limit: max_recommendations)
else
recs = []
end
recs
end
end