Files
Backend/docs/irrigation_fertilization_plan_parser_apis.md
2026-04-30 04:00:07 +03:30

620 lines
18 KiB
Markdown

# Free-Text Plan Parser APIs
این فایل برای تیم فرانت‌اند آماده شده و دو API جدید زیر را توضیح می‌دهد:
- `POST /api/irrigation/plan-from-text/`
- `POST /api/fertilization/plan-from-text/`
هدف هر دو API:
- کاربر یک متن آزاد می‌نویسد
- backend تلاش می‌کند برنامه آبیاری یا کودهی را به JSON ساختاریافته تبدیل کند
- اگر اطلاعات کامل باشد، JSON نهایی برمی‌گردد
- اگر اطلاعات ناقص باشد، API سوال‌های تکمیلی برمی‌گرداند
- فرانت‌اند سوال‌ها را از کاربر می‌پرسد و پاسخ‌ها را دوباره برای API می‌فرستد
---
## رفتار کلی هر دو API
هر دو endpoint یک flow یکسان دارند:
1. کاربر متن آزاد اولیه را می‌فرستد
2. اگر متن کامل باشد:
- `status = "completed"`
- `final_plan` برمی‌گردد
3. اگر متن ناقص باشد:
- `status = "needs_clarification"`
- `missing_fields` برمی‌گردد
- `questions` برمی‌گردد
4. فرانت‌اند پاسخ کاربر به سوال‌ها را جمع می‌کند
5. دوباره همان endpoint را با `answers` و `partial_plan` صدا می‌زند
6. این روند تا ساخته شدن `final_plan` ادامه پیدا می‌کند
---
## الگوی کلی response
هر دو API از envelope استاندارد استفاده می‌کنند:
```json
{
"code": 200,
"msg": "موفق",
"data": {}
}
```
### معنی فیلدهای envelope
| فیلد | نوع | توضیح |
|---|---|---|
| `code` | number | کد منطقی پاسخ |
| `msg` | string | پیام کوتاه پاسخ |
| `data` | object | داده اصلی API |
---
## 1) API استخراج برنامه آبیاری
### Endpoint
```http
POST /api/irrigation/plan-from-text/
```
### کاربرد
این API متن آزاد کاربر درباره برنامه آبیاری را به JSON ساختاریافته تبدیل می‌کند.
### Request Body
هر سه فیلد زیر اختیاری هستند، اما حداقل یکی از این‌ها باید ارسال شود:
- `message`
- `answers`
- `partial_plan`
#### ساختار request
```json
{
"message": "برای گوجه فرنگی با آبیاری قطره ای هر سه روز یک بار صبح زود 25 دقیقه آبیاری می کنم و حدود 18 لیتر برای هر بوته می دهم.",
"answers": {
"growth_stage": "گلدهی"
},
"partial_plan": {
"crop_name": "گوجه فرنگی",
"irrigation_method": "قطره ای"
},
"farm_uuid": "11111111-1111-1111-1111-111111111111"
}
```
### فیلدهای request
| فیلد | نوع | اجباری | توضیح |
|---|---|---:|---|
| `message` | string | خیر | متن آزاد کاربر |
| `answers` | object | خیر | پاسخ‌های تکمیلی کاربر به سوال‌هایی که قبلا API داده |
| `partial_plan` | object | خیر | خروجی مرحله قبل برای ادامه تکمیل |
| `farm_uuid` | string | خیر | برای غنی‌سازی context مزرعه در AI |
### قانون validation
اگر هیچ‌کدام از `message`، `answers` یا `partial_plan` ارسال نشوند:
```json
{
"code": 400,
"msg": "Bad Request",
"data": {
"non_field_errors": [
"حداقل یکی از message، answers یا partial_plan باید ارسال شود."
]
}
}
```
---
## پاسخ موفق - حالت تکمیل شده
وقتی همه اطلاعات لازم موجود باشد:
```json
{
"code": 200,
"msg": "موفق",
"data": {
"status": "completed",
"status_fa": "تکمیل شد",
"summary": "برنامه آبیاری برای گوجه‌فرنگی به روش قطره‌ای هر سه روز یک‌بار صبح زود به مدت 25 دقیقه اجرا می‌شود.",
"missing_fields": [],
"questions": [],
"collected_data": {
"crop_name": "گوجه‌فرنگی",
"growth_stage": "گلدهی",
"irrigation_method": "قطره‌ای",
"water_amount_per_event": "18 لیتر برای هر بوته",
"duration_minutes": 25,
"frequency_text": "هر سه روز یک‌بار",
"interval_days": 3,
"preferred_time_of_day": "صبح زود",
"start_date": "از امروز",
"target_area": "کل مزرعه",
"trigger_conditions": [],
"notes": []
},
"final_plan": {
"crop_name": "گوجه‌فرنگی",
"growth_stage": "گلدهی",
"irrigation_method": "قطره‌ای",
"water_amount_per_event": "18 لیتر برای هر بوته",
"duration_minutes": 25,
"frequency_text": "هر سه روز یک‌بار",
"interval_days": 3,
"preferred_time_of_day": "صبح زود",
"start_date": "از امروز",
"target_area": "کل مزرعه",
"trigger_conditions": [],
"notes": []
}
}
}
```
### فیلدهای `data`
| فیلد | نوع | توضیح |
|---|---|---|
| `status` | string | یکی از `completed` یا `needs_clarification` |
| `status_fa` | string | نسخه فارسی وضعیت |
| `summary` | string | خلاصه قابل نمایش برای کاربر |
| `missing_fields` | array[string] | فیلدهای ناقص |
| `questions` | array[object] | سوال‌های تکمیلی |
| `collected_data` | object | داده‌ای که تا الان از متن و جواب‌ها استخراج شده |
| `final_plan` | object/null | برنامه نهایی؛ فقط در حالت `completed` |
### فیلدهای `collected_data` و `final_plan`
| فیلد | نوع | توضیح |
|---|---|---|
| `crop_name` | string | نام محصول |
| `growth_stage` | string | مرحله رشد محصول |
| `irrigation_method` | string | روش آبیاری |
| `water_amount_per_event` | string | مقدار آب هر نوبت |
| `duration_minutes` | number | مدت هر نوبت آبیاری به دقیقه |
| `frequency_text` | string | توصیف متنی فاصله آبیاری |
| `interval_days` | number | فاصله آبیاری بر حسب روز |
| `preferred_time_of_day` | string | زمان مناسب اجرای آبیاری |
| `start_date` | string | زمان یا تاریخ شروع برنامه |
| `target_area` | string | محدوده هدف برنامه |
| `trigger_conditions` | array[string] | شرایط تریگر اختیاری |
| `notes` | array[string] | نکات تکمیلی |
---
## پاسخ موفق - حالت نیاز به سوال تکمیلی
اگر اطلاعات کامل نباشد:
```json
{
"code": 200,
"msg": "موفق",
"data": {
"status": "needs_clarification",
"status_fa": "نیازمند پرسش تکمیلی",
"summary": "اطلاعات برنامه آبیاری برای ساخت JSON نهایی کافی نیست و به چند پاسخ تکمیلی نیاز است.",
"missing_fields": [
"growth_stage",
"start_date",
"target_area"
],
"questions": [
{
"id": "growth_stage",
"field": "growth_stage",
"question": "محصول الان در چه مرحله رشدی قرار دارد؟",
"rationale": "مرحله رشد برای کامل شدن برنامه لازم است."
},
{
"id": "start_date",
"field": "start_date",
"question": "این برنامه از چه تاریخی یا از چه زمانی باید شروع شود؟",
"rationale": "زمان شروع برنامه هنوز مشخص نشده است."
},
{
"id": "target_area",
"field": "target_area",
"question": "این برنامه برای کل مزرعه است یا بخش/ناحیه خاصی از مزرعه؟",
"rationale": "محدوده اجرای برنامه باید مشخص باشد."
}
],
"collected_data": {
"crop_name": "گوجه‌فرنگی",
"growth_stage": null,
"irrigation_method": "قطره‌ای",
"water_amount_per_event": "18 لیتر برای هر بوته",
"duration_minutes": 25,
"frequency_text": "هر سه روز یک‌بار",
"interval_days": 3,
"preferred_time_of_day": "صبح زود",
"start_date": null,
"target_area": null,
"trigger_conditions": [],
"notes": []
},
"final_plan": null
}
}
```
### ساختار `questions`
| فیلد | نوع | توضیح |
|---|---|---|
| `id` | string | شناسه سوال |
| `field` | string | فیلدی که این سوال برای آن پرسیده شده |
| `question` | string | متن سوال برای نمایش به کاربر |
| `rationale` | string | توضیح کوتاه برای اینکه چرا این سوال لازم است |
---
## flow پیشنهادی فرانت‌اند برای آبیاری
### مرحله 1
کاربر متن آزاد می‌فرستد:
```json
{
"message": "برای گوجه فرنگی هر سه روز یک بار آبیاری می کنم."
}
```
### مرحله 2
اگر `status = needs_clarification` بود:
- سوال‌ها را از `data.questions` به کاربر نمایش بده
- پاسخ‌ها را جمع کن
### مرحله 3
درخواست تکمیلی بزن:
```json
{
"partial_plan": {
"crop_name": "گوجه فرنگی",
"growth_stage": null,
"irrigation_method": null,
"water_amount_per_event": null,
"duration_minutes": null,
"frequency_text": "هر سه روز یک بار",
"interval_days": 3,
"preferred_time_of_day": null,
"start_date": null,
"target_area": null,
"trigger_conditions": [],
"notes": []
},
"answers": {
"growth_stage": "گلدهی",
"irrigation_method": "قطره ای",
"water_amount_per_event": "18 لیتر برای هر بوته",
"duration_minutes": 25,
"preferred_time_of_day": "صبح زود",
"start_date": "از امروز",
"target_area": "کل مزرعه"
}
}
```
### مرحله 4
اگر `status = completed` شد:
- از `data.final_plan` به عنوان JSON نهایی استفاده کن
---
## 2) API استخراج برنامه کودهی
### Endpoint
```http
POST /api/fertilization/plan-from-text/
```
### کاربرد
این API متن آزاد کاربر درباره برنامه کودهی را به JSON ساختاریافته تبدیل می‌کند.
### Request Body
```json
{
"message": "برای گندم در مرحله پنجه زنی هر 12 روز یک بار 20-20-20 به مقدار 35 کیلوگرم در هکتار از طریق کودآبیاری می دهم.",
"answers": {
"timing": "هر 12 روز یک بار"
},
"partial_plan": {
"crop_name": "گندم"
},
"farm_uuid": "11111111-1111-1111-1111-111111111111"
}
```
### فیلدهای request
| فیلد | نوع | اجباری | توضیح |
|---|---|---:|---|
| `message` | string | خیر | متن آزاد کاربر |
| `answers` | object | خیر | پاسخ‌های تکمیلی کاربر |
| `partial_plan` | object | خیر | داده استخراج شده مرحله قبل |
| `farm_uuid` | string | خیر | برای context مزرعه |
### validation error
```json
{
"code": 400,
"msg": "Bad Request",
"data": {
"non_field_errors": [
"حداقل یکی از message، answers یا partial_plan باید ارسال شود."
]
}
}
```
---
## پاسخ موفق - حالت تکمیل شده
```json
{
"code": 200,
"msg": "موفق",
"data": {
"status": "completed",
"status_fa": "تکمیل شد",
"summary": "برنامه کودهی برای گندم در مرحله پنجه زنی با کود 20-20-20 به صورت کودآبیاری هر 12 روز یک بار اجرا می شود.",
"missing_fields": [],
"questions": [],
"collected_data": {
"crop_name": "گندم",
"growth_stage": "پنجه زنی",
"objective": "تقویت رشد رویشی",
"applications": [
{
"fertilizer_name": "کود کامل 20-20-20",
"formula": "20-20-20",
"amount": "35 کیلوگرم در هکتار",
"application_method": "کودآبیاری",
"timing": "هر 12 روز یک بار",
"interval_days": 12,
"purpose": "تقویت رشد رویشی"
}
],
"notes": []
},
"final_plan": {
"crop_name": "گندم",
"growth_stage": "پنجه زنی",
"objective": "تقویت رشد رویشی",
"applications": [
{
"fertilizer_name": "کود کامل 20-20-20",
"formula": "20-20-20",
"amount": "35 کیلوگرم در هکتار",
"application_method": "کودآبیاری",
"timing": "هر 12 روز یک بار",
"interval_days": 12,
"purpose": "تقویت رشد رویشی"
}
],
"notes": []
}
}
}
```
### فیلدهای `collected_data` و `final_plan`
| فیلد | نوع | توضیح |
|---|---|---|
| `crop_name` | string | نام محصول |
| `growth_stage` | string | مرحله رشد |
| `objective` | string/null | هدف برنامه |
| `applications` | array[object] | لیست نوبت‌ها یا اقلام کودی |
| `notes` | array[string] | نکات تکمیلی |
### ساختار هر application
| فیلد | نوع | توضیح |
|---|---|---|
| `fertilizer_name` | string | نام کود |
| `formula` | string | فرمول یا آنالیز کود |
| `amount` | string | مقدار مصرف |
| `application_method` | string | روش مصرف |
| `timing` | string | زمان‌بندی مصرف |
| `interval_days` | number | فاصله بین نوبت‌ها |
| `purpose` | string/null | هدف آن نوبت |
---
## پاسخ موفق - حالت نیاز به سوال تکمیلی
```json
{
"code": 200,
"msg": "موفق",
"data": {
"status": "needs_clarification",
"status_fa": "نیازمند پرسش تکمیلی",
"summary": "اطلاعات برنامه کودهی برای ساخت JSON نهایی کافی نیست و به چند پاسخ تکمیلی نیاز است.",
"missing_fields": [
"growth_stage",
"formula",
"interval_days"
],
"questions": [
{
"id": "growth_stage",
"field": "growth_stage",
"question": "محصول الان در چه مرحله رشدی قرار دارد؟",
"rationale": "مرحله رشد برای تکمیل برنامه لازم است."
},
{
"id": "formula",
"field": "formula",
"question": "فرمول یا آنالیز کود چیست؟ مثلا 20-20-20.",
"rationale": "ترکیب دقیق کود هنوز مشخص نشده است."
},
{
"id": "interval_days",
"field": "interval_days",
"question": "فاصله بین نوبت های مصرف کود چند روز است؟",
"rationale": "عدد فاصله بین نوبت ها برای JSON نهایی لازم است."
}
],
"collected_data": {
"crop_name": "گندم",
"growth_stage": null,
"objective": null,
"applications": [
{
"fertilizer_name": "کود کامل",
"formula": null,
"amount": "35 کیلوگرم در هکتار",
"application_method": "کودآبیاری",
"timing": "هر چند وقت یک بار",
"interval_days": null,
"purpose": null
}
],
"notes": []
},
"final_plan": null
}
}
```
---
## flow پیشنهادی فرانت‌اند برای کودهی
### درخواست اولیه
```json
{
"message": "برای گندم از کود کامل استفاده می کنم."
}
```
### اگر incomplete بود
- از `questions` سوال‌ها را بگیر
- در UI نمایش بده
- پاسخ‌ها را جمع کن
### درخواست تکمیلی
```json
{
"partial_plan": {
"crop_name": "گندم",
"growth_stage": null,
"objective": null,
"applications": [
{
"fertilizer_name": "کود کامل",
"formula": null,
"amount": null,
"application_method": null,
"timing": null,
"interval_days": null,
"purpose": null
}
],
"notes": []
},
"answers": {
"growth_stage": "پنجه زنی",
"formula": "20-20-20",
"amount": "35 کیلوگرم در هکتار",
"application_method": "کودآبیاری",
"timing": "هر 12 روز یک بار",
"interval_days": 12
}
}
```
### اگر complete شد
- از `final_plan` استفاده کن
---
## نکات مهم برای فرانت‌اند
### 1. به `status` تکیه کنید
مهم‌ترین فیلد برای کنترل flow:
- `completed`
- `needs_clarification`
### 2. اگر `needs_clarification` بود
باید:
- `questions` را به کاربر نمایش دهید
- `partial_plan` را نگه دارید
- پاسخ‌های کاربر را در `answers` ارسال کنید
### 3. اگر `completed` بود
باید:
- `final_plan` را به عنوان نسخه نهایی برنامه ذخیره یا نمایش دهید
### 4. `collected_data` همیشه مهم است
حتی اگر برنامه ناقص باشد، `collected_data` نشان می‌دهد سیستم تا این لحظه چه چیزهایی را فهمیده است.
### 5. null در حالت ناقص طبیعی است
در حالت `needs_clarification` ممکن است بعضی فیلدهای `collected_data` `null` باشند.
اما در حالت `completed` نباید فیلدهای اصلی ناقص باشند.
### 6. بهتر است سوال‌ها را step-by-step بپرسید
پیشنهاد:
- سوال اول را نشان بده
- جواب را بگیر
- همه جواب‌ها را در `answers` جمع کن
- دوباره API را صدا بزن
---
## جمع‌بندی تفاوت دو API
| API | موضوع | خروجی نهایی |
|---|---|---|
| `/api/irrigation/plan-from-text/` | استخراج برنامه آبیاری | `final_plan` با ساختار آبیاری |
| `/api/fertilization/plan-from-text/` | استخراج برنامه کودهی | `final_plan` با ساختار کودهی |
---
## مسیر فایل
این داکیومنت در این مسیر ذخیره شده:
`docs/irrigation_fertilization_plan_parser_apis.md`