refactored code

This commit is contained in:
Alexander Karpov 2023-05-28 00:11:44 +03:00
parent f8f0902e97
commit dff6a050ea
13 changed files with 523 additions and 440 deletions

View File

@ -23,7 +23,7 @@ def _update_or_create_site_with_sequence(site_model, connection, domain, name):
# site is created.
# To avoid this, we need to manually update DB sequence and make sure it's
# greater than the maximum value.
max_id = site_model.objects.order_by('-id').first().id
max_id = site_model.objects.order_by("-id").first().id
with connection.cursor() as cursor:
cursor.execute("SELECT last_value from django_site_id_seq")
(current_id,) = cursor.fetchone()

View File

@ -1,4 +1,4 @@
from django.contrib import admin
from .models import Hotel
admin.site.register([Hotel])
admin.site.register([Hotel])

View File

@ -1,47 +1,49 @@
city_in_hotels = {'Астрахань',
'Балашиха',
'Березники',
'Благовещенск',
'Владикавказ',
'Волгоград',
'Волгодонск',
'Волжский',
'Воронеж',
'Грозный',
'Дзержинск',
'Екатеринбург',
'Златоуст',
'Ижевск',
'Каменск-Уральский',
'Киров',
'Кисловодск',
'Колпино',
'Комсомольск-на-Амуре',
'Копейск',
'Кострома',
'Красноярск',
'Курган',
'Люберцы',
'Магнитогорск',
'Махачкала',
'Москва',
'Мытищи',
'Нальчик',
'Нижнекамск',
'Нижний Тагил',
'Новочебоксарск',
'Одинцово',
'Омск',
'Оренбург',
'Орск',
'Пермь',
'Подольск',
'Пятигорск',
'Салават',
'Санкт-Петербург',
'Томск',
'Тюмень',
'Уфа',
'Хасавюрт',
'Химки',
'Энгельс'}
city_in_hotels = {
"Астрахань",
"Балашиха",
"Березники",
"Благовещенск",
"Владикавказ",
"Волгоград",
"Волгодонск",
"Волжский",
"Воронеж",
"Грозный",
"Дзержинск",
"Екатеринбург",
"Златоуст",
"Ижевск",
"Каменск-Уральский",
"Киров",
"Кисловодск",
"Колпино",
"Комсомольск-на-Амуре",
"Копейск",
"Кострома",
"Красноярск",
"Курган",
"Люберцы",
"Магнитогорск",
"Махачкала",
"Москва",
"Мытищи",
"Нальчик",
"Нижнекамск",
"Нижний Тагил",
"Новочебоксарск",
"Одинцово",
"Омск",
"Оренбург",
"Орск",
"Пермь",
"Подольск",
"Пятигорск",
"Салават",
"Санкт-Петербург",
"Томск",
"Тюмень",
"Уфа",
"Хасавюрт",
"Химки",
"Энгельс",
}

View File

@ -72,41 +72,39 @@ class RouteInputSerializer(serializers.Serializer):
child=serializers.ChoiceField([1, 2, 3, 4, 5]),
required=False,
allow_empty=True,
allow_null=True
allow_null=True,
)
what_to_see = serializers.ListField(
child=serializers.ChoiceField(
[
'attractions',
'museum',
'movie',
'concert',
'artwork',
'plays',
'shop',
'gallery',
'theme_park',
'viewpoint',
'zoo'
"attractions",
"museum",
"movie",
"concert",
"artwork",
"plays",
"shop",
"gallery",
"theme_park",
"viewpoint",
"zoo",
]
),
required=False,
allow_empty=True,
allow_null=True
allow_null=True,
)
where_stay = serializers.ListField(
child=serializers.ChoiceField([
'hotel', 'apartment', 'hostel'
]),
child=serializers.ChoiceField(["hotel", "apartment", "hostel"]),
required=False,
allow_empty=True,
allow_null=True
allow_null=True,
)
where_eat = serializers.ListField(
child=serializers.ChoiceField(['restaurant', 'bar', 'cafe']),
child=serializers.ChoiceField(["restaurant", "bar", "cafe"]),
required=False,
allow_empty=True,
allow_null=True
allow_null=True,
)
with_kids = serializers.BooleanField(required=False, allow_null=True)
with_animals = serializers.BooleanField(required=False, allow_null=True)

View File

