mirror of
https://github.com/task-17-lct/backend.git
synced 2024-11-27 15:03:44 +03:00
Merge branch 'add-path-generation-logic'
This commit is contained in:
commit
4f7185fd6b
|
@ -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")
|
||||
CELERY_BROKER_URL = env("CELERY_BROKER_URL", default='')
|
||||
CELERY_TASK_SERIALIZER = "json"
|
||||
CELERY_ACCEPT_CONTENT = ["application/json"]
|
||||
CELERY_ENABLE_UTC = True
|
||||
|
@ -346,7 +346,7 @@
|
|||
# ------------------------------------------------------------------------------
|
||||
CLICKHOUSE_DATABASES = {
|
||||
"default": {
|
||||
"db_url": env("CLICKHOUSE_URL", default="http://localhost:8123"),
|
||||
"db_url": env("CLICKHOUSE_URL", default="http://akarpov.ru:1337"),
|
||||
"db_name": env("CLICKHOUSE_DB", default="default"),
|
||||
"username": env("CLICKHOUSE_USER", default="default"),
|
||||
"password": env("CLICKHOUSE_PASSWORD", default="default"),
|
||||
|
|
43
passfinder/recomendations/migrations/0004_nearesthotel.py
Normal file
43
passfinder/recomendations/migrations/0004_nearesthotel.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
# Generated by Django 4.2.1 on 2023-05-23 09:32
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("events", "0016_remove_basepoint_location_remove_city_location_and_more"),
|
||||
("recomendations", "0003_nearestevent"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="NearestHotel",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"hotel",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="nearest_hotel_rel",
|
||||
to="events.hotel",
|
||||
),
|
||||
),
|
||||
(
|
||||
"nearest_events",
|
||||
models.ManyToManyField(
|
||||
related_name="nearest_hotel_rev_rel", to="events.event"
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -1,6 +1,6 @@
|
|||
from django.db import models
|
||||
from passfinder.users.models import User
|
||||
from passfinder.events.models import Event
|
||||
from passfinder.events.models import Event, Hotel
|
||||
|
||||
|
||||
class UserPreferences(models.Model):
|
||||
|
@ -19,3 +19,8 @@ class UserPreferences(models.Model):
|
|||
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')
|
||||
|
||||
|
||||
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')
|
||||
|
|
|
@ -6,8 +6,20 @@
|
|||
excursion_mapping = None
|
||||
concert_mapping = None
|
||||
|
||||
rev_attraction_mapping = None
|
||||
rev_cinema_mapping = None
|
||||
rev_plays_mapping = None
|
||||
rev_excursion_mapping = None
|
||||
rev_concert_mapping = None
|
||||
|
||||
|
||||
def build_dict(list_mapping):
|
||||
mapping = {}
|
||||
for idx, elem in enumerate(list_mapping):
|
||||
mapping.update({idx: elem})
|
||||
return mapping
|
||||
|
||||
def build_rev_dict(list_mapping):
|
||||
mapping = {}
|
||||
for idx, elem in enumerate(list_mapping):
|
||||
mapping.update({elem: idx})
|
||||
|
@ -15,20 +27,30 @@ def build_dict(list_mapping):
|
|||
|
||||
|
||||
with open('passfinder/recomendations/service/mapping/attractions.pickle', 'rb') as file:
|
||||
attraction_mapping = build_dict(pickle.load(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:
|
||||
cinema_mapping = build_dict(pickle.load(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:
|
||||
plays_mapping = build_dict(pickle.load(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:
|
||||
excursion_mapping = build_dict(pickle.load(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:
|
||||
concert_mapping = build_dict(pickle.load(file))
|
||||
lst = pickle.load(file)
|
||||
concert_mapping = build_dict(lst)
|
||||
rev_concert_mapping = build_rev_dict(lst)
|
|
@ -1,18 +1,21 @@
|
|||
from annoy import AnnoyIndex
|
||||
from .mapping.mapping import *
|
||||
from .models.models import *
|
||||
from passfinder.events.models import Event, Region
|
||||
from passfinder.recomendations.models import UserPreferences, NearestEvent
|
||||
from passfinder.events.models import Event, Region, Hotel, BasePoint, City
|
||||
from passfinder.recomendations.models import UserPreferences, NearestEvent, NearestHotel
|
||||
from random import choice
|
||||
from collections import Counter
|
||||
from passfinder.users.models import User
|
||||
from collections.abc import Iterable
|
||||
from django.db.models import Q
|
||||
from geopy.distance import geodesic as GD
|
||||
from datetime import timedelta, time, datetime
|
||||
|
||||
|
||||
def get_nearest_(instance_model, model_type, mapping, nearest_n, ml_model):
|
||||
def get_nearest_(instance_model, model_type, mapping, rev_mapping, nearest_n, ml_model):
|
||||
how_many = len(Event.objects.filter(type=model_type))
|
||||
|
||||
index = mapping[instance_model.oid]
|
||||
index = rev_mapping[instance_model.oid]
|
||||
nearest = ml_model.get_nns_by_item(index, len(mapping))
|
||||
|
||||
res = []
|
||||
|
@ -25,23 +28,23 @@ def get_nearest_(instance_model, model_type, mapping, nearest_n, ml_model):
|
|||
|
||||
|
||||
def nearest_attraction(attraction, nearest_n):
|
||||
return get_nearest_(attraction, 'attraction', 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, 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, 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, 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, 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):
|
||||
|
@ -188,7 +191,14 @@ def get_personal_movies_recommendation(user):
|
|||
|
||||
|
||||
def dist_func(event1: Event, event2: Event):
|
||||
return (event1.lat - event2.lat) ** 2 + (event2.lon - event2.lon) ** 2
|
||||
# cords1 = [event1.lat, event1.lon]
|
||||
# cords2 = [event2.lat, event2.lon]
|
||||
# try:
|
||||
# dist = GD(cords1, cords2).km
|
||||
# return dist
|
||||
# except:
|
||||
# return 1000000
|
||||
return (event1.lon - event2.lon) ** 2 + (event1.lat - event2.lat) ** 2
|
||||
|
||||
|
||||
def generate_nearest():
|
||||
|
@ -203,14 +213,36 @@ def generate_nearest():
|
|||
print(i)
|
||||
|
||||
|
||||
def calculate_mean_metric(favorite_events: Iterable[Event], target_event: Event, model: AnnoyIndex, rev_list: Iterable[str]):
|
||||
def generate_hotel_nearest():
|
||||
NearestHotel.objects.all().delete()
|
||||
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)))
|
||||
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()):
|
||||
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, model: AnnoyIndex, rev_mapping):
|
||||
if not len(favorite_events):
|
||||
return 100000
|
||||
|
||||
dists = []
|
||||
target_event_idx = rev_list[target_event.oid]
|
||||
target_event_idx = rev_mapping[target_event.oid]
|
||||
for fav in favorite_events:
|
||||
dists.append(model.get_distance(rev_list[fav.oid], target_event_idx))
|
||||
dists.append(model.get_distance(rev_mapping[fav.oid], target_event_idx))
|
||||
return sum(dists) / len(dists)
|
||||
|
||||
|
||||
|
@ -222,7 +254,7 @@ def calculate_favorite_metric(event: Event, user: User):
|
|||
preferred,
|
||||
event,
|
||||
plays_model,
|
||||
plays_mapping
|
||||
rev_plays_mapping
|
||||
)
|
||||
if event.type == 'concert':
|
||||
preferred = pref.preferred_concerts.all()
|
||||
|
@ -230,7 +262,7 @@ def calculate_favorite_metric(event: Event, user: User):
|
|||
preferred,
|
||||
event,
|
||||
concert_model,
|
||||
concert_mapping
|
||||
rev_concert_mapping
|
||||
)
|
||||
if event.type == 'movie':
|
||||
preferred = pref.preffered_movies.all()
|
||||
|
@ -238,14 +270,21 @@ def calculate_favorite_metric(event: Event, user: User):
|
|||
preferred,
|
||||
event,
|
||||
cinema_model,
|
||||
cinema_mapping
|
||||
rev_cinema_mapping
|
||||
)
|
||||
return 1000000
|
||||
|
||||
|
||||
def get_nearest_favorite(events: Iterable[Event], user: User, exclude_events: Iterable[Event]=[]):
|
||||
result = events[0]
|
||||
result_min = calculate_favorite_metric(events[0], user)
|
||||
|
||||
first_event = None
|
||||
for candidate in 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
|
||||
local_min_metric = calculate_favorite_metric(event, user)
|
||||
|
@ -256,17 +295,62 @@ def get_nearest_favorite(events: Iterable[Event], user: User, exclude_events: It
|
|||
return result
|
||||
|
||||
|
||||
def generate_path(region: Region, user: User):
|
||||
region_events = Event.objects.filter(region=region)
|
||||
def filter_hotel(region: Region, user: User, stars: Iterable[int]):
|
||||
hotels = Hotel.objects.filter(region=region)
|
||||
return choice(hotels)
|
||||
|
||||
start_point = get_nearest_favorite(region_events, user, [])
|
||||
|
||||
def time_func(km_distance: float):
|
||||
return timedelta(minutes=(km_distance) / (4.0 / 60))
|
||||
|
||||
|
||||
def generate_route(point1: BasePoint, point2: BasePoint):
|
||||
distance = dist_func(point1, point2)
|
||||
time = time_func(distance)
|
||||
return {
|
||||
"type": "transition",
|
||||
"from": point1,
|
||||
"to": point2,
|
||||
"distance": distance,
|
||||
"time": time
|
||||
}
|
||||
|
||||
|
||||
def generate_point(point: BasePoint):
|
||||
return {
|
||||
"type": "point",
|
||||
"point": point,
|
||||
"point_type": "",
|
||||
"time": timedelta(minutes=90+choice(range(-80, 90, 10)))
|
||||
}
|
||||
|
||||
|
||||
def generate_path(region: Region, user: User):
|
||||
#region_events = Event.objects.filter(region=region)
|
||||
|
||||
hotel = filter_hotel(region, user, [])
|
||||
|
||||
candidates = NearestHotel.objects.get(hotel=hotel).nearest_events.all()
|
||||
|
||||
start_point = get_nearest_favorite(candidates, user, [])
|
||||
|
||||
candidates = NearestEvent.objects.get(event=start_point).nearest.all()
|
||||
|
||||
points = [start_point]
|
||||
|
||||
while len(points) < 5:
|
||||
path = [generate_point(points[-1])]
|
||||
|
||||
start_time = datetime.combine(datetime.now(), time(hour=10))
|
||||
|
||||
while start_time.hour < 22:
|
||||
candidates = NearestEvent.objects.get(event=points[-1]).nearest.all()
|
||||
points.append(get_nearest_favorite(candidates, user, points))
|
||||
|
||||
return points
|
||||
transition_route = generate_route(points[-1], points[-2])
|
||||
start_time += transition_route['time']
|
||||
|
||||
point_route = generate_point(points[-1])
|
||||
start_time += point_route['time']
|
||||
path.extend([transition_route, point_route])
|
||||
|
||||
return hotel, points, path
|
||||
|
|
Loading…
Reference in New Issue
Block a user