1
- import uvicorn
2
1
from fastapi import FastAPI , HTTPException
3
2
from fastapi .middleware .cors import CORSMiddleware
4
3
from fastapi .responses import FileResponse , JSONResponse
9
8
10
9
import os
11
10
12
- #from .config import AppConfig
13
11
import pandas as pd
14
12
import numpy as np
15
- from shapely .geometry import LineString
16
- import rasterio
17
- from rasterio .warp import calculate_default_transform , reproject , Resampling
18
13
19
14
from PIL import Image
20
15
from io import BytesIO
21
16
import base64
22
- # DEBUGGING
23
- import sys
24
- from time import sleep
25
17
26
18
app = FastAPI ()
27
19
frontend_origin = "http://localhost:3000"
@@ -184,33 +176,26 @@ def get_precipitation_data(selectedYear: int):
184
176
return monthly_avg .to_dict (orient = 'records' )
185
177
186
178
187
- '''app.get('/bird-data/{bird_name}')
188
- def get_bird_data(bird_name):
189
- if bird_name in bird_data:
190
- return bird_data'''
191
-
192
-
193
179
class PredictionInputs (BaseModel ):
194
180
bird : str
195
181
year : int
196
182
emissions : str
197
183
198
184
@app .put ('/prediction' )
199
- async def predict (prediction_input : PredictionInputs ):
185
+ async def get_predictions (prediction_input : PredictionInputs ):
200
186
selected_bird = prediction_input .bird
201
187
selected_year = str (prediction_input .year )
202
188
emission_Type = prediction_input .emissions
203
-
204
189
# For image data:
205
190
output_path = f"../../model/outputs/png-images/{ birdsModelDirs [selected_bird ]} /{ emission_Type } /{ selected_year } .png"
206
191
dataImg = Image .open (output_path )
207
192
buffer = BytesIO ()
208
193
dataImg .save (buffer , format = "png" )
209
194
210
- # Artificial delay to simulate model prediction time
211
- #sleep(2.5)
195
+ # FastAPI requests can handle asynchronous predictions.
196
+ # In practice, this would be waiting for a machine learning model to generate
197
+ # predictions. In this version, waiting wasn't necessary, so it returns immediately.
212
198
213
- #If we'll need to encapsulate a file, use this:
214
199
return {
215
200
"prediction" : base64 .b64encode (buffer .getvalue ()).decode (),
216
201
"resFormat" : dataImg .format
@@ -230,8 +215,8 @@ def get_bird_info(bird_name):
230
215
raise HTTPException (
231
216
status_code = 404 ,
232
217
detail = f"data for bird { bird_name } does not exist." )
233
-
234
-
218
+
219
+
235
220
@app .get ('/json/{filename}' )
236
221
def send_json (filename ):
237
222
climate_file_loc = os .path .join ('climate_data/json_data' , filename )
@@ -244,6 +229,7 @@ def send_json(filename):
244
229
245
230
@app .get ('/get_trajectory_data' )
246
231
def get_trajectory_data (bird : str , birdID : str ):
232
+
247
233
filename = f'./data/{ bird } .csv'
248
234
try :
249
235
df = pd .read_csv (filename )
@@ -253,77 +239,29 @@ def get_trajectory_data(bird: str, birdID: str):
253
239
if bird_data .empty :
254
240
raise HTTPException (
255
241
status_code = 404 ,
256
- details = 'No trajectory data found for given bird ID' )
242
+ detail = 'No trajectory data found for given bird ID' )
257
243
258
244
# Convert data to dictionary format
259
245
trajectory_data = bird_data [['LATITUDE' , 'LONGITUDE' , 'TIMESTAMP' ]].to_dict (orient = 'records' )
260
246
return trajectory_data
261
247
except FileNotFoundError :
262
248
raise HTTPException (
263
249
status_code = 404 ,
264
- details = f'CSV file for { bird } not found' )
250
+ detail = f'CSV file for { filename } not found' )
265
251
266
252
267
253
@app .get ('/get_bird_ids' )
268
254
def get_bird_ids (bird : str ):
269
255
filename = f'./data/{ bird } .csv'
256
+
270
257
try :
271
258
df = pd .read_csv (filename )
272
259
bird_ids = df ['ID' ].unique ().tolist ()
273
260
return bird_ids
274
261
except FileNotFoundError :
275
262
raise HTTPException (
276
263
status_code = 404 ,
277
- detail = f'CSV file for { bird } not found' )
278
-
279
-
280
- @app .get ('/get_general_migration' )
281
- def get_general_migration (selected_bird : str ):
282
- filename = f'./data/{ selected_bird } .csv'
283
-
284
- try :
285
- df = pd .read_csv (filename , low_memory = False )
286
-
287
- # Convert TIMESTAMP column to datetime
288
- df ['TIMESTAMP' ] = pd .to_datetime (df ['TIMESTAMP' ])
289
-
290
- # Group by ID and get the start and end months for each group
291
- grouped = df .groupby ('ID' )
292
- print (grouped )
293
- simplified_polylines = []
294
- for _ , group in grouped :
295
- # Sort by timestamp
296
- group = group .sort_values (by = 'TIMESTAMP' )
297
-
298
- # Get coordinates
299
- coordinates = list (zip (group ['LATITUDE' ], group ['LONGITUDE' ]))
300
-
301
- # Apply Douglas-Peucker algorithm for simplification
302
- simplified_line = simplify_line (coordinates )
303
-
304
- # Calculate direction for simplified line
305
- start_point = simplified_line [0 ]
306
- end_point = simplified_line [- 1 ]
307
- delta_lat = end_point [0 ] - start_point [0 ]
308
- delta_lon = end_point [1 ] - start_point [1 ]
309
- direction = np .arctan2 (delta_lat , delta_lon ) * (180 / np .pi )
310
-
311
- # Append simplified line with direction to simplified_polylines
312
- simplified_polylines .append ({
313
- 'coordinates' : simplified_line ,
314
- 'direction' : direction
315
- })
316
-
317
- return {'segmented_polylines' : simplified_polylines }
318
-
319
- except Exception as e :
320
- raise HTTPException (status_code = 400 , detail = str (e ))
321
-
322
-
323
- def simplify_line (coordinates , tolerance = 0.1 ):
324
- line = LineString (coordinates )
325
- simplified_line = line .simplify (tolerance , preserve_topology = False )
326
- return list (zip (* simplified_line .xy ))
264
+ detail = f'CSV file for { filename } not found' )
327
265
328
266
329
267
@app .get ('/get_heatmap_data' )
@@ -334,69 +272,4 @@ def get_heatmap_data(bird: str):
334
272
heatmap_data = df [['LATITUDE' , 'LONGITUDE' ]].values .tolist ()
335
273
return heatmap_data
336
274
except Exception as e :
337
- raise HTTPException (status_code = 400 , detail = str (e ))
338
-
339
- source_epsg = 'epsg:4326' # Input coordinates in EPSG 4326 (WGS84)
340
- target_epsg = 'epsg:3587'
341
-
342
- @app .get ('/get_SDM_data' )
343
- def get_SDM_data (prediction_input : PredictionInputs ):
344
- selected_bird = prediction_input .bird
345
- selected_year = str (prediction_input .year )
346
- emission_Type = prediction_input .emissions
347
-
348
- tiff_file_path = f"../model/outputs/tiff-images/{ birdsModelDirs [selected_bird ]} /{ emission_Type } /{ selected_year } /probability_1.0.tif"
349
-
350
- with rasterio .open (tiff_file_path ) as src :
351
- # Read the data from the TIFF file
352
- data = src .read (1 ) # Assuming a single band for simplicity
353
-
354
- # Get the transformation parameters for the reprojected image
355
- transform , width , height = calculate_default_transform (src .crs , target_epsg , src .width , src .height , * src .bounds )
356
-
357
- # Reproject the image
358
- data_reprojected = np .empty ((height , width ), dtype = data .dtype )
359
- reproject (
360
- source = data ,
361
- destination = data_reprojected ,
362
- src_transform = src .transform ,
363
- src_crs = src .crs ,
364
- dst_transform = transform ,
365
- dst_crs = target_epsg ,
366
- resampling = Resampling .nearest
367
- )
368
-
369
- # Convert numpy array to list for JSON serialization
370
- data_list = data_reprojected .tolist ()
371
-
372
- # Prepare data to send to frontend
373
- converted_data = {'data' : data_list }
374
-
375
- # Convert data to JSON
376
- json_data = json .dumps (converted_data )
377
-
378
- # Send converted data to frontend
379
- return JSONResponse (content = converted_data )
380
-
381
- '''@api.route('/get_SDM_data')
382
- @cross_origin(supports_credentials=True)
383
- def get_SDM_data():
384
- tiff_file_path = f"../model/outputs/tiff-images/{birdsModelDirs[session['bird']]}/{session['emissions']}/{session['year']}/probability_1.0.tif"
385
- try:
386
- # Open the image using Pillow
387
- img = Image.open(tiff_file_path)
388
- dataset = rasterio.open(tiff_file_path)
389
- print(dataset.bounds)
390
- # Extract data from the image
391
- img_array = np.array(img)
392
- response_data = {'tiff_data': img_array.tolist()}
393
- # Send the TIFF data as JSON response
394
- return jsonify(response_data)
395
-
396
- except Exception as e:
397
- return f'An error occurred: {e}'
398
- '''
399
-
400
- if __name__ == '__main__' :
401
- api .run (debug = True )
402
- socket_io .run (api , debug = True , port = 5000 )
275
+ raise HTTPException (status_code = 400 , detail = str (e ))
0 commit comments