Skip to content

Commit 8495ab7

Browse files
committed
Make ndvi prediction starting from current time
1 parent 56c557e commit 8495ab7

1 file changed

Lines changed: 66 additions & 25 deletions

File tree

chipnik_monitor/api.py

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -342,9 +342,9 @@ def _predict_ndvi_with_ml(history_data: List[Dict[str, Any]], weather_df: pd.Dat
342342
if training_df.empty:
343343
raise ValueError("No valid training data available")
344344

345-
# Create future dates for prediction (next year)
346-
current_year = datetime.now().year
347-
future_start = datetime(target_year, 1, 1)
345+
# Create future dates for prediction (from current time forward)
346+
current_time = datetime.now()
347+
future_start = current_time
348348
future_end = datetime(target_year, 12, 31)
349349

350350
# Create future dataframe with 16-day intervals (satellite revisit cycle)
@@ -723,7 +723,7 @@ def _generate_report(geojson_payload: Union[str, Dict[str, Any]], yield_profile:
723723
"yieldTph": 0.0,
724724
"ndviPeak": None,
725725
"ndviPeakAt": None,
726-
"model": _DEFAULT_MODEL,
726+
"ndviModel": _DEFAULT_MODEL,
727727
"confidence": 0.0,
728728
"yieldType": yield_profile["name"],
729729
}
@@ -749,7 +749,7 @@ def _generate_report(geojson_payload: Union[str, Dict[str, Any]], yield_profile:
749749
history: List[Dict[str, Any]] = []
750750
report_records: List[Dict[str, Any]] = []
751751

752-
for row in rows:
752+
for i, row in enumerate(rows):
753753
report = monitor.compute_index_for_row(row, index_types=index_types, bbox=bbox, token=token)
754754
if not report:
755755
continue
@@ -775,24 +775,32 @@ def _generate_report(geojson_payload: Union[str, Dict[str, Any]], yield_profile:
775775

776776
weather = weather_lookup.get(report_dt.date())
777777

778-
history.append(
779-
{
780-
"date": _isoformat_utc(report_dt),
781-
"ndvi": report.get("mean_NDVI"),
782-
"cloud_cover": float(row.cloud_cover) if getattr(row, "cloud_cover", None) is not None else None,
783-
"collection": getattr(row, "collection", None),
784-
"temperature_deg_c": weather["temperature_deg_c"] if weather else None,
785-
"humidity_pct": weather["humidity_pct"] if weather else None,
786-
"cloudcover_pct": weather["cloudcover_pct"] if weather else None,
787-
"wind_speed_mps": weather["wind_speed_mps"] if weather else None,
788-
"clarity_pct": weather["clarity_pct"] if weather else None,
789-
}
790-
)
778+
# Add historical data point
779+
historical_entry = {
780+
"date": _isoformat_utc(report_dt),
781+
"ndvi": report.get("mean_NDVI"),
782+
"cloud_cover": float(row.cloud_cover) if getattr(row, "cloud_cover", None) is not None else None,
783+
"collection": getattr(row, "collection", None),
784+
"temperature_deg_c": weather["temperature_deg_c"] if weather else None,
785+
"humidity_pct": weather["humidity_pct"] if weather else None,
786+
"cloudcover_pct": weather["cloudcover_pct"] if weather else None,
787+
"wind_speed_mps": weather["wind_speed_mps"] if weather else None,
788+
"clarity_pct": weather["clarity_pct"] if weather else None,
789+
"type": 0, # 0 = historic data, 1 = ML predicted data
790+
}
791+
792+
history.append(historical_entry)
793+
794+
# For the last row, append a copy with type 1
795+
if i == len(rows) - 1:
796+
transition_entry = historical_entry.copy()
797+
transition_entry["type"] = 1
798+
history.append(transition_entry)
791799

792800
history.sort(key=lambda item: item["date"])
793801

794802
# Try ML prediction first, fall back to heuristic method
795-
forecast_year = end_dt.year + 1
803+
forecast_year = end_dt.year
796804
ml_results = _predict_ndvi_with_ml(history, weather_df, forecast_year)
797805

798806
if ml_results.get('model') == 'prophet_ml':
@@ -804,6 +812,39 @@ def _generate_report(geojson_payload: Union[str, Dict[str, Any]], yield_profile:
804812
flowering_confidence = ml_results.get('flowering_confidence', 0)
805813
model_name = "prophet_ml"
806814

815+
# Add ML predictions to history with type 1
816+
ml_predictions = ml_results.get('predictions', [])
817+
for prediction in ml_predictions:
818+
pred_date = prediction['ds']
819+
if isinstance(pred_date, str):
820+
try:
821+
pred_dt = pd.to_datetime(pred_date).to_pydatetime()
822+
except Exception:
823+
continue
824+
elif isinstance(pred_date, pd.Timestamp):
825+
pred_dt = pred_date.to_pydatetime()
826+
else:
827+
pred_dt = pred_date
828+
829+
if pred_dt.tzinfo is None:
830+
pred_dt = pred_dt.replace(tzinfo=timezone.utc)
831+
832+
history.append({
833+
"date": _isoformat_utc(pred_dt),
834+
"ndvi": round(float(prediction['yhat']), 4),
835+
"cloud_cover": None, # No cloud cover for predictions
836+
"collection": "ML_Prediction",
837+
"temperature_deg_c": None, # Weather data not included in predictions
838+
"humidity_pct": None,
839+
"cloudcover_pct": None,
840+
"wind_speed_mps": None,
841+
"clarity_pct": None,
842+
"type": 1, # 1 = ML predicted data
843+
})
844+
845+
# Re-sort history after adding predictions
846+
history.sort(key=lambda item: item["date"])
847+
807848
# Calculate yield based on ML predictions
808849
reference_ndvi = ndvi_peak if ndvi_peak is not None else 0.0
809850
tolerance = float(yield_profile.get("ndvi_tolerance") or 0.25)
@@ -872,11 +913,11 @@ def _generate_report(geojson_payload: Union[str, Dict[str, Any]], yield_profile:
872913
forecast_dict = {
873914
"year": forecast_year,
874915
"yieldTph": round(yield_tph, 2),
916+
"yieldType": yield_profile["name"],
917+
"yieldConfidence": round(match_ratio, 2),
875918
"ndviPeak": round(ndvi_peak, 2) if ndvi_peak is not None else None,
876919
"ndviPeakAt": ndvi_peak_at,
877-
"model": model_name,
878-
"confidence": round(match_ratio, 2),
879-
"yieldType": yield_profile["name"],
920+
"ndviModel": model_name,
880921
}
881922

882923
# Add flowering information if available
@@ -886,9 +927,9 @@ def _generate_report(geojson_payload: Union[str, Dict[str, Any]], yield_profile:
886927
if isinstance(flowering_start_date, datetime):
887928
if flowering_start_date.tzinfo is None:
888929
flowering_start_date = flowering_start_date.replace(tzinfo=timezone.utc)
889-
forecast_dict["floweringStartDate"] = _isoformat_utc(flowering_start_date)
890-
forecast_dict["floweringConfidence"] = round(flowering_confidence, 2)
891-
forecast_dict["floweringMethod"] = ml_results.get('flowering_method')
930+
forecast_dict["ndviStartAt"] = _isoformat_utc(flowering_start_date)
931+
forecast_dict["ndviStartConfidence"] = round(flowering_confidence, 2)
932+
forecast_dict["ndviStartMethod"] = ml_results.get('flowering_method')
892933

893934
return {"history": history, "forecast": forecast_dict}
894935

0 commit comments

Comments
 (0)