@ -59,72 +59,67 @@ def get(self, request):
request=RouteInputSerializer, responses={200: RouteSerializer(many=True)}
)
def post(self, request):
movement_mapping = {
'walk': 3.0,
'bike': 15.0,
'scooter': 30.0,
'auto': 50.0
}
movement_mapping = {"walk": 3.0, "bike": 15.0, "scooter": 30.0, "auto": 50.0}
serializer = RouteInputSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
data = serializer.data
city_id = data["city"]
try:
start_date = datetime.strptime(data['date_from'], '%Y-%m-%d')
start_date = datetime.strptime(data["date_from"], "%Y-%m-%d")
except:
start_date = None
try:
end_date = datetime.strptime(data['date_to'], '%Y-%m-%d')
end_date = datetime.strptime(data["date_to"], "%Y-%m-%d")
except:
end_date = None
try:
movement = data['movement']
movement = data["movement"]
except KeyError:
movement = 'walk'
movement = "walk"
hotel_stars = data['stars']
hotel_stars = data["stars"]
if hotel_stars is None:
hotel_stars = []
hotel_type = data['where_stay']
hotel_type = data["where_stay"]
if hotel_type is None:
hotel_type = ['hotel']
hotel_type = ["hotel"]
where_eat = data['where_eat']
where_eat = data["where_eat"]
if where_eat is None:
where_eat = ['restaurant', 'bar', 'cafe']
where_eat = ["restaurant", "bar", "cafe"]
what_to_see = data['what_to_see']
what_to_see = data["what_to_see"]
if what_to_see is None:
what_to_see = [
'attractions',
'museum',
'movie',
'concert',
'artwork',
'plays',
'shop',
'gallery',
'theme_park',
'viewpoint',
'zoo'
"attractions",
"museum",
"movie",
"concert",
"artwork",
"plays",
"shop",
"gallery",
"theme_park",
"viewpoint",
"zoo",
]
if 'hotel' not in hotel_type:
if "hotel" not in hotel_type:
hotel_stars = []
region = None
res = []
for _ in range(5):
if city_id:
region = get_object_or_404(City, oid=city_id)
else:
region = choice(City.objects.annotate(points_count=Count('points')).filter(title__in=city_in_hotels).filter(points_count__gt=400))
region = choice(
City.objects.annotate(points_count=Count("points"))
.filter(title__in=city_in_hotels)
.filter(points_count__gt=400)
)
if not start_date and end_date:
tour_length = choice([timedelta(days=i) for i in range(1, 4)])
start_date = end_date - tour_length
@ -137,25 +132,25 @@ def post(self, request):
tour_length = choice([timedelta(days=i) for i in range(1, 4)])
end_date = start_date + tour_length
print(request.user, region, start_date, end_date)
tour = generate_tour(
request.user,
region,
start_date,
end_date,
request.user,
region,
start_date,
end_date,
avg_velocity=movement_mapping[movement],
stars=hotel_stars,
hotel_type=hotel_type,
where_eat=where_eat,
what_to_see=what_to_see
what_to_see=what_to_see,
)
res.append(
{
"city": region.title,
"date_from": start_date,
"date_to": end_date,
"path": tour[0],
}
)
res.append({
'city': region.title,
'date_from': start_date,
'date_to': end_date,
'path': tour[0]
})
return Response(data=res)
@ -168,7 +163,10 @@ class ListRegionApiView(ListAPIView):
class ListCityApiView(ListAPIView):
serializer_class = CitySerializer
queryset = (
City.objects.annotate(points_count=Count('points')).filter(title__in=city_in_hotels).filter(points_count__gt=200).order_by('title')
City.objects.annotate(points_count=Count("points"))
.filter(title__in=city_in_hotels)
.filter(points_count__gt=200)
.order_by("title")
)

View File

@ -277,7 +277,7 @@ def get_json(self):
"lon": self.point.lon,
"title": self.point.title,
"description": self.point.description,
"oid": self.point.oid
"oid": self.point.oid,
},
"point_type": self.point_type,
"time": self.duration,

View File

@ -1,4 +1,4 @@
from django.contrib import admin
from .models import UserPreferences
admin.site.register([UserPreferences])
admin.site.register([UserPreferences])

View File

@ -1,5 +1,9 @@
from rest_framework import serializers
from passfinder.events.api.serializers import EventSerializer, HotelSerializer, ObjectRouteSerializer
from passfinder.events.api.serializers import (
EventSerializer,
HotelSerializer,
ObjectRouteSerializer,
)
class TinderProceedSerializer(serializers.Serializer):
@ -27,12 +31,16 @@ class HotelOnboardingRetrieve(serializers.Serializer):
class TinderGetEventFilterSerializer(serializers.Serializer):
type = serializers.ListField(child=serializers.ChoiceField(['attraction', 'museum', 'movie', 'play', 'concert']))
type = serializers.ListField(
child=serializers.ChoiceField(
["attraction", "museum", "movie", "play", "concert"]
)
)
event = EventSerializer()
class DailySelectionNodeSerializer(serializers.Serializer):
action = serializers.ChoiceField(['left', 'right'])
action = serializers.ChoiceField(["left", "right"])
oid = serializers.CharField()
@ -56,9 +64,23 @@ class StarSelectionSerializer(serializers.Serializer):
class CategorySelectionSerializer(serializers.Serializer):
categories = serializers.ListField(child=serializers.ChoiceField(
['attractions', 'museum', 'movie', 'concert', 'artwork', 'plays', 'shop', 'gallery', 'theme_park', 'viewpoint', 'zoo']
))
categories = serializers.ListField(
child=serializers.ChoiceField(
[
"attractions",
"museum",
"movie",
"concert",
"artwork",
"plays",
"shop",
"gallery",
"theme_park",
"viewpoint",
"zoo",
]
)
)
class RecomendationNode(serializers.Serializer):
@ -66,6 +88,5 @@ class RecomendationNode(serializers.Serializer):
events = serializers.ListField(child=ObjectRouteSerializer())
class SelfRecomendationSerializer(serializers.Serializer):
recomendations = serializers.ListField(child=RecomendationNode(), write_only=True)
recomendations = serializers.ListField(child=RecomendationNode(), write_only=True)

View File

