diff --git a/app/controllers/recommended_posts_controller.rb b/app/controllers/recommended_posts_controller.rb index 9ee25479a..213a877a9 100644 --- a/app/controllers/recommended_posts_controller.rb +++ b/app/controllers/recommended_posts_controller.rb @@ -2,17 +2,10 @@ class RecommendedPostsController < ApplicationController respond_to :html, :json, :xml, :js def show - @max_recommendations = params.fetch(:max_recommendations, 100).to_i.clamp(0, 1000) - - 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 - + limit = params.fetch(:limit, 100).to_i.clamp(0, 200) + @recs = RecommenderService.search(params).take(limit) @posts = @recs.map { |rec| rec[:post] } + respond_with(@recs) end end diff --git a/app/logical/recommender_service.rb b/app/logical/recommender_service.rb index 8d1764775..f2fe8ecc9 100644 --- a/app/logical/recommender_service.rb +++ b/app/logical/recommender_service.rb @@ -21,20 +21,42 @@ module RecommenderService body, status = HttpartyCache.get("#{Danbooru.config.recommender_server}/recommend/#{user_id}", params: { limit: limit }, expiry: CACHE_LIFETIME) return [] if status != 200 - process_recs(body) + process_recs(body, uploader_id: user_id, favoriter_id: user_id) 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 } + process_recs(body, 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 } } + def process_recs(recs, post_id: nil, uploader_id: nil, favoriter_id: nil) + recs = JSON.parse(recs) + + posts = Post.where(id: recs.map(&:first)) + posts = posts.where.not(id: post_id) if post_id + posts = posts.where.not(uploader_id: uploader_id) if uploader_id + posts = posts.where.not(id: Favorite.where(user_id: favoriter_id).select(:post_id)) if favoriter_id + + 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_id].present? + user = User.find(params[:user_id]) + max_recommendations = params.fetch(:max_recommendations, user.favorite_count + 500).to_i.clamp(0, 50000) + recs = RecommenderService.recommend_for_user(params[:user_id], max_recommendations) + elsif params[:post_id].present? + max_recommendations = params.fetch(:max_recommendations, 50).to_i.clamp(0, 200) + recs = RecommenderService.recommend_for_post(params[:post_id], max_recommendations) + else + recs = [] + end + + recs + end end