resolve confs

This commit is contained in:
ilia 2023-05-28 17:24:30 +03:00
commit 7a12da6974
9 changed files with 222 additions and 52 deletions

View File

@ -378,4 +378,4 @@
} }
YANDEX_TOKEN = env("YANDEX_TOKEN", default="") YANDEX_TOKEN = env("YANDEX_TOKEN", default="56653e15-3063-43c9-9707-3476dc13ae9d")

View File

@ -10,9 +10,12 @@
from drf_spectacular.utils import extend_schema from drf_spectacular.utils import extend_schema
from django.db.models import Count from django.db.models import Count
from random import choice from random import choice
from passfinder.recomendations.service.service import generate_tour from passfinder.recomendations.service.service import generate_tour, get_events
from datetime import timedelta, datetime from datetime import timedelta, datetime
from .consts import * from .consts import *
from passfinder.recomendations.models import UserPreferences
from rest_framework.decorators import action
from random import sample
from passfinder.events.api.serializers import ( from passfinder.events.api.serializers import (
@ -55,6 +58,7 @@ def get(self, request):
) )
return Response(data=routes) return Response(data=routes)
@extend_schema( @extend_schema(
request=RouteInputSerializer, responses={200: RouteSerializer(many=True)} request=RouteInputSerializer, responses={200: RouteSerializer(many=True)}
) )
@ -111,7 +115,7 @@ def post(self, request):
hotel_stars = [] hotel_stars = []
res = [] res = []
for _ in range(5): for _ in range(2):
if city_id: if city_id:
region = get_object_or_404(City, oid=city_id) region = get_object_or_404(City, oid=city_id)
else: else:
@ -165,7 +169,7 @@ class ListCityApiView(ListAPIView):
queryset = ( queryset = (
City.objects.annotate(points_count=Count("points")) City.objects.annotate(points_count=Count("points"))
.filter(title__in=city_in_hotels) .filter(title__in=city_in_hotels)
.filter(points_count__gt=200) .filter(points_count__gt=400)
.order_by("title") .order_by("title")
) )
@ -178,17 +182,20 @@ def post(self, request, *args, **kwargs):
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
data = serializer.data data = serializer.data
route = UserRoute.objects.create(user=self.request.user) route = UserRoute.objects.create(user=self.request.user)
up, _ = UserPreferences.objects.get_or_create(user=request.user)
for date in data["points"]: for date in data["points"]:
date_obj = UserRouteDate.objects.create( date_obj = UserRouteDate.objects.create(
date=parse_datetime(date["date"]).date(), route=route date=parse_datetime(date["date"]).date(), route=route
) )
for point in date["paths"]: for point in date["paths"]:
if point["type"] == "point": if point["type"] == "point":
model_point = BasePoint.objects.get(oid=point["point"]["oid"])
UserRoutePoint.objects.create( UserRoutePoint.objects.create(
date=date_obj, date=date_obj,
duration=point["time"], duration=point["time"],
point=BasePoint.objects.get(oid=point["point"]["oid"]), point=model_point,
) )
up.add_point(model_point)
else: else:
UserRouteTransaction.objects.create( UserRouteTransaction.objects.create(
date=date_obj, date=date_obj,

View File

@ -13,9 +13,6 @@ def get_position_weather(lat: float, lon: float) -> list[(str, str)]:
if response.status_code == 200: if response.status_code == 200:
data = response.json() data = response.json()
days = [] temp_feels = data["forecasts"][0]["parts"]["day"]["feels_like"]
weather = data["forecasts"][0]["parts"]["day_short"]["condition"]
for d in data["forecasts"]: return temp_feels, weather
days.append((d["date"], d["parts"]["day_short"]["condition"]))
return days
return []

View File

@ -13,6 +13,8 @@
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.db.models import Count from django.db.models import Count
from random import sample from random import sample
from passfinder.events.api.serializers import RouteInputSerializer
from passfinder.events.api.consts import city_in_hotels
class TinderView(viewsets.GenericViewSet): class TinderView(viewsets.GenericViewSet):
@ -93,6 +95,7 @@ def get_daily_selection(self, request, *args, **kwargs):
@action(methods=["POST"], detail=False, serializer_class=DailySelectionSerializer) @action(methods=["POST"], detail=False, serializer_class=DailySelectionSerializer)
def generate_daily_selection(self, request, *args, **kwargs): def generate_daily_selection(self, request, *args, **kwargs):
points = [] points = []
print(request.data['nodes'])
for point in request.data["nodes"]: for point in request.data["nodes"]:
if point["action"] == "right": if point["action"] == "right":
points.append(Event.objects.get(oid=point["oid"])) points.append(Event.objects.get(oid=point["oid"]))
@ -101,6 +104,40 @@ def generate_daily_selection(self, request, *args, **kwargs):
return Response(data={"path": path}) return Response(data={"path": path})
@action(methods=['POST'], detail=False, serializer_class=RouteInputSerializer)
def build_events(self, request, *args, **kwargs):
serializer = RouteInputSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
data =serializer.data
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",
]
city_id = data["city"]
allowed_regions = []
if city_id:
allowed_regions = [City.objects.get(oid=city_id)]
else:
allowed_regions = sample(
list(City.objects.annotate(points_count=Count("points"))
.filter(title__in=city_in_hotels)
.filter(points_count__gt=400)), 5)
return Response(data=get_events(request.user, allowed_regions, what_to_see))
class OnboardingViewset(viewsets.GenericViewSet): class OnboardingViewset(viewsets.GenericViewSet):
serializer_class = EventSerializer serializer_class = EventSerializer

View File

@ -0,0 +1,19 @@
# Generated by Django 4.2.1 on 2023-05-28 07:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("events", "0027_city_temperature_city_weather_condition"),
("recomendations", "0008_userpreferences_preferred_categories_and_more"),
]
operations = [
migrations.AddField(
model_name="userpreferences",
name="prefered_other",
field=models.ManyToManyField(related_name="other_users", to="events.event"),
),
]