@ -20,28 +20,34 @@ class TinderView(viewsets.GenericViewSet):
model = Event
queryset = Event.objects.all()
@action(methods=['GET'], detail=False, serializer_class=EventSerializer)
@action(methods=["GET"], detail=False, serializer_class=EventSerializer)
def start(self, request: Request, *args: Any, **kwargs: Any):
UserPreferences.objects.get_or_create(user=request.user)
event = EventSerializer(choice(Event.objects.all()))
return Response(data=event.data, status=200)
@csrf_exempt
@action(methods=['POST'], detail=True, serializer_class=TinderProceedSerializer)
@action(methods=["POST"], detail=True, serializer_class=TinderProceedSerializer)
def proceed(self, request: Request, pk):
update_preferences_state(request.user, Event.objects.get(oid=pk), request.data['action'])
event = get_next_tinder(request.user, Event.objects.get(oid=pk), request.data['action'])
update_preferences_state(
request.user, Event.objects.get(oid=pk), request.data["action"]
)
event = get_next_tinder(
request.user, Event.objects.get(oid=pk), request.data["action"]
)
if event is None:
return Response(data={}, status=404)
return Response(data={'event': EventSerializer(event).data}, status=200)
return Response(data={"event": EventSerializer(event).data}, status=200)
@action(methods=['POST'], detail=False, serializer_class=TinderGetEventFilterSerializer)
@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)
events = Event.objects.filter(type__in=request.data["type"])
return Response(
data={"event": EventSerializer(choice(events)).data}, status=200
)
class PersonalRecommendation(viewsets.GenericViewSet):
@ -49,15 +55,11 @@ class PersonalRecommendation(viewsets.GenericViewSet):
model = Event
queryset = Event.objects.all()
@action(methods=["GET"], detail=False, serializer_class=SelfRecomendationSerializer)
def recommendations(self, request, *args, **kwargs):
return Response(data=get_personal_recomendations(request.user), status=200)
@action(methods=['GET'], detail=False, serializer_class=SelfRecomendationSerializer)
def recommendations(self, request, *args, **kwargs):
return Response(
data=get_personal_recomendations(request.user),
status=200
)
@action(methods=['GET'], detail=True)
@action(methods=["GET"], detail=True)
def get_nearest_user_distance(self, request, pk, *args, **kwargs):
request_point = pk
if len(Event.objects.filter(oid=pk)):
@ -68,96 +70,90 @@ def get_nearest_user_distance(self, request, pk, *args, **kwargs):
request_point = Hotel.objects.get(oid=pk)
res = nearest_distance_points(request_point, request.user)
return Response(
data=list(
map(
lambda event: EventSerializer(event).data,
res
)
),
status=200
data=list(map(lambda event: EventSerializer(event).data, res)), status=200
)
@action(methods=['GET'], detail=False, serializer_class=DailySelectionSerializerInput())
@action(
methods=["GET"], detail=False, serializer_class=DailySelectionSerializerInput()
)
def get_daily_selection(self, request, *args, **kwargs):
city = choice(City.objects.annotate(points_count=Count('points')).filter(points_count__gt=200))
city = choice(
City.objects.annotate(points_count=Count("points")).filter(
points_count__gt=200
)
)
events = sample(list(Event.objects.filter(city=city)), 10)
return Response(
data={
'city': city.title,
'events': list(
map(
lambda event: EventSerializer(event).data,
events
)
)
"city": city.title,
"events": list(map(lambda event: EventSerializer(event).data, events)),
}
)
@action(methods=['POST'], detail=False, serializer_class=DailySelectionSerializer)
@action(methods=["POST"], detail=False, serializer_class=DailySelectionSerializer)
def generate_daily_selection(self, request, *args, **kwargs):
points = []
for point in request.data['nodes']:
if point['action'] == 'right':
points.append(Event.objects.get(oid=point['oid']))
for point in request.data["nodes"]:
if point["action"] == "right":
points.append(Event.objects.get(oid=point["oid"]))
path = generate_points_path(request.user, points, 3)
return Response(
data={
'path': path
}
)
return Response(data={"path": path})
class OnboardingViewset(viewsets.GenericViewSet):
serializer_class = EventSerializer
model = Event
queryset = Event.objects.all()
@action(methods=['POST'], detail=False, serializer_class=HotelOnboardingRetrieve)
@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
hotels = get_onboarding_hotels(reqeust.data["stars"])
res = HotelOnboardingRetrieve({"hotels": hotels}).data
return Response(res, 200)
@action(methods=['POST'], detail=False, serializer_class=EventOnboardingRetrieve)
@action(methods=["POST"], detail=False, serializer_class=EventOnboardingRetrieve)
def event(self, request, *args, **kwargs):
events = get_onboarding_attractions()
res = EventOnboardingRetrieve({'events': events}).data
res = EventOnboardingRetrieve({"events": events}).data
return Response(res, 200)
@action(methods=['GET'], detail=True)
@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':
if event.type == "attraction":
pref.prefferred_attractions.add(event)
elif event.type == 'museum':
elif event.type == "museum":
pref.prefferred_museums.add(event)
elif event.type == 'movie':
elif event.type == "movie":
pref.preffered_movies.add(event)
elif event.type == 'play':
elif event.type == "play":
pref.preffered_plays.add(event)
elif event.type == 'concert':
elif event.type == "concert":
pref.preferred_concerts.add(event)
pref.save()
return Response(status=200)
@action(methods=['POST'], detail=False, serializer_class=StarSelectionSerializer)
@action(methods=["POST"], detail=False, serializer_class=StarSelectionSerializer)
def set_hotel_stars(self, request, *args, **kwargs):
up, _ = UserPreferences.objects.get_or_create(user=request.user)
up.preferred_stars = request.data['stars']
up.preferred_stars = request.data["stars"]
up.save()
return Response(status=200)
@action(methods=['POST'], detail=False, serializer_class=CategorySelectionSerializer)
@action(
methods=["POST"], detail=False, serializer_class=CategorySelectionSerializer
)
def set_categories(self, request, *args, **kwargs):
up, _ = UserPreferences.objects.get_or_create(user=request.user)
up.preferred_categories = request.data['categories']
up.preferred_categories = request.data["categories"]
up.save()
return Response(status=200)

