backend/feature/add-description #63
							
								
								
									
										0
									
								
								backend/src/landmarks/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								backend/src/landmarks/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -113,7 +113,7 @@ class ClusterManager: | ||||
|             points = [] | ||||
|             for elem in result: | ||||
|                 osm_type = elem.get('type') | ||||
|                  | ||||
|  | ||||
|                 # Get coordinates and append them to the points list | ||||
|                 _, coords = get_base_info(elem, osm_type) | ||||
|                 if coords is not None : | ||||
| @@ -217,7 +217,7 @@ class ClusterManager: | ||||
|  | ||||
|         # Define the bounding box for a given radius around the coordinates | ||||
|         bbox = create_bbox(cluster.centroid, 300) | ||||
|          | ||||
|  | ||||
|         # Query neighborhoods and shopping malls | ||||
|         selectors = ['"place"~"^(suburb|neighborhood|neighbourhood|quarter|city_block)$"'] | ||||
|  | ||||
|   | ||||
| @@ -298,6 +298,16 @@ class LandmarkManager: | ||||
|  | ||||
|     def description_and_keywords(self, tags: dict): | ||||
|         """ | ||||
|         Generates a description and a set of keywords for a given landmark based on its tags. | ||||
|  | ||||
|         Params: | ||||
|             tags (dict): A dictionary containing metadata about the landmark, including its name, | ||||
|                     importance, height, date of construction, and visitor information. | ||||
|  | ||||
|         Returns: | ||||
|             description (str): A string description of the landmark. | ||||
|             keywords (dict): A dictionary of keywords with fields such as 'importance', 'height', | ||||
|                         'place_type', and 'date'. | ||||
|         """ | ||||
|         # Extract relevant fields | ||||
|         name = tags.get('name') | ||||
| @@ -314,7 +324,7 @@ class LandmarkManager: | ||||
|         if importance is None : | ||||
|             if len(tags.keys()) < 5 : | ||||
|                 return None, None | ||||
|             elif len(tags.keys()) < 10 : | ||||
|             if len(tags.keys()) < 10 : | ||||
|                 description = f"{name} is a well known {place_type}." | ||||
|             elif len(tags.keys()) < 17 : | ||||
|                 importance = 'national' | ||||
| @@ -350,6 +360,17 @@ class LandmarkManager: | ||||
|  | ||||
|  | ||||
|     def get_place_type(self, data): | ||||
|         """ | ||||
|         Determines the type of the place based on available tags such as 'amenity', 'building', | ||||
|         'historic', and 'leisure'. The priority order is: 'historic' > 'building' (if not generic) >  | ||||
|         'amenity' > 'leisure'. | ||||
|  | ||||
|         Params: | ||||
|             data (dict): A dictionary containing metadata about the place. | ||||
|  | ||||
|         Returns: | ||||
|             place_type (str): The determined type of the place, or None if no relevant type is found. | ||||
|         """ | ||||
|         amenity = data.get('amenity', None) | ||||
|         building = data.get('building', None) | ||||
|         historic = data.get('historic', None) | ||||
| @@ -369,6 +390,16 @@ class LandmarkManager: | ||||
|  | ||||
|  | ||||
|     def get_date(self, data): | ||||
|         """ | ||||
|         Extracts the most relevant date from the available tags, prioritizing 'construction_date', | ||||
|         'start_date', 'year_of_construction', and 'opening_date' in that order. | ||||
|  | ||||
|         Params: | ||||
|             data (dict): A dictionary containing metadata about the place. | ||||
|  | ||||
|         Returns: | ||||
|             date (str): The most relevant date found, or None if no date is available. | ||||
|         """ | ||||
|         construction_date = data.get('construction_date', None) | ||||
|         opening_date = data.get('opening_date', None) | ||||
|         start_date = data.get('start_date', None) | ||||
|   | ||||
| @@ -94,6 +94,7 @@ def new_trip(preferences: Preferences, | ||||
|                             n_tags=0) | ||||
|  | ||||
|     start_time = time.time() | ||||
|  | ||||
|     # Generate the landmarks from the start location | ||||
|     landmarks, landmarks_short = manager.generate_landmarks_list( | ||||
|         center_coordinates = start, | ||||
| @@ -103,15 +104,6 @@ def new_trip(preferences: Preferences, | ||||
|     if len(landmarks) == 0 : | ||||
|         raise HTTPException(status_code=500, detail="No landmarks were found.") | ||||
|  | ||||
|  | ||||
|  | ||||
|     ###################### store landmarks in json file for debug ###################### | ||||
|     landmarks_list = [jsonable_encoder(item) for item in landmarks] | ||||
|     with open('landmarks.json', 'w+') as file: | ||||
|         json.dump(landmarks_list, file, indent=4) | ||||
|     #################################################################################### | ||||
|  | ||||
|  | ||||
|     # insert start and finish to the landmarks list | ||||
|     landmarks_short.insert(0, start_landmark) | ||||
|     landmarks_short.append(end_landmark) | ||||
|   | ||||
| @@ -278,7 +278,7 @@ class Refiner : | ||||
|             better_tour_poly = concave_hull(MultiPoint(coords))  # Create concave hull with "core" of tour leaving out start and finish | ||||
|             xs, ys = better_tour_poly.exterior.xy | ||||
|             """  | ||||
|             ERROR HERE :  | ||||
|             FIXED : ERROR HERE :  | ||||
|                 Exception has occurred: AttributeError | ||||
|                 'LineString' object has no attribute 'exterior' | ||||
|             """ | ||||
|   | ||||
| @@ -65,14 +65,12 @@ class Overpass : | ||||
|             self.logger.debug(f'Query string: {query_str}') | ||||
|             return self.fetch_data_from_api(query_str) | ||||
|  | ||||
|         # Hybrid cache: some data from Overpass, some data from cache. | ||||
|         else : | ||||
|             # Resize the bbox for smaller search area and build new query string. | ||||
|             non_cached_bbox = Overpass._get_non_cached_bbox(non_cached_cells, bbox) | ||||
|             query_str = Overpass.build_query(non_cached_bbox, osm_types, selector, conditions, out) | ||||
|             self.logger.debug(f'Query string: {query_str}') | ||||
|             non_cached_responses = self.fetch_data_from_api(query_str) | ||||
|             return Overpass._filter_landmarks(cached_responses, bbox) + non_cached_responses | ||||
|         # Resize the bbox for smaller search area and build new query string. | ||||
|         non_cached_bbox = Overpass._get_non_cached_bbox(non_cached_cells, bbox) | ||||
|         query_str = Overpass.build_query(non_cached_bbox, osm_types, selector, conditions, out) | ||||
|         self.logger.debug(f'Query string: {query_str}') | ||||
|         non_cached_responses = self.fetch_data_from_api(query_str) | ||||
|         return Overpass._filter_landmarks(cached_responses, bbox) + non_cached_responses | ||||
|  | ||||
|  | ||||
|     def fetch_data_from_api(self, query_str: str) -> List[dict]: | ||||
| @@ -97,8 +95,8 @@ class Overpass : | ||||
|                 return elements | ||||
|  | ||||
|         except urllib.error.URLError as e: | ||||
|             self.logger.error(f"Error connecting to Overpass API: {e}") | ||||
|             raise ConnectionError(f"Error connecting to Overpass API: {e}") from e | ||||
|             self.logger.error(f"Error connecting to Overpass API: {str(exc)}") | ||||
|             raise ConnectionError(f"Error connecting to Overpass API: {str(exc)}") from e | ||||
|         except Exception as exc : | ||||
|             raise Exception(f'An unexpected error occured: {str(exc)}') from exc | ||||
|  | ||||
| @@ -389,8 +387,8 @@ def get_base_info(elem: dict, osm_type: OSM_TYPES, with_name=False) : | ||||
|     if with_name : | ||||
|         name = elem.get('tags', {}).get('name') | ||||
|         return osm_id, coords, name | ||||
|     else : | ||||
|         return osm_id, coords | ||||
|  | ||||
|     return osm_id, coords | ||||
|  | ||||
|  | ||||
| def fill_cache(): | ||||
| @@ -421,4 +419,4 @@ def fill_cache(): | ||||
|                 except Exception as exc : | ||||
|                     overpass.logger.error(f'An error occured while parsing file {entry.path} as .json file: {str(exc)}') | ||||
|  | ||||
|     overpass.logger.info(f"Successfully filled {n_files}/{total} cache files.") | ||||
|     overpass.logger.info(f"Successfully filled {n_files}/{total} cache files.") | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| """Definition of the Landmark class to handle visitable objects across the world.""" | ||||
| from typing import Optional, Literal, List | ||||
| from typing import Optional, Literal | ||||
| from uuid import uuid4, UUID | ||||
| from pydantic import BaseModel, ConfigDict, Field | ||||
| from pydantic import BaseModel, Field | ||||
|  | ||||
|  | ||||
| # Output to frontend | ||||
| @@ -70,11 +70,6 @@ class Landmark(BaseModel) : | ||||
|     is_place_of_worship : Optional[bool] = False | ||||
|  | ||||
|  | ||||
|     class Config: | ||||
|         json_encoders = { | ||||
|             UUID: lambda v: str(v)  # Ensure UUID is serialized as a string | ||||
|         } | ||||
|  | ||||
|     def __str__(self) -> str: | ||||
|         """ | ||||
|         String representation of the Landmark object. | ||||
|   | ||||
| @@ -341,5 +341,3 @@ def test_shopping(client, request) :   # pylint: disable=redefined-outer-name | ||||
|     assert comp_time < 30, f"Computation time exceeded 30 seconds: {comp_time:.2f} seconds" | ||||
|     assert duration_minutes*0.8 < result['total_time'], f"Trip too short: {result['total_time']} instead of {duration_minutes}" | ||||
|     assert duration_minutes*1.2 > result['total_time'], f"Trip too long: {result['total_time']} instead of {duration_minutes}" | ||||
|      | ||||
|      | ||||
| @@ -1,7 +1,6 @@ | ||||
| """Helper methods for testing.""" | ||||
| import logging | ||||
| from fastapi import HTTPException | ||||
| from pydantic import ValidationError | ||||
|  | ||||
| from ..structs.landmark import Landmark | ||||
| from ..cache import client as cache_client | ||||
|   | ||||
							
								
								
									
										0
									
								
								backend/src/toilets/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								backend/src/toilets/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -1,3 +1,4 @@ | ||||
| """Defines the endpoint for fetching toilet locations.""" | ||||
| from fastapi import HTTPException, APIRouter, Query | ||||
|  | ||||
| from ..structs.toilets import Toilets | ||||
| @@ -33,5 +34,5 @@ def get_toilets(location: tuple[float, float] = Query(...), radius: int = 500) - | ||||
|         toilets_list = toilets_manager.generate_toilet_list() | ||||
|     except KeyError as exc: | ||||
|         raise HTTPException(status_code=404, detail="No toilets found") from exc | ||||
|      | ||||
|  | ||||
|     return toilets_list | ||||
|   | ||||
| @@ -24,4 +24,4 @@ def create_bbox(coords: tuple[float, float], radius: int): | ||||
|     lon_min = lon - d_lon * 180 / m.pi | ||||
|     lon_max = lon + d_lon * 180 / m.pi | ||||
|  | ||||
|     return (lat_min, lon_min, lat_max, lon_max) | ||||
|     return (lat_min, lon_min, lat_max, lon_max) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user