Spaces:
Build error
Build error
File size: 5,076 Bytes
b7aeeca 8a8c13b b7aeeca 8a8c13b b7aeeca 8a8c13b b7aeeca 8a8c13b b7aeeca 8a8c13b b7aeeca 8a8c13b b7aeeca 8a8c13b b7aeeca 8a8c13b b7aeeca 8a8c13b b7aeeca | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | 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) |