mirror of
https://github.com/task-17-lct/backend.git
synced 2024-11-27 12:03:44 +03:00
add museums and attractions
This commit is contained in:
parent
08bc90142b
commit
6b6348ffe1
|
@ -1,6 +1,6 @@
|
|||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from passfinder.recomendations.api.views import TinderView, PersonalRecommendation
|
||||
from passfinder.recomendations.api.views import TinderView, PersonalRecommendation, OnboardingViewset
|
||||
from passfinder.users.api.views import (
|
||||
UserViewSet,
|
||||
CreateUserPreferenceApiView,
|
||||
|
@ -12,6 +12,7 @@
|
|||
router.register("tinder", TinderView)
|
||||
router.register("recommendations", PersonalRecommendation)
|
||||
router.register("user", UserViewSet)
|
||||
router.register('onboarding', OnboardingViewset)
|
||||
|
||||
app_name = "api"
|
||||
urlpatterns = [
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from django.contrib import admin
|
||||
from .models import Hotel
|
||||
|
||||
# Register your models here.
|
||||
admin.site.register([Hotel])
|
|
@ -7,7 +7,7 @@
|
|||
class HotelPhoneSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = HotelPhone
|
||||
exclude = "hotel"
|
||||
exclude = ("hotel", )
|
||||
|
||||
|
||||
class HotelSerializer(serializers.ModelSerializer):
|
||||
|
@ -24,7 +24,7 @@ class MuseumSerializer(serializers.ModelSerializer):
|
|||
|
||||
class Meta:
|
||||
model = Hotel
|
||||
exclude = "oid"
|
||||
exclude = ("oid", )
|
||||
|
||||
|
||||
class EventSerializer(serializers.ModelSerializer):
|
||||
|
|
|
@ -1,7 +1,26 @@
|
|||
from rest_framework import serializers
|
||||
from passfinder.events.api.serializers import EventSerializer
|
||||
from passfinder.events.api.serializers import EventSerializer, HotelSerializer
|
||||
|
||||
|
||||
class TinderProceedSerializer(serializers.Serializer):
|
||||
action = serializers.ChoiceField(['left', 'right'], write_only=True)
|
||||
event = EventSerializer(read_only=True)
|
||||
|
||||
|
||||
class AddToPreferenceSerializer(serializers.Serializer):
|
||||
oid = serializers.CharField(write_only=True)
|
||||
|
||||
|
||||
class EventOnboardingRetrieve(serializers.Serializer):
|
||||
events = serializers.ListField(child=EventSerializer(), read_only=True)
|
||||
types = serializers.ListField(child=serializers.ChoiceField(['park', 'monument', 'museum', 'unseco']), write_only=True)
|
||||
|
||||
|
||||
class HotelOnboardingRetrieve(serializers.Serializer):
|
||||
stars = serializers.ListField(child=serializers.ChoiceField([1, 2, 3, 4, 5]), write_only=True)
|
||||
hotels = serializers.ListField(child=HotelSerializer(), read_only=True)
|
||||
|
||||
|
||||
class TinderGetEventFilterSerializer(serializers.Serializer):
|
||||
type = serializers.ListField(child=serializers.ChoiceField(['attraction', 'museum', 'movie', 'play', 'concert']))
|
||||
event = EventSerializer()
|
|
@ -3,14 +3,13 @@
|
|||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from passfinder.events.models import Event
|
||||
from passfinder.events.api.serializers import EventSerializer
|
||||
from passfinder.events.api.serializers import EventSerializer, HotelSerializer
|
||||
from random import choice
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
from .serializers import TinderProceedSerializer
|
||||
from .serializers import *
|
||||
from passfinder.recomendations.models import UserPreferences
|
||||
from ..service.service import update_preferences_state, get_next_tinder, get_personal_concerts_recommendation, \
|
||||
get_personal_plays_recommendation, get_personal_movies_recommendation
|
||||
from ..service.service import *
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
|
||||
|
@ -35,6 +34,14 @@ def proceed(self, request: Request, pk):
|
|||
return Response(data={}, status=404)
|
||||
return Response(data={'event': EventSerializer(event).data}, status=200)
|
||||
|
||||
@action(methods=['POST'], detail=False, serializer_class=TinderGetEventFilterSerializer)
|
||||
def get_event(self, request: Request):
|
||||
# отдавать под пользователя
|
||||
events = Event.objects.filter(type__in=request.data['type'])
|
||||
return Response(data={
|
||||
'event': EventSerializer(choice(events)).data
|
||||
}, status=200)
|
||||
|
||||
|
||||
class PersonalRecommendation(viewsets.GenericViewSet):
|
||||
serializer_class = EventSerializer
|
||||
|
@ -66,3 +73,44 @@ def movies(self, request, *args, **kwargs):
|
|||
for rec in recs:
|
||||
ans.append(EventSerializer(rec[1]).data)
|
||||
return Response(ans, 200)
|
||||
|
||||
|
||||
class OnboardingViewset(viewsets.GenericViewSet):
|
||||
serializer_class = EventSerializer
|
||||
model = Event
|
||||
queryset = Event.objects.all()
|
||||
|
||||
@action(methods=['POST'], detail=False, serializer_class=HotelOnboardingRetrieve)
|
||||
def hotels(self, reqeust, *args, **kwargs):
|
||||
hotels = get_onboarding_hotels(reqeust.data['stars'])
|
||||
res = HotelOnboardingRetrieve({'hotels': hotels}).data
|
||||
|
||||
return Response(res, 200)
|
||||
|
||||
@action(methods=['POST'], detail=False, serializer_class=EventOnboardingRetrieve)
|
||||
def event(self, request, *args, **kwargs):
|
||||
events = get_onboarding_attractions()
|
||||
res = EventOnboardingRetrieve({'events': events}).data
|
||||
|
||||
return Response(res, 200)
|
||||
|
||||
@action(methods=['GET'], detail=True)
|
||||
def add_to_favorites(self, request, pk, *args, **kwargs):
|
||||
pref, _ = UserPreferences.objects.get_or_create(user=request.user)
|
||||
|
||||
event = Event.objects.get(oid=pk)
|
||||
|
||||
if event.type == 'attraction':
|
||||
pref.prefferred_attractions.add(event)
|
||||
elif event.type == 'museum':
|
||||
pref.prefferred_museums.add(event)
|
||||
elif event.type == 'movie':
|
||||
pref.preffered_movies.add(event)
|
||||
elif event.type == 'play':
|
||||
pref.preffered_plays.add(event)
|
||||
elif event.type == 'concert':
|
||||
pref.preferred_concerts.add(event)
|
||||
|
||||
pref.save()
|
||||
|
||||
return Response(status=200)
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
# Generated by Django 4.2.1 on 2023-05-24 10:09
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("events", "0018_userroute_baseuserroutepoint_userroutetransaction_and_more"),
|
||||
("recomendations", "0004_nearesthotel"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="userpreferences",
|
||||
name="prefferred_attractions",
|
||||
field=models.ManyToManyField(
|
||||
related_name="preffered_users_attractions", to="events.event"
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="userpreferences",
|
||||
name="prefferred_museums",
|
||||
field=models.ManyToManyField(
|
||||
related_name="preffered_users_museums", to="events.event"
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="userpreferences",
|
||||
name="unprefferred_attractions",
|
||||
field=models.ManyToManyField(
|
||||
related_name="unpreffered_users_attractions", to="events.event"
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="userpreferences",
|
||||
name="unprefferred_museums",
|
||||
field=models.ManyToManyField(
|
||||
related_name="unpreffered_users_museums", to="events.event"
|
||||
),
|
||||
),
|
||||
]
|
|
@ -15,6 +15,13 @@ class UserPreferences(models.Model):
|
|||
preferred_concerts = models.ManyToManyField(Event, related_name='preffered_users_concert')
|
||||
unpreferred_concerts = models.ManyToManyField(Event, related_name='unpreffered_users_concert')
|
||||
|
||||
prefferred_attractions = models.ManyToManyField(Event, related_name='preffered_users_attractions')
|
||||
unprefferred_attractions = models.ManyToManyField(Event, related_name='unpreffered_users_attractions')
|
||||
|
||||
prefferred_museums = models.ManyToManyField(Event, related_name='preffered_users_museums')
|
||||
unprefferred_museums = models.ManyToManyField(Event, related_name='unpreffered_users_museums')
|
||||
|
||||
|
||||
|
||||
class NearestEvent(models.Model):
|
||||
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='nearest_model_rel')
|
||||
|
|
Binary file not shown.
|
@ -5,12 +5,14 @@
|
|||
plays_mapping = None
|
||||
excursion_mapping = None
|
||||
concert_mapping = None
|
||||
mus_mapping = None
|
||||
|
||||
rev_attraction_mapping = None
|
||||
rev_cinema_mapping = None
|
||||
rev_plays_mapping = None
|
||||
rev_excursion_mapping = None
|
||||
rev_concert_mapping = None
|
||||
mus_rev_mapping = None
|
||||
|
||||
|
||||
def build_dict(list_mapping):
|
||||
|
@ -54,3 +56,9 @@ def build_rev_dict(list_mapping):
|
|||
lst = pickle.load(file)
|
||||
concert_mapping = build_dict(lst)
|
||||
rev_concert_mapping = build_rev_dict(lst)
|
||||
|
||||
|
||||
with open('passfinder/recomendations/service/mapping/mus.pickle', 'rb') as file:
|
||||
lst = pickle.load(file)
|
||||
mus_mapping = build_dict(lst)
|
||||
rev_mus_mapping = build_rev_dict(lst)
|
Binary file not shown.
|
@ -20,3 +20,7 @@
|
|||
|
||||
concert_model = AnnoyIndex(N_DIMENSIONAL, 'angular')
|
||||
concert_model.load('passfinder/recomendations/service/models/concerts.ann')
|
||||
|
||||
|
||||
mus_model = AnnoyIndex(N_DIMENSIONAL, 'angular')
|
||||
mus_model.load('passfinder/recomendations/service/models/mus.ann')
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
from .models.models import *
|
||||
from passfinder.events.models import Event, Region, Hotel, BasePoint, City
|
||||
from passfinder.recomendations.models import UserPreferences, NearestEvent, NearestHotel
|
||||
from random import choice
|
||||
from random import choice, sample
|
||||
from collections import Counter
|
||||
from passfinder.users.models import User
|
||||
from collections.abc import Iterable
|
||||
|
@ -40,6 +40,17 @@ def nearest_attraction(attraction, nearest_n):
|
|||
)
|
||||
|
||||
|
||||
def nearest_mus(museum, nearest_n):
|
||||
return get_nearest_(
|
||||
museum,
|
||||
"museum",
|
||||
mus_mapping,
|
||||
rev_mus_mapping,
|
||||
nearest_n,
|
||||
mus_model
|
||||
)
|
||||
|
||||
|
||||
def nearest_movie(movie, nearest_n):
|
||||
return get_nearest_(
|
||||
movie, "movie", cinema_mapping, rev_cinema_mapping, nearest_n, cinema_model
|
||||
|
@ -81,6 +92,10 @@ def get_nearest_event(event, nearest_n):
|
|||
return nearest_concert(event, nearest_n)
|
||||
if event.type == "movie":
|
||||
return nearest_movie(event, nearest_n)
|
||||
if event.type == 'museum':
|
||||
return nearest_mus(event, nearest_n)
|
||||
if event.type == 'attraction':
|
||||
return nearest_attraction(event, nearest_n)
|
||||
|
||||
|
||||
def update_preferences_state(user, event, direction):
|
||||
|
@ -312,6 +327,12 @@ def calculate_favorite_metric(event: Event, user: User):
|
|||
if event.type == "movie":
|
||||
preferred = pref.preffered_movies.all()
|
||||
return calculate_mean_metric(preferred, event, cinema_model, rev_cinema_mapping)
|
||||
if event.type == 'attraction':
|
||||
preferred = pref.prefferred_attractions.all()
|
||||
return calculate_mean_metric(preferred, event, attracion_model, rev_attraction_mapping)
|
||||
if event.type == 'museum':
|
||||
preferred = pref.prefferred_museums.all()
|
||||
return calculate_mean_metric(preferred, event, mus_model, rev_mus_mapping)
|
||||
return 1000000
|
||||
|
||||
|
||||
|
@ -395,3 +416,40 @@ def generate_path(region: Region, user: User):
|
|||
path.extend([transition_route, point_route])
|
||||
|
||||
return hotel, points, path
|
||||
|
||||
|
||||
def calculate_distance(sample1: Event, samples: Iterable[Event], model: AnnoyIndex, rev_mapping):
|
||||
metrics = []
|
||||
|
||||
for sample in samples:
|
||||
metrics.append(model.get_distance(rev_mapping[sample1.oid], rev_mapping[sample.oid]))
|
||||
|
||||
return sum(metrics) / len(metrics)
|
||||
|
||||
|
||||
def get_onboarding_attractions():
|
||||
sample_attractions = sample(list(Event.objects.filter(type='attraction')), 200)
|
||||
first_attraction = choice(sample_attractions)
|
||||
|
||||
attractions = [first_attraction]
|
||||
|
||||
while len(attractions) < 10:
|
||||
mx_dist = 0
|
||||
mx_attraction = None
|
||||
for att in sample_attractions:
|
||||
if att in attractions: continue
|
||||
local_dist = calculate_distance(
|
||||
att,
|
||||
attractions,
|
||||
attracion_model,
|
||||
rev_attraction_mapping
|
||||
)
|
||||
if local_dist > mx_dist:
|
||||
mx_dist = local_dist
|
||||
mx_attraction = att
|
||||
attractions.append(mx_attraction)
|
||||
return attractions
|
||||
|
||||
|
||||
def get_onboarding_hotels(stars=Iterable[int]):
|
||||
return sample(list(Hotel.objects.filter(stars__in=stars)), 10)
|
Loading…
Reference in New Issue
Block a user