mirror of
https://github.com/task-17-lct/backend.git
synced 2024-11-27 11:33:48 +03:00
Merge branch 'remove-bugs'
This commit is contained in:
commit
bc173cdbee
270
passfinder/city.txt
Normal file
270
passfinder/city.txt
Normal file
|
@ -0,0 +1,270 @@
|
|||
Москва
|
||||
|
||||
|
||||
Санкт-Петербург
|
||||
|
||||
|
||||
Новосибирск
|
||||
|
||||
|
||||
Екатеринбург
|
||||
|
||||
|
||||
Нижний Новгород
|
||||
|
||||
|
||||
Самара
|
||||
|
||||
|
||||
Омск
|
||||
|
||||
|
||||
Казань
|
||||
|
||||
|
||||
Челябинск
|
||||
|
||||
|
||||
Ростов-на-Дону
|
||||
|
||||
|
||||
Уфа
|
||||
|
||||
|
||||
Волгоград
|
||||
|
||||
|
||||
Пермь
|
||||
|
||||
|
||||
Красноярск
|
||||
|
||||
Воронеж
|
||||
|
||||
Саратов
|
||||
|
||||
Краснодар
|
||||
|
||||
Тольятти
|
||||
|
||||
Ижевск
|
||||
|
||||
Ульяновск
|
||||
|
||||
Барнаул
|
||||
|
||||
Владивосток
|
||||
|
||||
Ярославль
|
||||
|
||||
Иркутск
|
||||
|
||||
Тюмень
|
||||
|
||||
Махачкала
|
||||
|
||||
Хабаровск
|
||||
|
||||
Оренбург
|
||||
|
||||
Новокузнецк
|
||||
|
||||
Кемерово
|
||||
|
||||
Рязань
|
||||
|
||||
Томск
|
||||
|
||||
Астрахань
|
||||
|
||||
Пенза
|
||||
|
||||
Набережные Челны
|
||||
|
||||
Липецк
|
||||
|
||||
Тула
|
||||
|
||||
Киров
|
||||
|
||||
Чебоксары
|
||||
|
||||
Калининград
|
||||
|
||||
Брянск
|
||||
|
||||
Курск
|
||||
|
||||
Иваново
|
||||
|
||||
Магнитогорск
|
||||
|
||||
Улан-Удэ
|
||||
|
||||
Тверь
|
||||
|
||||
Ставрополь
|
||||
|
||||
Нижний Тагил
|
||||
|
||||
Белгород
|
||||
|
||||
Архангельск
|
||||
|
||||
Владимир
|
||||
|
||||
Сочи
|
||||
|
||||
Курган
|
||||
|
||||
Смоленск
|
||||
|
||||
Калуга
|
||||
|
||||
Чита
|
||||
|
||||
Ор
|
||||
л
|
||||
|
||||
Волжский
|
||||
|
||||
Череповец
|
||||
|
||||
Владикавказ
|
||||
|
||||
Мурманск
|
||||
|
||||
Сургут
|
||||
|
||||
Вологда
|
||||
|
||||
Саранск
|
||||
|
||||
Тамбов
|
||||
|
||||
Стерлитамак
|
||||
|
||||
Грозный
|
||||
|
||||
Якутск
|
||||
|
||||
Кострома
|
||||
|
||||
Комсомольск-на-Амуре
|
||||
|
||||
Петрозаводск
|
||||
|
||||
Таганрог
|
||||
|
||||
Нижневартовск
|
||||
|
||||
Йошкар-Ола
|
||||
|
||||
Братск
|
||||
|
||||
Новороссийск
|
||||
|
||||
Дзержинск
|
||||
|
||||
Шахты
|
||||
|
||||
Нальчик
|
||||
|
||||
Орск
|
||||
|
||||
Сыктывкар
|
||||
|
||||
Нижнекамск
|
||||
|
||||
Ангарск
|
||||
|
||||
Старый Оскол
|
||||
|
||||
Великий Новгород
|
||||
|
||||
Балашиха
|
||||
|
||||
Благовещенск
|
||||
|
||||
Прокопьевск
|
||||
|
||||
Бийск
|
||||
|
||||
Химки
|
||||
|
||||
Псков
|
||||
|
||||
Энгельс
|
||||
|
||||
Рыбинск
|
||||
|
||||
Балаково
|
||||
|
||||
Северодвинск
|
||||
|
||||
Армавир
|
||||
|
||||
Подольск
|
||||
|
||||
Корол
|
||||
в
|
||||
|
||||
Южно-Сахалинск
|
||||
|
||||
Петропавловск-Камчатский
|
||||
|
||||
Сызрань
|
||||
|
||||
Норильск
|
||||
|
||||
Златоуст
|
||||
|
||||
Каменск-Уральский
|
||||
|
||||
Мытищи
|
||||
|
||||
Люберцы
|
||||
|
||||
Волгодонск
|
||||
|
||||
Новочеркасск
|
||||
|
||||
Абакан
|
||||
|
||||
Находка
|
||||
|
||||
Уссурийск
|
||||
|
||||
Березники
|
||||
|
||||
Салават
|
||||
|
||||
Электросталь
|
||||
|
||||
Миасс
|
||||
|
||||
Первоуральск
|
||||
|
||||
Рубцовск
|
||||
|
||||
Альметьевск
|
||||
|
||||
Ковров
|
||||
|
||||
Коломна
|
||||
|
||||
Майкоп
|
||||
|
||||
Пятигорск
|
||||
|
||||
Одинцово
|
||||
|
||||
Колпино
|
||||
|
||||
Копейск
|
||||
|
||||
Хасавюрт
|
||||
Новомосковск
|
||||
Кисловодск
|
||||
Серпухов
|
||||
Новочебоксарск
|
|
@ -1,226 +1,47 @@
|
|||
city_in_hotels = ['Абзаково',
|
||||
'Абрамовка',
|
||||
'Абрау-Дюрсо',
|
||||
'Адлер',
|
||||
'Азов',
|
||||
'Аксай',
|
||||
'Альметьевск',
|
||||
'Анапа',
|
||||
'Андрианово',
|
||||
'Арамиль',
|
||||
'Арзамас',
|
||||
'Арнеево',
|
||||
'Архипо-Осиповка',
|
||||
'Бабкино',
|
||||
'Базы отдыха ВТО',
|
||||
city_in_hotels = {'Астрахань',
|
||||
'Балашиха',
|
||||
'Батайск',
|
||||
'Беличье',
|
||||
'Белореченск',
|
||||
'Бердск',
|
||||
'Бердяш',
|
||||
'Березовка',
|
||||
'Бжид',
|
||||
'Битца',
|
||||
'Благовещенская',
|
||||
'Болтино',
|
||||
'Большой Сочи',
|
||||
'Бор, Нижегородская область',
|
||||
'Борисово',
|
||||
'Борносово',
|
||||
'Будённовск',
|
||||
'Вардане',
|
||||
'Васильево, Ленинградская область',
|
||||
'Васкелово',
|
||||
'Вербилки',
|
||||
'Веселовка, Краснодарский край',
|
||||
'Видное',
|
||||
'Витязево',
|
||||
'Владимировка',
|
||||
'Внуково',
|
||||
'Воскресенск',
|
||||
'Вотря',
|
||||
'Всеволожск',
|
||||
'Всходы',
|
||||
'Выборг',
|
||||
'Вырубово',
|
||||
'Гатчина',
|
||||
'Гвардейское',
|
||||
'Геленджик',
|
||||
'Голиково',
|
||||
'Головинка Краснодарский край',
|
||||
'Голубицкая',
|
||||
'Горки',
|
||||
'Городец',
|
||||
'Горячий ключ',
|
||||
'Григорчиково',
|
||||
'Гуамка',
|
||||
'Д/О Авангард',
|
||||
'Дагомыс',
|
||||
'Джемете',
|
||||
'Джубга',
|
||||
'Березники',
|
||||
'Благовещенск',
|
||||
'Владикавказ',
|
||||
'Волгоград',
|
||||
'Волгодонск',
|
||||
'Волжский',
|
||||
'Воронеж',
|
||||
'Грозный',
|
||||
'Дзержинск',
|
||||
'Дивеево',
|
||||
'Дивногорье, Краснодарский край',
|
||||
'Дивноморское',
|
||||
'Дмитров',
|
||||
'Домодедово',
|
||||
'Дракино',
|
||||
'Дранишники',
|
||||
'Дубечино',
|
||||
'Егорьевск',
|
||||
'Ейск',
|
||||
'Екатеринбург',
|
||||
'Ершово',
|
||||
'Ессентуки',
|
||||
'Железноводск',
|
||||
'Жуковский',
|
||||
'За Родину',
|
||||
'Звенигород',
|
||||
'Зеленая поляна',
|
||||
'Ивантеевка',
|
||||
'Ильичево',
|
||||
'Иннолово ',
|
||||
'Иноземцево',
|
||||
'Исаково',
|
||||
'Истра',
|
||||
'Кабардинка',
|
||||
'Казань',
|
||||
'Каменск-Шахтинский',
|
||||
'Каневская',
|
||||
'Кингисепп',
|
||||
'Златоуст',
|
||||
'Ижевск',
|
||||
'Каменск-Уральский',
|
||||
'Киров',
|
||||
'Кисловодск',
|
||||
'Клин',
|
||||
'Коломна',
|
||||
'Коробицыно',
|
||||
'Королев',
|
||||
'Косулино',
|
||||
'Котельники',
|
||||
'Красная Горка',
|
||||
'Красная Поляна',
|
||||
'Красногорск',
|
||||
'Краснодар',
|
||||
'Красный Колос',
|
||||
'Кудряшовский',
|
||||
'Курово',
|
||||
'Кусимовского Рудника',
|
||||
'Кучугуры',
|
||||
'Лабинск',
|
||||
'Лазаревское',
|
||||
'Лермонтово',
|
||||
'Лесной городок',
|
||||
'Лодейное Поле',
|
||||
'Лоо',
|
||||
'Лосево',
|
||||
'Колпино',
|
||||
'Комсомольск-на-Амуре',
|
||||
'Копейск',
|
||||
'Кострома',
|
||||
'Красноярск',
|
||||
'Курган',
|
||||
'Люберцы',
|
||||
'Магнитогорск',
|
||||
'Малые Решники',
|
||||
'Марьино, Ленинградская область',
|
||||
'Маяковского',
|
||||
'Мезмай',
|
||||
'Мещерино',
|
||||
'Миасс',
|
||||
'Минеральные Воды',
|
||||
'Мистолово',
|
||||
'Мишуткино',
|
||||
'Можайск',
|
||||
'Махачкала',
|
||||
'Москва',
|
||||
'Мостовской',
|
||||
'Мытищи',
|
||||
'Набережные Челны',
|
||||
'Наро-Фоминск',
|
||||
'Нарынка',
|
||||
'Небуг',
|
||||
'Нестерово',
|
||||
'Нижний Новгород',
|
||||
'Нальчик',
|
||||
'Нижнекамск',
|
||||
'Нижний Тагил',
|
||||
'Новая',
|
||||
'Новоабзаково',
|
||||
'Нововолково',
|
||||
'Новомихайловский',
|
||||
'Новороссийск',
|
||||
'Новосибирск',
|
||||
'Новочеркасск',
|
||||
'Новый путь',
|
||||
'Ногинск',
|
||||
'Нурлат',
|
||||
'Овсяники',
|
||||
'Новочебоксарск',
|
||||
'Одинцово',
|
||||
'Озеры',
|
||||
'Оксино',
|
||||
'Октябрьский, Московская область',
|
||||
'Ольгинка',
|
||||
'Остров, Московская область',
|
||||
'Павловск',
|
||||
'Падиково',
|
||||
'Пересвет',
|
||||
'Платформа 69-й километр, Сосновское сельское поселение',
|
||||
'Омск',
|
||||
'Оренбург',
|
||||
'Орск',
|
||||
'Пермь',
|
||||
'Подольск',
|
||||
'Подпорожье',
|
||||
'Полтавская',
|
||||
'Приморско-Ахтарск',
|
||||
'Приозерск',
|
||||
'Прохорово',
|
||||
'Пушкино',
|
||||
'Пятигорск',
|
||||
'Раменское',
|
||||
'Реутов',
|
||||
'Рождествено',
|
||||
'Роза Хутор',
|
||||
'Ростов-на-Дону',
|
||||
'Рощино',
|
||||
'Руза',
|
||||
'Салават',
|
||||
'Санкт-Петербург',
|
||||
'Светлое',
|
||||
'Светлый',
|
||||
'Свирица',
|
||||
'Сергиев Посад',
|
||||
'Серпухов',
|
||||
'Симагино',
|
||||
'Сириус',
|
||||
'Скоково',
|
||||
'Снегири',
|
||||
'Солнечногорск',
|
||||
'Солохаул',
|
||||
'Сосново',
|
||||
'Сосновый Бор, Ленинградская область',
|
||||
'Сосновый Бор, Московская область',
|
||||
'Софрино',
|
||||
'Сочи',
|
||||
'Ставрополь',
|
||||
'Станица Динская',
|
||||
'Станица Должанская',
|
||||
'Старая Руза',
|
||||
'Степаньково',
|
||||
'Суйда',
|
||||
'Сукко',
|
||||
'Супсех',
|
||||
'Таганрог',
|
||||
'Тарасово',
|
||||
'Тимашевск',
|
||||
'Тихвин',
|
||||
'Тихорецк',
|
||||
'Тобольск',
|
||||
'Туапсе',
|
||||
'Тучково',
|
||||
'Томск',
|
||||
'Тюмень',
|
||||
'Увильды ',
|
||||
'Углегорский',
|
||||
'Удельная',
|
||||
'Усть-Койсуг',
|
||||
'Усть-Лабинск',
|
||||
'Уфа',
|
||||
'Ушаки',
|
||||
'Фрязино',
|
||||
'Хадыженск',
|
||||
'Хасавюрт',
|
||||
'Химки',
|
||||
'Хоста',
|
||||
'Чебаркуль',
|
||||
'Челябинск',
|
||||
'Чехов, Сахалинская область',
|
||||
'Чудская',
|
||||
'Шахты',
|
||||
'Широкая балка',
|
||||
'Щёлково',
|
||||
'Эсто-Садок',
|
||||
'Якорная щель']
|
||||
'Энгельс'}
|
|
@ -65,6 +65,49 @@ class RouteInputSerializer(serializers.Serializer):
|
|||
min_length=24, max_length=24, required=False, allow_blank=True, allow_null=True
|
||||
)
|
||||
movement = serializers.ChoiceField(['walk', 'bike', 'scooter', 'auto'], required=False, allow_blank=True)
|
||||
stars = serializers.ListField(
|
||||
child=serializers.ChoiceField([1, 2, 3, 4, 5]),
|
||||
required=False,
|
||||
allow_empty=True,
|
||||
allow_null=True
|
||||
)
|
||||
what_to_see = serializers.ListField(
|
||||
child=serializers.ChoiceField(
|
||||
[
|
||||
'attractions',
|
||||
'museum',
|
||||
'movie',
|
||||
'concert',
|
||||
'artwork',
|
||||
'plays',
|
||||
'shop',
|
||||
'gallery',
|
||||
'theme_park',
|
||||
'viewpoint',
|
||||
'zoo'
|
||||
]
|
||||
),
|
||||
required=False,
|
||||
allow_empty=True,
|
||||
allow_null=True
|
||||
)
|
||||
where_stay = serializers.ListField(
|
||||
child=serializers.ChoiceField([
|
||||
'hotel', 'apartment', 'hostel'
|
||||
]),
|
||||
required=False,
|
||||
allow_empty=True,
|
||||
allow_null=True
|
||||
)
|
||||
where_eat = serializers.ListField(
|
||||
child=serializers.ChoiceField(['restaurant', 'bar', 'cafe']),
|
||||
required=False,
|
||||
allow_empty=True,
|
||||
allow_null=True
|
||||
)
|
||||
with_kids = serializers.BooleanField(required=False, allow_null=True)
|
||||
with_animals = serializers.BooleanField(required=False, allow_null=True)
|
||||
|
||||
|
||||
class CitySerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
|
|
|
@ -75,6 +75,40 @@ def post(self, request):
|
|||
movement = data['movement']
|
||||
except KeyError:
|
||||
movement = 'walk'
|
||||
|
||||
hotel_stars = data['stars']
|
||||
if hotel_stars is None:
|
||||
hotel_stars = []
|
||||
|
||||
|
||||
hotel_type = data['where_stay']
|
||||
if hotel_type is None:
|
||||
hotel_type = ['hotel']
|
||||
|
||||
where_eat = data['where_eat']
|
||||
if where_eat is None:
|
||||
where_eat = ['restaurant', 'bar', 'cafe']
|
||||
|
||||
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'
|
||||
]
|
||||
|
||||
|
||||
if 'hotel' not in hotel_type:
|
||||
hotel_stars = []
|
||||
|
||||
region = None
|
||||
|
||||
if city_id:
|
||||
|
@ -95,7 +129,17 @@ def post(self, request):
|
|||
|
||||
print(request.user, region, start_date, end_date)
|
||||
|
||||
tour = generate_tour(request.user, region, start_date, end_date, movement_mapping[movement])
|
||||
tour = generate_tour(
|
||||
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
|
||||
)
|
||||
print(len(tour[1]))
|
||||
|
||||
return Response(data=tour[0])
|
||||
|
@ -109,9 +153,7 @@ class ListRegionApiView(ListAPIView):
|
|||
class ListCityApiView(ListAPIView):
|
||||
serializer_class = CitySerializer
|
||||
queryset = (
|
||||
City.objects.annotate(points_num=Count("points"))
|
||||
.filter(points_num__gte=100)
|
||||
.order_by("title")
|
||||
City.objects.annotate(points_count=Count('points')).filter(title__in=city_in_hotels).filter(points_count__gt=200).order_by('title')
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from rest_framework import serializers
|
||||
from passfinder.events.api.serializers import EventSerializer, HotelSerializer
|
||||
from passfinder.events.api.serializers import EventSerializer, HotelSerializer, ObjectRouteSerializer
|
||||
|
||||
|
||||
class TinderProceedSerializer(serializers.Serializer):
|
||||
|
@ -49,3 +49,23 @@ class DailySelectionSerializer(serializers.Serializer):
|
|||
)
|
||||
)
|
||||
event = EventSerializer()
|
||||
|
||||
|
||||
class StarSelectionSerializer(serializers.Serializer):
|
||||
stars = serializers.ListField(child=serializers.IntegerField(), write_only=True)
|
||||
|
||||
|
||||
class CategorySelectionSerializer(serializers.Serializer):
|
||||
categories = serializers.ListField(child=serializers.ChoiceField(
|
||||
['attractions', 'museum', 'movie', 'concert', 'artwork', 'plays', 'shop', 'gallery', 'theme_park', 'viewpoint', 'zoo']
|
||||
))
|
||||
|
||||
|
||||
class RecomendationNode(serializers.Serializer):
|
||||
category = serializers.CharField()
|
||||
events = serializers.ListField(child=ObjectRouteSerializer())
|
||||
|
||||
|
||||
|
||||
class SelfRecomendationSerializer(serializers.Serializer):
|
||||
recomendations = serializers.ListField(child=RecomendationNode(), write_only=True)
|
|
@ -49,32 +49,13 @@ class PersonalRecommendation(viewsets.GenericViewSet):
|
|||
model = Event
|
||||
queryset = Event.objects.all()
|
||||
|
||||
@action(methods=['GET'], detail=False)
|
||||
def plays(self, request, *args, **kwargs):
|
||||
recs = get_personal_plays_recommendation(request.user)
|
||||
ans = []
|
||||
for rec in recs:
|
||||
ans.append(EventSerializer(rec[1]).data)
|
||||
return Response(ans, 200)
|
||||
|
||||
|
||||
@action(methods=['GET'], detail=False)
|
||||
def concerts(self, request, *args, **kwargs):
|
||||
recs = get_personal_concerts_recommendation(request.user)
|
||||
ans = []
|
||||
for rec in recs:
|
||||
ans.append(EventSerializer(rec[1]).data)
|
||||
return Response(ans, 200)
|
||||
|
||||
|
||||
@action(methods=['GET'], detail=False)
|
||||
def movies(self, request, *args, **kwargs):
|
||||
recs = get_personal_movies_recommendation(request.user)
|
||||
ans = []
|
||||
for rec in recs:
|
||||
ans.append(EventSerializer(rec[1]).data)
|
||||
return Response(ans, 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)
|
||||
def get_nearest_user_distance(self, request, pk, *args, **kwargs):
|
||||
|
@ -166,3 +147,17 @@ def add_to_favorites(self, request, pk, *args, **kwargs):
|
|||
pref.save()
|
||||
|
||||
return Response(status=200)
|
||||
|
||||
@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.save()
|
||||
return Response(status=200)
|
||||
|
||||
@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.save()
|
||||
return Response(status=200)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# Generated by Django 4.2.1 on 2023-05-27 10:21
|
||||
|
||||
import django.contrib.postgres.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("recomendations", "0007_nearesteventtorestaurant"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="userpreferences",
|
||||
name="preferred_categories",
|
||||
field=django.contrib.postgres.fields.ArrayField(
|
||||
base_field=models.CharField(max_length=100),
|
||||
blank=True,
|
||||
null=True,
|
||||
size=None,
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="userpreferences",
|
||||
name="preferred_stars",
|
||||
field=django.contrib.postgres.fields.ArrayField(
|
||||
base_field=models.IntegerField(), blank=True, null=True, size=None
|
||||
),
|
||||
),
|
||||
]
|
|
@ -1,6 +1,7 @@
|
|||
from django.db import models
|
||||
from passfinder.users.models import User
|
||||
from passfinder.events.models import Event, Hotel, Restaurant
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
|
||||
|
||||
class UserPreferences(models.Model):
|
||||
|
@ -21,6 +22,9 @@ class UserPreferences(models.Model):
|
|||
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):
|
||||
|
|
|
@ -266,8 +266,7 @@ def dist_func(event1: Event, event2: Event):
|
|||
return dist
|
||||
except:
|
||||
return 1000000
|
||||
#return (event1.lon - event2.lon) ** 2 + (event1.lat - event2.lat) ** 2
|
||||
# return (event1.lon - event2.lon) ** 2 + (event1.lat - event2.lat) ** 2
|
||||
return (event1.lon - event2.lon) ** 2 + (event1.lat - event2.lat) ** 2
|
||||
|
||||
|
||||
def generate_nearest():
|
||||
|
@ -349,6 +348,19 @@ def match_points():
|
|||
print(i)
|
||||
|
||||
|
||||
def match_restaurants():
|
||||
regions = list(City.objects.all())
|
||||
|
||||
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(
|
||||
favorite_events: Iterable[Event],
|
||||
target_event: Event,
|
||||
|
@ -393,21 +405,50 @@ def calculate_favorite_metric(event: Event, user: User):
|
|||
def get_exponential_koef(time: timedelta):
|
||||
time = time.seconds
|
||||
if time < 60 * 10:
|
||||
return 1
|
||||
return 2
|
||||
if time < 60 * 20:
|
||||
return 10
|
||||
return 5
|
||||
if time < 60 * 30:
|
||||
return 1000
|
||||
return 10
|
||||
if time < 60 * 40:
|
||||
return 100000
|
||||
return 20
|
||||
return int(1e10)
|
||||
|
||||
|
||||
def get_category_similarity_coef(event, user):
|
||||
up, _ = UserPreferences.objects.get_or_create(user=user)
|
||||
cat = up.preferred_categories
|
||||
if event.type in cat:
|
||||
return 0.7
|
||||
else:
|
||||
return 1.2
|
||||
|
||||
|
||||
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(events, key=lambda event: calculate_favorite_metric(event, user) * get_exponential_koef(time_func(dist_func(event, base_event), velocity))))
|
||||
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)
|
||||
)
|
||||
)
|
||||
|
||||
if top_k == 1:
|
||||
return sorted_events[0]
|
||||
|
@ -424,14 +465,6 @@ def time_func(km_distance: float, velocity: float):
|
|||
return timedelta(minutes=(km_distance) / (velocity / 60))
|
||||
|
||||
|
||||
def generate_route(point1: BasePoint, point2: BasePoint, velocity: float):
|
||||
distance = dist_func(point1, point2)
|
||||
time = time_func(distance, velocity)
|
||||
|
||||
|
||||
def time_func(km_distance: float, velocity):
|
||||
return timedelta(minutes=(km_distance) / (velocity / 60))
|
||||
|
||||
|
||||
def generate_route(point1: BasePoint, point2: BasePoint, velocity):
|
||||
distance = dist_func(point1, point2)
|
||||
|
@ -470,14 +503,40 @@ def generate_multiple_tours(user: User, city: City, start_date: datetime.date, e
|
|||
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):
|
||||
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']
|
||||
):
|
||||
UserPreferences.objects.get_or_create(user=user)
|
||||
hotel = choice(list(Hotel.objects.filter(city=city)))
|
||||
|
||||
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:
|
||||
hotel = city
|
||||
current_date = start_date
|
||||
paths, points, disallowed_rest = [], [], []
|
||||
|
||||
while current_date < end_date:
|
||||
local_points, local_paths, local_disallowed_rest = generate_path(user, points, hotel, disallowed_rest, avg_velocity)
|
||||
local_points, local_paths, local_disallowed_rest = generate_path(
|
||||
user,
|
||||
points,
|
||||
hotel,
|
||||
disallowed_rest,
|
||||
avg_velocity,
|
||||
where_eat=where_eat,
|
||||
what_to_see=what_to_see
|
||||
)
|
||||
points.extend(local_points)
|
||||
paths.append(
|
||||
{
|
||||
|
@ -514,22 +573,56 @@ def nearest_distance_points(point: BasePoint, user: User, velocity: float=3.0):
|
|||
|
||||
|
||||
|
||||
def generate_path(user: User, disallowed_points: Iterable[BasePoint], hotel: Hotel, disallowed_rests: Iterable[Restaurant], avg_velocity: float):
|
||||
# region_events = Event.objects.filter(region=region)
|
||||
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']
|
||||
):
|
||||
allowed_types = [
|
||||
'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
|
||||
else:
|
||||
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))
|
||||
else:
|
||||
start_points_candidate = NearestRestaurantToHotel.objects.filter(hotel=hotel).first().restaurants.filter(~Q(oid__in=disallowed_rests))
|
||||
|
||||
#candidates = NearestHotel.objects.get(hotel=hotel).nearest_events.all()
|
||||
allowed_types = ['museum', 'attraction']
|
||||
if len(start_points_candidate.filter(type__in=where_eat)):
|
||||
start_points_candidate = start_points_candidate.filter(type__in=where_eat)
|
||||
|
||||
start_point = NearestRestaurantToHotel.objects.filter(hotel=hotel).first().restaurants.filter(~Q(oid__in=disallowed_rests)).first()
|
||||
start_point = start_points_candidate[0]
|
||||
disallowed_rests.append(start_point.oid)
|
||||
candidates = list(filter(lambda x: x not in disallowed_points, hotel.nearest_hotel_rel.all().first().nearest_events.filter(type__in=allowed_types)))
|
||||
#candidates = list(filter(lambda x: x.type in allowed_types, map(lambda x: x.event, start_point.nearestrestauranttoevent_set.all()[0:100])))
|
||||
|
||||
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)
|
||||
]
|
||||
else:
|
||||
path = [
|
||||
generate_restaurant(start_point)
|
||||
]
|
||||
|
||||
start_time = datetime.combine(datetime.now(), time(hour=10))
|
||||
|
||||
|
@ -537,32 +630,53 @@ def generate_path(user: User, disallowed_points: Iterable[BasePoint], hotel: Hot
|
|||
|
||||
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):
|
||||
point = NearestRestaurantToEvent.objects.filter(event=points[-1]).first().restaurants.filter(~Q(oid__in=disallowed_rests))[0]
|
||||
print(points, start_time)
|
||||
try:
|
||||
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)
|
||||
if len(candidates) < 10:
|
||||
candidates = NearestEventToRestaurant.objects.get(restaurant=point).events.all()
|
||||
|
||||
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()
|
||||
|
||||
path.append(generate_restaurant(points[-1]))
|
||||
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']
|
||||
allowed_types = [
|
||||
'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)
|
||||
if len(candidates) < 10:
|
||||
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))
|
||||
|
||||
except AttributeError:
|
||||
except:
|
||||
points.append(get_nearest_favorite(candidates, user, points[-1], points))
|
||||
|
||||
transition_route = generate_route(points[-1], points[-2], avg_velocity)
|
||||
|
@ -576,15 +690,6 @@ def generate_path(user: User, disallowed_points: Iterable[BasePoint], hotel: Hot
|
|||
return points, path, disallowed_rests
|
||||
|
||||
|
||||
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 calculate_distance(
|
||||
sample1: Event, samples: Iterable[Event], model: AnnoyIndex, rev_mapping
|
||||
):
|
||||
|
@ -627,11 +732,6 @@ def get_onboarding_hotels(stars=Iterable[int]):
|
|||
|
||||
|
||||
def generate_points_path(user: User, points: Iterable[Event], velocity=3.0):
|
||||
"""
|
||||
Дописать
|
||||
1) генерить маршруты от многих точек (не только по 2) (salesman problem)
|
||||
2) Если в маршруте до 7 точек - добавлять похожие пока не станет 7 точек
|
||||
"""
|
||||
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))))
|
||||
|
@ -663,3 +763,114 @@ def generate_points_path(user: User, points: Iterable[Event], velocity=3.0):
|
|||
visited_points.append(pt)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def flat_list(lst):
|
||||
res = []
|
||||
for i in lst:
|
||||
res.extend(i)
|
||||
return res
|
||||
|
||||
|
||||
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]
|
||||
}
|
||||
|
||||
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]
|
||||
)
|
||||
)
|
||||
return candidates[0:10]
|
||||
return sample(candidates, 10)
|
||||
|
||||
|
||||
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()
|
||||
)
|
||||
),
|
||||
), 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)
|
||||
)
|
||||
res.append(
|
||||
{
|
||||
'category': category_candidate,
|
||||
'events': list(
|
||||
map(
|
||||
lambda x: ObjectRouteSerializer(x).data,
|
||||
ranged
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
return res
|
||||
|
|
Loading…
Reference in New Issue
Block a user