mirror of
https://github.com/task-17-lct/backend.git
synced 2024-11-10 22:46:37 +03:00
add all
This commit is contained in:
commit
08bc90142b
|
@ -1,7 +1,11 @@
|
|||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from passfinder.recomendations.api.views import TinderView, PersonalRecommendation
|
||||
from passfinder.users.api.views import UserViewSet, CreateUserPreferenceApiView
|
||||
from passfinder.users.api.views import (
|
||||
UserViewSet,
|
||||
CreateUserPreferenceApiView,
|
||||
ListUserFavoritePointsApiView,
|
||||
)
|
||||
|
||||
router = DefaultRouter()
|
||||
|
||||
|
@ -14,5 +18,6 @@
|
|||
path("", include("passfinder.events.api.urls")),
|
||||
path("auth/", include("passfinder.users.api.urls")),
|
||||
path("user/preference", CreateUserPreferenceApiView.as_view()),
|
||||
path("user/favorite", ListUserFavoritePointsApiView.as_view()),
|
||||
]
|
||||
urlpatterns += router.urls
|
||||
|
|
|
@ -291,7 +291,7 @@
|
|||
CELERY_REDIS_DB = env("CELERY_REDIS_DB", default=0)
|
||||
|
||||
CELERY_REDIS_SSL = env.bool("CELERY_REDIS_SSL", default=False)
|
||||
CELERY_BROKER_URL = env("CELERY_BROKER_URL", default='')
|
||||
CELERY_BROKER_URL = env("CELERY_BROKER_URL", default="")
|
||||
CELERY_TASK_SERIALIZER = "json"
|
||||
CELERY_ACCEPT_CONTENT = ["application/json"]
|
||||
CELERY_ENABLE_UTC = True
|
||||
|
@ -301,7 +301,6 @@
|
|||
"task": "django_clickhouse.tasks.clickhouse_auto_sync",
|
||||
"schedule": timedelta(seconds=5),
|
||||
"options": {"expires": 1},
|
||||
|
||||
},
|
||||
}
|
||||
# DRF
|
||||
|
@ -346,7 +345,7 @@
|
|||
# ------------------------------------------------------------------------------
|
||||
CLICKHOUSE_DATABASES = {
|
||||
"default": {
|
||||
"db_url": env("CLICKHOUSE_URL", default="http://akarpov.ru:1337"),
|
||||
"db_url": env("CLICKHOUSE_URL", default="http://localhost:8123"),
|
||||
"db_name": env("CLICKHOUSE_DB", default="default"),
|
||||
"username": env("CLICKHOUSE_USER", default="default"),
|
||||
"password": env("CLICKHOUSE_PASSWORD", default="default"),
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import json
|
||||
from pprint import pprint
|
||||
|
||||
from passfinder.events.models import Region
|
||||
from passfinder.events.models import Region, Event
|
||||
|
||||
with open("data/pos-attr.json") as f:
|
||||
data = json.load(f)
|
||||
|
||||
|
||||
reggg = {
|
||||
"г. Санкт-Петербург": "Санкт-Петербург",
|
||||
"г. Москва": "Москва",
|
||||
|
@ -16,7 +17,7 @@
|
|||
"Республика Северная Осетия - Алания": "Республика Северная Осетия – Алания",
|
||||
"Ханты-Мансийский автономный округ - Югра": "Ханты-Мансийский автономный округ — Югра",
|
||||
}
|
||||
|
||||
rett = []
|
||||
ret = []
|
||||
for infff in data:
|
||||
info = infff["general"]
|
||||
|
@ -38,6 +39,21 @@
|
|||
}
|
||||
if "typologies" in info:
|
||||
res["extra_kwargs"]["typologies"] = [x["value"] for x in info["typologies"]]
|
||||
if "securityInfo" in info or "borderInfo" in info:
|
||||
for ev in Event.objects.filter(
|
||||
title=info["name"],
|
||||
address=res["address"],
|
||||
lat=res["lat"],
|
||||
lon=res["lon"],
|
||||
):
|
||||
ddd = [
|
||||
info["securityInfo"] if "securityInfo" in info else "",
|
||||
info["borderInfo"] if "borderInfo" in info else "",
|
||||
]
|
||||
ddd = [x for x in ddd if x]
|
||||
ev.description = " ".join(ddd)
|
||||
ev.save()
|
||||
|
||||
ret.append(res)
|
||||
|
||||
|
||||
|
|
|
@ -10,11 +10,6 @@ class Meta:
|
|||
exclude = "hotel"
|
||||
|
||||
|
||||
class CitySerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = City
|
||||
|
||||
|
||||
class HotelSerializer(serializers.ModelSerializer):
|
||||
phones = HotelPhoneSerializer(many=True)
|
||||
source = serializers.CharField(source="parser_source")
|
||||
|
@ -41,11 +36,12 @@ class Meta:
|
|||
class PointSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = BasePoint
|
||||
fields = ["title", "description", "location", "icon"]
|
||||
fields = ["oid", "title", "description", "location", "icon"]
|
||||
|
||||
|
||||
class RouteSerializer(serializers.Serializer):
|
||||
name = serializers.CharField()
|
||||
date = serializers.DateField(allow_null=True)
|
||||
description = serializers.CharField()
|
||||
points = serializers.ListSerializer(child=PointSerializer())
|
||||
|
||||
|
@ -54,11 +50,59 @@ class RouteInputSerializer(serializers.Serializer):
|
|||
date_from = serializers.DateField(required=False, allow_null=True)
|
||||
date_to = serializers.DateField(required=False, allow_null=True)
|
||||
region = serializers.CharField(
|
||||
min_length=24, max_length=24, required=False, allow_blank=True
|
||||
min_length=24, max_length=24, required=False, allow_blank=True, allow_null=True
|
||||
)
|
||||
|
||||
|
||||
class CitySerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = City
|
||||
fields = ["oid", "title"]
|
||||
|
||||
|
||||
class RegionSerializer(serializers.ModelSerializer):
|
||||
cities = CitySerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = Region
|
||||
fields = ["oid", "title", "description_short"]
|
||||
fields = ["oid", "title", "description_short", "cities"]
|
||||
|
||||
|
||||
class InputRoutePointSerializer(serializers.Serializer):
|
||||
type = serializers.ChoiceField(choices=["point", "transition"])
|
||||
time = serializers.IntegerField(min_value=0, required=True)
|
||||
|
||||
# point
|
||||
point = serializers.CharField(
|
||||
min_length=24, max_length=24, required=False, allow_blank=True, allow_null=True
|
||||
)
|
||||
|
||||
# transition
|
||||
point_from = serializers.CharField(
|
||||
min_length=24, max_length=24, required=False, allow_blank=True, allow_null=True
|
||||
)
|
||||
point_to = serializers.CharField(
|
||||
min_length=24, max_length=24, required=False, allow_blank=True, allow_null=True
|
||||
)
|
||||
distance = serializers.FloatField(min_value=0, required=False, allow_null=True)
|
||||
|
||||
def validate(self, data):
|
||||
if data["type"] == "point":
|
||||
if "point" not in data or not data["point"]:
|
||||
raise serializers.ValidationError("Point id is required")
|
||||
get_object_or_404(BasePoint, oid=data["point"])
|
||||
else:
|
||||
if "point_to" not in data or not data["point_to"]:
|
||||
raise serializers.ValidationError("Point to id is required")
|
||||
get_object_or_404(BasePoint, oid=data["point_to"])
|
||||
if "point_from" not in data or not data["point_from"]:
|
||||
raise serializers.ValidationError("Point from id is required")
|
||||
get_object_or_404(BasePoint, oid=data["point_from"])
|
||||
if "distance" not in data or not data["distance"]:
|
||||
raise serializers.ValidationError("Distance is required")
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class InputRouteSerializer(serializers.Serializer):
|
||||
points = serializers.ListSerializer(child=InputRoutePointSerializer())
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
from django.urls import path
|
||||
|
||||
from passfinder.events.api.views import BuildRouteApiView, ListRegionApiView
|
||||
from passfinder.events.api.views import (
|
||||
BuildRouteApiView,
|
||||
ListRegionApiView,
|
||||
ListCityApiView,
|
||||
SaveRouteSerializer,
|
||||
)
|
||||
|
||||
app_name = "events"
|
||||
|
||||
urlpatterns = [
|
||||
path("route/build", BuildRouteApiView.as_view(), name="build_route"),
|
||||
path("regions", ListRegionApiView.as_view(), name="regions"),
|
||||
path("route/save", SaveRouteSerializer.as_view(), name="save_route"),
|
||||
path("data/regions", ListRegionApiView.as_view(), name="regions"),
|
||||
path("data/cities", ListCityApiView.as_view(), name="cities"),
|
||||
]
|
||||
|
|
|
@ -7,8 +7,17 @@
|
|||
RouteSerializer,
|
||||
RegionSerializer,
|
||||
RouteInputSerializer,
|
||||
CitySerializer,
|
||||
InputRouteSerializer,
|
||||
)
|
||||
from passfinder.events.models import (
|
||||
BasePoint,
|
||||
Region,
|
||||
City,
|
||||
UserRoute,
|
||||
UserRoutePoint,
|
||||
UserRouteTransaction,
|
||||
)
|
||||
from passfinder.events.models import BasePoint, Region
|
||||
|
||||
|
||||
class BuildRouteApiView(GenericAPIView):
|
||||
|
@ -21,6 +30,7 @@ def get(self, request):
|
|||
routes.append(
|
||||
{
|
||||
"name": "bebra",
|
||||
"date": None,
|
||||
"description": "bebra bebra bebra",
|
||||
"points": PointSerializer(many=True).to_representation(
|
||||
BasePoint.objects.order_by("?")[:10]
|
||||
|
@ -35,7 +45,8 @@ def get(self, request):
|
|||
def post(self, request):
|
||||
serializer = RouteInputSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
region = serializer.data["region"]
|
||||
data = serializer.data
|
||||
region = data["region"]
|
||||
routes = []
|
||||
if region:
|
||||
region = get_object_or_404(Region, oid=region)
|
||||
|
@ -43,6 +54,7 @@ def post(self, request):
|
|||
routes.append(
|
||||
{
|
||||
"name": "bebra",
|
||||
"date": data["date_from"],
|
||||
"description": "bebra bebra bebra",
|
||||
"points": PointSerializer(many=True).to_representation(
|
||||
region.points.all().order_by("?")[:10]
|
||||
|
@ -54,6 +66,7 @@ def post(self, request):
|
|||
routes.append(
|
||||
{
|
||||
"name": "bebra",
|
||||
"date": data["date_from"],
|
||||
"description": "bebra bebra bebra",
|
||||
"points": PointSerializer(many=True).to_representation(
|
||||
BasePoint.objects.order_by("?")[:10]
|
||||
|
@ -66,3 +79,31 @@ def post(self, request):
|
|||
class ListRegionApiView(ListAPIView):
|
||||
serializer_class = RegionSerializer
|
||||
queryset = Region.objects.all()
|
||||
|
||||
|
||||
class ListCityApiView(ListAPIView):
|
||||
serializer_class = CitySerializer
|
||||
queryset = City.objects.all().order_by("title")
|
||||
|
||||
|
||||
class SaveRouteSerializer(GenericAPIView):
|
||||
serializer_class = InputRouteSerializer
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
serializer = InputRouteSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
data = serializer.data
|
||||
route = UserRoute.objects.create(user=self.request.user)
|
||||
for point in data["points"]:
|
||||
if point["type"] == "point":
|
||||
UserRoutePoint.objects.create(
|
||||
route=route, point=BasePoint.objects.get(oid=point["point"])
|
||||
)
|
||||
else:
|
||||
UserRouteTransaction.objects.create(
|
||||
route=route,
|
||||
point_from=BasePoint.objects.get(oid=point["point_from"]),
|
||||
point_to=BasePoint.objects.get(oid=point["point_to"]),
|
||||
)
|
||||
|
||||
return Response(data=data)
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
# Generated by Django 4.2.1 on 2023-05-23 20:34
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("contenttypes", "0002_remove_content_type_name"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
("events", "0017_event_address_event_extra_kwargs_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="UserRoute",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("created", models.DateTimeField(auto_now_add=True)),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="routes",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="BaseUserRoutePoint",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"polymorphic_ctype",
|
||||
models.ForeignKey(
|
||||
editable=False,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="polymorphic_%(app_label)s.%(class)s_set+",
|
||||
to="contenttypes.contenttype",
|
||||
),
|
||||
),
|
||||
(
|
||||
"route",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="points",
|
||||
to="events.userroute",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
"base_manager_name": "objects",
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="UserRouteTransaction",
|
||||
fields=[
|
||||
(
|
||||
"baseuserroutepoint_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="events.baseuserroutepoint",
|
||||
),
|
||||
),
|
||||
("distance", models.FloatField()),
|
||||
(
|
||||
"point_from",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="user_route_point_from",
|
||||
to="events.basepoint",
|
||||
),
|
||||
),
|
||||
(
|
||||
"point_to",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="user_route_point_to",
|
||||
to="events.basepoint",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
"base_manager_name": "objects",
|
||||
},
|
||||
bases=("events.baseuserroutepoint",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="UserRoutePoint",
|
||||
fields=[
|
||||
(
|
||||
"baseuserroutepoint_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="events.baseuserroutepoint",
|
||||
),
|
||||
),
|
||||
(
|
||||
"point",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="events.basepoint",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
"base_manager_name": "objects",
|
||||
},
|
||||
bases=("events.baseuserroutepoint",),
|
||||
),
|
||||
]
|
|
@ -175,3 +175,35 @@ class Restaurant(BasePoint):
|
|||
avg_time_visit = models.IntegerField(null=True)
|
||||
working_time = models.JSONField(null=True)
|
||||
phones = ArrayField(models.CharField(max_length=18), null=True)
|
||||
|
||||
|
||||
class UserRoute(models.Model):
|
||||
user = models.ForeignKey(
|
||||
"users.User", related_name="routes", on_delete=models.CASCADE
|
||||
)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.user}'s route"
|
||||
|
||||
|
||||
class BaseUserRoutePoint(PolymorphicModel):
|
||||
route = models.ForeignKey(
|
||||
"UserRoute", related_name="points", on_delete=models.CASCADE
|
||||
)
|
||||
|
||||
|
||||
class UserRoutePoint(BaseUserRoutePoint):
|
||||
type = "point"
|
||||
point = models.ForeignKey("BasePoint", on_delete=models.CASCADE)
|
||||
|
||||
|
||||
class UserRouteTransaction(BaseUserRoutePoint):
|
||||
type = "transition"
|
||||
point_from = models.ForeignKey(
|
||||
"BasePoint", related_name="user_route_point_from", on_delete=models.CASCADE
|
||||
)
|
||||
point_to = models.ForeignKey(
|
||||
"BasePoint", related_name="user_route_point_to", on_delete=models.CASCADE
|
||||
)
|
||||
distance = models.FloatField()
|
||||
|
|
|
@ -22,109 +22,146 @@ def get_nearest_(instance_model, model_type, mapping, rev_mapping, nearest_n, ml
|
|||
for i in range(how_many):
|
||||
try:
|
||||
res.append(Event.objects.get(oid=mapping[nearest[i]]))
|
||||
except Event.DoesNotExist: ...
|
||||
if len(res) == nearest_n: break
|
||||
except Event.DoesNotExist:
|
||||
...
|
||||
if len(res) == nearest_n:
|
||||
break
|
||||
return res
|
||||
|
||||
|
||||
def nearest_attraction(attraction, nearest_n):
|
||||
return get_nearest_(attraction, 'attraction', attraction_mapping, rev_attraction_mapping, nearest_n, attracion_model)
|
||||
return get_nearest_(
|
||||
attraction,
|
||||
"attraction",
|
||||
attraction_mapping,
|
||||
rev_attraction_mapping,
|
||||
nearest_n,
|
||||
attracion_model,
|
||||
)
|
||||
|
||||
|
||||
def nearest_movie(movie, nearest_n):
|
||||
return get_nearest_(movie, 'movie', cinema_mapping, rev_cinema_mapping, nearest_n, cinema_model)
|
||||
return get_nearest_(
|
||||
movie, "movie", cinema_mapping, rev_cinema_mapping, nearest_n, cinema_model
|
||||
)
|
||||
|
||||
|
||||
def nearest_plays(play, nearest_n):
|
||||
return get_nearest_(play, 'plays', plays_mapping, rev_plays_mapping, nearest_n, plays_model)
|
||||
return get_nearest_(
|
||||
play, "plays", plays_mapping, rev_plays_mapping, nearest_n, plays_model
|
||||
)
|
||||
|
||||
|
||||
def nearest_excursion(excursion, nearest_n):
|
||||
return get_nearest_(excursion, 'excursion', excursion_mapping, rev_excursion_mapping, nearest_n, excursion_model)
|
||||
return get_nearest_(
|
||||
excursion,
|
||||
"excursion",
|
||||
excursion_mapping,
|
||||
rev_excursion_mapping,
|
||||
nearest_n,
|
||||
excursion_model,
|
||||
)
|
||||
|
||||
|
||||
def nearest_concert(concert, nearest_n):
|
||||
return get_nearest_(concert, 'concert', concert_mapping, rev_concert_mapping, nearest_n, concert_model)
|
||||
return get_nearest_(
|
||||
concert,
|
||||
"concert",
|
||||
concert_mapping,
|
||||
rev_concert_mapping,
|
||||
nearest_n,
|
||||
concert_model,
|
||||
)
|
||||
|
||||
|
||||
def get_nearest_event(event, nearest_n):
|
||||
if event.type == 'plays':
|
||||
if event.type == "plays":
|
||||
return nearest_plays(event, nearest_n)
|
||||
if event.type == 'concert':
|
||||
if event.type == "concert":
|
||||
return nearest_concert(event, nearest_n)
|
||||
if event.type == 'movie':
|
||||
if event.type == "movie":
|
||||
return nearest_movie(event, nearest_n)
|
||||
|
||||
|
||||
def update_preferences_state(user, event, direction):
|
||||
pref = UserPreferences.objects.get(user=user)
|
||||
|
||||
if direction == 'left':
|
||||
if event.type == 'plays':
|
||||
|
||||
if direction == "left":
|
||||
if event.type == "plays":
|
||||
pref.unpreffered_plays.add(event)
|
||||
if event.type == 'movie':
|
||||
if event.type == "movie":
|
||||
pref.unpreffered_movies.add(event)
|
||||
if event.type == 'concert':
|
||||
if event.type == "concert":
|
||||
pref.unpreferred_concerts.add(event)
|
||||
else:
|
||||
if event.type == 'plays':
|
||||
if event.type == "plays":
|
||||
pref.preffered_plays.add(event)
|
||||
if event.type == 'movie':
|
||||
if event.type == "movie":
|
||||
pref.preffered_movies.add(event)
|
||||
if event.type == 'concert':
|
||||
if event.type == "concert":
|
||||
pref.preferred_concerts.add(event)
|
||||
pref.save()
|
||||
|
||||
|
||||
|
||||
def get_next_tinder(user, prev_event, prev_direction):
|
||||
pref = UserPreferences.objects.get(user=user)
|
||||
print(prev_event.type, len(pref.preferred_concerts.all()))
|
||||
if prev_direction == 'left':
|
||||
if prev_event.type == 'plays' and len(pref.unpreffered_plays.all()) <= 2:
|
||||
if prev_direction == "left":
|
||||
if prev_event.type == "plays" and len(pref.unpreffered_plays.all()) <= 2:
|
||||
candidates = nearest_plays(prev_event, 100)
|
||||
# print(candidates, type(candidates), len(Event.objects.filter(type='plays')))
|
||||
return candidates[-1]
|
||||
if prev_event.type == 'movie' and len(pref.unpreffered_movies.all()) <= 2:
|
||||
if prev_event.type == "movie" and len(pref.unpreffered_movies.all()) <= 2:
|
||||
candidates = nearest_movie(prev_event, 100)
|
||||
return candidates[-1]
|
||||
if prev_event.type == 'concert' and len(pref.unpreferred_concerts.all()) <= 2:
|
||||
if prev_event.type == "concert" and len(pref.unpreferred_concerts.all()) <= 2:
|
||||
candidates = nearest_concert(prev_event, 100)
|
||||
return candidates[-1]
|
||||
|
||||
if prev_direction == 'right':
|
||||
if prev_event.type == 'plays' and len(pref.preffered_plays.all()) < 2:
|
||||
|
||||
if prev_direction == "right":
|
||||
if prev_event.type == "plays" and len(pref.preffered_plays.all()) < 2:
|
||||
candidates = nearest_plays(prev_event, 2)
|
||||
return candidates[1]
|
||||
if prev_event.type == 'movie' and len(pref.preffered_movies.all()) < 2:
|
||||
if prev_event.type == "movie" and len(pref.preffered_movies.all()) < 2:
|
||||
candidates = nearest_movie(prev_event, 2)
|
||||
return candidates[1]
|
||||
if prev_event.type == 'concert' and len(pref.preferred_concerts.all()) < 2:
|
||||
if prev_event.type == "concert" and len(pref.preferred_concerts.all()) < 2:
|
||||
candidates = nearest_concert(prev_event, 2)
|
||||
return candidates[1]
|
||||
|
||||
if prev_event.type == 'plays':
|
||||
if not len(pref.preffered_movies.all()) and not len(pref.unpreffered_movies.all()):
|
||||
return choice(Event.objects.filter(type='movie'))
|
||||
if not len(pref.preferred_concerts.all()) and not len(pref.unpreferred_concerts.all()):
|
||||
return choice(Event.objects.filter(type='concert'))
|
||||
|
||||
if prev_event.type == 'movie':
|
||||
if not len(pref.preffered_plays.all()) and not len(pref.unpreffered_plays.all()):
|
||||
return choice(Event.objects.filter(type='plays'))
|
||||
if not len(pref.preferred_concerts.all()) and not len(pref.unpreferred_concerts.all()):
|
||||
return choice(Event.objects.filter(type='concert'))
|
||||
|
||||
if prev_event.type == 'concert':
|
||||
if not len(pref.preffered_plays.all()) and not len(pref.unpreffered_plays.all()):
|
||||
return choice(Event.objects.filter(type='plays'))
|
||||
if not len(pref.preffered_movies.all()) and not len(pref.unpreffered_movies.all()):
|
||||
return choice(Event.objects.filter(type='movie'))
|
||||
|
||||
if prev_event.type == "plays":
|
||||
if not len(pref.preffered_movies.all()) and not len(
|
||||
pref.unpreffered_movies.all()
|
||||
):
|
||||
return choice(Event.objects.filter(type="movie"))
|
||||
if not len(pref.preferred_concerts.all()) and not len(
|
||||
pref.unpreferred_concerts.all()
|
||||
):
|
||||
return choice(Event.objects.filter(type="concert"))
|
||||
|
||||
if prev_event.type == "movie":
|
||||
if not len(pref.preffered_plays.all()) and not len(
|
||||
pref.unpreffered_plays.all()
|
||||
):
|
||||
return choice(Event.objects.filter(type="plays"))
|
||||
if not len(pref.preferred_concerts.all()) and not len(
|
||||
pref.unpreferred_concerts.all()
|
||||
):
|
||||
return choice(Event.objects.filter(type="concert"))
|
||||
|
||||
if prev_event.type == "concert":
|
||||
if not len(pref.preffered_plays.all()) and not len(
|
||||
pref.unpreffered_plays.all()
|
||||
):
|
||||
return choice(Event.objects.filter(type="plays"))
|
||||
if not len(pref.preffered_movies.all()) and not len(
|
||||
pref.unpreffered_movies.all()
|
||||
):
|
||||
return choice(Event.objects.filter(type="movie"))
|
||||
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def rank_candidates(candidates_list, negative_candidates_list):
|
||||
flatten_c_list = []
|
||||
ranks = {}
|
||||
|
@ -133,21 +170,27 @@ def rank_candidates(candidates_list, negative_candidates_list):
|
|||
|
||||
for negative in negative_candidates_list:
|
||||
flatten_negatives.extend(negative)
|
||||
|
||||
|
||||
for lst in candidates_list:
|
||||
flatten_c_list.extend(lst)
|
||||
for cand in lst:
|
||||
ranks.update({cand: {'rank': 0, 'lst': lst}})
|
||||
|
||||
ranks.update({cand: {"rank": 0, "lst": lst}})
|
||||
|
||||
cnt = Counter(flatten_c_list)
|
||||
|
||||
for candidate, how_many in cnt.most_common(len(flatten_c_list)):
|
||||
ranks[candidate]['rank'] = how_many * (len(ranks[candidate]['lst']) - ranks[candidate]['lst'].index(candidate))
|
||||
|
||||
ranks[candidate]["rank"] = how_many * (
|
||||
len(ranks[candidate]["lst"]) - ranks[candidate]["lst"].index(candidate)
|
||||
)
|
||||
|
||||
res = []
|
||||
for cand in ranks.keys():
|
||||
res.append((ranks[cand]['rank'], cand))
|
||||
return list(filter(lambda x: x[1] not in flatten_negatives, sorted(res, key=lambda x: -x[0])))
|
||||
res.append((ranks[cand]["rank"], cand))
|
||||
return list(
|
||||
filter(
|
||||
lambda x: x[1] not in flatten_negatives, sorted(res, key=lambda x: -x[0])
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def get_personal_recommendation(prefer, unprefer):
|
||||
|
@ -156,10 +199,12 @@ def get_personal_recommendation(prefer, unprefer):
|
|||
|
||||
for rec in prefer:
|
||||
candidates.append(list(map(lambda x: x.oid, get_nearest_event(rec, 10)[1:])))
|
||||
|
||||
|
||||
for neg in unprefer:
|
||||
negative_candidates.append(list(map(lambda x: x.oid, get_nearest_event(neg, 10)[1:])))
|
||||
|
||||
negative_candidates.append(
|
||||
list(map(lambda x: x.oid, get_nearest_event(neg, 10)[1:]))
|
||||
)
|
||||
|
||||
ranked = rank_candidates(candidates, negative_candidates)
|
||||
|
||||
return list(map(lambda x: (x[0], Event.objects.get(oid=x[1])), ranked[0:5]))
|
||||
|
@ -189,7 +234,6 @@ def get_personal_movies_recommendation(user):
|
|||
return get_personal_recommendation(prefer, unprefer)
|
||||
|
||||
|
||||
|
||||
def dist_func(event1: Event, event2: Event):
|
||||
# cords1 = [event1.lat, event1.lon]
|
||||
# cords2 = [event2.lat, event2.lon]
|
||||
|
@ -205,7 +249,9 @@ def generate_nearest():
|
|||
NearestEvent.objects.all().delete()
|
||||
all_events = list(Event.objects.all())
|
||||
for i, event in enumerate(Event.objects.all()):
|
||||
event_all_events = list(sorted(all_events.copy(), key=lambda x: dist_func(event, x)))
|
||||
event_all_events = list(
|
||||
sorted(all_events.copy(), key=lambda x: dist_func(event, x))
|
||||
)
|
||||
nearest = NearestEvent.objects.create(event=event)
|
||||
nearest.nearest.set(event_all_events[0:100])
|
||||
nearest.save()
|
||||
|
@ -218,12 +264,15 @@ def generate_hotel_nearest():
|
|||
all_events = list(Event.objects.all())
|
||||
hotels = list(Hotel.objects.all())
|
||||
for i, hotel in enumerate(hotels):
|
||||
event_all_events = list(sorted(all_events.copy(), key=lambda x: dist_func(hotel, x)))
|
||||
event_all_events = list(
|
||||
sorted(all_events.copy(), key=lambda x: dist_func(hotel, x))
|
||||
)
|
||||
nearest = NearestHotel.objects.create(hotel=hotel)
|
||||
nearest.nearest_events.set(event_all_events[0:100])
|
||||
if i % 100 == 0:
|
||||
print(i)
|
||||
|
||||
|
||||
def match_points():
|
||||
regions = list(City.objects.all())
|
||||
for i, point in enumerate(Event.objects.all()):
|
||||
|
@ -234,11 +283,15 @@ def match_points():
|
|||
print(i)
|
||||
|
||||
|
||||
|
||||
def calculate_mean_metric(favorite_events: Iterable[Event], target_event: Event, model: AnnoyIndex, rev_mapping):
|
||||
def calculate_mean_metric(
|
||||
favorite_events: Iterable[Event],
|
||||
target_event: Event,
|
||||
model: AnnoyIndex,
|
||||
rev_mapping,
|
||||
):
|
||||
if not len(favorite_events):
|
||||
return 100000
|
||||
|
||||
|
||||
dists = []
|
||||
target_event_idx = rev_mapping[target_event.oid]
|
||||
for fav in favorite_events:
|
||||
|
@ -248,45 +301,34 @@ def calculate_mean_metric(favorite_events: Iterable[Event], target_event: Event,
|
|||
|
||||
def calculate_favorite_metric(event: Event, user: User):
|
||||
pref = UserPreferences.objects.get(user=user)
|
||||
if event.type == 'plays':
|
||||
if event.type == "plays":
|
||||
preferred = pref.preffered_plays.all()
|
||||
return calculate_mean_metric(
|
||||
preferred,
|
||||
event,
|
||||
plays_model,
|
||||
rev_plays_mapping
|
||||
)
|
||||
if event.type == 'concert':
|
||||
return calculate_mean_metric(preferred, event, plays_model, rev_plays_mapping)
|
||||
if event.type == "concert":
|
||||
preferred = pref.preferred_concerts.all()
|
||||
return calculate_mean_metric(
|
||||
preferred,
|
||||
event,
|
||||
concert_model,
|
||||
rev_concert_mapping
|
||||
preferred, event, concert_model, rev_concert_mapping
|
||||
)
|
||||
if event.type == 'movie':
|
||||
if event.type == "movie":
|
||||
preferred = pref.preffered_movies.all()
|
||||
return calculate_mean_metric(
|
||||
preferred,
|
||||
event,
|
||||
cinema_model,
|
||||
rev_cinema_mapping
|
||||
)
|
||||
return calculate_mean_metric(preferred, event, cinema_model, rev_cinema_mapping)
|
||||
return 1000000
|
||||
|
||||
|
||||
def get_nearest_favorite(events: Iterable[Event], user: User, exclude_events: Iterable[Event]=[]):
|
||||
|
||||
def get_nearest_favorite(
|
||||
events: Iterable[Event], user: User, exclude_events: Iterable[Event] = []
|
||||
):
|
||||
first_event = None
|
||||
for candidate in events:
|
||||
if candidate not in exclude_events:
|
||||
if candidate not in exclude_events:
|
||||
first_event = candidate
|
||||
break
|
||||
|
||||
result = first_event
|
||||
result_min = calculate_favorite_metric(result, user)
|
||||
for event in events:
|
||||
if event in exclude_events: continue
|
||||
if event in exclude_events:
|
||||
continue
|
||||
local_min_metric = calculate_favorite_metric(event, user)
|
||||
if local_min_metric < result_min:
|
||||
result_min = local_min_metric
|
||||
|
@ -312,7 +354,7 @@ def generate_route(point1: BasePoint, point2: BasePoint):
|
|||
"from": point1,
|
||||
"to": point2,
|
||||
"distance": distance,
|
||||
"time": time
|
||||
"time": time,
|
||||
}
|
||||
|
||||
|
||||
|
@ -324,9 +366,8 @@ def generate_point(point: BasePoint):
|
|||
"time": timedelta(minutes=90+choice(range(-10, 90, 10)))
|
||||
}
|
||||
|
||||
|
||||
def generate_path(region: City, user: User):
|
||||
#region_events = Event.objects.filter(region=region)
|
||||
def generate_path(region: Region, user: User):
|
||||
# region_events = Event.objects.filter(region=region)
|
||||
|
||||
hotel = filter_hotel(region, user, [])
|
||||
|
||||
|
@ -345,12 +386,12 @@ def generate_path(region: City, user: User):
|
|||
while start_time.hour < 22:
|
||||
candidates = NearestEvent.objects.get(event=points[-1]).nearest.all()
|
||||
points.append(get_nearest_favorite(candidates, user, points))
|
||||
|
||||
|
||||
transition_route = generate_route(points[-1], points[-2])
|
||||
start_time += transition_route['time']
|
||||
start_time += transition_route["time"]
|
||||
|
||||
point_route = generate_point(points[-1])
|
||||
start_time += point_route['time']
|
||||
start_time += point_route["time"]
|
||||
path.extend([transition_route, point_route])
|
||||
|
||||
|
||||
return hotel, points, path
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
UserRegisterSerializer,
|
||||
UserPreferenceSerializer,
|
||||
)
|
||||
from ..models import UserPreference
|
||||
from ...events.api.serializers import PointSerializer
|
||||
from ...events.models import BasePoint
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
@ -45,3 +48,12 @@ def post(self, request, *args, **kwargs):
|
|||
|
||||
class CreateUserPreferenceApiView(generics.CreateAPIView):
|
||||
serializer_class = UserPreferenceSerializer
|
||||
|
||||
|
||||
class ListUserFavoritePointsApiView(generics.ListAPIView):
|
||||
serializer_class = PointSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
return BasePoint.objects.filter(
|
||||
user_preferences__user=self.request.user, user_preferences__type="favorite"
|
||||
)
|
||||
|
|
38
poetry.lock
generated
38
poetry.lock
generated
|
@ -1274,6 +1274,42 @@ prometheus-client = ">=0.8.0"
|
|||
pytz = "*"
|
||||
tornado = ">=5.0.0,<7.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "geographiclib"
|
||||
version = "2.0"
|
||||
description = "The geodesic routines from GeographicLib"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "geographiclib-2.0-py3-none-any.whl", hash = "sha256:6b7225248e45ff7edcee32becc4e0a1504c606ac5ee163a5656d482e0cd38734"},
|
||||
{file = "geographiclib-2.0.tar.gz", hash = "sha256:f7f41c85dc3e1c2d3d935ec86660dc3b2c848c83e17f9a9e51ba9d5146a15859"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "geopy"
|
||||
version = "2.3.0"
|
||||
description = "Python Geocoding Toolbox"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "geopy-2.3.0-py3-none-any.whl", hash = "sha256:4a29a16d41d8e56ba8e07310802a1cbdf098eeb6069cc3d6d3068fc770629ffc"},
|
||||
{file = "geopy-2.3.0.tar.gz", hash = "sha256:228cd53b6eef699b2289d1172e462a90d5057779a10388a7366291812601187f"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
geographiclib = ">=1.52,<3"
|
||||
|
||||
[package.extras]
|
||||
aiohttp = ["aiohttp"]
|
||||
dev = ["coverage", "flake8 (>=5.0,<5.1)", "isort (>=5.10.0,<5.11.0)", "pytest (>=3.10)", "pytest-asyncio (>=0.17)", "readme-renderer", "sphinx (<=4.3.2)", "sphinx-issues", "sphinx-rtd-theme (>=0.5.0)"]
|
||||
dev-docs = ["readme-renderer", "sphinx (<=4.3.2)", "sphinx-issues", "sphinx-rtd-theme (>=0.5.0)"]
|
||||
dev-lint = ["flake8 (>=5.0,<5.1)", "isort (>=5.10.0,<5.11.0)"]
|
||||
dev-test = ["coverage", "pytest (>=3.10)", "pytest-asyncio (>=0.17)", "sphinx (<=4.3.2)"]
|
||||
requests = ["requests (>=2.16.2)", "urllib3 (>=1.24.2)"]
|
||||
timezone = ["pytz"]
|
||||
|
||||
[[package]]
|
||||
name = "humanize"
|
||||
version = "4.6.0"
|
||||
|
@ -3079,4 +3115,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.8"
|
||||
content-hash = "c715e551faec63d192743332fc0fd568147d4f164ff58a2ad843a7c10a5f4799"
|
||||
content-hash = "2f8d96eb5b506fcf8f61c7ba8bfd68a0b740e9b06b5f32d9a22afb84fd480f2f"
|
||||
|
|
|
@ -53,6 +53,7 @@ django-filter = "^23.2"
|
|||
djangorestframework-simplejwt = "^5.2.2"
|
||||
beautifulsoup4 = "^4.12.2"
|
||||
django-clickhouse = "^1.2.1"
|
||||
geopy = "^2.3.0"
|
||||
|
||||
|
||||
[build-system]
|
||||
|
|
Loading…
Reference in New Issue
Block a user