[31b88f42] Finalize staff locations and travel time logic
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import requests
|
||||
import os
|
||||
import io
|
||||
import pandas as pd
|
||||
from fastapi import FastAPI, File, UploadFile, HTTPException
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
import pandas as pd
|
||||
import io
|
||||
from pydantic import BaseModel
|
||||
from typing import Dict, List
|
||||
|
||||
@@ -21,6 +23,12 @@ df_storage = None
|
||||
plz_column_name = None
|
||||
plz_geocoord_df = None
|
||||
|
||||
# OpenRouteService API Key (should be in .env)
|
||||
ORS_API_KEY = os.getenv("ORS_API_KEY")
|
||||
if ORS_API_KEY:
|
||||
# Strip quotes if they were passed literally from .env
|
||||
ORS_API_KEY = ORS_API_KEY.strip("'\"")
|
||||
|
||||
STAFF_DATA = {
|
||||
"sales": [
|
||||
{"name": "Alexander Kiss", "plz": "86911"},
|
||||
@@ -37,6 +45,43 @@ STAFF_DATA = {
|
||||
]
|
||||
}
|
||||
|
||||
# --- Pydantic Models ---
|
||||
class IsochroneRequest(BaseModel):
|
||||
locations: List[Dict[str, float]] # List of {"lat": ..., "lon": ...}
|
||||
range_minutes: int
|
||||
|
||||
@app.get("/api/isochrones")
|
||||
async def get_isochrones(lat: float, lon: float, minutes: int):
|
||||
if not ORS_API_KEY:
|
||||
# Return a warning or a simple "simulated" isochrone if no key is provided
|
||||
return {"error": "ORS_API_KEY missing", "simulated": True}
|
||||
|
||||
url = "https://api.openrouteservice.org/v2/isochrones/driving-car"
|
||||
|
||||
headers = {
|
||||
'Accept': 'application/json, application/geo+json, application/gpx+xml, img/png; charset=utf-8',
|
||||
'Authorization': ORS_API_KEY,
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
}
|
||||
|
||||
# ORS expects [lon, lat]
|
||||
body = {
|
||||
"locations": [[lon, lat]],
|
||||
"range": [minutes * 60], # range is in seconds
|
||||
"range_type": "time"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, json=body, headers=headers)
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
print(f"ORS Error: {response.status_code} - {response.text}")
|
||||
raise HTTPException(status_code=response.status_code, detail=f"ORS API error: {response.text}")
|
||||
except Exception as e:
|
||||
print(f"Request failed: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.on_event("startup")
|
||||
def load_plz_data():
|
||||
global plz_geocoord_df
|
||||
@@ -75,10 +120,14 @@ class PlzColumnRequest(BaseModel):
|
||||
def read_root():
|
||||
return {"message": "Heatmap Tool Backend"}
|
||||
|
||||
@app.get("/health")
|
||||
def health_check():
|
||||
return {"status": "ok", "geocoding_loaded": not plz_geocoord_df.empty if plz_geocoord_df is not None else False}
|
||||
|
||||
@app.get("/api/staff-locations")
|
||||
async def get_staff_locations():
|
||||
global plz_geocoord_df
|
||||
if plz_geocoord_df.empty:
|
||||
if plz_geocoord_df is None or plz_geocoord_df.empty:
|
||||
raise HTTPException(status_code=500, detail="Geocoding data is not available on the server.")
|
||||
|
||||
result = {"sales": [], "technicians": []}
|
||||
@@ -88,6 +137,10 @@ async def get_staff_locations():
|
||||
plz = person["plz"]
|
||||
if plz in plz_geocoord_df.index:
|
||||
coords = plz_geocoord_df.loc[plz]
|
||||
# If there are duplicates, loc returns a DataFrame. Take the first row.
|
||||
if isinstance(coords, pd.DataFrame):
|
||||
coords = coords.iloc[0]
|
||||
|
||||
result[category].append({
|
||||
"name": person["name"],
|
||||
"plz": plz,
|
||||
|
||||
@@ -3,3 +3,4 @@ uvicorn[standard]
|
||||
pandas
|
||||
openpyxl
|
||||
python-multipart
|
||||
requests
|
||||
|
||||
Reference in New Issue
Block a user