Files
Ai/docs/plant_service_relation.md
T
2026-05-13 22:28:56 +03:30

11 KiB

ارتباط سرویس‌ها با Plant و گیاهان

این سند توضیح می‌دهد که در پروژه، داده‌ی گیاه از کجا می‌آید، چطور در farm_data نگه‌داری می‌شود، چگونه به سرویس‌های crop_simulation می‌رسد و در نهایت چطور در location_data برای پیشنهاد گیاه هر کلاستر استفاده می‌شود.

نمای کلی

در این پروژه سه لایه اصلی برای کار با گیاه وجود دارد:

  1. plant
  2. farm_data
  3. crop_simulation و location_data

نقش هر لایه:

  • plant: مرجع canonical نام گیاه و aliasها است.
  • farm_data: نسخه snapshot شده‌ی گیاهان Backend و assignment هر مزرعه به گیاه‌ها را نگه می‌دارد.
  • crop_simulation: از گیاه انتخاب‌شده برای ساخت ورودی شبیه‌سازی استفاده می‌کند.
  • location_data: داده‌ی کلاسترهای KMeans را با گیاه‌های مزرعه ترکیب می‌کند و پیشنهاد گیاه می‌سازد.

1) لایه plant

اپ plant مرجع اصلی برای resolve کردن نام گیاه است.

فایل مهم:

  • plant/apps.py

تابع مهم:

  • resolve_plant_name

رفتار این تابع:

  • نام ورودی را می‌گیرد.
  • اگر همان نام در جدول plant.Plant وجود داشته باشد، همان را برمی‌گرداند.
  • اگر alias برای آن تعریف شده باشد، alias را به نام canonical تبدیل می‌کند.
  • اگر از نظر نرمال‌سازی متنی با یک گیاه match شود، همان نام canonical را برمی‌گرداند.

در نتیجه:

  • ورودی‌هایی مثل plant_name، crop یا crop_name قبل از ورود به شبیه‌سازی، به نام استاندارد تبدیل می‌شوند.

2) لایه farm_data

اپ farm_data مدل read-model مربوط به گیاهان هر مزرعه را نگه می‌دارد.

مدل‌های اصلی:

  • farm_data.models.PlantCatalogSnapshot
  • farm_data.models.FarmPlantAssignment
  • farm_data.models.SensorData

PlantCatalogSnapshot

این مدل کپی محلی و خواندنی از کاتالوگ گیاه Backend است.

اطلاعاتی که در آن نگه‌داری می‌شود:

  • نام گیاه
  • توضیحات
  • growth_profile
  • irrigation_profile
  • health_profile
  • فصل کاشت، زمان برداشت، فاصله کاشت، کود و ...

این مدل منبع اصلی هوش مصنوعی برای خواندن پروفایل گیاه است، نه relation قدیمی SensorData.plants.

FarmPlantAssignment

این مدل مشخص می‌کند هر مزرعه چه گیاه‌هایی دارد.

فیلدهای مهم:

  • farm
  • plant
  • position
  • stage
  • metadata

یعنی هر مزرعه می‌تواند چند گیاه داشته باشد و ترتیب و مرحله رشد هرکدام هم ثبت می‌شود.

توابع مهم در farm_data/services.py

فایل مهم:

  • farm_data/services.py

توابع کلیدی:

  • sync_plant_catalog_from_backend
  • assign_farm_plants_from_backend_ids
  • get_farm_plant_assignments
  • get_farm_plant_snapshots
  • get_primary_plant_snapshot
  • get_farm_plant_snapshot_by_name
  • clone_snapshot_as_runtime_plant
  • get_runtime_plant_for_farm
  • list_runtime_plants_for_farm

جریان داده در farm_data

  1. کاتالوگ گیاه از Backend خوانده می‌شود و داخل PlantCatalogSnapshot ذخیره می‌شود.
  2. گیاه‌های انتخاب‌شده‌ی هر مزرعه با FarmPlantAssignment ثبت می‌شوند.
  3. اگر سرویس شبیه‌سازی یک plant_name مشخص بگیرد، همان گیاه از assignmentها پیدا می‌شود.
  4. اگر plant_name ارسال نشود، گیاه اول مزرعه به عنوان پیش‌فرض انتخاب می‌شود.

Runtime Plant

تابع get_runtime_plant_for_farm یک snapshot را به یک object سبک runtime تبدیل می‌کند تا downstream serviceها بدون وابستگی مستقیم به مدل DB از آن استفاده کنند.

این object شامل فیلدهایی مثل:

  • name
  • growth_profile
  • irrigation_profile
  • health_profile
  • planting_season
  • harvest_time

است.

3) ورود گیاه به crop_simulation

فایل‌های مهم:

  • crop_simulation/services.py
  • crop_simulation/growth_simulation.py
  • crop_simulation/harvest_prediction.py
  • crop_simulation/yield_prediction.py

build_simulation_payload_from_farm

مهم‌ترین نقطه اتصال بین farm_data و crop_simulation این تابع است:

  • crop_simulation.services.build_simulation_payload_from_farm

این تابع:

  1. مزرعه را با get_canonical_farm_record پیدا می‌کند.
  2. گیاه را با get_runtime_plant_for_farm resolve می‌کند.
  3. snapshot هوش مصنوعی مزرعه را می‌خواند.
  4. weather, soil, site_parameters را می‌سازد.
  5. از پروفایل گیاه، crop_parameters و در صورت وجود agromanagement پیش‌فرض را استخراج می‌کند.

