UPDATE
This commit is contained in:
@@ -2,7 +2,7 @@ from rest_framework import status
|
|||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from drf_spectacular.utils import extend_schema
|
from drf_spectacular.utils import OpenApiParameter, OpenApiTypes, extend_schema
|
||||||
|
|
||||||
from config.swagger import code_response
|
from config.swagger import code_response
|
||||||
from farm_hub.models import FarmHub
|
from farm_hub.models import FarmHub
|
||||||
@@ -16,6 +16,9 @@ class FarmFeatureAuthorizationView(APIView):
|
|||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
tags=["Access Control"],
|
tags=["Access Control"],
|
||||||
|
parameters=[
|
||||||
|
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.PATH, default="11111111-1111-1111-1111-111111111111"),
|
||||||
|
],
|
||||||
request=FeatureAuthorizationRequestSerializer,
|
request=FeatureAuthorizationRequestSerializer,
|
||||||
responses={200: code_response("FarmFeatureAuthorizationResponse")},
|
responses={200: code_response("FarmFeatureAuthorizationResponse")},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -34,7 +34,11 @@ INSTALLED_APPS = [
|
|||||||
"crop_zoning",
|
"crop_zoning",
|
||||||
"plant_simulator",
|
"plant_simulator",
|
||||||
"pest_detection",
|
"pest_detection",
|
||||||
|
"weather_forecast.apps.WeatherForecastConfig",
|
||||||
"irrigation_recommendation",
|
"irrigation_recommendation",
|
||||||
|
"yield_harvest.apps.YieldHarvestConfig",
|
||||||
|
"economic_overview.apps.EconomicOverviewConfig",
|
||||||
|
"farm_alerts.apps.FarmAlertsConfig",
|
||||||
"fertilization_recommendation",
|
"fertilization_recommendation",
|
||||||
"farm_ai_assistant",
|
"farm_ai_assistant",
|
||||||
"notifications.apps.NotificationsConfig",
|
"notifications.apps.NotificationsConfig",
|
||||||
|
|||||||
@@ -18,8 +18,12 @@ urlpatterns = [
|
|||||||
path("api/plant-simulator/", include("plant_simulator.urls")),
|
path("api/plant-simulator/", include("plant_simulator.urls")),
|
||||||
path("api/pest-detection/", include("pest_detection.urls")),
|
path("api/pest-detection/", include("pest_detection.urls")),
|
||||||
path("api/irrigation-recommendation/", include("irrigation_recommendation.urls")),
|
path("api/irrigation-recommendation/", include("irrigation_recommendation.urls")),
|
||||||
|
path("api/weather-forecast/", include("weather_forecast.urls")),
|
||||||
|
path("api/yield-harvest/", include("yield_harvest.urls")),
|
||||||
|
path("api/economic-overview/", include("economic_overview.urls")),
|
||||||
path("api/fertilization-recommendation/", include("fertilization_recommendation.urls")),
|
path("api/fertilization-recommendation/", include("fertilization_recommendation.urls")),
|
||||||
path("api/farm-ai-assistant/", include("farm_ai_assistant.urls")),
|
path("api/farm-ai-assistant/", include("farm_ai_assistant.urls")),
|
||||||
path("api/notifications/", include("notifications.urls")),
|
path("api/notifications/", include("notifications.urls")),
|
||||||
|
path("api/farm-alerts/", include("farm_alerts.urls")),
|
||||||
path("api/sensor-external-api/", include("sensor_external_api.urls")),
|
path("api/sensor-external-api/", include("sensor_external_api.urls")),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ AREA_QUERY_PARAMETERS = [
|
|||||||
location=OpenApiParameter.QUERY,
|
location=OpenApiParameter.QUERY,
|
||||||
required=True,
|
required=True,
|
||||||
description="UUID مزرعه برای گرفتن يا ساخت آخرين پردازش محدوده همان مزرعه.",
|
description="UUID مزرعه برای گرفتن يا ساخت آخرين پردازش محدوده همان مزرعه.",
|
||||||
),
|
default="11111111-1111-1111-1111-111111111111"),
|
||||||
OpenApiParameter(
|
OpenApiParameter(
|
||||||
name="page",
|
name="page",
|
||||||
type=OpenApiTypes.INT,
|
type=OpenApiTypes.INT,
|
||||||
|
|||||||
+2
-2
@@ -53,7 +53,7 @@ class FarmAccessMixin:
|
|||||||
get=extend_schema(
|
get=extend_schema(
|
||||||
tags=["Farm Dashboard"],
|
tags=["Farm Dashboard"],
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True),
|
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True, default="11111111-1111-1111-1111-111111111111"),
|
||||||
],
|
],
|
||||||
responses={200: code_response("FarmDashboardConfigGetResponse", data=FarmDashboardConfigSerializer())},
|
responses={200: code_response("FarmDashboardConfigGetResponse", data=FarmDashboardConfigSerializer())},
|
||||||
),
|
),
|
||||||
@@ -109,7 +109,7 @@ class FarmDashboardConfigView(FarmAccessMixin, APIView):
|
|||||||
get=extend_schema(
|
get=extend_schema(
|
||||||
tags=["Farm Dashboard"],
|
tags=["Farm Dashboard"],
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True),
|
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True, default="11111111-1111-1111-1111-111111111111"),
|
||||||
],
|
],
|
||||||
responses={200: code_response("FarmDashboardCardsResponse", data=serializers.JSONField())},
|
responses={200: code_response("FarmDashboardCardsResponse", data=serializers.JSONField())},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class EconomicOverviewConfig(AppConfig):
|
||||||
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
|
name = "economic_overview"
|
||||||
|
verbose_name = "Economic Overview"
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("farm_hub", "0001_initial"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="EconomicOverviewLog",
|
||||||
|
fields=[
|
||||||
|
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||||
|
("uuid", models.UUIDField(default=uuid.uuid4, editable=False, unique=True, db_index=True)),
|
||||||
|
("farm", models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name="economic_overview_logs", to="farm_hub.farmhub")),
|
||||||
|
("economic_data", models.JSONField(blank=True, default=list)),
|
||||||
|
("chart_series", models.JSONField(blank=True, default=list)),
|
||||||
|
("chart_categories", models.JSONField(blank=True, default=list)),
|
||||||
|
("fetched_at", models.DateTimeField(auto_now_add=True)),
|
||||||
|
],
|
||||||
|
options={"db_table": "economic_overview_logs", "ordering": ["-fetched_at"]},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
ECONOMIC_OVERVIEW = {
|
||||||
|
"economicData": [
|
||||||
|
{
|
||||||
|
"title": "هزینه آب",
|
||||||
|
"value": "€720",
|
||||||
|
"subtitle": "این ماه",
|
||||||
|
"avatarIcon": "tabler-droplet",
|
||||||
|
"avatarColor": "primary",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "صرفهجویی آب هوشمند",
|
||||||
|
"value": "€156",
|
||||||
|
"subtitle": "۱۸٪ صرفهجویی شده",
|
||||||
|
"avatarIcon": "tabler-bulb",
|
||||||
|
"avatarColor": "success",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "بازده سرمایه پلتفرم",
|
||||||
|
"value": "127%",
|
||||||
|
"subtitle": "نسبت به سال گذشته",
|
||||||
|
"avatarIcon": "tabler-chart-line",
|
||||||
|
"avatarColor": "info",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "پیشبینی درآمد",
|
||||||
|
"value": "€42k",
|
||||||
|
"subtitle": "این فصل",
|
||||||
|
"avatarIcon": "tabler-currency-euro",
|
||||||
|
"avatarColor": "success",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"chartSeries": [
|
||||||
|
{"name": "هزینه آب", "data": [120, 115, 110, 125, 118, 122]},
|
||||||
|
{"name": "کود", "data": [80, 85, 90, 75, 82, 78]},
|
||||||
|
],
|
||||||
|
"chartCategories": ["ژانویه", "فوریه", "مارس", "آوریل", "می", "ژوئن"],
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import uuid as uuid_lib
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
from farm_hub.models import FarmHub
|
||||||
|
|
||||||
|
|
||||||
|
class EconomicOverviewLog(models.Model):
|
||||||
|
uuid = models.UUIDField(default=uuid_lib.uuid4, unique=True, editable=False, db_index=True)
|
||||||
|
farm = models.ForeignKey(
|
||||||
|
FarmHub,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name="economic_overview_logs",
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
economic_data = models.JSONField(default=list, blank=True)
|
||||||
|
chart_series = models.JSONField(default=list, blank=True)
|
||||||
|
chart_categories = models.JSONField(default=list, blank=True)
|
||||||
|
fetched_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "economic_overview_logs"
|
||||||
|
ordering = ["-fetched_at"]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
farm_label = str(self.farm_id) if self.farm_id else "no-farm"
|
||||||
|
return f"{farm_label} — {self.fetched_at}"
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
|
||||||
|
class EconomicDataItemSerializer(serializers.Serializer):
|
||||||
|
title = serializers.CharField()
|
||||||
|
value = serializers.CharField()
|
||||||
|
subtitle = serializers.CharField()
|
||||||
|
avatarIcon = serializers.CharField()
|
||||||
|
avatarColor = serializers.CharField()
|
||||||
|
|
||||||
|
|
||||||
|
class ChartSeriesSerializer(serializers.Serializer):
|
||||||
|
name = serializers.CharField()
|
||||||
|
data = serializers.ListField(child=serializers.FloatField())
|
||||||
|
|
||||||
|
|
||||||
|
class EconomicOverviewSerializer(serializers.Serializer):
|
||||||
|
economicData = EconomicDataItemSerializer(many=True)
|
||||||
|
chartSeries = ChartSeriesSerializer(many=True)
|
||||||
|
chartCategories = serializers.ListField(child=serializers.CharField())
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from .views import EconomicOverviewView
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path("summary/", EconomicOverviewView.as_view(), name="economic-overview-summary"),
|
||||||
|
]
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
|
from .mock_data import ECONOMIC_OVERVIEW
|
||||||
|
from .serializers import EconomicOverviewSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class EconomicOverviewView(APIView):
|
||||||
|
def get(self, request):
|
||||||
|
serializer = EconomicOverviewSerializer(ECONOMIC_OVERVIEW)
|
||||||
|
return Response({"status": "success", "result": serializer.data})
|
||||||
@@ -600,5 +600,26 @@
|
|||||||
"status_code": 200,
|
"status_code": 200,
|
||||||
"description": "Task status failure",
|
"description": "Task status failure",
|
||||||
"file": "json/mock_data/tasks/status/get_200_failure.json"
|
"file": "json/mock_data/tasks/status/get_200_failure.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/pest-detection/risk-summary/",
|
||||||
|
"status_code": 200,
|
||||||
|
"description": "Pest and disease risk summary success",
|
||||||
|
"file": "json/ai/pest-detection/risk-summary/get_200_success.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/weather-forecast/card/",
|
||||||
|
"status_code": 200,
|
||||||
|
"description": "Farm weather card data",
|
||||||
|
"file": "json/ai/weather-forecast/card/get_200_success.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/api/yield-harvest/summary/",
|
||||||
|
"status_code": 200,
|
||||||
|
"description": "Yield prediction card, chart and harvest prediction card",
|
||||||
|
"file": "json/ai/yield-harvest/summary/get_200_success.json"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"service": "ai",
|
||||||
|
"path": "/pest-detection/risk-summary",
|
||||||
|
"result": {
|
||||||
|
"disease_risk": {
|
||||||
|
"id": "disease_risk",
|
||||||
|
"title": "ریسک بیماری",
|
||||||
|
"subtitle": "۷ روز اخیر",
|
||||||
|
"stats": "پایین",
|
||||||
|
"avatarColor": "success",
|
||||||
|
"avatarIcon": "tabler-bug",
|
||||||
|
"chipText": "5%",
|
||||||
|
"chipColor": "success",
|
||||||
|
"details": {
|
||||||
|
"risk_level": "low",
|
||||||
|
"risk_percentage": 5,
|
||||||
|
"detected_diseases": [],
|
||||||
|
"last_assessed_at": "2025-07-10T06:00:00Z",
|
||||||
|
"recommendation": "شرایط فعلی مناسب است. پایش هفتگی توصیه میشود."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pest_risk": {
|
||||||
|
"id": "pest_risk",
|
||||||
|
"title": "ریسک آفات",
|
||||||
|
"subtitle": "پیشبینی هوشمند",
|
||||||
|
"stats": "15%",
|
||||||
|
"avatarColor": "warning",
|
||||||
|
"avatarIcon": "tabler-bug-off",
|
||||||
|
"chipText": "تحت نظر",
|
||||||
|
"chipColor": "warning",
|
||||||
|
"details": {
|
||||||
|
"risk_level": "moderate",
|
||||||
|
"risk_percentage": 15,
|
||||||
|
"detected_pests": [
|
||||||
|
{
|
||||||
|
"name": "شپشک",
|
||||||
|
"confidence": 0.72,
|
||||||
|
"affected_area_percent": 8
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"last_assessed_at": "2025-07-10T06:00:00Z",
|
||||||
|
"recommendation": "بازرسی مزرعه هر ۳ روز یک بار انجام شود. در صورت افزایش، اسپری روغن نیم توصیه میشود."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"service": "ai",
|
||||||
|
"path": "/weather-forecast/card",
|
||||||
|
"result": {
|
||||||
|
"condition": "صاف",
|
||||||
|
"temperature": 24,
|
||||||
|
"unit": "°C",
|
||||||
|
"humidity": 45,
|
||||||
|
"windSpeed": 12,
|
||||||
|
"windUnit": "km/h",
|
||||||
|
"chartData": {
|
||||||
|
"labels": ["۶ صبح", "۹ صبح", "۱۲ ظهر", "۳ بعدازظهر", "۶ عصر", "۹ شب", "۱۲ شب"],
|
||||||
|
"series": [[18, 22, 26, 28, 25, 20, 18]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"status": "success",
|
||||||
|
"service": "ai",
|
||||||
|
"path": "/yield-harvest/summary",
|
||||||
|
"result": {
|
||||||
|
"yield_prediction_card": {
|
||||||
|
"id": "yield_prediction",
|
||||||
|
"title": "پیشبینی عملکرد",
|
||||||
|
"subtitle": "این فصل",
|
||||||
|
"stats": "42 تن",
|
||||||
|
"avatarColor": "secondary",
|
||||||
|
"avatarIcon": "tabler-chart-bar",
|
||||||
|
"chipText": "+8%",
|
||||||
|
"chipColor": "success"
|
||||||
|
},
|
||||||
|
"yield_prediction_chart": {
|
||||||
|
"categories": [
|
||||||
|
"ژانویه", "فوریه", "مارس", "آوریل", "می", "ژوئن",
|
||||||
|
"ژوئیه", "آگوست", "سپتامبر", "اکتبر", "نوامبر", "دسامبر"
|
||||||
|
],
|
||||||
|
"series": [
|
||||||
|
{"name": "امسال", "data": [35, 38, 40, 42, 45, 48, 50, 48, 46, 44, 42, 42]},
|
||||||
|
{"name": "سال گذشته", "data": [32, 34, 36, 38, 40, 42, 44, 42, 40, 38, 36, 38]}
|
||||||
|
],
|
||||||
|
"summary": [
|
||||||
|
{
|
||||||
|
"title": "عملکرد پیشبینیشده",
|
||||||
|
"subtitle": "این فصل",
|
||||||
|
"amount": "42 تن",
|
||||||
|
"avatarColor": "primary",
|
||||||
|
"avatarIcon": "tabler-chart-bar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "تاریخ برداشت",
|
||||||
|
"subtitle": "حدود ۱۵ اکتبر",
|
||||||
|
"amount": "+8%",
|
||||||
|
"avatarColor": "success",
|
||||||
|
"avatarIcon": "tabler-calendar"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"harvest_prediction_card": {
|
||||||
|
"date": "2025-10-15",
|
||||||
|
"dateFormatted": "۱۵ اکتبر ۲۰۲۵",
|
||||||
|
"daysUntil": 58,
|
||||||
|
"description": "بر اساس تجمع GDD فعلی و پیشبینی آب و هوا. بازه بهینه برداشت: ۱۲ تا ۱۸ اکتبر.",
|
||||||
|
"optimalWindowStart": "2025-10-12",
|
||||||
|
"optimalWindowEnd": "2025-10-18"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,7 +46,7 @@ class ContextView(FarmAccessMixin, APIView):
|
|||||||
@extend_schema(
|
@extend_schema(
|
||||||
tags=["Farm AI Assistant"],
|
tags=["Farm AI Assistant"],
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True),
|
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True, default="11111111-1111-1111-1111-111111111111"),
|
||||||
],
|
],
|
||||||
responses={200: status_response("FarmAiAssistantContextResponse", data=serializers.JSONField())},
|
responses={200: status_response("FarmAiAssistantContextResponse", data=serializers.JSONField())},
|
||||||
)
|
)
|
||||||
@@ -329,7 +329,7 @@ class ChatListCreateView(ConversationAccessMixin, APIView):
|
|||||||
@extend_schema(
|
@extend_schema(
|
||||||
tags=["Farm AI Assistant"],
|
tags=["Farm AI Assistant"],
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True),
|
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True, default="11111111-1111-1111-1111-111111111111"),
|
||||||
],
|
],
|
||||||
responses={200: status_response("FarmAiAssistantConversationListResponse", data=ConversationSummarySerializer(many=True))},
|
responses={200: status_response("FarmAiAssistantConversationListResponse", data=ConversationSummarySerializer(many=True))},
|
||||||
)
|
)
|
||||||
@@ -378,7 +378,7 @@ class ChatMessagesView(ConversationAccessMixin, APIView):
|
|||||||
tags=["Farm AI Assistant"],
|
tags=["Farm AI Assistant"],
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(name="conversation_id", type=OpenApiTypes.UUID, location=OpenApiParameter.PATH),
|
OpenApiParameter(name="conversation_id", type=OpenApiTypes.UUID, location=OpenApiParameter.PATH),
|
||||||
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True),
|
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True, default="11111111-1111-1111-1111-111111111111"),
|
||||||
],
|
],
|
||||||
responses={200: status_response("FarmAiAssistantMessageListResponse", data=ConversationMessagesSerializer())},
|
responses={200: status_response("FarmAiAssistantMessageListResponse", data=ConversationMessagesSerializer())},
|
||||||
)
|
)
|
||||||
@@ -407,7 +407,7 @@ class ChatDetailView(ConversationAccessMixin, APIView):
|
|||||||
tags=["Farm AI Assistant"],
|
tags=["Farm AI Assistant"],
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(name="conversation_id", type=OpenApiTypes.UUID, location=OpenApiParameter.PATH),
|
OpenApiParameter(name="conversation_id", type=OpenApiTypes.UUID, location=OpenApiParameter.PATH),
|
||||||
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True),
|
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True, default="11111111-1111-1111-1111-111111111111"),
|
||||||
],
|
],
|
||||||
responses={200: status_response("FarmAiAssistantConversationDeleteResponse", data=ConversationDeleteSerializer())},
|
responses={200: status_response("FarmAiAssistantConversationDeleteResponse", data=ConversationDeleteSerializer())},
|
||||||
)
|
)
|
||||||
@@ -578,7 +578,7 @@ class ChatTaskStatusView(ConversationAccessMixin, APIView):
|
|||||||
tags=["Farm AI Assistant"],
|
tags=["Farm AI Assistant"],
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(name="task_id", type=OpenApiTypes.STR, location=OpenApiParameter.PATH),
|
OpenApiParameter(name="task_id", type=OpenApiTypes.STR, location=OpenApiParameter.PATH),
|
||||||
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True),
|
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True, default="11111111-1111-1111-1111-111111111111"),
|
||||||
],
|
],
|
||||||
responses={200: status_response("FarmAiAssistantChatTaskStatusResponse", data=ChatTaskStatusDataSerializer())},
|
responses={200: status_response("FarmAiAssistantChatTaskStatusResponse", data=ChatTaskStatusDataSerializer())},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class FarmAlertsConfig(AppConfig):
|
||||||
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
|
name = "farm_alerts"
|
||||||
|
verbose_name = "Farm Alerts"
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import uuid
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("farm_hub", "0001_initial"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="FarmAlert",
|
||||||
|
fields=[
|
||||||
|
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||||
|
("uuid", models.UUIDField(default=uuid.uuid4, editable=False, unique=True, db_index=True)),
|
||||||
|
("farm", models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name="farm_alerts", to="farm_hub.farmhub")),
|
||||||
|
("title", models.CharField(max_length=255)),
|
||||||
|
("description", models.TextField(blank=True, default="")),
|
||||||
|
("color", models.CharField(default="info", max_length=32)),
|
||||||
|
("avatar_icon", models.CharField(blank=True, default="", max_length=64)),
|
||||||
|
("avatar_color", models.CharField(blank=True, default="", max_length=32)),
|
||||||
|
("is_active", models.BooleanField(default=True)),
|
||||||
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||||
|
],
|
||||||
|
options={"db_table": "farm_alerts", "ordering": ["-created_at"]},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="AnomalyDetection",
|
||||||
|
fields=[
|
||||||
|
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||||
|
("uuid", models.UUIDField(default=uuid.uuid4, editable=False, unique=True, db_index=True)),
|
||||||
|
("farm", models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name="anomalies", to="farm_hub.farmhub")),
|
||||||
|
("sensor", models.CharField(max_length=255)),
|
||||||
|
("value", models.CharField(max_length=64)),
|
||||||
|
("expected", models.CharField(max_length=64)),
|
||||||
|
("deviation", models.CharField(max_length=64)),
|
||||||
|
("severity", models.CharField(default="warning", max_length=32)),
|
||||||
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||||
|
],
|
||||||
|
options={"db_table": "farm_anomaly_detections", "ordering": ["-created_at"]},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Recommendation",
|
||||||
|
fields=[
|
||||||
|
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
|
||||||
|
("uuid", models.UUIDField(default=uuid.uuid4, editable=False, unique=True, db_index=True)),
|
||||||
|
("farm", models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name="recommendations", to="farm_hub.farmhub")),
|
||||||
|
("title", models.CharField(max_length=255)),
|
||||||
|
("subtitle", models.TextField(blank=True, default="")),
|
||||||
|
("avatar_icon", models.CharField(blank=True, default="", max_length=64)),
|
||||||
|
("avatar_color", models.CharField(blank=True, default="", max_length=32)),
|
||||||
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||||
|
],
|
||||||
|
options={"db_table": "farm_recommendations", "ordering": ["-created_at"]},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
ARM_ALERTS_TRACKER = {
|
||||||
|
"totalAlerts": 3,
|
||||||
|
"radialBarValue": 30,
|
||||||
|
"alertStats": [
|
||||||
|
{
|
||||||
|
"title": "کمبود آب",
|
||||||
|
"count": "2",
|
||||||
|
"avatarColor": "error",
|
||||||
|
"avatarIcon": "tabler-droplet-half-2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "ریسک قارچی",
|
||||||
|
"count": "1",
|
||||||
|
"avatarColor": "warning",
|
||||||
|
"avatarIcon": "tabler-mushroom",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "هشدار یخبندان",
|
||||||
|
"count": "0",
|
||||||
|
"avatarColor": "info",
|
||||||
|
"avatarIcon": "tabler-snowflake",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
FARM_ALERTS_TIMELINE = {
|
||||||
|
"alerts": [
|
||||||
|
{
|
||||||
|
"title": "ریسک کمبود آب",
|
||||||
|
"description": "رطوبت خاک در عمق ۱۰ سانتیمتر (۴۲٪) کمتر از حد بهینه است. پیشبینی: در صورت عدم آبیاری، تنش طی ۲ تا ۳ روز. توصیه: آبیاری ظرف ۲۴ ساعت.",
|
||||||
|
"time": "۱۵ دقیقه پیش",
|
||||||
|
"color": "warning",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "ریسک بیماری قارچی",
|
||||||
|
"description": "رطوبت بالا (۶۵٪) و دمای ۲۴ درجه شرایط مساعد برای رشد قارچ. استفاده از قارچکش پیشگیرانه یا کاهش آبیاری را در نظر بگیرید.",
|
||||||
|
"time": "۱ ساعت پیش",
|
||||||
|
"color": "error",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "پیشنهاد آبیاری",
|
||||||
|
"description": "بازه بهینه آبیاری: ۶:۰۰ تا ۸:۰۰ صبح. حجم پیشنهادی: ۴۵۰ مترمکعب برای زون آ. بهبود راندمان مورد انتظار: ۱۲٪.",
|
||||||
|
"time": "۲ ساعت پیش",
|
||||||
|
"color": "info",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "بررسی شوری خاک",
|
||||||
|
"description": "مقدار هدایت الکتریکی ۱/۲ dS/m در محدوده مجاز است. نیازی به اقدام نیست. بررسی بعدی توصیه میشود ظرف ۵ روز.",
|
||||||
|
"time": "۴ ساعت پیش",
|
||||||
|
"color": "success",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
ANOMALY_DETECTION_CARD = {
|
||||||
|
"anomalies": [
|
||||||
|
{
|
||||||
|
"sensor": "رطوبت خاک زون ۳",
|
||||||
|
"value": "38%",
|
||||||
|
"expected": "45-65%",
|
||||||
|
"deviation": "-12%",
|
||||||
|
"severity": "warning",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sensor": "pH بخش ۲",
|
||||||
|
"value": "5.2",
|
||||||
|
"expected": "6.0-7.0",
|
||||||
|
"deviation": "-0.8",
|
||||||
|
"severity": "error",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
RECOMMENDATIONS_LIST = {
|
||||||
|
"recommendations": [
|
||||||
|
{
|
||||||
|
"title": "آبیاری: ۶:۰۰ تا ۸:۰۰ صبح",
|
||||||
|
"subtitle": "۴۵۰ مترمکعب برای زون آ. بدون آبیاری، عملکرد ممکن است حدود ۸٪ کاهش یابد.",
|
||||||
|
"avatarIcon": "tabler-droplet",
|
||||||
|
"avatarColor": "primary",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "کود: NPK 20-20-20",
|
||||||
|
"subtitle": "اعمال ۲۵ کیلوگرم در هکتار ظرف ۷ روز. کمبود نیتروژن فعلی در بخش ۲.",
|
||||||
|
"avatarIcon": "tabler-leaf",
|
||||||
|
"avatarColor": "success",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "قارچکش: پیشگیرانه",
|
||||||
|
"subtitle": "رطوبت و دما مساعد قارچ. سمپاشی بر پایه مس را در نظر بگیرید.",
|
||||||
|
"avatarIcon": "tabler-mushroom",
|
||||||
|
"avatarColor": "warning",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "بازه برداشت: ۱۲ تا ۱۸ اکتبر",
|
||||||
|
"subtitle": "اوج رسیدگی حدود ۱۵ اکتبر. نیروی کار را متناسب برنامهریزی کنید.",
|
||||||
|
"avatarIcon": "tabler-calendar-event",
|
||||||
|
"avatarColor": "info",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import uuid as uuid_lib
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
from farm_hub.models import FarmHub
|
||||||
|
|
||||||
|
|
||||||
|
SEVERITY_CHOICES = [
|
||||||
|
("info", "Info"),
|
||||||
|
("warning", "Warning"),
|
||||||
|
("error", "Error"),
|
||||||
|
("success", "Success"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class FarmAlert(models.Model):
|
||||||
|
uuid = models.UUIDField(default=uuid_lib.uuid4, unique=True, editable=False, db_index=True)
|
||||||
|
farm = models.ForeignKey(FarmHub, on_delete=models.CASCADE, related_name="farm_alerts", null=True, blank=True)
|
||||||
|
title = models.CharField(max_length=255)
|
||||||
|
description = models.TextField(blank=True, default="")
|
||||||
|
color = models.CharField(max_length=32, default="info", choices=SEVERITY_CHOICES)
|
||||||
|
avatar_icon = models.CharField(max_length=64, blank=True, default="")
|
||||||
|
avatar_color = models.CharField(max_length=32, blank=True, default="")
|
||||||
|
is_active = models.BooleanField(default=True)
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "farm_alerts"
|
||||||
|
ordering = ["-created_at"]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.title} ({self.color})"
|
||||||
|
|
||||||
|
|
||||||
|
class AnomalyDetection(models.Model):
|
||||||
|
uuid = models.UUIDField(default=uuid_lib.uuid4, unique=True, editable=False, db_index=True)
|
||||||
|
farm = models.ForeignKey(FarmHub, on_delete=models.CASCADE, related_name="anomalies", null=True, blank=True)
|
||||||
|
sensor = models.CharField(max_length=255)
|
||||||
|
value = models.CharField(max_length=64)
|
||||||
|
expected = models.CharField(max_length=64)
|
||||||
|
deviation = models.CharField(max_length=64)
|
||||||
|
severity = models.CharField(max_length=32, default="warning", choices=SEVERITY_CHOICES)
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "farm_anomaly_detections"
|
||||||
|
ordering = ["-created_at"]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.sensor}: {self.value}"
|
||||||
|
|
||||||
|
|
||||||
|
class Recommendation(models.Model):
|
||||||
|
uuid = models.UUIDField(default=uuid_lib.uuid4, unique=True, editable=False, db_index=True)
|
||||||
|
farm = models.ForeignKey(FarmHub, on_delete=models.CASCADE, related_name="recommendations", null=True, blank=True)
|
||||||
|
title = models.CharField(max_length=255)
|
||||||
|
subtitle = models.TextField(blank=True, default="")
|
||||||
|
avatar_icon = models.CharField(max_length=64, blank=True, default="")
|
||||||
|
avatar_color = models.CharField(max_length=32, blank=True, default="")
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "farm_recommendations"
|
||||||
|
ordering = ["-created_at"]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.title
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
|
||||||
|
class AlertStatSerializer(serializers.Serializer):
|
||||||
|
title = serializers.CharField()
|
||||||
|
count = serializers.CharField()
|
||||||
|
avatarColor = serializers.CharField()
|
||||||
|
avatarIcon = serializers.CharField()
|
||||||
|
|
||||||
|
|
||||||
|
class AlertTrackerSerializer(serializers.Serializer):
|
||||||
|
totalAlerts = serializers.IntegerField()
|
||||||
|
radialBarValue = serializers.IntegerField()
|
||||||
|
alertStats = AlertStatSerializer(many=True)
|
||||||
|
|
||||||
|
|
||||||
|
class AlertTimelineItemSerializer(serializers.Serializer):
|
||||||
|
title = serializers.CharField()
|
||||||
|
description = serializers.CharField()
|
||||||
|
time = serializers.CharField()
|
||||||
|
color = serializers.CharField()
|
||||||
|
|
||||||
|
|
||||||
|
class AlertTimelineSerializer(serializers.Serializer):
|
||||||
|
alerts = AlertTimelineItemSerializer(many=True)
|
||||||
|
|
||||||
|
|
||||||
|
class AnomalyItemSerializer(serializers.Serializer):
|
||||||
|
sensor = serializers.CharField()
|
||||||
|
value = serializers.CharField()
|
||||||
|
expected = serializers.CharField()
|
||||||
|
deviation = serializers.CharField()
|
||||||
|
severity = serializers.CharField()
|
||||||
|
|
||||||
|
|
||||||
|
class AnomalyDetectionSerializer(serializers.Serializer):
|
||||||
|
anomalies = AnomalyItemSerializer(many=True)
|
||||||
|
|
||||||
|
|
||||||
|
class RecommendationItemSerializer(serializers.Serializer):
|
||||||
|
title = serializers.CharField()
|
||||||
|
subtitle = serializers.CharField()
|
||||||
|
avatarIcon = serializers.CharField()
|
||||||
|
avatarColor = serializers.CharField()
|
||||||
|
|
||||||
|
|
||||||
|
class RecommendationsListSerializer(serializers.Serializer):
|
||||||
|
recommendations = RecommendationItemSerializer(many=True)
|
||||||
|
|
||||||
|
|
||||||
|
class CreateAlertSerializer(serializers.Serializer):
|
||||||
|
farm_uuid = serializers.UUIDField(required=False, allow_null=True)
|
||||||
|
title = serializers.CharField(max_length=255)
|
||||||
|
description = serializers.CharField(required=False, default="", allow_blank=True)
|
||||||
|
color = serializers.ChoiceField(choices=["info", "warning", "error", "success"], default="info")
|
||||||
|
avatar_icon = serializers.CharField(required=False, default="", allow_blank=True)
|
||||||
|
avatar_color = serializers.CharField(required=False, default="", allow_blank=True)
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
from farm_hub.models import FarmHub
|
||||||
|
from notifications.models import FarmNotification
|
||||||
|
|
||||||
|
from .models import FarmAlert
|
||||||
|
|
||||||
|
|
||||||
|
class AlertService:
|
||||||
|
@staticmethod
|
||||||
|
def create_alert(
|
||||||
|
title: str,
|
||||||
|
description: str = "",
|
||||||
|
color: str = "info",
|
||||||
|
avatar_icon: str = "",
|
||||||
|
avatar_color: str = "",
|
||||||
|
farm_uuid=None,
|
||||||
|
) -> FarmAlert:
|
||||||
|
farm = None
|
||||||
|
if farm_uuid:
|
||||||
|
try:
|
||||||
|
farm = FarmHub.objects.get(uuid=farm_uuid)
|
||||||
|
except FarmHub.DoesNotExist:
|
||||||
|
pass
|
||||||
|
|
||||||
|
alert = FarmAlert.objects.create(
|
||||||
|
farm=farm,
|
||||||
|
title=title,
|
||||||
|
description=description,
|
||||||
|
color=color,
|
||||||
|
avatar_icon=avatar_icon,
|
||||||
|
avatar_color=avatar_color,
|
||||||
|
)
|
||||||
|
|
||||||
|
AlertService._send_notification(alert, farm)
|
||||||
|
return alert
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _send_notification(alert: FarmAlert, farm) -> None:
|
||||||
|
if farm is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
level_map = {"error": "error", "warning": "warning", "info": "info", "success": "success"}
|
||||||
|
|
||||||
|
FarmNotification.objects.create(
|
||||||
|
farm=farm,
|
||||||
|
title=alert.title,
|
||||||
|
message=alert.description,
|
||||||
|
level=level_map.get(alert.color, "info"),
|
||||||
|
metadata={"alert_uuid": str(alert.uuid), "color": alert.color},
|
||||||
|
)
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from .views import (
|
||||||
|
AlertTrackerView,
|
||||||
|
AlertTimelineView,
|
||||||
|
AnomalyDetectionView,
|
||||||
|
RecommendationsListView,
|
||||||
|
CreateAlertView,
|
||||||
|
)
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path("tracker/", AlertTrackerView.as_view(), name="farm-alerts-tracker"),
|
||||||
|
path("timeline/", AlertTimelineView.as_view(), name="farm-alerts-timeline"),
|
||||||
|
path("anomalies/", AnomalyDetectionView.as_view(), name="farm-alerts-anomalies"),
|
||||||
|
path("recommendations/", RecommendationsListView.as_view(), name="farm-alerts-recommendations"),
|
||||||
|
path("create/", CreateAlertView.as_view(), name="farm-alerts-create"),
|
||||||
|
]
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
from rest_framework import status
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
|
from farm_hub.models import FarmHub
|
||||||
|
|
||||||
|
from .mock_data import (
|
||||||
|
ANOMALY_DETECTION_CARD,
|
||||||
|
ARM_ALERTS_TRACKER,
|
||||||
|
FARM_ALERTS_TIMELINE,
|
||||||
|
RECOMMENDATIONS_LIST,
|
||||||
|
)
|
||||||
|
from .serializers import (
|
||||||
|
AlertTimelineSerializer,
|
||||||
|
AlertTrackerSerializer,
|
||||||
|
AnomalyDetectionSerializer,
|
||||||
|
CreateAlertSerializer,
|
||||||
|
RecommendationsListSerializer,
|
||||||
|
)
|
||||||
|
from .services import AlertService
|
||||||
|
|
||||||
|
|
||||||
|
class AlertTrackerView(APIView):
|
||||||
|
def get(self, request):
|
||||||
|
serializer = AlertTrackerSerializer(ARM_ALERTS_TRACKER)
|
||||||
|
return Response({"status": "success", "result": serializer.data})
|
||||||
|
|
||||||
|
|
||||||
|
class AlertTimelineView(APIView):
|
||||||
|
def get(self, request):
|
||||||
|
serializer = AlertTimelineSerializer(FARM_ALERTS_TIMELINE)
|
||||||
|
return Response({"status": "success", "result": serializer.data})
|
||||||
|
|
||||||
|
|
||||||
|
class AnomalyDetectionView(APIView):
|
||||||
|
def get(self, request):
|
||||||
|
serializer = AnomalyDetectionSerializer(ANOMALY_DETECTION_CARD)
|
||||||
|
return Response({"status": "success", "result": serializer.data})
|
||||||
|
|
||||||
|
|
||||||
|
class RecommendationsListView(APIView):
|
||||||
|
def get(self, request):
|
||||||
|
serializer = RecommendationsListSerializer(RECOMMENDATIONS_LIST)
|
||||||
|
return Response({"status": "success", "result": serializer.data})
|
||||||
|
|
||||||
|
|
||||||
|
class CreateAlertView(APIView):
|
||||||
|
def post(self, request):
|
||||||
|
serializer = CreateAlertSerializer(data=request.data)
|
||||||
|
if not serializer.is_valid():
|
||||||
|
return Response(
|
||||||
|
{"status": "error", "errors": serializer.errors},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
|
)
|
||||||
|
|
||||||
|
data = serializer.validated_data
|
||||||
|
farm = None
|
||||||
|
farm_uuid = data.get("farm_uuid")
|
||||||
|
if farm_uuid:
|
||||||
|
try:
|
||||||
|
farm = FarmHub.objects.get(uuid=farm_uuid)
|
||||||
|
except FarmHub.DoesNotExist:
|
||||||
|
return Response(
|
||||||
|
{"status": "error", "message": "farm not found"},
|
||||||
|
status=status.HTTP_404_NOT_FOUND,
|
||||||
|
)
|
||||||
|
|
||||||
|
alert = AlertService.create_alert(
|
||||||
|
title=data["title"],
|
||||||
|
description=data.get("description", ""),
|
||||||
|
color=data.get("color", "info"),
|
||||||
|
avatar_icon=data.get("avatar_icon", ""),
|
||||||
|
avatar_color=data.get("avatar_color", ""),
|
||||||
|
farm=farm,
|
||||||
|
)
|
||||||
|
|
||||||
|
return Response(
|
||||||
|
{"status": "success", "result": {"uuid": str(alert.uuid), "title": alert.title}},
|
||||||
|
status=status.HTTP_201_CREATED,
|
||||||
|
)
|
||||||
+10
-1
@@ -3,7 +3,7 @@ from rest_framework import serializers, status
|
|||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from drf_spectacular.utils import extend_schema
|
from drf_spectacular.utils import OpenApiParameter, OpenApiTypes, extend_schema
|
||||||
|
|
||||||
from config.swagger import code_response
|
from config.swagger import code_response
|
||||||
from .models import FarmHub, FarmType, Product
|
from .models import FarmHub, FarmType, Product
|
||||||
@@ -105,6 +105,9 @@ class FarmTypeProductsView(FarmHubBaseView):
|
|||||||
class FarmDetailView(FarmHubBaseView):
|
class FarmDetailView(FarmHubBaseView):
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
tags=["Farm Hub"],
|
tags=["Farm Hub"],
|
||||||
|
parameters=[
|
||||||
|
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.PATH, default="11111111-1111-1111-1111-111111111111"),
|
||||||
|
],
|
||||||
responses={
|
responses={
|
||||||
200: code_response("FarmDetailResponse", data=FarmHubSerializer()),
|
200: code_response("FarmDetailResponse", data=FarmHubSerializer()),
|
||||||
404: code_response("FarmNotFoundResponse"),
|
404: code_response("FarmNotFoundResponse"),
|
||||||
@@ -119,6 +122,9 @@ class FarmDetailView(FarmHubBaseView):
|
|||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
tags=["Farm Hub"],
|
tags=["Farm Hub"],
|
||||||
|
parameters=[
|
||||||
|
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.PATH, default="11111111-1111-1111-1111-111111111111"),
|
||||||
|
],
|
||||||
request=FarmHubCreateSerializer,
|
request=FarmHubCreateSerializer,
|
||||||
responses={
|
responses={
|
||||||
200: code_response("FarmUpdateResponse", data=FarmHubSerializer()),
|
200: code_response("FarmUpdateResponse", data=FarmHubSerializer()),
|
||||||
@@ -138,6 +144,9 @@ class FarmDetailView(FarmHubBaseView):
|
|||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
tags=["Farm Hub"],
|
tags=["Farm Hub"],
|
||||||
|
parameters=[
|
||||||
|
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.PATH, default="11111111-1111-1111-1111-111111111111"),
|
||||||
|
],
|
||||||
responses={
|
responses={
|
||||||
200: code_response("FarmDeleteResponse"),
|
200: code_response("FarmDeleteResponse"),
|
||||||
404: code_response("FarmDeleteNotFoundResponse"),
|
404: code_response("FarmDeleteNotFoundResponse"),
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class ConfigView(FarmAccessMixin, APIView):
|
|||||||
@extend_schema(
|
@extend_schema(
|
||||||
tags=["Fertilization Recommendation"],
|
tags=["Fertilization Recommendation"],
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True),
|
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True, default="11111111-1111-1111-1111-111111111111"),
|
||||||
],
|
],
|
||||||
responses={200: status_response("FertilizationConfigResponse", data=serializers.JSONField())},
|
responses={200: status_response("FertilizationConfigResponse", data=serializers.JSONField())},
|
||||||
)
|
)
|
||||||
@@ -85,7 +85,7 @@ class RecommendTaskStatusView(FarmAccessMixin, APIView):
|
|||||||
tags=["Fertilization Recommendation"],
|
tags=["Fertilization Recommendation"],
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(name="task_id", type=OpenApiTypes.STR, location=OpenApiParameter.PATH),
|
OpenApiParameter(name="task_id", type=OpenApiTypes.STR, location=OpenApiParameter.PATH),
|
||||||
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True),
|
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True, default="11111111-1111-1111-1111-111111111111"),
|
||||||
],
|
],
|
||||||
responses={200: status_response("FertilizationRecommendTaskStatusResponse", data=FertilizationTaskStatusDataSerializer())},
|
responses={200: status_response("FertilizationRecommendTaskStatusResponse", data=FertilizationTaskStatusDataSerializer())},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class ConfigView(FarmAccessMixin, APIView):
|
|||||||
@extend_schema(
|
@extend_schema(
|
||||||
tags=["Irrigation Recommendation"],
|
tags=["Irrigation Recommendation"],
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True),
|
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True, default="11111111-1111-1111-1111-111111111111"),
|
||||||
],
|
],
|
||||||
responses={200: status_response("IrrigationConfigResponse", data=serializers.JSONField())},
|
responses={200: status_response("IrrigationConfigResponse", data=serializers.JSONField())},
|
||||||
)
|
)
|
||||||
@@ -116,7 +116,7 @@ class RecommendTaskStatusView(FarmAccessMixin, APIView):
|
|||||||
tags=["Irrigation Recommendation"],
|
tags=["Irrigation Recommendation"],
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(name="task_id", type=OpenApiTypes.STR, location=OpenApiParameter.PATH),
|
OpenApiParameter(name="task_id", type=OpenApiTypes.STR, location=OpenApiParameter.PATH),
|
||||||
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True),
|
OpenApiParameter(name="farm_uuid", type=OpenApiTypes.UUID, location=OpenApiParameter.QUERY, required=True, default="11111111-1111-1111-1111-111111111111"),
|
||||||
],
|
],
|
||||||
responses={200: status_response("IrrigationRecommendTaskStatusResponse", data=IrrigationTaskStatusDataSerializer())},
|
responses={200: status_response("IrrigationRecommendTaskStatusResponse", data=IrrigationTaskStatusDataSerializer())},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 202,
|
|
||||||
"msg": "dashboard task queued",
|
|
||||||
"data": {
|
|
||||||
"task_id": "dashboard-task-123",
|
|
||||||
"status_url": "/api/dashboard-data/dashboard-task-123/status/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"msg": "پارامتر sensor_id الزامی است.",
|
|
||||||
"data": null
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "dashboard-task-123",
|
|
||||||
"status": "FAILURE",
|
|
||||||
"error": "خطا در ساخت کارتهای داشبورد."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "dashboard-task-123",
|
|
||||||
"status": "PENDING",
|
|
||||||
"message": "تسک در صف یا یافت نشد."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "dashboard-task-123",
|
|
||||||
"status": "PROGRESS",
|
|
||||||
"progress": {
|
|
||||||
"current": 5,
|
|
||||||
"total": 15,
|
|
||||||
"card": "sensorValuesList",
|
|
||||||
"message": "processing sensorValuesList"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,611 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "dashboard-task-123",
|
|
||||||
"status": "SUCCESS",
|
|
||||||
"result": {
|
|
||||||
"sensor_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
||||||
"all_cards": {
|
|
||||||
"farmOverviewKpis": {
|
|
||||||
"kpis": [
|
|
||||||
{
|
|
||||||
"id": "farm_health_score",
|
|
||||||
"title": "امتیاز سلامت مزرعه",
|
|
||||||
"subtitle": "تحلیل هوشمند",
|
|
||||||
"stats": "87%",
|
|
||||||
"avatarColor": "success",
|
|
||||||
"avatarIcon": "tabler-heartbeat",
|
|
||||||
"chipText": "خوب",
|
|
||||||
"chipColor": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "water_stress_index",
|
|
||||||
"title": "شاخص تنش آبی",
|
|
||||||
"subtitle": "فعلی",
|
|
||||||
"stats": "12%",
|
|
||||||
"avatarColor": "info",
|
|
||||||
"avatarIcon": "tabler-droplet",
|
|
||||||
"chipText": "پایین",
|
|
||||||
"chipColor": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "disease_risk",
|
|
||||||
"title": "ریسک بیماری",
|
|
||||||
"subtitle": "۷ روز اخیر",
|
|
||||||
"stats": "پایین",
|
|
||||||
"avatarColor": "success",
|
|
||||||
"avatarIcon": "tabler-bug",
|
|
||||||
"chipText": "5%",
|
|
||||||
"chipColor": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "avg_soil_moisture",
|
|
||||||
"title": "میانگین رطوبت خاک",
|
|
||||||
"subtitle": "کل مزرعه",
|
|
||||||
"stats": "65%",
|
|
||||||
"avatarColor": "primary",
|
|
||||||
"avatarIcon": "tabler-plant-2",
|
|
||||||
"chipText": "بهینه",
|
|
||||||
"chipColor": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "yield_prediction",
|
|
||||||
"title": "پیشبینی عملکرد",
|
|
||||||
"subtitle": "این فصل",
|
|
||||||
"stats": "42 تن",
|
|
||||||
"avatarColor": "secondary",
|
|
||||||
"avatarIcon": "tabler-chart-bar",
|
|
||||||
"chipText": "+8%",
|
|
||||||
"chipColor": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "pest_risk",
|
|
||||||
"title": "ریسک آفات",
|
|
||||||
"subtitle": "پیشبینی هوشمند",
|
|
||||||
"stats": "15%",
|
|
||||||
"avatarColor": "warning",
|
|
||||||
"avatarIcon": "tabler-bug-off",
|
|
||||||
"chipText": "تحت نظر",
|
|
||||||
"chipColor": "warning"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"farmWeatherCard": {
|
|
||||||
"condition": "صاف",
|
|
||||||
"temperature": 24,
|
|
||||||
"unit": "°C",
|
|
||||||
"humidity": 45,
|
|
||||||
"windSpeed": 12,
|
|
||||||
"windUnit": "km/h",
|
|
||||||
"chartData": {
|
|
||||||
"labels": [
|
|
||||||
"۶ صبح",
|
|
||||||
"۹ صبح",
|
|
||||||
"۱۲ ظهر",
|
|
||||||
"۳ بعدازظهر",
|
|
||||||
"۶ عصر",
|
|
||||||
"۹ شب",
|
|
||||||
"۱۲ شب"
|
|
||||||
],
|
|
||||||
"series": [
|
|
||||||
[
|
|
||||||
18,
|
|
||||||
22,
|
|
||||||
26,
|
|
||||||
28,
|
|
||||||
25,
|
|
||||||
20,
|
|
||||||
18
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"farmAlertsTracker": {
|
|
||||||
"totalAlerts": 3,
|
|
||||||
"radialBarValue": 30,
|
|
||||||
"alertStats": [
|
|
||||||
{
|
|
||||||
"title": "کمبود آب",
|
|
||||||
"count": "2",
|
|
||||||
"avatarColor": "error",
|
|
||||||
"avatarIcon": "tabler-droplet-half-2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "ریسک قارچی",
|
|
||||||
"count": "1",
|
|
||||||
"avatarColor": "warning",
|
|
||||||
"avatarIcon": "tabler-mushroom"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "هشدار یخبندان",
|
|
||||||
"count": "0",
|
|
||||||
"avatarColor": "info",
|
|
||||||
"avatarIcon": "tabler-snowflake"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sensorValuesList": {
|
|
||||||
"sensors": [
|
|
||||||
{
|
|
||||||
"title": "28°C",
|
|
||||||
"subtitle": "دمای هوا",
|
|
||||||
"trendNumber": 2.1,
|
|
||||||
"trend": "positive",
|
|
||||||
"unit": "°C"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "24°C",
|
|
||||||
"subtitle": "دمای خاک",
|
|
||||||
"trendNumber": -0.5,
|
|
||||||
"trend": "negative",
|
|
||||||
"unit": "°C"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "65%",
|
|
||||||
"subtitle": "رطوبت هوا",
|
|
||||||
"trendNumber": 3.2,
|
|
||||||
"trend": "positive",
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "42%",
|
|
||||||
"subtitle": "رطوبت خاک (۱۰ سانتیمتر)",
|
|
||||||
"trendNumber": -1.8,
|
|
||||||
"trend": "negative",
|
|
||||||
"unit": "%"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "6.8",
|
|
||||||
"subtitle": "pH خاک",
|
|
||||||
"trendNumber": 0.2,
|
|
||||||
"trend": "positive",
|
|
||||||
"unit": "pH"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "1.2",
|
|
||||||
"subtitle": "هدایت الکتریکی (dS/m)",
|
|
||||||
"trendNumber": 0.1,
|
|
||||||
"trend": "positive",
|
|
||||||
"unit": "dS/m"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "850",
|
|
||||||
"subtitle": "شدت نور (لوکس)",
|
|
||||||
"trendNumber": 15.3,
|
|
||||||
"trend": "positive",
|
|
||||||
"unit": "lux"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "12",
|
|
||||||
"subtitle": "سرعت باد (کیلومتر/ساعت)",
|
|
||||||
"trendNumber": -2.4,
|
|
||||||
"trend": "negative",
|
|
||||||
"unit": "km/h"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sensorRadarChart": {
|
|
||||||
"labels": [
|
|
||||||
"دما",
|
|
||||||
"رطوبت",
|
|
||||||
"pH",
|
|
||||||
"هدایت الکتریکی",
|
|
||||||
"نور",
|
|
||||||
"باد"
|
|
||||||
],
|
|
||||||
"series": [
|
|
||||||
{
|
|
||||||
"name": "امروز",
|
|
||||||
"data": [
|
|
||||||
75,
|
|
||||||
65,
|
|
||||||
80,
|
|
||||||
70,
|
|
||||||
85,
|
|
||||||
60
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ایدهآل",
|
|
||||||
"data": [
|
|
||||||
80,
|
|
||||||
70,
|
|
||||||
75,
|
|
||||||
75,
|
|
||||||
90,
|
|
||||||
50
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sensorComparisonChart": {
|
|
||||||
"currentValue": 48,
|
|
||||||
"vsLastWeek": "+5%",
|
|
||||||
"vsLastWeekValue": 5,
|
|
||||||
"categories": [
|
|
||||||
"دوشنبه",
|
|
||||||
"سهشنبه",
|
|
||||||
"چهارشنبه",
|
|
||||||
"پنجشنبه",
|
|
||||||
"جمعه",
|
|
||||||
"شنبه",
|
|
||||||
"یکشنبه"
|
|
||||||
],
|
|
||||||
"series": [
|
|
||||||
{
|
|
||||||
"name": "امروز",
|
|
||||||
"data": [
|
|
||||||
42,
|
|
||||||
45,
|
|
||||||
48,
|
|
||||||
52,
|
|
||||||
50,
|
|
||||||
48,
|
|
||||||
46
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "هفته قبل",
|
|
||||||
"data": [
|
|
||||||
38,
|
|
||||||
40,
|
|
||||||
42,
|
|
||||||
45,
|
|
||||||
43,
|
|
||||||
40,
|
|
||||||
38
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"anomalyDetectionCard": {
|
|
||||||
"anomalies": [
|
|
||||||
{
|
|
||||||
"sensor": "رطوبت خاک زون ۳",
|
|
||||||
"value": "38%",
|
|
||||||
"expected": "45-65%",
|
|
||||||
"deviation": "-12%",
|
|
||||||
"severity": "warning"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"sensor": "pH بخش ۲",
|
|
||||||
"value": "5.2",
|
|
||||||
"expected": "6.0-7.0",
|
|
||||||
"deviation": "-0.8",
|
|
||||||
"severity": "error"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"farmAlertsTimeline": {
|
|
||||||
"alerts": [
|
|
||||||
{
|
|
||||||
"title": "ریسک کمبود آب",
|
|
||||||
"description": "رطوبت خاک در عمق ۱۰ سانتیمتر (۴۲٪) کمتر از حد بهینه است. پیشبینی: در صورت عدم آبیاری، تنش طی ۲ تا ۳ روز. توصیه: آبیاری ظرف ۲۴ ساعت.",
|
|
||||||
"time": "۱۵ دقیقه پیش",
|
|
||||||
"color": "warning"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "ریسک بیماری قارچی",
|
|
||||||
"description": "رطوبت بالا (۶۵٪) و دمای ۲۴ درجه شرایط مساعد برای رشد قارچ. استفاده از قارچکش پیشگیرانه یا کاهش آبیاری را در نظر بگیرید.",
|
|
||||||
"time": "۱ ساعت پیش",
|
|
||||||
"color": "error"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "پیشنهاد آبیاری",
|
|
||||||
"description": "بازه بهینه آبیاری: ۶:۰۰ تا ۸:۰۰ صبح. حجم پیشنهادی: ۴۵۰ مترمکعب برای زون آ. بهبود راندمان مورد انتظار: ۱۲٪.",
|
|
||||||
"time": "۲ ساعت پیش",
|
|
||||||
"color": "info"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "بررسی شوری خاک",
|
|
||||||
"description": "مقدار هدایت الکتریکی ۱/۲ dS/m در محدوده مجاز است. نیازی به اقدام نیست. بررسی بعدی توصیه میشود ظرف ۵ روز.",
|
|
||||||
"time": "۴ ساعت پیش",
|
|
||||||
"color": "success"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"waterNeedPrediction": {
|
|
||||||
"totalNext7Days": 3290,
|
|
||||||
"unit": "m³",
|
|
||||||
"categories": [
|
|
||||||
"روز ۱",
|
|
||||||
"روز ۲",
|
|
||||||
"روز ۳",
|
|
||||||
"روز ۴",
|
|
||||||
"روز ۵",
|
|
||||||
"روز ۶",
|
|
||||||
"روز ۷"
|
|
||||||
],
|
|
||||||
"series": [
|
|
||||||
{
|
|
||||||
"name": "نیاز آبی",
|
|
||||||
"data": [
|
|
||||||
420,
|
|
||||||
450,
|
|
||||||
480,
|
|
||||||
460,
|
|
||||||
490,
|
|
||||||
510,
|
|
||||||
480
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"harvestPredictionCard": {
|
|
||||||
"date": "2025-10-15",
|
|
||||||
"dateFormatted": "۱۵ اکتبر ۲۰۲۵",
|
|
||||||
"daysUntil": 58,
|
|
||||||
"description": "بر اساس تجمع GDD فعلی و پیشبینی آب و هوا. بازه بهینه برداشت: ۱۲ تا ۱۸ اکتبر.",
|
|
||||||
"optimalWindowStart": "2025-10-12",
|
|
||||||
"optimalWindowEnd": "2025-10-18"
|
|
||||||
},
|
|
||||||
"yieldPredictionChart": {
|
|
||||||
"categories": [
|
|
||||||
"ژانویه",
|
|
||||||
"فوریه",
|
|
||||||
"مارس",
|
|
||||||
"آوریل",
|
|
||||||
"می",
|
|
||||||
"ژوئن",
|
|
||||||
"ژوئیه",
|
|
||||||
"آگوست",
|
|
||||||
"سپتامبر",
|
|
||||||
"اکتبر",
|
|
||||||
"نوامبر",
|
|
||||||
"دسامبر"
|
|
||||||
],
|
|
||||||
"series": [
|
|
||||||
{
|
|
||||||
"name": "امسال",
|
|
||||||
"data": [
|
|
||||||
35,
|
|
||||||
38,
|
|
||||||
40,
|
|
||||||
42,
|
|
||||||
45,
|
|
||||||
48,
|
|
||||||
50,
|
|
||||||
48,
|
|
||||||
46,
|
|
||||||
44,
|
|
||||||
42,
|
|
||||||
42
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "سال گذشته",
|
|
||||||
"data": [
|
|
||||||
32,
|
|
||||||
34,
|
|
||||||
36,
|
|
||||||
38,
|
|
||||||
40,
|
|
||||||
42,
|
|
||||||
44,
|
|
||||||
42,
|
|
||||||
40,
|
|
||||||
38,
|
|
||||||
36,
|
|
||||||
38
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"summary": [
|
|
||||||
{
|
|
||||||
"title": "عملکرد پیشبینیشده",
|
|
||||||
"subtitle": "این فصل",
|
|
||||||
"amount": "42 تن",
|
|
||||||
"avatarColor": "primary",
|
|
||||||
"avatarIcon": "tabler-chart-bar"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "تاریخ برداشت",
|
|
||||||
"subtitle": "حدود ۱۵ اکتبر",
|
|
||||||
"amount": "+8%",
|
|
||||||
"avatarColor": "success",
|
|
||||||
"avatarIcon": "tabler-calendar"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"soilMoistureHeatmap": {
|
|
||||||
"zones": [
|
|
||||||
"زون ۱",
|
|
||||||
"زون ۲",
|
|
||||||
"زون ۳",
|
|
||||||
"زون ۴",
|
|
||||||
"زون ۵",
|
|
||||||
"زون ۶",
|
|
||||||
"زون ۷"
|
|
||||||
],
|
|
||||||
"hours": [
|
|
||||||
"۶ ص",
|
|
||||||
"۸ ص",
|
|
||||||
"۱۰ ص",
|
|
||||||
"۱۲ ظ",
|
|
||||||
"۱۴ ع",
|
|
||||||
"۱۶ ع",
|
|
||||||
"۱۸ ع"
|
|
||||||
],
|
|
||||||
"series": [
|
|
||||||
{
|
|
||||||
"name": "زون ۱",
|
|
||||||
"data": [
|
|
||||||
{
|
|
||||||
"x": "۶ ص",
|
|
||||||
"y": 52
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x": "۸ ص",
|
|
||||||
"y": 48
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x": "۱۰ ص",
|
|
||||||
"y": 55
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x": "۱۲ ظ",
|
|
||||||
"y": 60
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x": "۱۴ ع",
|
|
||||||
"y": 58
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x": "۱۶ ع",
|
|
||||||
"y": 54
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x": "۱۸ ع",
|
|
||||||
"y": 50
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "زون ۲",
|
|
||||||
"data": [
|
|
||||||
{
|
|
||||||
"x": "۶ ص",
|
|
||||||
"y": 45
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x": "۸ ص",
|
|
||||||
"y": 42
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x": "۱۰ ص",
|
|
||||||
"y": 48
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x": "۱۲ ظ",
|
|
||||||
"y": 52
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x": "۱۴ ع",
|
|
||||||
"y": 50
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x": "۱۶ ع",
|
|
||||||
"y": 47
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"x": "۱۸ ع",
|
|
||||||
"y": 44
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ndviHealthCard": {
|
|
||||||
"ndviIndex": 0.78,
|
|
||||||
"healthData": [
|
|
||||||
{
|
|
||||||
"title": "تنش نیتروژن",
|
|
||||||
"value": "پایین",
|
|
||||||
"color": "success",
|
|
||||||
"icon": "tabler-leaf"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "سلامت محصول",
|
|
||||||
"value": "خوب",
|
|
||||||
"color": "success",
|
|
||||||
"icon": "tabler-plant"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"recommendationsList": {
|
|
||||||
"recommendations": [
|
|
||||||
{
|
|
||||||
"title": "آبیاری: ۶:۰۰ تا ۸:۰۰ صبح",
|
|
||||||
"subtitle": "۴۵۰ مترمکعب برای زون آ. بدون آبیاری، عملکرد ممکن است حدود ۸٪ کاهش یابد.",
|
|
||||||
"avatarIcon": "tabler-droplet",
|
|
||||||
"avatarColor": "primary"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "کود: NPK 20-20-20",
|
|
||||||
"subtitle": "اعمال ۲۵ کیلوگرم در هکتار ظرف ۷ روز. کمبود نیتروژن فعلی در بخش ۲.",
|
|
||||||
"avatarIcon": "tabler-leaf",
|
|
||||||
"avatarColor": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "قارچکش: پیشگیرانه",
|
|
||||||
"subtitle": "رطوبت و دما مساعد قارچ. سمپاشی بر پایه مس را در نظر بگیرید.",
|
|
||||||
"avatarIcon": "tabler-mushroom",
|
|
||||||
"avatarColor": "warning"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "بازه برداشت: ۱۲ تا ۱۸ اکتبر",
|
|
||||||
"subtitle": "اوج رسیدگی حدود ۱۵ اکتبر. نیروی کار را متناسب برنامهریزی کنید.",
|
|
||||||
"avatarIcon": "tabler-calendar-event",
|
|
||||||
"avatarColor": "info"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"economicOverview": {
|
|
||||||
"economicData": [
|
|
||||||
{
|
|
||||||
"title": "هزینه آب",
|
|
||||||
"value": "€720",
|
|
||||||
"subtitle": "این ماه",
|
|
||||||
"avatarIcon": "tabler-droplet",
|
|
||||||
"avatarColor": "primary"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "صرفهجویی آب هوشمند",
|
|
||||||
"value": "€156",
|
|
||||||
"subtitle": "۱۸٪ صرفهجویی شده",
|
|
||||||
"avatarIcon": "tabler-bulb",
|
|
||||||
"avatarColor": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "بازده سرمایه پلتفرم",
|
|
||||||
"value": "127%",
|
|
||||||
"subtitle": "نسبت به سال گذشته",
|
|
||||||
"avatarIcon": "tabler-chart-line",
|
|
||||||
"avatarColor": "info"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "پیشبینی درآمد",
|
|
||||||
"value": "€42k",
|
|
||||||
"subtitle": "این فصل",
|
|
||||||
"avatarIcon": "tabler-currency-euro",
|
|
||||||
"avatarColor": "success"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"chartSeries": [
|
|
||||||
{
|
|
||||||
"name": "هزینه آب",
|
|
||||||
"data": [
|
|
||||||
120,
|
|
||||||
115,
|
|
||||||
110,
|
|
||||||
125,
|
|
||||||
118,
|
|
||||||
122
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "کود",
|
|
||||||
"data": [
|
|
||||||
80,
|
|
||||||
85,
|
|
||||||
90,
|
|
||||||
75,
|
|
||||||
82,
|
|
||||||
78
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"chartCategories": [
|
|
||||||
"ژانویه",
|
|
||||||
"فوریه",
|
|
||||||
"مارس",
|
|
||||||
"آوریل",
|
|
||||||
"می",
|
|
||||||
"ژوئن"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 202,
|
|
||||||
"msg": "تسک توصیه کودهی در صف قرار گرفت.",
|
|
||||||
"data": {
|
|
||||||
"task_id": "fert-task-123",
|
|
||||||
"status_url": "/api/fertilization/recommend/fert-task-123/status/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"msg": "داده نامعتبر.",
|
|
||||||
"data": {
|
|
||||||
"farm_uuid": [
|
|
||||||
"This field is required."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "fert-task-123",
|
|
||||||
"status": "FAILURE",
|
|
||||||
"error": "خطا در دریافت توصیه کودهی."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "fert-task-123",
|
|
||||||
"status": "PENDING",
|
|
||||||
"message": "تسک در صف یا یافت نشد."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "fert-task-123",
|
|
||||||
"status": "PROGRESS",
|
|
||||||
"progress": {
|
|
||||||
"message": "در حال پردازش توصیه کودهی..."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "fert-task-123",
|
|
||||||
"status": "SUCCESS",
|
|
||||||
"result": {
|
|
||||||
"plan": {
|
|
||||||
"npkRatio": "20-20-20",
|
|
||||||
"amountPerHectare": "150 kg/ha",
|
|
||||||
"applicationMethod": "کودآبیاری در دو نوبت",
|
|
||||||
"applicationInterval": "هر ۱۰ روز",
|
|
||||||
"reasoning": "نیتروژن و پتاسیم خاک در محدوده متوسط است و گیاه در فاز رویشی نیاز تغذیهای بالاتری دارد."
|
|
||||||
},
|
|
||||||
"raw_response": "{\"plan\":{\"npkRatio\":\"20-20-20\"}}",
|
|
||||||
"status": "completed"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,604 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/dashboard-data/generate/",
|
|
||||||
"status_code": 202,
|
|
||||||
"description": "Dashboard data task queued",
|
|
||||||
"file": "json/mock_data/dashboard-data/generate/post_202.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/dashboard-data/generate/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Missing sensor_id",
|
|
||||||
"file": "json/mock_data/dashboard-data/generate/post_400.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/dashboard-data/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Pending dashboard task",
|
|
||||||
"file": "json/mock_data/dashboard-data/status/get_200_pending.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/dashboard-data/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Dashboard task in progress",
|
|
||||||
"file": "json/mock_data/dashboard-data/status/get_200_progress.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/dashboard-data/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Successful dashboard task",
|
|
||||||
"file": "json/mock_data/dashboard-data/status/get_200_success.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/dashboard-data/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Failed dashboard task",
|
|
||||||
"file": "json/mock_data/dashboard-data/status/get_200_failure.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/fertilization/recommend/",
|
|
||||||
"status_code": 202,
|
|
||||||
"description": "Fertilization task queued",
|
|
||||||
"file": "json/mock_data/fertilization/recommend/post_202.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/fertilization/recommend/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Validation error",
|
|
||||||
"file": "json/mock_data/fertilization/recommend/post_400.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/fertilization/recommend/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Fertilization status pending",
|
|
||||||
"file": "json/mock_data/fertilization/status/get_200_pending.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/fertilization/recommend/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Fertilization status progress",
|
|
||||||
"file": "json/mock_data/fertilization/status/get_200_progress.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/fertilization/recommend/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Fertilization status success",
|
|
||||||
"file": "json/mock_data/fertilization/status/get_200_success.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/fertilization/recommend/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Fertilization status failure",
|
|
||||||
"file": "json/mock_data/fertilization/status/get_200_failure.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/irrigation/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "List irrigation methods",
|
|
||||||
"file": "json/mock_data/irrigation/methods/get_200.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/irrigation/",
|
|
||||||
"status_code": 201,
|
|
||||||
"description": "Create irrigation method",
|
|
||||||
"file": "json/mock_data/irrigation/methods/post_201.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/irrigation/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Irrigation create validation error",
|
|
||||||
"file": "json/mock_data/irrigation/methods/post_400.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/irrigation/recommend/",
|
|
||||||
"status_code": 202,
|
|
||||||
"description": "Irrigation recommendation task queued",
|
|
||||||
"file": "json/mock_data/irrigation/recommend/post_202.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/irrigation/recommend/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Irrigation recommendation validation error",
|
|
||||||
"file": "json/mock_data/irrigation/recommend/post_400.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/irrigation/recommend/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Irrigation recommendation status pending",
|
|
||||||
"file": "json/mock_data/irrigation/recommend/status/get_200_pending.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/irrigation/recommend/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Irrigation recommendation status progress",
|
|
||||||
"file": "json/mock_data/irrigation/recommend/status/get_200_progress.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/irrigation/recommend/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Irrigation recommendation status success",
|
|
||||||
"file": "json/mock_data/irrigation/recommend/status/get_200_success.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/irrigation/recommend/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Irrigation recommendation status failure",
|
|
||||||
"file": "json/mock_data/irrigation/recommend/status/get_200_failure.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/irrigation/{pk}/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Irrigation method get success",
|
|
||||||
"file": "json/mock_data/irrigation/method-detail/get_200.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/irrigation/{pk}/",
|
|
||||||
"status_code": 404,
|
|
||||||
"description": "Irrigation method get not found",
|
|
||||||
"file": "json/mock_data/irrigation/method-detail/get_404.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PUT",
|
|
||||||
"path": "/api/irrigation/{pk}/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Irrigation method put success",
|
|
||||||
"file": "json/mock_data/irrigation/method-detail/put_200.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PUT",
|
|
||||||
"path": "/api/irrigation/{pk}/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Irrigation method put validation error",
|
|
||||||
"file": "json/mock_data/irrigation/method-detail/put_400.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PUT",
|
|
||||||
"path": "/api/irrigation/{pk}/",
|
|
||||||
"status_code": 404,
|
|
||||||
"description": "Irrigation method put not found",
|
|
||||||
"file": "json/mock_data/irrigation/method-detail/put_404.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PATCH",
|
|
||||||
"path": "/api/irrigation/{pk}/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Irrigation method patch success",
|
|
||||||
"file": "json/mock_data/irrigation/method-detail/patch_200.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PATCH",
|
|
||||||
"path": "/api/irrigation/{pk}/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Irrigation method patch validation error",
|
|
||||||
"file": "json/mock_data/irrigation/method-detail/patch_400.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PATCH",
|
|
||||||
"path": "/api/irrigation/{pk}/",
|
|
||||||
"status_code": 404,
|
|
||||||
"description": "Irrigation method patch not found",
|
|
||||||
"file": "json/mock_data/irrigation/method-detail/patch_404.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "DELETE",
|
|
||||||
"path": "/api/irrigation/{pk}/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Delete irrigation method",
|
|
||||||
"file": "json/mock_data/irrigation/method-detail/delete_200.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "DELETE",
|
|
||||||
"path": "/api/irrigation/{pk}/",
|
|
||||||
"status_code": 404,
|
|
||||||
"description": "Delete irrigation method not found",
|
|
||||||
"file": "json/mock_data/irrigation/method-detail/delete_404.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/soil-data/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Soil data served from database",
|
|
||||||
"file": "json/mock_data/soil-data/get_200_database.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/soil-data/",
|
|
||||||
"status_code": 202,
|
|
||||||
"description": "Soil data fetch task queued",
|
|
||||||
"file": "json/mock_data/soil-data/get_202_queued.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/soil-data/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Soil data validation error",
|
|
||||||
"file": "json/mock_data/soil-data/get_400.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/soil-data/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Soil data POST served from database",
|
|
||||||
"file": "json/mock_data/soil-data/post_200_database.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/soil-data/",
|
|
||||||
"status_code": 202,
|
|
||||||
"description": "Soil data POST task queued",
|
|
||||||
"file": "json/mock_data/soil-data/post_202_queued.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/soil-data/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Soil data POST validation error",
|
|
||||||
"file": "json/mock_data/soil-data/post_400.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/soil-data/tasks/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Soil task status pending",
|
|
||||||
"file": "json/mock_data/soil-data/status/get_200_pending.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/soil-data/tasks/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Soil task status progress",
|
|
||||||
"file": "json/mock_data/soil-data/status/get_200_progress.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/soil-data/tasks/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Soil task status success",
|
|
||||||
"file": "json/mock_data/soil-data/status/get_200_success.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/soil-data/tasks/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Soil task status failure",
|
|
||||||
"file": "json/mock_data/soil-data/status/get_200_failure.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/plants/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "List plants",
|
|
||||||
"file": "json/mock_data/plant/list-get_200.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/plants/",
|
|
||||||
"status_code": 201,
|
|
||||||
"description": "Create plant",
|
|
||||||
"file": "json/mock_data/plant/create-post_201.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/plants/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Plant create validation error",
|
|
||||||
"file": "json/mock_data/plant/create-post_400.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/plants/{pk}/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Plant detail get success",
|
|
||||||
"file": "json/mock_data/plant/detail-get_200.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/plants/{pk}/",
|
|
||||||
"status_code": 404,
|
|
||||||
"description": "Plant detail get not found",
|
|
||||||
"file": "json/mock_data/plant/detail-get_404.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PUT",
|
|
||||||
"path": "/api/plants/{pk}/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Plant detail put success",
|
|
||||||
"file": "json/mock_data/plant/detail-put_200.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PUT",
|
|
||||||
"path": "/api/plants/{pk}/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Plant detail put validation error",
|
|
||||||
"file": "json/mock_data/plant/detail-put_400.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PUT",
|
|
||||||
"path": "/api/plants/{pk}/",
|
|
||||||
"status_code": 404,
|
|
||||||
"description": "Plant detail put not found",
|
|
||||||
"file": "json/mock_data/plant/detail-put_404.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PATCH",
|
|
||||||
"path": "/api/plants/{pk}/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Plant detail patch success",
|
|
||||||
"file": "json/mock_data/plant/detail-patch_200.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PATCH",
|
|
||||||
"path": "/api/plants/{pk}/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Plant detail patch validation error",
|
|
||||||
"file": "json/mock_data/plant/detail-patch_400.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PATCH",
|
|
||||||
"path": "/api/plants/{pk}/",
|
|
||||||
"status_code": 404,
|
|
||||||
"description": "Plant detail patch not found",
|
|
||||||
"file": "json/mock_data/plant/detail-patch_404.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "DELETE",
|
|
||||||
"path": "/api/plants/{pk}/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Delete plant success",
|
|
||||||
"file": "json/mock_data/plant/detail-delete_200.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "DELETE",
|
|
||||||
"path": "/api/plants/{pk}/",
|
|
||||||
"status_code": 404,
|
|
||||||
"description": "Delete plant not found",
|
|
||||||
"file": "json/mock_data/plant/detail-delete_404.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/plants/fetch-info/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Fetch plant info success",
|
|
||||||
"file": "json/mock_data/plant/fetch-info-post_200.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/plants/fetch-info/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Fetch plant info missing name",
|
|
||||||
"file": "json/mock_data/plant/fetch-info-post_400.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/plants/fetch-info/",
|
|
||||||
"status_code": 503,
|
|
||||||
"description": "Fetch plant info service unavailable",
|
|
||||||
"file": "json/mock_data/plant/fetch-info-post_503.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/rag/chat/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "RAG chat streaming response",
|
|
||||||
"file": "json/mock_data/rag/chat-post_200_stream.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/rag/chat/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Missing query",
|
|
||||||
"file": "json/mock_data/rag/chat-post_400_missing_query.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/rag/chat/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Invalid service id",
|
|
||||||
"file": "json/mock_data/rag/chat-post_400_invalid_service.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/rag/chat/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Missing user_id for service",
|
|
||||||
"file": "json/mock_data/rag/chat-post_400_missing_user.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/rag/recommend/irrigation/",
|
|
||||||
"status_code": 202,
|
|
||||||
"description": "RAG irrigation task queued",
|
|
||||||
"file": "json/mock_data/rag/irrigation/post_202.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/rag/recommend/irrigation/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "RAG irrigation validation error",
|
|
||||||
"file": "json/mock_data/rag/irrigation/post_400.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/rag/recommend/irrigation/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "RAG irrigation status pending",
|
|
||||||
"file": "json/mock_data/rag/irrigation/status/get_200_pending.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/rag/recommend/irrigation/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "RAG irrigation status progress",
|
|
||||||
"file": "json/mock_data/rag/irrigation/status/get_200_progress.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/rag/recommend/irrigation/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "RAG irrigation status success",
|
|
||||||
"file": "json/mock_data/rag/irrigation/status/get_200_success.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/rag/recommend/irrigation/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "RAG irrigation status failure",
|
|
||||||
"file": "json/mock_data/rag/irrigation/status/get_200_failure.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/rag/recommend/fertilization/",
|
|
||||||
"status_code": 202,
|
|
||||||
"description": "RAG fertilization task queued",
|
|
||||||
"file": "json/mock_data/rag/fertilization/post_202.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/rag/recommend/fertilization/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "RAG fertilization validation error",
|
|
||||||
"file": "json/mock_data/rag/fertilization/post_400.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/rag/recommend/fertilization/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "RAG fertilization status pending",
|
|
||||||
"file": "json/mock_data/rag/fertilization/status/get_200_pending.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/rag/recommend/fertilization/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "RAG fertilization status progress",
|
|
||||||
"file": "json/mock_data/rag/fertilization/status/get_200_progress.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/rag/recommend/fertilization/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "RAG fertilization status success",
|
|
||||||
"file": "json/mock_data/rag/fertilization/status/get_200_success.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/rag/recommend/fertilization/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "RAG fertilization status failure",
|
|
||||||
"file": "json/mock_data/rag/fertilization/status/get_200_failure.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PUT",
|
|
||||||
"path": "/api/sensor-data/{farm_uuid}/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Sensor update put success",
|
|
||||||
"file": "json/mock_data/sensor-data/update-put_200.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PUT",
|
|
||||||
"path": "/api/sensor-data/{farm_uuid}/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Sensor update put validation error",
|
|
||||||
"file": "json/mock_data/sensor-data/update-put_400.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PUT",
|
|
||||||
"path": "/api/sensor-data/{farm_uuid}/",
|
|
||||||
"status_code": 404,
|
|
||||||
"description": "Sensor update put location not found",
|
|
||||||
"file": "json/mock_data/sensor-data/update-put_404.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PATCH",
|
|
||||||
"path": "/api/sensor-data/{farm_uuid}/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Sensor update patch success",
|
|
||||||
"file": "json/mock_data/sensor-data/update-patch_200.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PATCH",
|
|
||||||
"path": "/api/sensor-data/{farm_uuid}/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Sensor update patch validation error",
|
|
||||||
"file": "json/mock_data/sensor-data/update-patch_400.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "PATCH",
|
|
||||||
"path": "/api/sensor-data/{farm_uuid}/",
|
|
||||||
"status_code": 404,
|
|
||||||
"description": "Sensor update patch location not found",
|
|
||||||
"file": "json/mock_data/sensor-data/update-patch_404.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/sensor-data/parameters/",
|
|
||||||
"status_code": 201,
|
|
||||||
"description": "Create sensor parameter",
|
|
||||||
"file": "json/mock_data/sensor-data/parameters-post_201.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/sensor-data/parameters/",
|
|
||||||
"status_code": 400,
|
|
||||||
"description": "Sensor parameter validation error",
|
|
||||||
"file": "json/mock_data/sensor-data/parameters-post_400.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "POST",
|
|
||||||
"path": "/api/tasks/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Task trigger success",
|
|
||||||
"file": "json/mock_data/tasks/post_200.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/tasks/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Task status pending",
|
|
||||||
"file": "json/mock_data/tasks/status/get_200_pending.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/tasks/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Task status progress",
|
|
||||||
"file": "json/mock_data/tasks/status/get_200_progress.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/tasks/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Task status success",
|
|
||||||
"file": "json/mock_data/tasks/status/get_200_success.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"method": "GET",
|
|
||||||
"path": "/api/tasks/{task_id}/status/",
|
|
||||||
"status_code": 200,
|
|
||||||
"description": "Task status failure",
|
|
||||||
"file": "json/mock_data/tasks/status/get_200_failure.json"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "روش آبیاری با موفقیت حذف شد.",
|
|
||||||
"data": null
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 404,
|
|
||||||
"msg": "روش آبیاری یافت نشد.",
|
|
||||||
"data": null
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"id": 1,
|
|
||||||
"name": "آبیاری قطرهای",
|
|
||||||
"category": "موضعی",
|
|
||||||
"description": "آبیاری با دبی کم و راندمان بالا",
|
|
||||||
"water_efficiency_percent": 90.0,
|
|
||||||
"water_pressure_required": "۱-۲ اتمسفر",
|
|
||||||
"flow_rate": "۲-۸ لیتر در ساعت",
|
|
||||||
"coverage_area": "بسته به طراحی سیستم",
|
|
||||||
"soil_type": "اکثر خاکها",
|
|
||||||
"climate_suitability": "گرم و خشک",
|
|
||||||
"created_at": "2025-03-20T10:00:00Z",
|
|
||||||
"updated_at": "2025-03-24T10:00:00Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 404,
|
|
||||||
"msg": "روش آبیاری یافت نشد.",
|
|
||||||
"data": null
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"id": 1,
|
|
||||||
"name": "آبیاری قطرهای",
|
|
||||||
"category": "موضعی",
|
|
||||||
"description": "آبیاری با دبی کم و راندمان بالا",
|
|
||||||
"water_efficiency_percent": 90.0,
|
|
||||||
"water_pressure_required": "۱-۲ اتمسفر",
|
|
||||||
"flow_rate": "۲-۸ لیتر در ساعت",
|
|
||||||
"coverage_area": "بسته به طراحی سیستم",
|
|
||||||
"soil_type": "اکثر خاکها",
|
|
||||||
"climate_suitability": "گرم و خشک",
|
|
||||||
"created_at": "2025-03-20T10:00:00Z",
|
|
||||||
"updated_at": "2025-03-24T10:00:00Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"msg": "داده نامعتبر.",
|
|
||||||
"data": {
|
|
||||||
"name": [
|
|
||||||
"This field may not be blank."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 404,
|
|
||||||
"msg": "روش آبیاری یافت نشد.",
|
|
||||||
"data": null
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"id": 1,
|
|
||||||
"name": "آبیاری قطرهای",
|
|
||||||
"category": "موضعی",
|
|
||||||
"description": "آبیاری با دبی کم و راندمان بالا",
|
|
||||||
"water_efficiency_percent": 90.0,
|
|
||||||
"water_pressure_required": "۱-۲ اتمسفر",
|
|
||||||
"flow_rate": "۲-۸ لیتر در ساعت",
|
|
||||||
"coverage_area": "بسته به طراحی سیستم",
|
|
||||||
"soil_type": "اکثر خاکها",
|
|
||||||
"climate_suitability": "گرم و خشک",
|
|
||||||
"created_at": "2025-03-20T10:00:00Z",
|
|
||||||
"updated_at": "2025-03-24T10:00:00Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"msg": "داده نامعتبر.",
|
|
||||||
"data": {
|
|
||||||
"name": [
|
|
||||||
"This field may not be blank."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 404,
|
|
||||||
"msg": "روش آبیاری یافت نشد.",
|
|
||||||
"data": null
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"name": "آبیاری قطرهای",
|
|
||||||
"category": "موضعی",
|
|
||||||
"description": "آبیاری با دبی کم و راندمان بالا",
|
|
||||||
"water_efficiency_percent": 90.0,
|
|
||||||
"water_pressure_required": "۱-۲ اتمسفر",
|
|
||||||
"flow_rate": "۲-۸ لیتر در ساعت",
|
|
||||||
"coverage_area": "بسته به طراحی سیستم",
|
|
||||||
"soil_type": "اکثر خاکها",
|
|
||||||
"climate_suitability": "گرم و خشک",
|
|
||||||
"created_at": "2025-03-20T10:00:00Z",
|
|
||||||
"updated_at": "2025-03-24T10:00:00Z"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 201,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"id": 1,
|
|
||||||
"name": "آبیاری قطرهای",
|
|
||||||
"category": "موضعی",
|
|
||||||
"description": "آبیاری با دبی کم و راندمان بالا",
|
|
||||||
"water_efficiency_percent": 90.0,
|
|
||||||
"water_pressure_required": "۱-۲ اتمسفر",
|
|
||||||
"flow_rate": "۲-۸ لیتر در ساعت",
|
|
||||||
"coverage_area": "بسته به طراحی سیستم",
|
|
||||||
"soil_type": "اکثر خاکها",
|
|
||||||
"climate_suitability": "گرم و خشک",
|
|
||||||
"created_at": "2025-03-20T10:00:00Z",
|
|
||||||
"updated_at": "2025-03-24T10:00:00Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"msg": "داده نامعتبر.",
|
|
||||||
"data": {
|
|
||||||
"name": [
|
|
||||||
"This field is required."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 202,
|
|
||||||
"msg": "تسک توصیه آبیاری در صف قرار گرفت.",
|
|
||||||
"data": {
|
|
||||||
"task_id": "irr-task-123",
|
|
||||||
"status_url": "/api/irrigation/recommend/irr-task-123/status/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"msg": "داده نامعتبر.",
|
|
||||||
"data": {
|
|
||||||
"farm_uuid": [
|
|
||||||
"This field is required."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "irr-task-123",
|
|
||||||
"status": "FAILURE",
|
|
||||||
"error": "خطا در دریافت توصیه آبیاری."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "irr-task-123",
|
|
||||||
"status": "PENDING",
|
|
||||||
"message": "تسک در صف یا یافت نشد."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "irr-task-123",
|
|
||||||
"status": "PROGRESS",
|
|
||||||
"progress": {
|
|
||||||
"message": "در حال پردازش توصیه آبیاری..."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "irr-task-123",
|
|
||||||
"status": "SUCCESS",
|
|
||||||
"result": {
|
|
||||||
"plan": {
|
|
||||||
"frequencyPerWeek": 3,
|
|
||||||
"durationMinutes": 42,
|
|
||||||
"bestTimeOfDay": "صبح زود",
|
|
||||||
"moistureLevel": 68,
|
|
||||||
"warning": "در صورت بارش موثر، نوبت سوم این هفته را حذف کنید."
|
|
||||||
},
|
|
||||||
"raw_response": "{\"plan\":{\"frequencyPerWeek\":3,\"durationMinutes\":42}}",
|
|
||||||
"water_balance": {
|
|
||||||
"daily": [
|
|
||||||
{
|
|
||||||
"forecast_date": "2025-03-25",
|
|
||||||
"et0_mm": 4.7,
|
|
||||||
"etc_mm": 5.6,
|
|
||||||
"effective_rainfall_mm": 0.0,
|
|
||||||
"gross_irrigation_mm": 6.2,
|
|
||||||
"irrigation_timing": "06:00-08:00"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"crop_profile": {
|
|
||||||
"kc_initial": 0.6,
|
|
||||||
"kc_mid": 1.15,
|
|
||||||
"kc_end": 0.8
|
|
||||||
},
|
|
||||||
"active_kc": 1.15
|
|
||||||
},
|
|
||||||
"status": "completed"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 201,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"id": 1,
|
|
||||||
"name": "گوجهفرنگی",
|
|
||||||
"light": "آفتاب کامل",
|
|
||||||
"watering": "منظم، هفتهای ۲ تا ۳ بار",
|
|
||||||
"soil": "لومی، غنی از مواد آلی",
|
|
||||||
"temperature": "۲۰ تا ۳۰ درجه سانتیگراد",
|
|
||||||
"planting_season": "بهار",
|
|
||||||
"harvest_time": "۷۰ تا ۹۰ روز پس از کاشت",
|
|
||||||
"spacing": "۴۵ تا ۶۰ سانتیمتر",
|
|
||||||
"fertilizer": "کود NPK متعادل",
|
|
||||||
"created_at": "2025-03-20T10:00:00Z",
|
|
||||||
"updated_at": "2025-03-24T10:00:00Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"msg": "داده نامعتبر.",
|
|
||||||
"data": {
|
|
||||||
"name": [
|
|
||||||
"This field is required."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "گیاه با موفقیت حذف شد.",
|
|
||||||
"data": null
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 404,
|
|
||||||
"msg": "گیاه یافت نشد.",
|
|
||||||
"data": null
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"id": 1,
|
|
||||||
"name": "گوجهفرنگی",
|
|
||||||
"light": "آفتاب کامل",
|
|
||||||
"watering": "منظم، هفتهای ۲ تا ۳ بار",
|
|
||||||
"soil": "لومی، غنی از مواد آلی",
|
|
||||||
"temperature": "۲۰ تا ۳۰ درجه سانتیگراد",
|
|
||||||
"planting_season": "بهار",
|
|
||||||
"harvest_time": "۷۰ تا ۹۰ روز پس از کاشت",
|
|
||||||
"spacing": "۴۵ تا ۶۰ سانتیمتر",
|
|
||||||
"fertilizer": "کود NPK متعادل",
|
|
||||||
"created_at": "2025-03-20T10:00:00Z",
|
|
||||||
"updated_at": "2025-03-24T10:00:00Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 404,
|
|
||||||
"msg": "گیاه یافت نشد.",
|
|
||||||
"data": null
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"id": 1,
|
|
||||||
"name": "گوجهفرنگی",
|
|
||||||
"light": "آفتاب کامل",
|
|
||||||
"watering": "منظم، هفتهای ۲ تا ۳ بار",
|
|
||||||
"soil": "لومی، غنی از مواد آلی",
|
|
||||||
"temperature": "۲۰ تا ۳۰ درجه سانتیگراد",
|
|
||||||
"planting_season": "بهار",
|
|
||||||
"harvest_time": "۷۰ تا ۹۰ روز پس از کاشت",
|
|
||||||
"spacing": "۴۵ تا ۶۰ سانتیمتر",
|
|
||||||
"fertilizer": "کود NPK متعادل",
|
|
||||||
"created_at": "2025-03-20T10:00:00Z",
|
|
||||||
"updated_at": "2025-03-24T10:00:00Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"msg": "داده نامعتبر.",
|
|
||||||
"data": {
|
|
||||||
"name": [
|
|
||||||
"This field may not be blank."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 404,
|
|
||||||
"msg": "گیاه یافت نشد.",
|
|
||||||
"data": null
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"id": 1,
|
|
||||||
"name": "گوجهفرنگی",
|
|
||||||
"light": "آفتاب کامل",
|
|
||||||
"watering": "منظم، هفتهای ۲ تا ۳ بار",
|
|
||||||
"soil": "لومی، غنی از مواد آلی",
|
|
||||||
"temperature": "۲۰ تا ۳۰ درجه سانتیگراد",
|
|
||||||
"planting_season": "بهار",
|
|
||||||
"harvest_time": "۷۰ تا ۹۰ روز پس از کاشت",
|
|
||||||
"spacing": "۴۵ تا ۶۰ سانتیمتر",
|
|
||||||
"fertilizer": "کود NPK متعادل",
|
|
||||||
"created_at": "2025-03-20T10:00:00Z",
|
|
||||||
"updated_at": "2025-03-24T10:00:00Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"msg": "داده نامعتبر.",
|
|
||||||
"data": {
|
|
||||||
"name": [
|
|
||||||
"This field may not be blank."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 404,
|
|
||||||
"msg": "گیاه یافت نشد.",
|
|
||||||
"data": null
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"id": 1,
|
|
||||||
"name": "گوجهفرنگی",
|
|
||||||
"light": "آفتاب کامل",
|
|
||||||
"watering": "منظم، هفتهای ۲ تا ۳ بار",
|
|
||||||
"soil": "لومی، غنی از مواد آلی",
|
|
||||||
"temperature": "۲۰ تا ۳۰ درجه سانتیگراد",
|
|
||||||
"planting_season": "بهار",
|
|
||||||
"harvest_time": "۷۰ تا ۹۰ روز پس از کاشت",
|
|
||||||
"spacing": "۴۵ تا ۶۰ سانتیمتر",
|
|
||||||
"fertilizer": "کود NPK متعادل",
|
|
||||||
"created_at": "2025-03-20T10:00:00Z",
|
|
||||||
"updated_at": "2025-03-24T10:00:00Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"msg": "نام گیاه الزامی است.",
|
|
||||||
"data": null
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 503,
|
|
||||||
"msg": "سرویس API هنوز پیادهسازی نشده است.",
|
|
||||||
"data": null
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"name": "گوجهفرنگی",
|
|
||||||
"light": "آفتاب کامل",
|
|
||||||
"watering": "منظم، هفتهای ۲ تا ۳ بار",
|
|
||||||
"soil": "لومی، غنی از مواد آلی",
|
|
||||||
"temperature": "۲۰ تا ۳۰ درجه سانتیگراد",
|
|
||||||
"planting_season": "بهار",
|
|
||||||
"harvest_time": "۷۰ تا ۹۰ روز پس از کاشت",
|
|
||||||
"spacing": "۴۵ تا ۶۰ سانتیمتر",
|
|
||||||
"fertilizer": "کود NPK متعادل",
|
|
||||||
"created_at": "2025-03-20T10:00:00Z",
|
|
||||||
"updated_at": "2025-03-24T10:00:00Z"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"content": "Here is the recommended plan.",
|
|
||||||
"sections": [
|
|
||||||
{
|
|
||||||
"type": "recommendation",
|
|
||||||
"title": "Irrigation Plan",
|
|
||||||
"icon": "droplet",
|
|
||||||
"frequency": "3 times per week",
|
|
||||||
"amount": "15 liters per plant",
|
|
||||||
"timing": "Early morning",
|
|
||||||
"expandableExplanation": "Loamy soil holds moisture well, so moderate frequency is enough."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "list",
|
|
||||||
"title": "Important Notes",
|
|
||||||
"icon": "leaf",
|
|
||||||
"items": [
|
|
||||||
"Avoid watering at noon",
|
|
||||||
"Check leaf stress every two days"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "warning",
|
|
||||||
"title": "Heat Alert",
|
|
||||||
"icon": "warning",
|
|
||||||
"content": "Increase irrigation if temperature rises above 35°C."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"msg": "service_id نامعتبر است: unknown_service"
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"msg": "پارامتر query الزامی است."
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"msg": "برای این service_id، پارامتر user_id الزامی است."
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 202,
|
|
||||||
"msg": "تسک توصیه کودهی در صف قرار گرفت.",
|
|
||||||
"data": {
|
|
||||||
"task_id": "rag-fert-123",
|
|
||||||
"status_url": "/api/rag/recommend/fertilization/rag-fert-123/status/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"msg": "پارامتر farm_uuid الزامی است.",
|
|
||||||
"data": null
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "rag-fert-123",
|
|
||||||
"status": "FAILURE",
|
|
||||||
"error": "خطا در دریافت توصیه کودهی."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "rag-fert-123",
|
|
||||||
"status": "PENDING",
|
|
||||||
"message": "تسک در صف یا یافت نشد."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "rag-fert-123",
|
|
||||||
"status": "PROGRESS",
|
|
||||||
"progress": {
|
|
||||||
"message": "در حال پردازش توصیه کودهی..."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "rag-fert-123",
|
|
||||||
"status": "SUCCESS",
|
|
||||||
"result": {
|
|
||||||
"plan": {
|
|
||||||
"npkRatio": "20-20-20",
|
|
||||||
"amountPerHectare": "150 kg/ha",
|
|
||||||
"applicationMethod": "کودآبیاری در دو نوبت",
|
|
||||||
"applicationInterval": "هر ۱۰ روز",
|
|
||||||
"reasoning": "نیتروژن و پتاسیم خاک در محدوده متوسط است و گیاه در فاز رویشی نیاز تغذیهای بالاتری دارد."
|
|
||||||
},
|
|
||||||
"raw_response": "{\"plan\":{\"npkRatio\":\"20-20-20\"}}",
|
|
||||||
"status": "completed"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 202,
|
|
||||||
"msg": "تسک توصیه آبیاری در صف قرار گرفت.",
|
|
||||||
"data": {
|
|
||||||
"task_id": "rag-irr-123",
|
|
||||||
"status_url": "/api/rag/recommend/irrigation/rag-irr-123/status/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"msg": "پارامتر farm_uuid الزامی است.",
|
|
||||||
"data": null
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "rag-irr-123",
|
|
||||||
"status": "FAILURE",
|
|
||||||
"error": "خطا در دریافت توصیه آبیاری."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "rag-irr-123",
|
|
||||||
"status": "PENDING",
|
|
||||||
"message": "تسک در صف یا یافت نشد."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "rag-irr-123",
|
|
||||||
"status": "PROGRESS",
|
|
||||||
"progress": {
|
|
||||||
"message": "در حال پردازش توصیه آبیاری..."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"task_id": "rag-irr-123",
|
|
||||||
"status": "SUCCESS",
|
|
||||||
"result": {
|
|
||||||
"plan": {
|
|
||||||
"frequencyPerWeek": 3,
|
|
||||||
"durationMinutes": 42,
|
|
||||||
"bestTimeOfDay": "صبح زود",
|
|
||||||
"moistureLevel": 68,
|
|
||||||
"warning": "در صورت بارش موثر، نوبت سوم این هفته را حذف کنید."
|
|
||||||
},
|
|
||||||
"raw_response": "{\"plan\":{\"frequencyPerWeek\":3,\"durationMinutes\":42}}",
|
|
||||||
"water_balance": {
|
|
||||||
"daily": [
|
|
||||||
{
|
|
||||||
"forecast_date": "2025-03-25",
|
|
||||||
"et0_mm": 4.7,
|
|
||||||
"etc_mm": 5.6,
|
|
||||||
"effective_rainfall_mm": 0.0,
|
|
||||||
"gross_irrigation_mm": 6.2,
|
|
||||||
"irrigation_timing": "06:00-08:00"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"crop_profile": {
|
|
||||||
"kc_initial": 0.6,
|
|
||||||
"kc_mid": 1.15,
|
|
||||||
"kc_end": 0.8
|
|
||||||
},
|
|
||||||
"active_kc": 1.15
|
|
||||||
},
|
|
||||||
"status": "completed"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 201,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"id": 3,
|
|
||||||
"code": "soil_moisture",
|
|
||||||
"name_fa": "رطوبت خاک",
|
|
||||||
"unit": "%",
|
|
||||||
"created_at": "2025-03-24T10:00:00Z",
|
|
||||||
"action": "added"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"msg": "داده نامعتبر.",
|
|
||||||
"data": {
|
|
||||||
"code": [
|
|
||||||
"This field is required."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"msg": "success",
|
|
||||||
"data": {
|
|
||||||
"farm_uuid": "550e8400-e29b-41d4-a716-446655440000",
|
|
||||||
"location_id": 12,
|
|
||||||
"soil_moisture": 45.2,
|
|
||||||
"soil_temperature": 22.5,
|
|
||||||
"soil_ph": 6.8,
|
|
||||||
"electrical_conductivity": 1.2,
|
|
||||||
"nitrogen": 30.0,
|
|
||||||
"phosphorus": 15.0,
|
|
||||||
"potassium": 20.0,
|
|
||||||
"plant_ids": [
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"created_at": "2025-03-20T10:00:00Z",
|
|
||||||
"updated_at": "2025-03-24T10:00:00Z"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"code": 400,
|
|
||||||
"msg": "داده نامعتبر.",
|
|
||||||
"data": {
|
|
||||||
"location_id": [
|
|
||||||
"This field is required."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user