gauthamnairy's picture
Update backend/main.py
8a8c13b verified
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
import httpx
import pyproj
from typing import List, Dict, Optional, Any
from distance import calculate_distance
from area import calculate_area
from coordinate_converter import convert_coordinates
from terrain import extract_terrain_data
app = FastAPI(title="GIS Tools API")
# Configure CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Define request and response models
class CoordinateRequest(BaseModel):
latitude: float
longitude: float
crs: str = "EPSG:4326"
class ElevationResponse(BaseModel):
latitude: float
longitude: float
elevation: float
wgs84_latitude: float
wgs84_longitude: float
original_crs: str
class CRSInfo(BaseModel):
code: str
name: str
class DistanceRequest(BaseModel):
point1: CoordinateRequest
point2: CoordinateRequest
class AreaRequest(BaseModel):
coordinates: List[CoordinateRequest]
class TerrainRequest(BaseModel):
latitude: float
longitude: float
crs: str = "EPSG:4326"
# Helper: Convert to WGS84
def convert_to_wgs84(lon, lat, source_crs):
if source_crs == "EPSG:4326":
return (lon, lat)
try:
transformer = pyproj.Transformer.from_crs(source_crs, "EPSG:4326", always_xy=True)
lon, lat = transformer.transform(lon, lat)
return (lon, lat)
except Exception as e:
raise Exception(f"Coordinate transformation error: {str(e)}")
# Helper: Query Open-Meteo
async def query_open_meteo(lat, lon):
url = f"https://api.open-meteo.com/v1/elevation?latitude={lat}&longitude={lon}"
async with httpx.AsyncClient() as client:
try:
response = await client.get(url)
response.raise_for_status()
data = response.json()
if "elevation" in data and isinstance(data["elevation"], list) and len(data["elevation"]) > 0:
return float(data["elevation"][0])
else:
raise Exception("No elevation data found in API response")
except httpx.HTTPStatusError as e:
raise Exception(f"Elevation API error: {str(e)}")
except Exception as e:
raise Exception(f"Error querying elevation: {str(e)}")
# Route for fetching elevation data
@app.post("/api/elevation", response_model=ElevationResponse)
async def get_elevation(request: CoordinateRequest):
try:
wgs84_coords = convert_to_wgs84(request.longitude, request.latitude, request.crs)
elevation = await query_open_meteo(wgs84_coords[1], wgs84_coords[0])
return ElevationResponse(
latitude=request.latitude,
longitude=request.longitude,
elevation=elevation,
wgs84_latitude=wgs84_coords[1],
wgs84_longitude=wgs84_coords[0],
original_crs=request.crs
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# Route for calculating distance
@app.post("/api/distance")
async def calculate_distance_route(request: DistanceRequest):
# Extract coordinates and CRS
p1 = (request.point1.longitude, request.point1.latitude, request.point1.crs)
p2 = (request.point2.longitude, request.point2.latitude, request.point2.crs)
return {"distance": calculate_distance(p1, p2)}
# Route for calculating area
@app.post("/api/area")
async def calculate_area_route(request: AreaRequest):
# Convert CoordinateRequest list to list of (lon, lat, crs)
coords = [(c.longitude, c.latitude, c.crs) for c in request.coordinates]
return {"area": calculate_area(coords)}
# Route for converting coordinates
@app.post("/api/coordinate-converter")
async def coordinate_converter_route(request: CoordinateRequest):
return convert_coordinates(request.longitude, request.latitude, request.crs)
# Route for extracting terrain data
@app.post("/api/terrain")
async def terrain_data_route(request: TerrainRequest):
return await extract_terrain_data(request.latitude, request.longitude, request.crs)
# Route for fetching CRS list
@app.get("/api/crs-list", response_model=List[CRSInfo])
async def get_crs_list():
crs_list = [
{"code": "EPSG:4326", "name": "WGS 84"},
{"code": "EPSG:3857", "name": "Web Mercator"},
{"code": "EPSG:2154", "name": "RGF93 / Lambert-93"},
{"code": "EPSG:27700", "name": "OSGB 1936 / British National Grid"},
{"code": "EPSG:3785", "name": "Popular Visualisation CRS / Mercator"},
{"code": "EPSG:4269", "name": "NAD83"},
{"code": "EPSG:4267", "name": "NAD27"},
{"code": "EPSG:32633", "name": "WGS 84 / UTM zone 33N"},
]
return crs_list
# Health check endpoint
@app.get("/api/health")
async def health_check():
return {"status": "ok"}
if __name__ == "__main__":
import uvicorn
import os
port = int(os.environ.get("PORT", 7860))
uvicorn.run(app, host="0.0.0.0", port=port)