View File

@ -7,29 +7,53 @@
class UserPreferences(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
preffered_plays = models.ManyToManyField(Event, related_name='preffered_user_play')
unpreffered_plays = models.ManyToManyField(Event, related_name='unpreffered_users_play')
preffered_plays = models.ManyToManyField(Event, related_name="preffered_user_play")
unpreffered_plays = models.ManyToManyField(
Event, related_name="unpreffered_users_play"
)
preffered_movies = models.ManyToManyField(Event, related_name='preffered_user_movie')
unpreffered_movies = models.ManyToManyField(Event, related_name='unpreffered_user_movie')
preffered_movies = models.ManyToManyField(
Event, related_name="preffered_user_movie"
)
unpreffered_movies = models.ManyToManyField(
Event, related_name="unpreffered_user_movie"
)
preferred_concerts = models.ManyToManyField(Event, related_name='preffered_users_concert')
unpreferred_concerts = models.ManyToManyField(Event, related_name='unpreffered_users_concert')
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_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')
preferred_categories = ArrayField(base_field=models.CharField(max_length=100), null=True, blank=True)
preferred_stars = ArrayField(base_field=models.IntegerField(), null=True, blank=True)
prefferred_museums = models.ManyToManyField(
Event, related_name="preffered_users_museums"
)
unprefferred_museums = models.ManyToManyField(
Event, related_name="unpreffered_users_museums"
)
preferred_categories = ArrayField(
base_field=models.CharField(max_length=100), null=True, blank=True
)
preferred_stars = ArrayField(
base_field=models.IntegerField(), null=True, blank=True
)
class NearestEvent(models.Model):
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='nearest_model_rel')
nearest = models.ManyToManyField(Event, related_name='nearest_model_rev_rel')
event = models.ForeignKey(
Event, on_delete=models.CASCADE, related_name="nearest_model_rel"
)
nearest = models.ManyToManyField(Event, related_name="nearest_model_rev_rel")
"""
from passfinder.recomendations.service.service import generate_tour
@ -50,9 +74,12 @@ class NearestEvent(models.Model):
"""
class NearestHotel(models.Model):
hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE, related_name='nearest_hotel_rel')
nearest_events = models.ManyToManyField(Event, related_name='nearest_hotel_rev_rel')
hotel = models.ForeignKey(
Hotel, on_delete=models.CASCADE, related_name="nearest_hotel_rel"
)
nearest_events = models.ManyToManyField(Event, related_name="nearest_hotel_rev_rel")
class NearestRestaurantToEvent(models.Model):
@ -60,7 +87,6 @@ class NearestRestaurantToEvent(models.Model):
restaurants = models.ManyToManyField(Restaurant)
class NearestRestaurantToHotel(models.Model):
hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE)
restaurants = models.ManyToManyField(Restaurant)
@ -68,4 +94,4 @@ class NearestRestaurantToHotel(models.Model):
class NearestEventToRestaurant(models.Model):
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
events = models.ManyToManyField(Event)
events = models.ManyToManyField(Event)

View File

@ -21,6 +21,7 @@ def build_dict(list_mapping):
mapping.update({idx: elem})
return mapping
def build_rev_dict(list_mapping):
mapping = {}
for idx, elem in enumerate(list_mapping):
@ -28,37 +29,37 @@ def build_rev_dict(list_mapping):
return mapping
with open('passfinder/recomendations/service/mapping/attractions.pickle', 'rb') as file:
with open("passfinder/recomendations/service/mapping/attractions.pickle", "rb") as file:
lst = pickle.load(file)
attraction_mapping = build_dict(lst)
rev_attraction_mapping = build_rev_dict(lst)
with open('passfinder/recomendations/service/mapping/kino.pickle', 'rb') as file:
with open("passfinder/recomendations/service/mapping/kino.pickle", "rb") as file:
lst = pickle.load(file)
cinema_mapping = build_dict(lst)
rev_cinema_mapping = build_rev_dict(lst)
with open('passfinder/recomendations/service/mapping/spektakli.pickle', 'rb') as file:
with open("passfinder/recomendations/service/mapping/spektakli.pickle", "rb") as file:
lst = pickle.load(file)
plays_mapping = build_dict(lst)
rev_plays_mapping = build_rev_dict(lst)
with open('passfinder/recomendations/service/mapping/excursii.pickle', 'rb') as file:
with open("passfinder/recomendations/service/mapping/excursii.pickle", "rb") as file:
lst = pickle.load(file)
excursion_mapping = build_dict(lst)
rev_excursion_mapping = build_rev_dict(lst)
with open('passfinder/recomendations/service/mapping/concerts.pickle', 'rb') as file:
with open("passfinder/recomendations/service/mapping/concerts.pickle", "rb") as file:
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:
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)
rev_mus_mapping = build_rev_dict(lst)

