Esempio n. 1
0
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}
Esempio n. 2
0
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)
Esempio n. 3
0
    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
Esempio n. 4
0
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}
Esempio n. 5
0
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
                  })