خروجی این تابع شامل این بخش‌هاست:

  • plant
  • runtime_plants
  • weather
  • soil
  • site_parameters
  • crop_parameters
  • agromanagement

یعنی تمام چیزی که موتور شبیه‌سازی لازم دارد.

استفاده در Growth Simulation

در crop_simulation/growth_simulation.py اگر farm_uuid داده شود:

  • build_growth_context از build_simulation_payload_from_farm استفاده می‌کند.
  • گیاه انتخاب‌شده وارد context می‌شود.
  • سپس شبیه‌سازی PCSE یا fallback projection روی همان گیاه اجرا می‌شود.

استفاده در Harvest Prediction

در crop_simulation/harvest_prediction.py اگر plant_name ارسال نشود:

  • سرویس با get_runtime_plant_for_farm گیاه پیش‌فرض مزرعه را پیدا می‌کند.
  • سپس از همان گیاه برای محاسبه‌ی GDD و پیش‌بینی برداشت استفاده می‌شود.

استفاده در Yield Prediction

در crop_simulation/yield_prediction.py:

  • سرویس chart فعلی مزرعه را صدا می‌زند.
  • chart هم قبلاً گیاه را از مسیر canonical مزرعه resolve کرده است.
  • بنابراین yield همیشه روی یک گیاه مشخص از assignmentهای مزرعه محاسبه می‌شود.

4) نقش serializerها در resolve کردن نام گیاه

فایل مهم:

  • crop_simulation/serializers.py

کلاس مهم:

  • PlantNameAliasMixin

این mixin:

  • plant_name
  • crop
  • crop_name

را قبول می‌کند و با apps.get_app_config("plant").resolve_plant_name(...) آن را canonical می‌کند.

پس حتی اگر کلاینت نام گیاه را با alias بفرستد، سرویس شبیه‌سازی با نام استاندارد کار می‌کند.

5) ارتباط location_data با گیاه‌ها

فایل مهم:

  • location_data/cluster_recommendation.py

تابع اصلی:

  • build_cluster_crop_recommendations

این تابع ارتباط بین کلاسترهای KMeans و گیاه‌های مزرعه را می‌سازد.

ورودی

  • farm_uuid

کارهایی که انجام می‌دهد

  1. مزرعه را از farm_data پیدا می‌کند.
  2. لیست گیاه‌های ثبت‌شده را با get_farm_plant_assignments می‌خواند.
  3. snapshot کلاسترهای location_data را می‌گیرد.
  4. برای هر گیاه ثبت‌شده، با build_simulation_payload_from_farm یک payload پایه می‌سازد.
  5. برای هر کلاستر:
    • متریک‌های همان کلاستر مثل ndvi, ndwi, soil_vv, soil_vv_db را جمع می‌کند.
    • پارامترهای soil/site را با داده همان کلاستر override می‌کند.
    • برای تک‌تک گیاه‌های مزرعه شبیه‌سازی اجرا می‌کند.
    • خروجی‌ها را بر اساس yield_estimate رتبه‌بندی می‌کند.
  6. بهترین گیاه را به عنوان suggested_plant برمی‌گرداند.

نتیجه

location_data خودش مرجع گیاه نیست؛ فقط:

  • گیاه‌ها را از farm_data
  • نام canonical را از plant
  • منطق شبیه‌سازی را از crop_simulation

می‌گیرد و روی داده‌های کلاستر اعمال می‌کند.

6) ترتیب مسئولیت‌ها

برای جلوگیری از ابهام، مسئولیت هر بخش این است:

  • plant:

    • canonical name
    • alias resolving
  • farm_data:

    • snapshot گیاه
    • assignment گیاه به مزرعه
    • تبدیل snapshot به runtime plant
  • crop_simulation:

    • ساخت payload شبیه‌سازی از مزرعه و گیاه
    • اجرای شبیه‌سازی رشد، عملکرد و برداشت
  • location_data:

    • خواندن کلاسترهای KMeans
    • مقایسه گیاه‌های مزرعه برای هر کلاستر
    • پیشنهاد گیاه برای sub-block

7) نکات مهم طراحی

  • relation قدیمی SensorData.plants مسیر legacy است و منبع canonical نیست.
  • مسیر canonical برای گیاه‌های مزرعه، FarmPlantAssignment و PlantCatalogSnapshot است.
  • سرویس‌های شبیه‌سازی نباید مستقیم از plant.Plant برای گیاه مزرعه استفاده کنند؛ مسیر درست، farm_data.services.get_runtime_plant_for_farm است.
  • اگر plant_name صریح داده نشود، معمولاً گیاه اول assignmentهای مزرعه انتخاب می‌شود.
  • اگر چند گیاه برای مزرعه ثبت شده باشد، endpoint پیشنهاد کلاستر همه‌ی آن‌ها را compare می‌کند.

8) خلاصه جریان end-to-end

جریان کامل به این صورت است:

  1. Backend plant catalog -> PlantCatalogSnapshot
  2. farm selected plants -> FarmPlantAssignment
  3. client request with farm_uuid
  4. farm -> runtime plant resolution
  5. runtime plant + farm metrics -> simulation payload
  6. simulation payload -> PCSE/projection
  7. cluster metrics + plant candidates -> recommended crop per cluster

9) فایل‌های کلیدی برای مرور سریع

  • plant/apps.py
  • farm_data/models.py
  • farm_data/services.py
  • crop_simulation/services.py
  • crop_simulation/growth_simulation.py
  • crop_simulation/harvest_prediction.py
  • crop_simulation/yield_prediction.py
  • location_data/cluster_recommendation.py