93 lines
3.2 KiB
Python
93 lines
3.2 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from typing import Any
|
||
|
|
|
||
|
|
from farm_data.models import SensorData
|
||
|
|
from .remote_sensing import fetch_or_get_ndvi_observation
|
||
|
|
|
||
|
|
|
||
|
|
def _ndvi_explanation(observation, ai_bundle: dict | None = None) -> str:
|
||
|
|
ai_bundle = ai_bundle or {}
|
||
|
|
ai_payload = ai_bundle.get("ndviHealthCard", {}) if isinstance(ai_bundle, dict) else {}
|
||
|
|
explanation = ai_payload.get("explanation")
|
||
|
|
if isinstance(explanation, str) and explanation.strip():
|
||
|
|
return explanation.strip()
|
||
|
|
return (
|
||
|
|
f"میانگین NDVI مزرعه {observation.mean_ndvi} ثبت شده و کلاس سلامت پوشش گیاهی "
|
||
|
|
f"در وضعیت {observation.vegetation_health_class} قرار دارد."
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def _build_ndvi_health_card(location: Any, ai_bundle: dict | None = None) -> dict[str, Any]:
|
||
|
|
if location is None:
|
||
|
|
return {
|
||
|
|
"mean_ndvi": None,
|
||
|
|
"ndvi_map": {},
|
||
|
|
"vegetation_health_class": None,
|
||
|
|
"observation_date": None,
|
||
|
|
"satellite_source": None,
|
||
|
|
"healthData": [],
|
||
|
|
}
|
||
|
|
|
||
|
|
observation = fetch_or_get_ndvi_observation(location)
|
||
|
|
if observation is None:
|
||
|
|
return {
|
||
|
|
"mean_ndvi": None,
|
||
|
|
"ndvi_map": {},
|
||
|
|
"vegetation_health_class": "Unavailable",
|
||
|
|
"observation_date": None,
|
||
|
|
"satellite_source": None,
|
||
|
|
"healthData": [
|
||
|
|
{
|
||
|
|
"title": "وضعیت NDVI",
|
||
|
|
"value": "داده ماهوارهای موجود نیست",
|
||
|
|
"color": "warning",
|
||
|
|
"icon": "tabler-satellite-off",
|
||
|
|
},
|
||
|
|
],
|
||
|
|
}
|
||
|
|
|
||
|
|
mean_value = round(observation.mean_ndvi, 2)
|
||
|
|
vegetation_class = observation.vegetation_health_class
|
||
|
|
return {
|
||
|
|
"ndviIndex": mean_value,
|
||
|
|
"mean_ndvi": mean_value,
|
||
|
|
"ndvi_map": observation.ndvi_map,
|
||
|
|
"vegetation_health_class": vegetation_class,
|
||
|
|
"observation_date": observation.observation_date.isoformat(),
|
||
|
|
"satellite_source": observation.satellite_source,
|
||
|
|
"healthData": [
|
||
|
|
{
|
||
|
|
"title": "سلامت پوشش گیاهی",
|
||
|
|
"value": vegetation_class,
|
||
|
|
"color": "success" if mean_value > 0.6 else "warning" if mean_value >= 0.4 else "error",
|
||
|
|
"icon": "tabler-plant",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"title": "تاریخ مشاهده",
|
||
|
|
"value": observation.observation_date.isoformat(),
|
||
|
|
"color": "info",
|
||
|
|
"icon": "tabler-calendar",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"title": "تفسیر",
|
||
|
|
"value": _ndvi_explanation(observation, ai_bundle=ai_bundle),
|
||
|
|
"color": "primary",
|
||
|
|
"icon": "tabler-message-2",
|
||
|
|
},
|
||
|
|
],
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
class NdviHealthService:
|
||
|
|
def get_ndvi_health(self, *, farm_uuid: str) -> dict[str, Any]:
|
||
|
|
sensor = (
|
||
|
|
SensorData.objects.select_related("center_location")
|
||
|
|
.filter(farm_uuid=farm_uuid)
|
||
|
|
.first()
|
||
|
|
)
|
||
|
|
if sensor is None:
|
||
|
|
raise ValueError("Farm not found.")
|
||
|
|
|
||
|
|
return _build_ndvi_health_card(sensor.center_location, ai_bundle=None)
|