View File

@ -2,25 +2,25 @@
N_DIMENSIONAL = 768
attracion_model = AnnoyIndex(N_DIMENSIONAL, 'angular')
attracion_model.load('passfinder/recomendations/service/models/dost.ann')
attracion_model = AnnoyIndex(N_DIMENSIONAL, "angular")
attracion_model.load("passfinder/recomendations/service/models/dost.ann")
cinema_model = AnnoyIndex(N_DIMENSIONAL, 'angular')
cinema_model.load('passfinder/recomendations/service/models/kino.ann')
cinema_model = AnnoyIndex(N_DIMENSIONAL, "angular")
cinema_model.load("passfinder/recomendations/service/models/kino.ann")
plays_model = AnnoyIndex(N_DIMENSIONAL, 'angular')
plays_model.load('passfinder/recomendations/service/models/spektatli.ann')
plays_model = AnnoyIndex(N_DIMENSIONAL, "angular")
plays_model.load("passfinder/recomendations/service/models/spektatli.ann")
excursion_model = AnnoyIndex(N_DIMENSIONAL, 'angular')
excursion_model.load('passfinder/recomendations/service/models/excursii.ann')
excursion_model = AnnoyIndex(N_DIMENSIONAL, "angular")
excursion_model.load("passfinder/recomendations/service/models/excursii.ann")
concert_model = AnnoyIndex(N_DIMENSIONAL, 'angular')
concert_model.load('passfinder/recomendations/service/models/concerts.ann')
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')
mus_model = AnnoyIndex(N_DIMENSIONAL, "angular")
mus_model.load("passfinder/recomendations/service/models/mus.ann")

View File

