anyway/backend/src/main.py
Remy Moll cdc9b0ecd1
Some checks failed
Build and deploy the backend to staging / Build and push image (pull_request) Successful in 2m4s
Build and deploy the backend to staging / Deploy to staging (pull_request) Failing after 18s
ensure attractiveness is always an int
2024-09-27 09:47:10 +02:00

88 lines
3.6 KiB
Python

import logging
from fastapi import FastAPI, Query, Body, HTTPException
from structs.landmark import Landmark
from structs.preferences import Preferences
from structs.linked_landmarks import LinkedLandmarks
from structs.trip import Trip
from utils.landmarks_manager import LandmarkManager
from utils.optimizer import Optimizer
from utils.refiner import Refiner
from persistence import client as cache_client
logger = logging.getLogger(__name__)
app = FastAPI()
manager = LandmarkManager()
optimizer = Optimizer()
refiner = Refiner(optimizer=optimizer)
@app.post("/trip/new")
def new_trip(preferences: Preferences, start: tuple[float, float], end: tuple[float, float] | None = None) -> Trip:
'''
Main function to call the optimizer.
:param preferences: the preferences specified by the user as the post body
:param start: the coordinates of the starting point as a tuple of floats (as url query parameters)
:param end: the coordinates of the finishing point as a tuple of floats (as url query parameters)
:return: the uuid of the first landmark in the optimized route
'''
if preferences is None:
raise HTTPException(status_code=406, detail="Preferences not provided")
if preferences.shopping.score == 0 and preferences.sightseeing.score == 0 and preferences.nature.score == 0:
raise HTTPException(status_code=406, detail="All preferences are 0.")
if start is None:
raise HTTPException(status_code=406, detail="Start coordinates not provided")
if end is None:
end = start
logger.info("No end coordinates provided. Using start=end.")
start_landmark = Landmark(name='start', type='start', location=(start[0], start[1]), osm_type='start', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
end_landmark = Landmark(name='finish', type='finish', location=(end[0], end[1]), osm_type='end', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
# Generate the landmarks from the start location
landmarks, landmarks_short = manager.generate_landmarks_list(
center_coordinates = start,
preferences = preferences
)
# insert start and finish to the landmarks list
landmarks_short.insert(0, start_landmark)
landmarks_short.append(end_landmark)
# First stage optimization
try:
base_tour = optimizer.solve_optimization(preferences.max_time_minute, landmarks_short)
except ArithmeticError:
raise HTTPException(status_code=500, detail="No solution found")
except TimeoutError:
raise HTTPException(status_code=500, detail="Optimzation took too long")
# Second stage optimization
refined_tour = refiner.refine_optimization(landmarks, base_tour, preferences.max_time_minute, preferences.detour_tolerance_minute)
linked_tour = LinkedLandmarks(refined_tour)
# upon creation of the trip, persistence of both the trip and its landmarks is ensured
trip = Trip.from_linked_landmarks(linked_tour, cache_client)
return trip
#### For already existing trips/landmarks
@app.get("/trip/{trip_uuid}")
def get_trip(trip_uuid: str) -> Trip:
try:
trip = cache_client.get(f"trip_{trip_uuid}")
return trip
except KeyError:
raise HTTPException(status_code=404, detail="Trip not found")
@app.get("/landmark/{landmark_uuid}")
def get_landmark(landmark_uuid: str) -> Landmark:
try:
landmark = cache_client.get(f"landmark_{landmark_uuid}")
return landmark
except KeyError:
raise HTTPException(status_code=404, detail="Landmark not found")