Aniket2006 commited on
Commit
fdb0281
·
1 Parent(s): c5d4c4d

Fix: Add on-demand prediction for /timeseries when no cache

Browse files
Files changed (1) hide show
  1. app.py +97 -4
app.py CHANGED
@@ -527,10 +527,103 @@ async def get_timeseries(request: TimeSeriesRequest):
527
  timestamp=datetime.now().isoformat()
528
  )
529
 
530
- # No cache - run prediction
531
- logger.info(f"No cache for {field_hash}, running fresh prediction...")
532
- # ... (keep original logic for fresh prediction)
533
- raise HTTPException(404, f"No cached data. Use POST /predict to start prediction job.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
534
 
535
 
536
  if __name__ == "__main__":
 
527
  timestamp=datetime.now().isoformat()
528
  )
529
 
530
+ # No cache - run on-demand prediction for single metric
531
+ logger.info(f"No cache for {field_hash}, running on-demand prediction...")
532
+
533
+ try:
534
+ # Fetch satellite data
535
+ fetcher = SatelliteFetcher(polygon)
536
+
537
+ if request.metric in ['VV', 'VH']:
538
+ fetcher.fetch_sar_data('sar_data.csv')
539
+ csv_file = 'sar_data.csv'
540
+ target_col = f'{request.metric}_mean_dB'
541
+ else:
542
+ fetcher.fetch_sentinel2_data('sentinel2_data.csv')
543
+ csv_file = 'sentinel2_data.csv'
544
+ target_col = request.metric
545
+
546
+ # Read historical data
547
+ if not os.path.exists(csv_file):
548
+ raise HTTPException(404, "No satellite data available for this location")
549
+
550
+ df = pd.read_csv(csv_file)
551
+ if 'ds' not in df.columns:
552
+ raise HTTPException(500, "Invalid data format")
553
+
554
+ # Convert to DataPoint list
555
+ historical = []
556
+ for _, row in df.iterrows():
557
+ if target_col in row and not pd.isna(row[target_col]):
558
+ historical.append(DataPoint(
559
+ date=str(row['ds']),
560
+ value=round(float(row[target_col]), 4)
561
+ ))
562
+
563
+ if len(historical) < 10:
564
+ raise HTTPException(400, f"Insufficient data points ({len(historical)}) for forecasting")
565
+
566
+ logger.info(f"Historical data: {len(historical)} points")
567
+
568
+ # Run AutoNHITS prediction
569
+ logger.info(f"Running AutoNHITS prediction...")
570
+ predictor = AutoTimeSeriesPredictor()
571
+
572
+ predictions = predictor.tune_and_predict(
573
+ csv_path=csv_file,
574
+ field_coords=polygon,
575
+ target_col=target_col,
576
+ output_file='predictions.csv',
577
+ num_samples=3 # Quick tuning for API
578
+ )
579
+
580
+ # Convert predictions to ForecastPoint list
581
+ forecast = []
582
+ for _, row in predictions.iterrows():
583
+ value = float(row['predicted_y'])
584
+ forecast.append(ForecastPoint(
585
+ date=str(row['ds'].date()) if hasattr(row['ds'], 'date') else str(row['ds']),
586
+ value=round(value, 4),
587
+ confidence_low=round(value * 0.9, 4),
588
+ confidence_high=round(value * 1.1, 4)
589
+ ))
590
+
591
+ logger.info(f"Forecast: {len(forecast)} points")
592
+
593
+ # Calculate stats
594
+ all_values = [p.value for p in historical]
595
+ stats = {
596
+ "min": round(min(all_values), 4),
597
+ "max": round(max(all_values), 4),
598
+ "mean": round(sum(all_values) / len(all_values), 4),
599
+ "count": len(all_values),
600
+ "forecast_count": len(forecast)
601
+ }
602
+
603
+ # Cleanup temp files
604
+ for f in ['sar_data.csv', 'sentinel2_data.csv', 'predictions.csv']:
605
+ if os.path.exists(f):
606
+ os.remove(f)
607
+
608
+ logger.info(f"SUCCESS - Trend: {calculate_trend(all_values)}")
609
+
610
+ return TimeSeriesResponse(
611
+ success=True,
612
+ metric=request.metric,
613
+ historical=historical,
614
+ forecast=forecast,
615
+ trend=calculate_trend(all_values[-20:] if len(all_values) > 20 else all_values),
616
+ stats=stats,
617
+ timestamp=datetime.now().isoformat()
618
+ )
619
+
620
+ except HTTPException:
621
+ raise
622
+ except Exception as e:
623
+ logger.error(f"Error: {str(e)}")
624
+ import traceback
625
+ logger.error(traceback.format_exc())
626
+ raise HTTPException(500, str(e))
627
 
628
 
629
  if __name__ == "__main__":