first pylint correction
Some checks failed
Build and deploy the backend to staging / Build and push image (pull_request) Successful in 2m26s
Run linting on the backend code / Build (pull_request) Failing after 30s
Run testing on the backend code / Build (pull_request) Successful in 2m12s
Build and deploy the backend to staging / Deploy to staging (pull_request) Successful in 15s
Some checks failed
Build and deploy the backend to staging / Build and push image (pull_request) Successful in 2m26s
Run linting on the backend code / Build (pull_request) Failing after 30s
Run testing on the backend code / Build (pull_request) Successful in 2m12s
Build and deploy the backend to staging / Deploy to staging (pull_request) Successful in 15s
This commit is contained in:
@@ -1,10 +1,41 @@
|
||||
"""Definition of the Landmark class to handle visitable objects across the world."""
|
||||
|
||||
from typing import Optional, Literal
|
||||
from uuid import uuid4
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from uuid import uuid4
|
||||
|
||||
# Output to frontend
|
||||
class Landmark(BaseModel) :
|
||||
"""
|
||||
A class representing a landmark or point of interest (POI) in the context of a trip.
|
||||
|
||||
The Landmark class is used to model visitable locations, such as tourist attractions,
|
||||
natural sites, shopping locations, and start/end points in travel itineraries. It
|
||||
holds information about the landmark's attributes and supports comparisons and
|
||||
calculations, such as distance between landmarks.
|
||||
|
||||
Attributes:
|
||||
name (str): The name of the landmark.
|
||||
type (Literal): The type of the landmark, which can be one of ['sightseeing', 'nature',
|
||||
'shopping', 'start', 'finish'].
|
||||
location (tuple): A tuple representing the (latitude, longitude) of the landmark.
|
||||
osm_type (str): The OpenStreetMap (OSM) type of the landmark.
|
||||
osm_id (int): The OpenStreetMap (OSM) ID of the landmark.
|
||||
attractiveness (int): A score representing the attractiveness of the landmark.
|
||||
n_tags (int): The number of tags associated with the landmark.
|
||||
image_url (Optional[str]): A URL to an image of the landmark.
|
||||
website_url (Optional[str]): A URL to the landmark's official website.
|
||||
description (Optional[str]): A text description of the landmark.
|
||||
duration (Optional[int]): The estimated time to visit the landmark (in minutes).
|
||||
name_en (Optional[str]): The English name of the landmark.
|
||||
uuid (str): A unique identifier for the landmark, generated by default using uuid4.
|
||||
must_do (Optional[bool]): Whether the landmark is a "must-do" attraction.
|
||||
must_avoid (Optional[bool]): Whether the landmark should be avoided.
|
||||
is_secondary (Optional[bool]): Whether the landmark is secondary or less important.
|
||||
time_to_reach_next (Optional[int]): Estimated time (in minutes) to reach the next landmark.
|
||||
next_uuid (Optional[str]): UUID of the next landmark in sequence (if applicable).
|
||||
"""
|
||||
|
||||
# Properties of the landmark
|
||||
name : str
|
||||
@@ -26,12 +57,19 @@ class Landmark(BaseModel) :
|
||||
# Additional properties depending on specific tour
|
||||
must_do : Optional[bool] = False
|
||||
must_avoid : Optional[bool] = False
|
||||
is_secondary : Optional[bool] = False # TODO future
|
||||
is_secondary : Optional[bool] = False
|
||||
|
||||
time_to_reach_next : Optional[int] = 0
|
||||
next_uuid : Optional[str] = None
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""
|
||||
String representation of the Landmark object.
|
||||
|
||||
Returns:
|
||||
str: A formatted string with the landmark's type, name, location, attractiveness score,
|
||||
time to the next landmark (if available), and whether the landmark is secondary.
|
||||
"""
|
||||
time_to_next_str = f", time_to_next={self.time_to_reach_next}" if self.time_to_reach_next else ""
|
||||
is_secondary_str = f", secondary" if self.is_secondary else ""
|
||||
type_str = '(' + self.type + ')'
|
||||
@@ -39,12 +77,36 @@ class Landmark(BaseModel) :
|
||||
return f'Landmark{type_str}: [{self.name} @{self.location}, score={self.attractiveness}{time_to_next_str}{is_secondary_str}]'
|
||||
|
||||
def distance(self, value: 'Landmark') -> float:
|
||||
"""
|
||||
Calculates the squared distance between this landmark and another.
|
||||
|
||||
Args:
|
||||
value (Landmark): Another Landmark object to calculate the distance to.
|
||||
|
||||
Returns:
|
||||
float: The squared Euclidean distance between the two landmarks.
|
||||
"""
|
||||
return (self.location[0] - value.location[0])**2 + (self.location[1] - value.location[1])**2
|
||||
|
||||
def __hash__(self) -> int:
|
||||
"""
|
||||
Generates a hash for the Landmark based on its name.
|
||||
|
||||
Returns:
|
||||
int: The hash of the landmark.
|
||||
"""
|
||||
return hash(self.name)
|
||||
|
||||
def __eq__(self, value: 'Landmark') -> bool:
|
||||
"""
|
||||
Checks equality between two Landmark objects based on UUID, OSM ID, and name.
|
||||
|
||||
Args:
|
||||
value (Landmark): Another Landmark object to compare.
|
||||
|
||||
Returns:
|
||||
bool: True if the landmarks are equal, False otherwise.
|
||||
"""
|
||||
# eq and hash must be consistent
|
||||
# in particular, if two objects are equal, their hash must be equal
|
||||
# uuid and osm_id are just shortcuts to avoid comparing all the properties
|
||||
|
@@ -1,10 +1,15 @@
|
||||
"""Linked and ordered list of Landmarks that represents the visiting order."""
|
||||
|
||||
from .landmark import Landmark
|
||||
from ..utils.get_time_separation import get_time
|
||||
|
||||
class LinkedLandmarks:
|
||||
"""
|
||||
A list of landmarks that are linked together, e.g. in a route.
|
||||
Each landmark serves as a node in the linked list, but since we expect these to be consumed through the rest API, a pythonic reference to the next landmark is not well suited. Instead we use the uuid of the next landmark to reference the next landmark in the list. This is not very efficient, but appropriate for the expected use case ("short" trips with onyl few landmarks).
|
||||
Each landmark serves as a node in the linked list, but since we expect these to be consumed through the rest API,
|
||||
a pythonic reference to the next landmark is not well suited. Instead we use the uuid of the next landmark
|
||||
to reference the next landmark in the list. This is not very efficient, but appropriate for the expected use case
|
||||
("short" trips with onyl few landmarks).
|
||||
"""
|
||||
|
||||
_landmarks = list[Landmark]
|
||||
@@ -12,8 +17,9 @@ class LinkedLandmarks:
|
||||
|
||||
def __init__(self, data: list[Landmark] = None) -> None:
|
||||
"""
|
||||
Initialize a new LinkedLandmarks object. This expects an ORDERED list of landmarks, where the first landmark is the starting point and the last landmark is the end point.
|
||||
|
||||
Initialize a new LinkedLandmarks object. This expects an ORDERED list of landmarks,
|
||||
where the first landmark is the starting point and the last landmark is the end point.
|
||||
|
||||
Args:
|
||||
data (list[Landmark], optional): The list of landmarks that are linked together. Defaults to None.
|
||||
"""
|
||||
@@ -41,16 +47,19 @@ class LinkedLandmarks:
|
||||
self._landmarks[-1].time_to_reach_next = 0
|
||||
|
||||
def update_secondary_landmarks(self) -> None:
|
||||
"""
|
||||
Mark landmarks with lower importance as secondary.
|
||||
"""
|
||||
# Extract the attractiveness scores and sort them in descending order
|
||||
scores = sorted([landmark.attractiveness for landmark in self._landmarks], reverse=True)
|
||||
|
||||
|
||||
# Determine the 10th highest score
|
||||
if len(scores) >= 10:
|
||||
threshold_score = scores[9]
|
||||
else:
|
||||
# If there are fewer than 10 landmarks, use the lowest score in the list as the threshold
|
||||
threshold_score = min(scores) if scores else 0
|
||||
|
||||
|
||||
# Update 'is_secondary' for landmarks with attractiveness below the threshold score
|
||||
for landmark in self._landmarks:
|
||||
if landmark.attractiveness < threshold_score and landmark.type not in ["start", "finish"]:
|
||||
@@ -59,7 +68,7 @@ class LinkedLandmarks:
|
||||
|
||||
def __getitem__(self, index: int) -> Landmark:
|
||||
return self._landmarks[index]
|
||||
|
||||
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"LinkedLandmarks [{' ->'.join([str(landmark) for landmark in self._landmarks])}]"
|
||||
|
@@ -1,12 +1,26 @@
|
||||
from pydantic import BaseModel
|
||||
"""Defines the Preferences used as input for trip generation."""
|
||||
|
||||
from typing import Optional, Literal
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Preference(BaseModel) :
|
||||
"""
|
||||
Type of preference.
|
||||
|
||||
Attributes:
|
||||
type: what kind of landmark type.
|
||||
score: how important that type is.
|
||||
"""
|
||||
type: Literal['sightseeing', 'nature', 'shopping', 'start', 'finish']
|
||||
score: int # score could be from 1 to 5
|
||||
|
||||
|
||||
# Input for optimization
|
||||
class Preferences(BaseModel) :
|
||||
""""
|
||||
Full collection of preferences needed to generate a personalized trip.
|
||||
"""
|
||||
# Sightseeing / History & Culture (Musées, bâtiments historiques, opéras, églises)
|
||||
sightseeing : Preference
|
||||
|
||||
|
@@ -1,10 +1,24 @@
|
||||
"""Definition of the Trip class."""
|
||||
|
||||
import uuid
|
||||
from pydantic import BaseModel, Field
|
||||
from pymemcache.client.base import Client
|
||||
|
||||
from .linked_landmarks import LinkedLandmarks
|
||||
import uuid
|
||||
|
||||
|
||||
class Trip(BaseModel):
|
||||
""""
|
||||
A Trip represents the final guided tour that can be passed to frontend.
|
||||
|
||||
Attributes:
|
||||
uuid: unique identifier for this particular trip.
|
||||
total_time: duration of the trip (in minutes).
|
||||
first_landmark_uuid: unique identifier of the first Landmark to visit.
|
||||
|
||||
Methods:
|
||||
from_linked_landmarks: create a Trip from LinkedLandmarks object.
|
||||
"""
|
||||
uuid: str = Field(default_factory=uuid.uuid4)
|
||||
total_time: int
|
||||
first_landmark_uuid: str
|
||||
|
Reference in New Issue
Block a user