|
14 | 14 | from fastapi import FastAPI, Query |
15 | 15 | from fastapi.responses import JSONResponse |
16 | 16 | from osgeo import gdal |
| 17 | +from pyproj import Transformer |
| 18 | +from shapely.geometry import box |
| 19 | +from shapely.geometry import Point |
| 20 | +import requests |
17 | 21 |
|
18 | 22 | from app.logger_config import configure_logger |
19 | 23 | from app.utils import ( |
@@ -88,6 +92,57 @@ def show_welcome_page(): |
88 | 92 | } |
89 | 93 |
|
90 | 94 |
|
| 95 | +@app.get("/find_image", tags=["Find Image"]) |
| 96 | +async def find_image( |
| 97 | + gps_point: tuple[str, str], |
| 98 | + nuts_id: str, |
| 99 | + year: int = Query(2021, ge=2018, le=2024) |
| 100 | +) -> str: |
| 101 | + """ |
| 102 | + Find image path for a given NUTS3 and year. |
| 103 | +
|
| 104 | + Args: |
| 105 | + gps_point (tuple[str, str]): the gps point. |
| 106 | + nuts_id (str): The ID of the NUTS. |
| 107 | + year (int): The year of the satellite images. |
| 108 | + Returns: |
| 109 | + str: Image filepath if the image is finded, otherwise None. |
| 110 | +
|
| 111 | + """ |
| 112 | + logger.info(f"Find the image filepath for this gps point: {gps_point}") |
| 113 | + gc.collect() |
| 114 | + |
| 115 | + url = f"https://minio.lab.sspcloud.fr/projet-formation/diffusion/funathon/2026/project3/data/images/{nuts3}/{year}/filename2bbox.parquet" |
| 116 | + |
| 117 | + response = requests.head(url) |
| 118 | + |
| 119 | + if response.status_code == 200: |
| 120 | + df = pd.read_parquet(url) |
| 121 | + else: |
| 122 | + print(f"❌ No data for NUTS3='{nuts3}' and year={year} (HTTP {response.status_code})") |
| 123 | + return None |
| 124 | + |
| 125 | + # Création de la géométrie |
| 126 | + df["geometry"] = df.apply( |
| 127 | + lambda row: box(row["bbox"][0], row["bbox"][1], row["bbox"][2], row["bbox"][3]), |
| 128 | + axis=1 |
| 129 | + ) |
| 130 | + |
| 131 | + # Conversion en GeoDataFrame |
| 132 | + gdf = gpd.GeoDataFrame(df, geometry="geometry", crs="EPSG:3035") |
| 133 | + |
| 134 | + lat, lon = gps_point |
| 135 | + |
| 136 | + # Convertir le point GPS (EPSG:4326) en EPSG:3035 |
| 137 | + transformer = Transformer.from_crs("EPSG:4326", "EPSG:3035", always_xy=True) |
| 138 | + x, y = transformer.transform(lon, lat) |
| 139 | + |
| 140 | + point = Point(x, y) |
| 141 | + result = gdf[gdf.contains(point)] |
| 142 | + |
| 143 | + return result["filename"].values |
| 144 | + |
| 145 | + |
91 | 146 | @app.get("/predict_image", tags=["Predict Image"]) |
92 | 147 | async def predict_image(image: str, polygons: bool = False) -> Dict: |
93 | 148 | """ |
@@ -159,10 +214,32 @@ def predict_nuts( |
159 | 214 | # nuts = gpd.read_file("/api/nuts_2021.gpkg") |
160 | 215 | # nuts = gpd.GeoDataFrame(nuts, geometry="geometry", crs="EPSG:4326") |
161 | 216 |
|
| 217 | + path = f"s3://projet-formation/diffusion/funathon/2026/project3/data/images/{nuts_id}" |
| 218 | + |
| 219 | + if fs.exists(path): |
| 220 | + print(f"✅ {nuts_id} is in the database") |
| 221 | + else: |
| 222 | + logger.info(f"""No {nuts_id} in the database.""") |
| 223 | + return JSONResponse( |
| 224 | + content={ |
| 225 | + "predictions": gpd.GeoDataFrame(columns=["geometry"], crs="EPSG:3035").to_json() |
| 226 | + } |
| 227 | + ) |
| 228 | + |
| 229 | + if fs.exists(path+f"/{year}"): |
| 230 | + print(f"✅ {year} is in the database for {nuts_id}.") |
| 231 | + else: |
| 232 | + logger.info(f"""No {year} in {nuts_id} in the database.""") |
| 233 | + return JSONResponse( |
| 234 | + content={ |
| 235 | + "predictions": gpd.GeoDataFrame(columns=["geometry"], crs="EPSG:3035").to_json() |
| 236 | + } |
| 237 | + ) |
| 238 | + |
162 | 239 | images = [ |
163 | 240 | img |
164 | 241 | for img in fs.ls( |
165 | | - f"s3://projet-formation/diffusion/funathon/2026/project3/data/images/{nuts_id}/{year}/" |
| 242 | + path+f"/{year}/" |
166 | 243 | ) |
167 | 244 | if img.endswith(".tif") |
168 | 245 | ] |
|
0 commit comments