Files
Ai/irrigation/views.py
T
2026-04-25 17:22:41 +03:30

375 lines
14 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django.apps import apps
from drf_spectacular.utils import OpenApiExample, extend_schema
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from config.openapi import (
build_envelope_serializer,
build_response,
)
from .models import IrrigationMethod
from .serializers import (
IrrigationMethodSerializer,
IrrigationRecommendRequestSerializer,
WaterStressRequestSerializer,
WaterStressResponseSerializer,
)
IrrigationMethodListResponseSerializer = build_envelope_serializer(
"IrrigationMethodListResponseSerializer",
IrrigationMethodSerializer,
many=True,
)
IrrigationMethodDetailResponseSerializer = build_envelope_serializer(
"IrrigationMethodDetailResponseSerializer",
IrrigationMethodSerializer,
)
IrrigationValidationErrorSerializer = build_envelope_serializer(
"IrrigationValidationErrorSerializer",
data_required=False,
allow_null=True,
)
IrrigationRecommendResponseSerializer = build_envelope_serializer(
"IrrigationRecommendResponseSerializer",
data_schema=None,
)
WaterStressEnvelopeSerializer = build_envelope_serializer(
"WaterStressEnvelopeSerializer",
WaterStressResponseSerializer,
)
class IrrigationMethodListCreateView(APIView):
"""لیست تمام روش‌های آبیاری و ایجاد روش جدید."""
@extend_schema(
tags=["Irrigation"],
summary="لیست روش‌های آبیاری",
description="لیست تمام روش‌های آبیاری ذخیره‌شده را برمی‌گرداند.",
responses={
200: build_response(
IrrigationMethodListResponseSerializer,
"لیست روش‌های آبیاری ذخیره‌شده.",
),
},
)
def get(self, request):
methods = IrrigationMethod.objects.all()
serializer = IrrigationMethodSerializer(methods, many=True)
return Response(
{"code": 200, "msg": "success", "data": serializer.data},
status=status.HTTP_200_OK,
)
@extend_schema(
tags=["Irrigation"],
summary="ایجاد روش آبیاری جدید",
description="یک روش آبیاری جدید ایجاد می‌کند.",
request=IrrigationMethodSerializer,
responses={
201: build_response(
IrrigationMethodDetailResponseSerializer,
"روش آبیاری جدید با موفقیت ایجاد شد.",
),
400: build_response(
IrrigationValidationErrorSerializer,
"داده ورودی نامعتبر است.",
),
},
examples=[
OpenApiExample(
"نمونه درخواست",
value={
"name": "آبیاری قطره‌ای",
"category": "موضعی",
"description": "آبیاری با دبی کم و فشار مناسب",
"water_efficiency_percent": 90.0,
"water_pressure_required": "۱-۲ اتمسفر",
"flow_rate": "۲-۸ لیتر در ساعت",
"coverage_area": "بسته به طراحی سیستم",
"soil_type": "تمام انواع خاک",
"climate_suitability": "گرم و خشک",
},
request_only=True,
),
],
)
def post(self, request):
serializer = IrrigationMethodSerializer(data=request.data)
if not serializer.is_valid():
return Response(
{"code": 400, "msg": "داده نامعتبر.", "data": serializer.errors},
status=status.HTTP_400_BAD_REQUEST,
)
serializer.save()
return Response(
{"code": 201, "msg": "success", "data": serializer.data},
status=status.HTTP_201_CREATED,
)
class IrrigationRecommendView(APIView):
"""
توصیه آبیاری به صورت مستقیم.
POST با farm_uuid، plant_name، growth_stage، irrigation_method_name.
اطلاعات گیاه از plant app و روش آبیاری از irrigation app دریافت می‌شود.
"""
@extend_schema(
tags=["Irrigation Recommendation"],
summary="درخواست توصیه آبیاری",
description=(
"داده‌های سنسور، گیاه و روش آبیاری را دریافت کرده و "
"توصیه آبیاری را مستقیم برمی‌گرداند. "
"اطلاعات گیاه از جدول Plant و روش آبیاری از جدول IrrigationMethod بارگذاری می‌شود. "
"محاسبات ET₀ و ETc با مدل FAO-56 در بک‌اند انجام می‌شود و مدل زبانی فقط توضیح برنامه آبیاری را تولید می‌کند."
),
request=IrrigationRecommendRequestSerializer,
responses={
200: build_response(
IrrigationRecommendResponseSerializer,
"توصیه آبیاری با موفقیت تولید شد.",
),
400: build_response(
IrrigationValidationErrorSerializer,
"پارامتر ورودی نامعتبر است.",
),
500: build_response(
IrrigationValidationErrorSerializer,
"خطا در تولید توصیه آبیاری.",
),
},
examples=[
OpenApiExample(
"نمونه درخواست",
value={
"farm_uuid": "11111111-1111-1111-1111-111111111111",
"plant_name": "گوجه‌فرنگی",
"growth_stage": "گلدهی",
"irrigation_method_name": "آبیاری قطره‌ای",
},
request_only=True,
),
],
)
def post(self, request):
from rag.services.irrigation import get_irrigation_recommendation
serializer = IrrigationRecommendRequestSerializer(data=request.data)
if not serializer.is_valid():
return Response(
{"code": 400, "msg": "داده نامعتبر.", "data": serializer.errors},
status=status.HTTP_400_BAD_REQUEST,
)
validated = serializer.validated_data
farm_uuid = validated["farm_uuid"]
plant_name = validated.get("plant_name")
growth_stage = validated.get("growth_stage")
irrigation_method_name = validated.get("irrigation_method_name")
query = validated.get("query")
try:
result = get_irrigation_recommendation(
farm_uuid=farm_uuid,
plant_name=plant_name,
growth_stage=growth_stage,
irrigation_method_name=irrigation_method_name,
query=query,
)
except Exception as exc:
return Response(
{"code": 500, "msg": f"خطا در تولید توصیه آبیاری: {exc}", "data": None},
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
)
return Response(
{"code": 200, "msg": "success", "data": result},
status=status.HTTP_200_OK,
)
class IrrigationMethodDetailView(APIView):
"""دریافت، ویرایش و حذف یک روش آبیاری."""
def _get_method(self, pk):
return IrrigationMethod.objects.filter(pk=pk).first()
@extend_schema(
tags=["Irrigation"],
summary="جزئیات روش آبیاری",
description="مشخصات یک روش آبیاری را بر اساس شناسه برمی‌گرداند.",
responses={
200: build_response(
IrrigationMethodDetailResponseSerializer,
"جزئیات روش آبیاری.",
),
404: build_response(
IrrigationValidationErrorSerializer,
"روش آبیاری یافت نشد.",
),
},
)
def get(self, request, pk):
method = self._get_method(pk)
if not method:
return Response(
{"code": 404, "msg": "روش آبیاری یافت نشد.", "data": None},
status=status.HTTP_404_NOT_FOUND,
)
serializer = IrrigationMethodSerializer(method)
return Response(
{"code": 200, "msg": "success", "data": serializer.data},
status=status.HTTP_200_OK,
)
class WaterStressView(APIView):
@extend_schema(
tags=["Irrigation"],
summary="شاخص تنش آبی مزرعه",
description=(
"با دریافت farm_uuid، شاخص تنش آبی مزرعه را با استفاده از شبیه سازی "
"crop_simulation و داده هایی مثل رطوبت خاک، ET0، بارش، مرحله رشد و پارامترهای خاک برمی گرداند."
),
request=WaterStressRequestSerializer,
responses={
200: build_response(WaterStressEnvelopeSerializer, "شاخص تنش آبی مزرعه."),
400: build_response(IrrigationValidationErrorSerializer, "پارامتر ورودی نامعتبر است."),
404: build_response(IrrigationValidationErrorSerializer, "مزرعه یافت نشد."),
},
examples=[
OpenApiExample(
"نمونه درخواست water stress",
value={"farm_uuid": "11111111-1111-1111-1111-111111111111"},
request_only=True,
)
],
)
def post(self, request):
serializer = WaterStressRequestSerializer(data=request.data)
if not serializer.is_valid():
return Response(
{"code": 400, "msg": "داده نامعتبر.", "data": serializer.errors},
status=status.HTTP_400_BAD_REQUEST,
)
service = apps.get_app_config("irrigation").get_water_stress_service()
try:
data = service.get_water_stress(farm_uuid=serializer.validated_data["farm_uuid"])
except ValueError as exc:
return Response(
{"code": 404, "msg": str(exc), "data": None},
status=status.HTTP_404_NOT_FOUND,
)
return Response({"code": 200, "msg": "success", "data": data}, status=status.HTTP_200_OK)
@extend_schema(
tags=["Irrigation"],
summary="ویرایش کامل روش آبیاری",
description="تمام فیلدهای یک روش آبیاری را آپدیت می‌کند.",
request=IrrigationMethodSerializer,
responses={
200: build_response(
IrrigationMethodDetailResponseSerializer,
"روش آبیاری با موفقیت به‌روزرسانی شد.",
),
400: build_response(
IrrigationValidationErrorSerializer,
"داده ورودی نامعتبر است.",
),
404: build_response(
IrrigationValidationErrorSerializer,
"روش آبیاری یافت نشد.",
),
},
)
def put(self, request, pk):
method = self._get_method(pk)
if not method:
return Response(
{"code": 404, "msg": "روش آبیاری یافت نشد.", "data": None},
status=status.HTTP_404_NOT_FOUND,
)
serializer = IrrigationMethodSerializer(method, data=request.data)
if not serializer.is_valid():
return Response(
{"code": 400, "msg": "داده نامعتبر.", "data": serializer.errors},
status=status.HTTP_400_BAD_REQUEST,
)
serializer.save()
return Response(
{"code": 200, "msg": "success", "data": serializer.data},
status=status.HTTP_200_OK,
)
@extend_schema(
tags=["Irrigation"],
summary="ویرایش جزئی روش آبیاری",
description="فقط فیلدهای ارسال‌شده آپدیت می‌شوند.",
request=IrrigationMethodSerializer,
responses={
200: build_response(
IrrigationMethodDetailResponseSerializer,
"روش آبیاری با موفقیت به‌روزرسانی شد.",
),
400: build_response(
IrrigationValidationErrorSerializer,
"داده ورودی نامعتبر است.",
),
404: build_response(
IrrigationValidationErrorSerializer,
"روش آبیاری یافت نشد.",
),
},
)
def patch(self, request, pk):
method = self._get_method(pk)
if not method:
return Response(
{"code": 404, "msg": "روش آبیاری یافت نشد.", "data": None},
status=status.HTTP_404_NOT_FOUND,
)
serializer = IrrigationMethodSerializer(method, data=request.data, partial=True)
if not serializer.is_valid():
return Response(
{"code": 400, "msg": "داده نامعتبر.", "data": serializer.errors},
status=status.HTTP_400_BAD_REQUEST,
)
serializer.save()
return Response(
{"code": 200, "msg": "success", "data": serializer.data},
status=status.HTTP_200_OK,
)
@extend_schema(
tags=["Irrigation"],
summary="حذف روش آبیاری",
description="یک روش آبیاری را حذف می‌کند.",
responses={
200: build_response(
IrrigationValidationErrorSerializer,
"روش آبیاری با موفقیت حذف شد.",
),
404: build_response(
IrrigationValidationErrorSerializer,
"روش آبیاری یافت نشد.",
),
},
)
def delete(self, request, pk):
method = self._get_method(pk)
if not method:
return Response(
{"code": 404, "msg": "روش آبیاری یافت نشد.", "data": None},
status=status.HTTP_404_NOT_FOUND,
)
method.delete()
return Response(
{"code": 200, "msg": "روش آبیاری با موفقیت حذف شد.", "data": None},
status=status.HTTP_200_OK,
)