View File

@ -0,0 +1,26 @@
# Generated by Django 4.2.1 on 2023-05-28 08:12
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("events", "0027_city_temperature_city_weather_condition"),
("recomendations", "0009_userpreferences_prefered_other"),
]
operations = [
migrations.AddField(
model_name="userpreferences",
name="prefered_hotels",
field=models.ManyToManyField(related_name="hotels_user", to="events.hotel"),
),
migrations.AddField(
model_name="userpreferences",
name="prefered_restaurants",
field=models.ManyToManyField(
related_name="restaurant_user", to="events.restaurant"
),
),
]

View File

@ -1,6 +1,7 @@
from django.db import models from django.db import models
from passfinder.users.models import User from passfinder.users.models import User
from passfinder.events.models import Event, Hotel, Restaurant from passfinder.events.models import Event, Hotel, Restaurant, BasePoint
from passfinder.events.api.serializers import ObjectRouteSerializer
from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.fields import ArrayField
@ -47,6 +48,52 @@ class UserPreferences(models.Model):
base_field=models.IntegerField(), null=True, blank=True base_field=models.IntegerField(), null=True, blank=True
) )
prefered_other = models.ManyToManyField(Event, related_name='other_users')
prefered_hotels = models.ManyToManyField(Hotel, related_name='hotels_user')
prefered_restaurants = models.ManyToManyField(Restaurant, related_name='restaurant_user')
def add_point(self, point: BasePoint):
print(point, type(point))
if isinstance(point, Event):
event = point
if event.type == 'play':
self.preferred_concerts.add(event)
elif event.type == 'movie':
self.preffered_movies.add(event)
elif event.type == 'attraction':
self.prefferred_attractions.add(event)
elif event.type == 'museum':
self.prefferred_museums.add(event)
else:
self.prefered_other.add(event)
self.save()
if isinstance(point, Hotel):
self.prefered_hotels.add(point)
self.save()
if isinstance(point, Restaurant):
self.prefered_restaurants.add(point)
self.save()
def get_points(self):
points = [
*list(self.preffered_plays.all()),
*list(self.prefered_hotels.all()),
*list(self.prefered_restaurants.all()),
*list(self.preferred_concerts.all()),
*list(self.preffered_movies.all()),
*list(self.prefferred_attractions.all()),
*list(self.prefferred_museums.all()),
*list(self.prefered_other.all()),
]
return list(
map(
lambda x: ObjectRouteSerializer(x).data,
points
)
)
class NearestEvent(models.Model): class NearestEvent(models.Model):
event = models.ForeignKey( event = models.ForeignKey(
@ -55,26 +102,6 @@ class NearestEvent(models.Model):
nearest = models.ManyToManyField(Event, related_name="nearest_model_rev_rel") nearest = models.ManyToManyField(Event, related_name="nearest_model_rev_rel")
"""
from passfinder.recomendations.service.service import generate_tour
from passfinder.users.models import User
from passfinder.events.models import City
from datetime import datetime
start_date = datetime(year=2023, month=6, day=10)
end_date = datetime(year=2023, month=6, day=13)
c = City.objects.get(title='Таганрог')
u = User.objects.all()[0]
generate_tour(u, c, start_date, end_date)
"""
class NearestHotel(models.Model): class NearestHotel(models.Model):
hotel = models.ForeignKey( hotel = models.ForeignKey(
Hotel, on_delete=models.CASCADE, related_name="nearest_hotel_rel" Hotel, on_delete=models.CASCADE, related_name="nearest_hotel_rel"

View File

@ -367,8 +367,13 @@ def calculate_mean_metric(
except: except:
return 10 return 10
for fav in favorite_events: for fav in favorite_events:
try:
dists.append(model.get_distance(rev_mapping[fav.oid], target_event_idx)) dists.append(model.get_distance(rev_mapping[fav.oid], target_event_idx))
except: pass
try:
return sum(dists) / len(dists) return sum(dists) / len(dists)
except ZeroDivisionError:
return 10
def calculate_favorite_metric(event: Event, user: User): def calculate_favorite_metric(event: Event, user: User):
@ -720,6 +725,14 @@ def generate_path(
start_time += timedelta(seconds=point_route["time"]) start_time += timedelta(seconds=point_route["time"])
path.extend([transition_route, point_route]) path.extend([transition_route, point_route])
candidates = None candidates = None
# = "Сгенерируй описание туристического маршрута, проходящего через следующие точки:\n"
# prompt += 'Отель: {hotel.name}\n'
# for i in points:
# prompt += f'Название: {i.title}\nОписание: {i.description}\nТип: {i.type}\n\n'
# print(promptprompt)
return points, path, disallowed_rests return points, path, disallowed_rests
@ -814,20 +827,25 @@ def range_candidates(candidates, user, favorite_events):
"concert": [concert_model, rev_concert_mapping], "concert": [concert_model, rev_concert_mapping],
"plays": [plays_model, rev_plays_mapping], "plays": [plays_model, rev_plays_mapping],
} }
try:
if candidates[0].type in ["attraction", "museum", "movie", "concert", "plays"]: if candidates[0].type in ["attraction", "museum", "movie", "concert", "plays"]:
candidates = sorted( candidates = sorted(
candidates, map(
key=lambda cand: calculate_mean_metric( lambda x: [
favorite_events, cand, *model_mappings[cand.type] calculate_mean_metric(
favorite_events, x, *model_mappings[x.type]
), x
],
candidates
), ),
key=lambda x: x[0],
) )
return candidates[0:10] return candidates[0:10]
return sample(candidates, 10) return sample(candidates, 10)
except: return []
def get_personal_recomendations(user):
up, _ = UserPreferences.objects.get_or_create(user=user)
candidates_generate_strategy = { candidates_generate_strategy = {
"plays": [ "plays": [
lambda pref: flat_list( lambda pref: flat_list(
@ -903,8 +921,17 @@ def get_personal_recomendations(user):
lambda pref: sample(list(Event.objects.filter(type="zoo")), 10), lambda pref: sample(list(Event.objects.filter(type="zoo")), 10),
lambda x: [], lambda x: [],
], ],
"artwork": [
lambda pref: sample(list(Event.objects.filter(type="zoo")), 10),
lambda x: [],
],
} }
def get_personal_recomendations(user):
up, _ = UserPreferences.objects.get_or_create(user=user)
res = [] res = []
for category_candidate in up.preferred_categories: for category_candidate in up.preferred_categories:
candidates = candidates_generate_strategy[category_candidate][0](up) candidates = candidates_generate_strategy[category_candidate][0](up)
@ -914,7 +941,36 @@ def get_personal_recomendations(user):
res.append( res.append(
{ {
"category": category_candidate, "category": category_candidate,
"events": list(map(lambda x: ObjectRouteSerializer(x).data, ranged)), "events": list(map(lambda x: ObjectRouteSerializer(x[1]).data, ranged)),
} }
) )
return res return res
def get_events(
user: User,
allowed_regions: Iterable[City],
what_to_see: Iterable[str]
):
up, _ = UserPreferences.objects.get_or_create(user=user)
events = Event.objects.filter(type__in=what_to_see, city__in=allowed_regions)
ranged = []
for category in what_to_see:
candidates = events.filter(type=category)
ranged.extend(
range_candidates(
candidates,
user,
candidates_generate_strategy[category][1](up)
)
)
ranged.sort(key=lambda x: x[0])
return list(
map(
lambda x: ObjectRouteSerializer(x[1]).data,
ranged[0:10]
)
)
def remap_points(date: datetime.date, region: City, )

View File

@ -6,6 +6,8 @@
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet from rest_framework.viewsets import GenericViewSet
from passfinder.recomendations.models import UserPreferences
from .serializers import ( from .serializers import (
UserSerializer, UserSerializer,
UserRegisterSerializer, UserRegisterSerializer,
@ -54,6 +56,5 @@ class ListUserFavoritePointsApiView(generics.ListAPIView):
serializer_class = PointSerializer serializer_class = PointSerializer
def get_queryset(self): def get_queryset(self):
return BasePoint.objects.filter( up, _ = UserPreferences.objects.get_or_create(user=self.request.user)
user_preferences__user=self.request.user, user_preferences__type="favorite" return up.get_points()
)