@ -51,12 +51,7 @@ 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
museum, "museum", mus_mapping, rev_mus_mapping, nearest_n, mus_model
)
@ -101,9 +96,9 @@ 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':
if event.type == "museum":
return nearest_mus(event, nearest_n)
if event.type == 'attraction':
if event.type == "attraction":
return nearest_attraction(event, nearest_n)
@ -288,10 +283,7 @@ def generate_nearest_rest():
all_events = list(Event.objects.all())
for i, rest in enumerate(Restaurant.objects.all()):
sorted_events = list(
sorted(
all_events.copy(),
key=lambda event: dist_func(rest, event)
)
sorted(all_events.copy(), key=lambda event: dist_func(rest, event))
)
nearest = NearestEventToRestaurant.objects.create(restaurant=rest)
nearest.events.set(sorted_events[0:100])
@ -339,7 +331,7 @@ def match_points():
point.city = s_regions[0]
point.save()
if i % 10 == 0:
print(i)
print(i)
for i, point in enumerate(Hotel.objects.all()):
s_regions = list(sorted(regions.copy(), key=lambda x: dist_func(point, x)))
point.city = s_regions[0]
@ -354,11 +346,10 @@ def match_restaurants():
for i, point in enumerate(Restaurant.objects.all()):
s_regions = list(sorted(regions.copy(), key=lambda x: dist_func(point, x)))
point.city = s_regions[0]
point.save()
if i % 10 == 0:
print(i)
def calculate_mean_metric(
@ -393,10 +384,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':
if event.type == "attraction":
preferred = pref.prefferred_attractions.all()
return calculate_mean_metric(preferred, event, attracion_model, rev_attraction_mapping)
if event.type == 'museum':
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 10
@ -425,30 +418,22 @@ def get_category_similarity_coef(event, user):
def get_nearest_favorite(
events: Iterable[Event],
user: User,
base_event: Event,
exclude_events: Iterable[Event] = [],
velocity=3.0,
top_k=1
events: Iterable[Event],
user: User,
base_event: Event,
exclude_events: Iterable[Event] = [],
velocity=3.0,
top_k=1,
):
sorted_events = list(
sorted(
filter(lambda event: event not in exclude_events, events),
key=lambda event:
calculate_favorite_metric(event, user) *
get_exponential_koef(
time_func(
dist_func(
event, base_event
),
velocity
)
) *
get_category_similarity_coef(event, user)
)
filter(lambda event: event not in exclude_events, events),
key=lambda event: calculate_favorite_metric(event, user)
* get_exponential_koef(time_func(dist_func(event, base_event), velocity))
* get_category_similarity_coef(event, user),
)
)
if top_k == 1:
return sorted_events[0]
@ -465,7 +450,6 @@ def time_func(km_distance: float, velocity: float):
return timedelta(minutes=(km_distance) / (velocity / 60))
def generate_route(point1: BasePoint, point2: BasePoint, velocity):
distance = dist_func(point1, point2)
time = time_func(distance, velocity)
@ -482,8 +466,8 @@ def generate_point(point: BasePoint):
"type": "point",
"point": event_data,
"point_type": "point",
"time": timedelta(minutes=90+choice(range(-10, 90, 10))).seconds,
"distance": 0
"time": timedelta(minutes=90 + choice(range(-10, 90, 10))).seconds,
"distance": 0,
}
@ -494,33 +478,49 @@ def generate_restaurant(point: BasePoint):
"type": "point",
"point": rest_data,
"point_type": "restaurant",
"time": timedelta(minutes=90+choice(range(-10, 90, 10))).seconds
"time": timedelta(minutes=90 + choice(range(-10, 90, 10))).seconds,
}
def generate_multiple_tours(user: User, city: City, start_date: datetime.date, end_date: datetime.date):
def generate_multiple_tours(
user: User, city: City, start_date: datetime.date, end_date: datetime.date
):
hotels = sample(list(Hotel.objects.filter(city=city)), 5)
pool = Pool(5)
return pool.map(generate_tour, [(user, start_date, end_date, hotel) for hotel in hotels])
return pool.map(
generate_tour, [(user, start_date, end_date, hotel) for hotel in hotels]
)
def generate_tour(
user: User,
city: City,
start_date: datetime.date,
end_date: datetime.date,
avg_velocity=3.0,
stars=[],
hotel_type=['hotel', 'hostel', 'apartment'],
where_eat=['restaurant', 'bar', 'cafe'],
what_to_see=['attractions', 'museum', 'movie', 'concert', 'artwork', 'plays', 'shop', 'gallery', 'theme_park', 'viewpoint', 'zoo']
):
user: User,
city: City,
start_date: datetime.date,
end_date: datetime.date,
avg_velocity=3.0,
stars=[],
hotel_type=["hotel", "hostel", "apartment"],
where_eat=["restaurant", "bar", "cafe"],
what_to_see=[
"attractions",
"museum",
"movie",
"concert",
"artwork",
"plays",
"shop",
"gallery",
"theme_park",
"viewpoint",
"zoo",
],
):
UserPreferences.objects.get_or_create(user=user)
hotels_candidates = Hotel.objects.filter(city=city)
if len(hotels_candidates.filter(stars__in=stars)):
hotels_candidates = hotels_candidates.filter(stars__in=stars)
try:
hotel = choice(list(hotels_candidates))
except:
@ -530,21 +530,16 @@ def generate_tour(
while current_date < end_date:
local_points, local_paths, local_disallowed_rest = generate_path(
user,
points,
hotel,
disallowed_rest,
user,
points,
hotel,
disallowed_rest,
avg_velocity,
where_eat=where_eat,
what_to_see=what_to_see
what_to_see=what_to_see,
)
points.extend(local_points)
paths.append(
{
'date': current_date,
'paths': local_paths
}
)
paths.append({"date": current_date, "paths": local_paths})
disallowed_rest = local_disallowed_rest
current_date += timedelta(days=1)
return paths, points
@ -557,11 +552,11 @@ def generate_hotel(hotel: Hotel):
"point": hotel_data,
"point_type": "hotel",
"time": 0,
"distance": 0
"distance": 0,
}
def nearest_distance_points(point: BasePoint, user: User, velocity: float=3.0):
def nearest_distance_points(point: BasePoint, user: User, velocity: float = 3.0):
nearest = []
print(isinstance(point, Event), point)
if isinstance(point, Event):
@ -570,31 +565,42 @@ def nearest_distance_points(point: BasePoint, user: User, velocity: float=3.0):
nearest = NearestHotel.objects.get(hotel=point).nearest_events.all()
if isinstance(point, Restaurant):
nearest = NearestEventToRestaurant.objects.get(restaurant=point).events.all()
top_nearest = get_nearest_favorite(nearest, user, point, [], velocity, top_k=10)
return top_nearest
def generate_path(
user: User,
disallowed_points: Iterable[BasePoint],
hotel: Hotel,
disallowed_rests: Iterable[Restaurant],
avg_velocity: float,
where_eat=['restaurant', 'bar', 'cafe'],
what_to_see=['attractions', 'museum', 'movie', 'concert', 'artwork', 'plays', 'shop', 'gallery', 'theme_park', 'viewpoint', 'zoo']
):
user: User,
disallowed_points: Iterable[BasePoint],
hotel: Hotel,
disallowed_rests: Iterable[Restaurant],
avg_velocity: float,
where_eat=["restaurant", "bar", "cafe"],
what_to_see=[
"attractions",
"museum",
"movie",
"concert",
"artwork",
"plays",
"shop",
"gallery",
"theme_park",
"viewpoint",
"zoo",
],
):
allowed_types = [
'museum',
'attraction',
'artwork',
'shop',
'gallery',
'theme_park',
'zoo',
'other',
'viewpoint'
"museum",
"attraction",
"artwork",
"shop",
"gallery",
"theme_park",
"zoo",
"other",
"viewpoint",
]
if len(set(allowed_types) & set(what_to_see)) == 0:
allowed_types = what_to_see
@ -602,83 +608,107 @@ def generate_path(
allowed_types = list(set(allowed_types) & set(what_to_see))
print(allowed_types, hotel)
if isinstance(hotel, City):
start_points_candidate = Restaurant.objects.filter(city=hotel).filter(~Q(oid__in=disallowed_rests))
start_points_candidate = Restaurant.objects.filter(city=hotel).filter(
~Q(oid__in=disallowed_rests)
)
else:
start_points_candidate = NearestRestaurantToHotel.objects.filter(hotel=hotel).first().restaurants.filter(~Q(oid__in=disallowed_rests))
start_points_candidate = (
NearestRestaurantToHotel.objects.filter(hotel=hotel)
.first()
.restaurants.filter(~Q(oid__in=disallowed_rests))
)
if len(start_points_candidate.filter(type__in=where_eat)):
start_points_candidate = start_points_candidate.filter(type__in=where_eat)
start_point = start_points_candidate[0]
disallowed_rests.append(start_point.oid)
candidates = NearestEventToRestaurant.objects.get(restaurant=start_point).events.all().filter(type__in=allowed_types)
candidates = (
NearestEventToRestaurant.objects.get(restaurant=start_point)
.events.all()
.filter(type__in=allowed_types)
)
points = [start_point]
if isinstance(hotel, Hotel):
path = [
generate_hotel(hotel),
generate_route(start_point, hotel, avg_velocity),
generate_restaurant(start_point)
generate_route(start_point, hotel, avg_velocity),
generate_restaurant(start_point),
]
else:
path = [
generate_restaurant(start_point)
]
path = [generate_restaurant(start_point)]
start_time = datetime.combine(datetime.now(), time(hour=10))
how_many_eat = 1
while start_time.hour < 22 and start_time.day == datetime.now().day:
if (start_time.hour > 14 and how_many_eat == 1) or (start_time.hour > 20 and how_many_eat == 2):
if (start_time.hour > 14 and how_many_eat == 1) or (
start_time.hour > 20 and how_many_eat == 2
):
print(points, start_time)
try:
point_candidates = NearestRestaurantToEvent.objects.filter(event=points[-1]).first().restaurants.filter(~Q(oid__in=disallowed_rests))
point_candidates = (
NearestRestaurantToEvent.objects.filter(event=points[-1])
.first()
.restaurants.filter(~Q(oid__in=disallowed_rests))
)
if len(point_candidates.filter(type__in=where_eat)):
point_candidates = point_candidates.filter(type__in=where_eat)
point = point_candidates[0]
disallowed_rests.append(point.oid)
points.append(point)
candidates = NearestEventToRestaurant.objects.get(restaurant=point).events.all().filter(type__in=allowed_types)
candidates = (
NearestEventToRestaurant.objects.get(restaurant=point)
.events.all()
.filter(type__in=allowed_types)
)
if len(candidates) < 2:
candidates = NearestEventToRestaurant.objects.get(restaurant=point).events.all()
candidates = NearestEventToRestaurant.objects.get(
restaurant=point
).events.all()
path.append(generate_restaurant(points[-1]))
start_time += timedelta(seconds=path[-1]['time'])
start_time += timedelta(seconds=path[-1]["time"])
how_many_eat += 1
continue
except:
return points, path, disallowed_rests
if start_time.hour > 17:
allowed_types = [
'play',
'concert',
'movie',
'shop',
'gallery',
'theme_park',
'viewpoint'
"play",
"concert",
"movie",
"shop",
"gallery",
"theme_park",
"viewpoint",
]
if len(set(allowed_types) & set(what_to_see)) == 0:
allowed_types = what_to_see
else:
allowed_types = list(set(allowed_types) & set(what_to_see))
if candidates is None:
candidates = NearestEvent.objects.get(event=points[-1]).nearest.filter(type__in=allowed_types)
candidates = NearestEvent.objects.get(event=points[-1]).nearest.filter(
type__in=allowed_types
)
if len(candidates) < 2:
candidates = NearestEvent.objects.get(event=points[-1]).nearest.all()
try:
points.append(get_nearest_favorite(candidates, user, points[-1], points + disallowed_points))
points.append(
get_nearest_favorite(
candidates, user, points[-1], points + disallowed_points
)
)
except:
points.append(get_nearest_favorite(candidates, user, points[-1], points))
@ -716,12 +746,10 @@ def get_onboarding_attractions():
mx_dist = 0
mx_attraction = None
for att in sample_attractions:
if att in attractions: continue
if att in attractions:
continue
local_dist = calculate_distance(
att,
attractions,
attracion_model,
rev_attraction_mapping
att, attractions, attracion_model, rev_attraction_mapping
)
if local_dist > mx_dist:
mx_dist = local_dist
@ -737,12 +765,20 @@ def get_onboarding_hotels(stars=Iterable[int]):
def generate_points_path(user: User, points: Iterable[Event], velocity=3.0):
if len(points) < 7:
candidates = NearestEvent.objects.get(event=points[0]).nearest.all()
points.extend(list(get_nearest_favorite(candidates, user, points[0], [], velocity, 7-len(points))))
points.extend(
list(
get_nearest_favorite(
candidates, user, points[0], [], velocity, 7 - len(points)
)
)
)
dist_matrix = [[0 for j in range(len(points))] for i in range(len(points))]
for i in range(len(dist_matrix)):
for j in range(len(dist_matrix)):
dist_matrix[i][j] = time_func(dist_func(points[i], points[j]), velocity).seconds
dist_matrix[i][j] = time_func(
dist_func(points[i], points[j]), velocity
).seconds
for i in range(len(dist_matrix)):
dist_matrix[i][0] = 0
dist_matrix = np.array(dist_matrix)
@ -755,14 +791,9 @@ def generate_points_path(user: User, points: Iterable[Event], velocity=3.0):
visited_points = [perm_pts[0]]
for pt in perm_pts[1:]:
res.extend([
generate_route(
visited_points[-1],
pt,
velocity
),
generate_point(pt)
])
res.extend(
[generate_route(visited_points[-1], pt, velocity), generate_point(pt)]
)
visited_points.append(pt)
return res
@ -777,21 +808,19 @@ def flat_list(lst):
def range_candidates(candidates, user, favorite_events):
model_mappings = {
'attraction': [attracion_model, rev_attraction_mapping],
'museum': [mus_model, rev_mus_mapping],
'movie': [cinema_model, rev_cinema_mapping],
'concert': [concert_model, rev_concert_mapping],
'plays': [plays_model, rev_plays_mapping]
"attraction": [attracion_model, rev_attraction_mapping],
"museum": [mus_model, rev_mus_mapping],
"movie": [cinema_model, rev_cinema_mapping],
"concert": [concert_model, rev_concert_mapping],
"plays": [plays_model, rev_plays_mapping],
}
if candidates[0].type in ['attraction', 'museum', 'movie', 'concert', 'plays']:
if candidates[0].type in ["attraction", "museum", "movie", "concert", "plays"]:
candidates = sorted(
candidates,
key=lambda cand: calculate_mean_metric(
favorite_events,
cand,
*model_mappings[cand.type]
)
favorite_events, cand, *model_mappings[cand.type]
),
)
return candidates[0:10]
return sample(candidates, 10)
@ -800,80 +829,92 @@ def range_candidates(candidates, user, favorite_events):
def get_personal_recomendations(user):
up, _ = UserPreferences.objects.get_or_create(user=user)
candidates_generate_strategy = {
'plays': [lambda pref: flat_list(
list(
map(
lambda cand: nearest_plays(
cand, 30
),
pref.preffered_plays.all()
)
),
), lambda pref: pref.preffered_plays.all()],
'movie': [lambda pref: flat_list(
list(
map(
lambda cand: nearest_movie(
cand, 30
),
pref.preffered_movies.all()
)
),
), lambda pref: pref.preffered_movies.all()],
'concert': [lambda pref: flat_list(
list(
map(
lambda cand: nearest_concert(
cand, 30
),
pref.preferred_concerts.all()
)
),
), lambda pref: pref.preferred_concerts.all()],
'attractions': [lambda pref: flat_list(
list(
map(
lambda cand: nearest_attraction(
cand, 30
),
pref.prefferred_attractions.all()
)
"plays": [
lambda pref: flat_list(
list(
map(
lambda cand: nearest_plays(cand, 30), pref.preffered_plays.all()
)
),
),
), lambda pref: pref.prefferred_attractions.all()],
'museum': [lambda pref: flat_list(
list(
map(
lambda cand: nearest_mus(
cand, 30
),
pref.prefferred_museums.all()
)
lambda pref: pref.preffered_plays.all(),
],
"movie": [
lambda pref: flat_list(
list(
map(
lambda cand: nearest_movie(cand, 30),
pref.preffered_movies.all(),
)
),
),
), lambda pref: pref.prefferred_museums.all()],
'shop': [lambda pref: sample(list(Event.objects.filter(type='shop')), 10), lambda x: []],
'gallery': [lambda pref: sample(list(Event.objects.filter(type='gallery')), 10), lambda x: []],
'theme_park': [lambda pref: sample(list(Event.objects.filter(type='theme_park')), 10), lambda x: []],
'viewpoint': [lambda pref: sample(list(Event.objects.filter(type='viewpoint')), 10), lambda x: []],
'zoo': [lambda pref: sample(list(Event.objects.filter(type='zoo')), 10), lambda x: []],
lambda pref: pref.preffered_movies.all(),
],
"concert": [
lambda pref: flat_list(
list(
map(
lambda cand: nearest_concert(cand, 30),
pref.preferred_concerts.all(),
)
),
),
lambda pref: pref.preferred_concerts.all(),
],
"attractions": [
lambda pref: flat_list(
list(
map(
lambda cand: nearest_attraction(cand, 30),
pref.prefferred_attractions.all(),
)
),
),
lambda pref: pref.prefferred_attractions.all(),
],
"museum": [
lambda pref: flat_list(
list(
map(
lambda cand: nearest_mus(cand, 30),
pref.prefferred_museums.all(),
)
),
),
lambda pref: pref.prefferred_museums.all(),
],
"shop": [
lambda pref: sample(list(Event.objects.filter(type="shop")), 10),
lambda x: [],
],
"gallery": [
lambda pref: sample(list(Event.objects.filter(type="gallery")), 10),
lambda x: [],
],
"theme_park": [
lambda pref: sample(list(Event.objects.filter(type="theme_park")), 10),
lambda x: [],
],
"viewpoint": [
lambda pref: sample(list(Event.objects.filter(type="viewpoint")), 10),
lambda x: [],
],
"zoo": [
lambda pref: sample(list(Event.objects.filter(type="zoo")), 10),
lambda x: [],
],
}
res = []
for category_candidate in up.preferred_categories:
candidates = candidates_generate_strategy[category_candidate][0](up)
ranged = range_candidates(
candidates,
user,
candidates_generate_strategy[category_candidate][1](up)
candidates, user, candidates_generate_strategy[category_candidate][1](up)
)
res.append(
{
'category': category_candidate,
'events': list(
map(
lambda x: ObjectRouteSerializer(x).data,
ranged
)
)
"category": category_candidate,
"events": list(map(lambda x: ObjectRouteSerializer(x).data, ranged)),
}
)
return res