mirror of
https://github.com/task-17-lct/backend.git
synced 2024-11-27 18:53:48 +03:00
Merge branch 'add-path-generation-logic'
This commit is contained in:
commit
affe5b1e2c
|
@ -291,7 +291,7 @@
|
||||||
CELERY_REDIS_DB = env("CELERY_REDIS_DB", default=0)
|
CELERY_REDIS_DB = env("CELERY_REDIS_DB", default=0)
|
||||||
|
|
||||||
CELERY_REDIS_SSL = env.bool("CELERY_REDIS_SSL", default=False)
|
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_TASK_SERIALIZER = "json"
|
||||||
CELERY_ACCEPT_CONTENT = ["application/json"]
|
CELERY_ACCEPT_CONTENT = ["application/json"]
|
||||||
CELERY_ENABLE_UTC = True
|
CELERY_ENABLE_UTC = True
|
||||||
|
@ -346,7 +346,7 @@
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
CLICKHOUSE_DATABASES = {
|
CLICKHOUSE_DATABASES = {
|
||||||
"default": {
|
"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"),
|
"db_name": env("CLICKHOUSE_DB", default="default"),
|
||||||
"username": env("CLICKHOUSE_USER", default="default"),
|
"username": env("CLICKHOUSE_USER", default="default"),
|
||||||
"password": env("CLICKHOUSE_PASSWORD", 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 django.db import models
|
||||||
from passfinder.users.models import User
|
from passfinder.users.models import User
|
||||||
from passfinder.events.models import Event
|
from passfinder.events.models import Event, Hotel
|
||||||
|
|
||||||
|
|
||||||
class UserPreferences(models.Model):
|
class UserPreferences(models.Model):
|
||||||
|
@ -19,3 +19,8 @@ class UserPreferences(models.Model):
|
||||||
class NearestEvent(models.Model):
|
class NearestEvent(models.Model):
|
||||||
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='nearest_model_rel')
|
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='nearest_model_rel')
|
||||||
nearest = models.ManyToManyField(Event, related_name='nearest_model_rev_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
|
excursion_mapping = None
|
||||||
concert_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):
|
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 = {}
|
mapping = {}
|
||||||
for idx, elem in enumerate(list_mapping):
|
for idx, elem in enumerate(list_mapping):
|
||||||
mapping.update({elem: idx})
|
mapping.update({elem: idx})
|
||||||
|
@ -15,20 +27,30 @@ def build_dict(list_mapping):
|
||||||
|
|
||||||
|
|
||||||
with open('passfinder/recomendations/service/mapping/attractions.pickle', 'rb') as file:
|
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:
|
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:
|
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:
|
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:
|
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 annoy import AnnoyIndex
|
||||||
from .mapping.mapping import *
|
from .mapping.mapping import *
|
||||||
from .models.models import *
|
from .models.models import *
|
||||||
from passfinder.events.models import Event, Region
|
from passfinder.events.models import Event, Region, Hotel, BasePoint, City
|
||||||
from passfinder.recomendations.models import UserPreferences, NearestEvent
|
from passfinder.recomendations.models import UserPreferences, NearestEvent, NearestHotel
|
||||||
from random import choice
|
from random import choice
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from passfinder.users.models import User
|
from passfinder.users.models import User
|
||||||
from collections.abc import Iterable
|
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))
|
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))
|
nearest = ml_model.get_nns_by_item(index, len(mapping))
|
||||||
|
|
||||||
res = []
|
res = []
|
||||||
|
@ -25,23 +28,23 @@ def get_nearest_(instance_model, model_type, mapping, nearest_n, ml_model):
|
||||||
|
|
||||||
|
|
||||||
def nearest_attraction(attraction, nearest_n):
|
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):
|
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):
|
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):
|
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):
|
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):
|
def get_nearest_event(event, nearest_n):
|
||||||
|
@ -188,7 +191,14 @@ def get_personal_movies_recommendation(user):
|
||||||
|
|
||||||
|
|
||||||
def dist_func(event1: Event, event2: Event):
|
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():
|
def generate_nearest():
|
||||||
|
@ -203,14 +213,36 @@ def generate_nearest():
|
||||||
print(i)
|
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):
|
if not len(favorite_events):
|
||||||
return 100000
|
return 100000
|
||||||
|
|
||||||
dists = []
|
dists = []
|
||||||
target_event_idx = rev_list[target_event.oid]
|
target_event_idx = rev_mapping[target_event.oid]
|
||||||
for fav in favorite_events:
|
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)
|
return sum(dists) / len(dists)
|
||||||
|
|
||||||
|
|
||||||
|
@ -222,7 +254,7 @@ def calculate_favorite_metric(event: Event, user: User):
|
||||||
preferred,
|
preferred,
|
||||||
event,
|
event,
|
||||||
plays_model,
|
plays_model,
|
||||||
plays_mapping
|
rev_plays_mapping
|
||||||
)
|
)
|
||||||
if event.type == 'concert':
|
if event.type == 'concert':
|
||||||
preferred = pref.preferred_concerts.all()
|
preferred = pref.preferred_concerts.all()
|
||||||
|
@ -230,7 +262,7 @@ def calculate_favorite_metric(event: Event, user: User):
|
||||||
preferred,
|
preferred,
|
||||||
event,
|
event,
|
||||||
concert_model,
|
concert_model,
|
||||||
concert_mapping
|
rev_concert_mapping
|
||||||
)
|
)
|
||||||
if event.type == 'movie':
|
if event.type == 'movie':
|
||||||
preferred = pref.preffered_movies.all()
|
preferred = pref.preffered_movies.all()
|
||||||
|
@ -238,14 +270,21 @@ def calculate_favorite_metric(event: Event, user: User):
|
||||||
preferred,
|
preferred,
|
||||||
event,
|
event,
|
||||||
cinema_model,
|
cinema_model,
|
||||||
cinema_mapping
|
rev_cinema_mapping
|
||||||
)
|
)
|
||||||
return 1000000
|
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]=[]):
|
||||||
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:
|
for event in events:
|
||||||
if event in exclude_events: continue
|
if event in exclude_events: continue
|
||||||
local_min_metric = calculate_favorite_metric(event, user)
|
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
|
return result
|
||||||
|
|
||||||
|
|
||||||
def generate_path(region: Region, user: User):
|
def filter_hotel(region: Region, user: User, stars: Iterable[int]):
|
||||||
region_events = Event.objects.filter(region=region)
|
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()
|
candidates = NearestEvent.objects.get(event=start_point).nearest.all()
|
||||||
|
|
||||||
points = [start_point]
|
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()
|
candidates = NearestEvent.objects.get(event=points[-1]).nearest.all()
|
||||||
points.append(get_nearest_favorite(candidates, user, points))
|
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