def get_reco_algo(request, algo_name='knn', category='all'): chrono = Chrono(is_enabled=CHRONO_ENABLED) already_rated_works = list(current_user_ratings(request)) if request.user.is_anonymous: assert request.user.id is None # We only support KNN for anonymous users, since the offline models did # not learn anything about them. # FIXME: We should also force KNN for new users for which we have no # offline trained model available. algo_name = 'knn' chrono.save('get rated works') try: algo = get_algo_backup(algo_name) dataset = get_dataset_backup(algo_name) except FileNotFoundError: triplets = list( Rating.objects.values_list('user_id', 'work_id', 'choice')) chrono.save('get all %d interesting ratings' % len(triplets)) dataset, algo = fit_algo(algo_name, triplets) if algo_name == 'knn': framed_rated_works = pd.DataFrame(list(current_user_ratings(request).items()), columns=['work_id', 'choice']) framed_rated_works['work_id'] = dataset.encode_works(framed_rated_works['work_id']) framed_rated_works['rating'] = framed_rated_works['choice'].map(rating_values) nb_rated_works = len(framed_rated_works['work_id']) ratings_from_user = coo_matrix((framed_rated_works['rating'],([0.] * nb_rated_works, framed_rated_works['work_id'])), shape=(1, algo.nb_works)) ratings_from_user = ratings_from_user.tocsr() #Expands knn.M with current user ratings (vstack is too slow) algo.M.data = np.hstack((algo.M.data, ratings_from_user.data)) algo.M.indices = np.hstack((algo.M.indices, ratings_from_user.indices)) algo.M.indptr = np.hstack((algo.M.indptr, (ratings_from_user.indptr + algo.M.nnz)[1:])) algo.M._shape = (algo.M.shape[0] + ratings_from_user.shape[0], ratings_from_user.shape[1]) chrono.save('loading knn and expanding with current user ratings') chrono.save('fit %s' % algo.get_shortname()) if category != 'all': category_filter = set(Work.objects.filter(category__slug=category).values_list('id', flat=True)) else: category_filter = dataset.interesting_works filtered_works = list((dataset.interesting_works & category_filter) - set(already_rated_works)) chrono.save('remove already rated') pos_of_best = get_pos_of_best_works_for_user_via_algo(algo, dataset, request.user.id, filtered_works, limit=NB_RECO) best_work_ids = [filtered_works[pos] for pos in pos_of_best] chrono.save('compute every prediction') works = Work.objects.in_bulk(best_work_ids) # Some of the works may have been deleted since the algo backup was created. ranked_work_ids = [work_id for work_id in best_work_ids if work_id in works] chrono.save('get bulk') return {'work_ids': ranked_work_ids, 'works': works}
def get_card(request: Request, category: str, slot_sort_type: str): """ Fetch the work card from the `category` using the `slot_sort_type` as "sorting" method. """ card_slot_query_serializer = CardSlotQuerySerializer( data={ 'category': category, 'slot_type': slot_sort_type }) if not card_slot_query_serializer.is_valid(): return Response(card_slot_query_serializer.errors, status=400) card_slot_query = card_slot_query_serializer.data queryset = (Category.objects.get( slug=card_slot_query['category']).work_set.all()) rated_works = current_user_ratings(request) slot_type_chosen = SlotCardTypes[card_slot_query['slot_type']] queryset = (slot_dispatchers[slot_type_chosen](queryset).exclude( id__in=list(rated_works))) works = queryset[:POSTERS_PER_PAGE] return Response( CardSlotSerializer(works, many=True, context={ 'request': request }).data)
def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) work_list = list(context['object_list']) ratings = current_user_ratings(self.request, work_list) for work in work_list: work.rating = ratings.get(work.id, None) context['object_list'] = [{'work': work} for work in work_list] return context
def get_reco_algo(request, algo_name='als', category='all'): chrono = Chrono(is_enabled=CHRONO_ENABLED) user_ratings = current_user_ratings(request) already_rated_works = list(user_ratings) chrono.save('get rated works') algo = get_algo_backup_or_fit_knn(algo_name) available_works = set(algo.dataset.encode_work.keys()) df_rated_works = (pd.DataFrame( list(user_ratings.items()), columns=['work_id', 'choice']).query('work_id in @available_works')) enc_rated_works = df_rated_works['work_id'].map(algo.dataset.encode_work) user_rating_values = df_rated_works['choice'].map(rating_values) # User gave the same rating to all works considered in the reco if algo_name == 'als' and len(set(user_rating_values)) == 1: algo = get_algo_backup_or_fit_knn('knn') chrono.save('retrieve or fit %s' % algo.get_shortname()) category_filter = algo.dataset.interesting_works if category != 'all': category_filter &= set( Work.objects.filter(category__slug=category).values_list( 'id', flat=True)) filtered_works = list((algo.dataset.interesting_works & category_filter) - set(already_rated_works)) chrono.save('remove already rated, left {:d}'.format(len(filtered_works))) pos_of_best = get_personalized_ranking(algo, request.user.id, filtered_works, enc_rated_works, user_rating_values, limit=NB_RECO) best_work_ids = [filtered_works[pos] for pos in pos_of_best] chrono.save('compute every prediction') works = Work.objects.in_bulk(best_work_ids) # Some of the works may have been deleted since the algo backup was created ranked_work_ids = [ work_id for work_id in best_work_ids if work_id in works ] chrono.save('get bulk') return {'work_ids': ranked_work_ids, 'works': works}
def get_reco(request): category = request.GET.get('category', 'all') algo_name = request.GET.get('algo', 'svd' if user_exists_in_backup(request.user, 'svd') else 'knn') if current_user_ratings(request): reco_list = [{ 'work': Work(title='Chargement…', ext_poster='/static/img/chiro.gif') } for _ in range(4)] else: reco_list = [] return render(request, 'mangaki/reco_list.html', { 'reco_list': reco_list, 'category': category, 'algo': algo_name, 'config': VANILLA_UI_CONFIG_FOR_RATINGS })