1032 lines
23 KiB
Markdown
1032 lines
23 KiB
Markdown
|
|
# مستند کامل response های Location Data
|
||
|
|
|
||
|
|
این فایل، response همه endpointهای اصلی `Location Data` را به زبان ساده و دقیق توضیح میدهد.
|
||
|
|
|
||
|
|
مسیرهای این مستند:
|
||
|
|
|
||
|
|
- `GET /api/location-data/`
|
||
|
|
- `POST /api/location-data/`
|
||
|
|
- `POST /api/location-data/ndvi-health/`
|
||
|
|
- `GET /api/location-data/remote-sensing/`
|
||
|
|
- `POST /api/location-data/remote-sensing/`
|
||
|
|
- `GET /api/location-data/remote-sensing/cluster-blocks/{cluster_uuid}/live/`
|
||
|
|
- `GET /api/location-data/remote-sensing/cluster-recommendations/`
|
||
|
|
- `GET /api/location-data/remote-sensing/results/{result_id}/k-options/`
|
||
|
|
- `POST /api/location-data/remote-sensing/results/{result_id}/k-options/activate/`
|
||
|
|
- `GET /api/location-data/remote-sensing/runs/{run_id}/status/`
|
||
|
|
|
||
|
|
## 1) ساختار عمومی همه response ها
|
||
|
|
|
||
|
|
تقریبا همه endpointها این envelope را دارند:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 200,
|
||
|
|
"msg": "success",
|
||
|
|
"data": {}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
توضیح فیلدها:
|
||
|
|
|
||
|
|
- `code`: کد منطقی response در body
|
||
|
|
- `msg`: پیام کوتاه
|
||
|
|
- `data`: payload اصلی
|
||
|
|
|
||
|
|
در خطاها معمولا یکی از این دو حالت برمیگردد:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 400,
|
||
|
|
"msg": "داده نامعتبر.",
|
||
|
|
"data": {
|
||
|
|
"field_name": ["error message"]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
یا:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 404,
|
||
|
|
"msg": "location پیدا نشد.",
|
||
|
|
"data": null
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 2) `GET /api/location-data/`
|
||
|
|
|
||
|
|
کاربرد:
|
||
|
|
|
||
|
|
- خواندن ساختار ذخیرهشده مزرعه
|
||
|
|
- خواندن بلوکها
|
||
|
|
- خواندن subdivisionها
|
||
|
|
- خواندن snapshotهای ماهوارهای ذخیره/تجمیعشده
|
||
|
|
|
||
|
|
### response موفق `200`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 200,
|
||
|
|
"msg": "success",
|
||
|
|
"data": {
|
||
|
|
"source": "database",
|
||
|
|
"id": 12,
|
||
|
|
"lon": "51.389000",
|
||
|
|
"lat": "35.689200",
|
||
|
|
"input_block_count": 2,
|
||
|
|
"farm_boundary": {},
|
||
|
|
"block_layout": {},
|
||
|
|
"block_subdivisions": [],
|
||
|
|
"satellite_snapshots": []
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### توضیح فیلدهای `data`
|
||
|
|
|
||
|
|
- `source`: در این endpoint همیشه از دیتابیس است و معمولا مقدار آن `database` است
|
||
|
|
- `id`: شناسه داخلی `SoilLocation`
|
||
|
|
- `lon`: طول جغرافیایی location
|
||
|
|
- `lat`: عرض جغرافیایی location
|
||
|
|
- `input_block_count`: تعداد بلوکهای تعریفشده برای این مزرعه
|
||
|
|
- `farm_boundary`: مرز کل مزرعه به صورت GeoJSON
|
||
|
|
- `block_layout`: ساختار کلی بلوکها، وضعیت الگوریتم، sub-blockها و metadata سطح مزرعه
|
||
|
|
- `block_subdivisions`: لیست subdivisionهای سطح بلوک
|
||
|
|
- `satellite_snapshots`: خلاصههای سنجشازدور هر بلوک و هر sub-block
|
||
|
|
|
||
|
|
### ساختار هر آیتم `block_subdivisions`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"block_code": "block-1",
|
||
|
|
"chunk_size_sqm": 900,
|
||
|
|
"grid_points": [],
|
||
|
|
"centroid_points": [],
|
||
|
|
"grid_point_count": 0,
|
||
|
|
"centroid_count": 0,
|
||
|
|
"elbow_plot": null,
|
||
|
|
"status": "defined",
|
||
|
|
"metadata": {},
|
||
|
|
"created_at": "2026-05-13T14:00:00Z",
|
||
|
|
"updated_at": "2026-05-13T14:00:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
توضیح:
|
||
|
|
|
||
|
|
- `block_code`: کد بلوک
|
||
|
|
- `chunk_size_sqm`: اندازه هر سلول تحلیل
|
||
|
|
- `grid_points`: نقاط grid تولیدشده
|
||
|
|
- `centroid_points`: centroidهای grid
|
||
|
|
- `grid_point_count`: تعداد نقاط grid
|
||
|
|
- `centroid_count`: تعداد centroidها
|
||
|
|
- `elbow_plot`: تصویر elbow plot اگر ساخته شده باشد
|
||
|
|
- `status`: وضعیت subdivision مثل `defined`، `created`، `subdivided`
|
||
|
|
- `metadata`: دادههای تکمیلی
|
||
|
|
|
||
|
|
### `400`
|
||
|
|
|
||
|
|
وقتی `lat` یا `lon` نامعتبر باشد:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 400,
|
||
|
|
"msg": "داده نامعتبر.",
|
||
|
|
"data": {
|
||
|
|
"lat": ["..."],
|
||
|
|
"lon": ["..."]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### `404`
|
||
|
|
|
||
|
|
وقتی location پیدا نشود:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 404,
|
||
|
|
"msg": "location پیدا نشد.",
|
||
|
|
"data": null
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 3) `POST /api/location-data/`
|
||
|
|
|
||
|
|
کاربرد:
|
||
|
|
|
||
|
|
- ثبت یا بهروزرسانی مزرعه
|
||
|
|
- ثبت مرز مزرعه
|
||
|
|
- ثبت بلوکهای کشاورز
|
||
|
|
|
||
|
|
### response موفق `200`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 200,
|
||
|
|
"msg": "success",
|
||
|
|
"data": {
|
||
|
|
"source": "created",
|
||
|
|
"id": 12,
|
||
|
|
"lon": "51.389000",
|
||
|
|
"lat": "35.689200",
|
||
|
|
"input_block_count": 2,
|
||
|
|
"farm_boundary": {},
|
||
|
|
"block_layout": {},
|
||
|
|
"block_subdivisions": [],
|
||
|
|
"satellite_snapshots": []
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### توضیح `source`
|
||
|
|
|
||
|
|
- `created`: این location تازه ساخته شده
|
||
|
|
- `database`: location از قبل وجود داشته و فقط update شده یا همان داده قبلی برگشته
|
||
|
|
|
||
|
|
### `400`
|
||
|
|
|
||
|
|
حالت اول: body نامعتبر باشد:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 400,
|
||
|
|
"msg": "داده نامعتبر.",
|
||
|
|
"data": {
|
||
|
|
"farm_boundary": ["مختصات گوشههای کل زمین باید ارسال شود."]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
حالت دوم: مرز کل مزرعه نه در request آمده و نه قبلا ذخیره شده:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 400,
|
||
|
|
"msg": "داده نامعتبر.",
|
||
|
|
"data": {
|
||
|
|
"farm_boundary": [
|
||
|
|
"برای ثبت location باید گوشههای کل زمین ارسال یا قبلاً ذخیره شده باشد."
|
||
|
|
]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 4) `POST /api/location-data/ndvi-health/`
|
||
|
|
|
||
|
|
کاربرد:
|
||
|
|
|
||
|
|
- برگرداندن وضعیت سلامت پوشش گیاهی مزرعه بر اساس NDVI
|
||
|
|
|
||
|
|
### response موفق `200`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 200,
|
||
|
|
"msg": "success",
|
||
|
|
"data": {
|
||
|
|
"ndviIndex": 0.63,
|
||
|
|
"mean_ndvi": 0.63,
|
||
|
|
"ndvi_map": {},
|
||
|
|
"vegetation_health_class": "healthy",
|
||
|
|
"observation_date": "2026-05-12",
|
||
|
|
"satellite_source": "sentinel-2",
|
||
|
|
"healthData": [
|
||
|
|
{
|
||
|
|
"title": "میانگین NDVI",
|
||
|
|
"value": 0.63,
|
||
|
|
"color": "green",
|
||
|
|
"icon": "leaf"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### توضیح فیلدها
|
||
|
|
|
||
|
|
- `ndviIndex`: شاخص اصلی NDVI برای UI
|
||
|
|
- `mean_ndvi`: میانگین NDVI محاسبهشده
|
||
|
|
- `ndvi_map`: داده نقشه یا لایه NDVI
|
||
|
|
- `vegetation_health_class`: کلاس سلامت پوشش گیاهی
|
||
|
|
- `observation_date`: تاریخ مشاهده
|
||
|
|
- `satellite_source`: منبع داده ماهوارهای
|
||
|
|
- `healthData`: کارتهای خلاصه برای نمایش در فرانت
|
||
|
|
|
||
|
|
### ساختار هر آیتم `healthData`
|
||
|
|
|
||
|
|
- `title`: عنوان آیتم
|
||
|
|
- `value`: مقدار عددی یا ساختار JSON
|
||
|
|
- `color`: رنگ پیشنهادی UI
|
||
|
|
- `icon`: آیکون پیشنهادی UI
|
||
|
|
|
||
|
|
### `400`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 400,
|
||
|
|
"msg": "داده نامعتبر.",
|
||
|
|
"data": {
|
||
|
|
"farm_uuid": ["..."]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### `404`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 404,
|
||
|
|
"msg": "مزرعه پیدا نشد.",
|
||
|
|
"data": null
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 5) `GET /api/location-data/remote-sensing/`
|
||
|
|
|
||
|
|
کاربرد:
|
||
|
|
|
||
|
|
- فقط نتایج cache شده remote sensing و subdivision را میخواند
|
||
|
|
- هیچ پردازش جدیدی اجرا نمیکند
|
||
|
|
|
||
|
|
### response موفق `200`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 200,
|
||
|
|
"msg": "success",
|
||
|
|
"data": {
|
||
|
|
"status": "success",
|
||
|
|
"source": "database",
|
||
|
|
"location": {},
|
||
|
|
"block_code": "",
|
||
|
|
"chunk_size_sqm": 900,
|
||
|
|
"temporal_extent": {
|
||
|
|
"start_date": "2026-04-12",
|
||
|
|
"end_date": "2026-05-12"
|
||
|
|
},
|
||
|
|
"summary": {
|
||
|
|
"cell_count": 12,
|
||
|
|
"ndvi_mean": 0.54,
|
||
|
|
"ndwi_mean": 0.21,
|
||
|
|
"soil_vv_db_mean": -8.92
|
||
|
|
},
|
||
|
|
"cells": [],
|
||
|
|
"run": {},
|
||
|
|
"subdivision_result": {},
|
||
|
|
"pagination": {},
|
||
|
|
"metadata": {
|
||
|
|
"farm_uuid": "11111111-1111-1111-1111-111111111111",
|
||
|
|
"cache_hit": true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### حالتهای مهم `status`
|
||
|
|
|
||
|
|
- `success`: داده کامل در DB موجود است
|
||
|
|
- `processing`: run در حال انجام است و هنوز observation نهایی کامل نشده
|
||
|
|
- `not_found`: runی وجود داشته ولی observation قابل استفاده برنگشته
|
||
|
|
|
||
|
|
### توضیح فیلدها
|
||
|
|
|
||
|
|
- `status`: وضعیت نتیجه
|
||
|
|
- `source`: معمولا `database` یا `processing`
|
||
|
|
- `location`: همان ساختار `SoilLocationResponse`
|
||
|
|
- `block_code`: برای full farm معمولا رشته خالی `""`
|
||
|
|
- `chunk_size_sqm`: اندازه سلول تحلیل
|
||
|
|
- `temporal_extent.start_date`: شروع بازه تحلیل
|
||
|
|
- `temporal_extent.end_date`: پایان بازه تحلیل
|
||
|
|
- `summary`: خلاصه آماری observationها
|
||
|
|
- `cells`: observationهای صفحه فعلی
|
||
|
|
- `run`: اطلاعات run مرتبط
|
||
|
|
- `subdivision_result`: نتیجه clustering و KMeans
|
||
|
|
- `pagination`: اطلاعات صفحهبندی `cells` و گاهی `assignments`
|
||
|
|
- `metadata.cache_hit`: نشان میدهد پاسخ از cache/DB آمده
|
||
|
|
|
||
|
|
### ساختار `summary`
|
||
|
|
|
||
|
|
- `cell_count`: تعداد سلولها
|
||
|
|
- `ndvi_mean`: میانگین NDVI
|
||
|
|
- `ndwi_mean`: میانگین NDWI
|
||
|
|
- `soil_vv_db_mean`: میانگین `soil_vv_db`
|
||
|
|
|
||
|
|
### ساختار هر آیتم `cells`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"cell_code": "cell-1",
|
||
|
|
"block_code": "",
|
||
|
|
"chunk_size_sqm": 900,
|
||
|
|
"centroid_lat": "35.689500",
|
||
|
|
"centroid_lon": "51.389500",
|
||
|
|
"geometry": {},
|
||
|
|
"temporal_start": "2026-04-12",
|
||
|
|
"temporal_end": "2026-05-12",
|
||
|
|
"ndvi": 0.61,
|
||
|
|
"ndwi": 0.22,
|
||
|
|
"soil_vv": 0.13,
|
||
|
|
"soil_vv_db": -8.860566,
|
||
|
|
"metadata": {}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### ساختار `run`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": 10,
|
||
|
|
"block_code": "",
|
||
|
|
"chunk_size_sqm": 900,
|
||
|
|
"temporal_start": "2026-04-12",
|
||
|
|
"temporal_end": "2026-05-12",
|
||
|
|
"status": "success",
|
||
|
|
"status_label": "completed",
|
||
|
|
"pipeline_status": "completed",
|
||
|
|
"stage": "completed",
|
||
|
|
"selected_features": ["ndvi", "ndwi", "soil_vv_db"],
|
||
|
|
"requested_cluster_count": null,
|
||
|
|
"metadata": {},
|
||
|
|
"error_message": "",
|
||
|
|
"started_at": null,
|
||
|
|
"finished_at": null,
|
||
|
|
"created_at": "2026-05-13T14:00:00Z",
|
||
|
|
"updated_at": "2026-05-13T14:00:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### ساختار `subdivision_result`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": 5,
|
||
|
|
"block_code": "",
|
||
|
|
"chunk_size_sqm": 900,
|
||
|
|
"temporal_start": "2026-04-12",
|
||
|
|
"temporal_end": "2026-05-12",
|
||
|
|
"cluster_count": 3,
|
||
|
|
"selected_features": ["ndvi", "ndwi", "soil_vv_db"],
|
||
|
|
"skipped_cell_codes": [],
|
||
|
|
"metadata": {},
|
||
|
|
"available_k_options": [],
|
||
|
|
"cluster_blocks": [],
|
||
|
|
"assignments": [],
|
||
|
|
"created_at": "2026-05-13T14:00:00Z",
|
||
|
|
"updated_at": "2026-05-13T14:00:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### ساختار هر `assignment`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"cell_code": "cell-1",
|
||
|
|
"cluster_label": 0,
|
||
|
|
"centroid_lat": "35.689500",
|
||
|
|
"centroid_lon": "51.389500",
|
||
|
|
"raw_feature_values": {
|
||
|
|
"ndvi": 0.61
|
||
|
|
},
|
||
|
|
"scaled_feature_values": {
|
||
|
|
"ndvi": 0.21
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### ساختار هر `cluster_block`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"uuid": "11111111-1111-1111-1111-111111111111",
|
||
|
|
"sub_block_code": "cluster-0",
|
||
|
|
"cluster_label": 0,
|
||
|
|
"chunk_size_sqm": 900,
|
||
|
|
"centroid_lat": "35.689500",
|
||
|
|
"centroid_lon": "51.389500",
|
||
|
|
"center_cell_code": "cell-1",
|
||
|
|
"center_cell_lat": "35.689500",
|
||
|
|
"center_cell_lon": "51.389500",
|
||
|
|
"cell_count": 4,
|
||
|
|
"cell_codes": ["cell-1", "cell-2"],
|
||
|
|
"geometry": {},
|
||
|
|
"metadata": {},
|
||
|
|
"created_at": "2026-05-13T14:00:00Z",
|
||
|
|
"updated_at": "2026-05-13T14:00:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### `400`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 400,
|
||
|
|
"msg": "داده نامعتبر.",
|
||
|
|
"data": {
|
||
|
|
"farm_uuid": ["..."]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### `404`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 404,
|
||
|
|
"msg": "location پیدا نشد.",
|
||
|
|
"data": null
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 6) `POST /api/location-data/remote-sensing/`
|
||
|
|
|
||
|
|
کاربرد:
|
||
|
|
|
||
|
|
- اجرای async تحلیل سنجشازدور
|
||
|
|
- ساخت run و task قابل polling
|
||
|
|
- اگر داده قبلا در DB موجود باشد هم یک `task_id` tracking برمیگرداند تا status بلافاصله نتیجه را بدهد
|
||
|
|
|
||
|
|
### response موفق `202`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 202,
|
||
|
|
"msg": "تحلیل سنجشازدور در صف قرار گرفت.",
|
||
|
|
"data": {
|
||
|
|
"status": "processing",
|
||
|
|
"source": "processing",
|
||
|
|
"location": {},
|
||
|
|
"block_code": "",
|
||
|
|
"chunk_size_sqm": 900,
|
||
|
|
"temporal_extent": {
|
||
|
|
"start_date": "2026-04-12",
|
||
|
|
"end_date": "2026-05-12"
|
||
|
|
},
|
||
|
|
"summary": {
|
||
|
|
"cell_count": 0,
|
||
|
|
"ndvi_mean": null,
|
||
|
|
"ndwi_mean": null,
|
||
|
|
"soil_vv_db_mean": null
|
||
|
|
},
|
||
|
|
"cells": [],
|
||
|
|
"run": {},
|
||
|
|
"task_id": "11111111-1111-1111-1111-111111111111"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### دو حالت مهم
|
||
|
|
|
||
|
|
#### حالت اول: واقعا task جدید ساخته شده
|
||
|
|
|
||
|
|
- `status = processing`
|
||
|
|
- `source = processing`
|
||
|
|
- `task_id` مربوط به Celery run جدید است
|
||
|
|
|
||
|
|
#### حالت دوم: data از قبل در DB وجود دارد
|
||
|
|
|
||
|
|
- باز هم `202` برمیگردد
|
||
|
|
- `status` ممکن است `success` باشد
|
||
|
|
- `source` معمولا `database` است
|
||
|
|
- `task_id` برای polling ساخته میشود
|
||
|
|
- `GET /runs/{run_id}/status/` بلافاصله نتیجه کامل را میدهد
|
||
|
|
|
||
|
|
### `400`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 400,
|
||
|
|
"msg": "داده نامعتبر.",
|
||
|
|
"data": {
|
||
|
|
"farm_uuid": ["..."]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### `404`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 404,
|
||
|
|
"msg": "location پیدا نشد.",
|
||
|
|
"data": null
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 7) `GET /api/location-data/remote-sensing/cluster-blocks/{cluster_uuid}/live/`
|
||
|
|
|
||
|
|
کاربرد:
|
||
|
|
|
||
|
|
- دریافت metricهای زنده یا cache شده برای یک cluster block
|
||
|
|
|
||
|
|
### response موفق `200`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 200,
|
||
|
|
"msg": "success",
|
||
|
|
"data": {
|
||
|
|
"status": "success",
|
||
|
|
"source": "database",
|
||
|
|
"cluster_block": {},
|
||
|
|
"temporal_extent": {
|
||
|
|
"start_date": "2026-04-12",
|
||
|
|
"end_date": "2026-05-12"
|
||
|
|
},
|
||
|
|
"selected_features": ["ndvi", "ndwi", "soil_vv_db"],
|
||
|
|
"summary": {
|
||
|
|
"cell_count": 2,
|
||
|
|
"ndvi_mean": 0.54,
|
||
|
|
"ndwi_mean": 0.17,
|
||
|
|
"soil_vv_db_mean": -9.0
|
||
|
|
},
|
||
|
|
"metrics": {
|
||
|
|
"ndvi": 0.54,
|
||
|
|
"ndwi": 0.17,
|
||
|
|
"soil_vv": 0.14,
|
||
|
|
"soil_vv_db": -9.0
|
||
|
|
},
|
||
|
|
"metadata": {
|
||
|
|
"requested_cluster_uuid": "11111111-1111-1111-1111-111111111111",
|
||
|
|
"cache_hit": true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### توضیح فیلدها
|
||
|
|
|
||
|
|
- `source`: اگر از observationهای DB آمده باشد `database` و اگر مستقیم از openEO آمده باشد `openeo`
|
||
|
|
- `cluster_block`: ساختار کامل sub-block
|
||
|
|
- `selected_features`: metricهایی که برای تحلیل استفاده میشوند
|
||
|
|
- `summary`: خلاصه آماری cluster
|
||
|
|
- `metrics`: metric تجمیعشده همان cluster
|
||
|
|
- `metadata`: اطلاعات تکمیلی مثل backend، source_result_id، source_run_id
|
||
|
|
|
||
|
|
### `400`
|
||
|
|
|
||
|
|
- پارامترهای تاریخ نامعتبر باشند
|
||
|
|
- یا هندسه cluster معتبر نباشد
|
||
|
|
|
||
|
|
نمونه:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 400,
|
||
|
|
"msg": "هندسه زیربلاک KMeans نامعتبر است.",
|
||
|
|
"data": {
|
||
|
|
"cluster_uuid": ["11111111-1111-1111-1111-111111111111"]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### `404`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 404,
|
||
|
|
"msg": "زیربلاک KMeans پیدا نشد.",
|
||
|
|
"data": null
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### `502`
|
||
|
|
|
||
|
|
وقتی openEO پاسخ ندهد:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 502,
|
||
|
|
"msg": "خواندن داده از openEO ناموفق بود.",
|
||
|
|
"data": {
|
||
|
|
"detail": "..."
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 8) `GET /api/location-data/remote-sensing/cluster-recommendations/`
|
||
|
|
|
||
|
|
کاربرد:
|
||
|
|
|
||
|
|
- مقایسه گیاههای ثبتشده در `farm_data`
|
||
|
|
- استفاده از داده کلاسترها
|
||
|
|
- استفاده از `crop_simulation`
|
||
|
|
- پیشنهاد بهترین گیاه برای هر cluster
|
||
|
|
|
||
|
|
### response موفق `200`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 200,
|
||
|
|
"msg": "success",
|
||
|
|
"data": {
|
||
|
|
"farm_uuid": "11111111-1111-1111-1111-111111111111",
|
||
|
|
"location_id": 12,
|
||
|
|
"evaluated_plant_count": 2,
|
||
|
|
"cluster_count": 2,
|
||
|
|
"registered_plants": [],
|
||
|
|
"clusters": [],
|
||
|
|
"source_metadata": {}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### توضیح فیلدهای سطح بالا
|
||
|
|
|
||
|
|
- `farm_uuid`: شناسه مزرعه
|
||
|
|
- `location_id`: شناسه داخلی location
|
||
|
|
- `evaluated_plant_count`: تعداد گیاههایی که وارد simulation شدهاند
|
||
|
|
- `cluster_count`: تعداد clusterهای بررسیشده
|
||
|
|
- `registered_plants`: گیاههای ثبتشده روی مزرعه
|
||
|
|
- `clusters`: خروجی نهایی هر cluster
|
||
|
|
- `source_metadata`: metadata کلی پاسخ
|
||
|
|
|
||
|
|
### ساختار هر آیتم `registered_plants`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"plant_id": 101,
|
||
|
|
"plant_name": "Tomato",
|
||
|
|
"position": 0,
|
||
|
|
"stage": "vegetative"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### ساختار هر آیتم `clusters`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"block_code": "block-1",
|
||
|
|
"cluster_uuid": "11111111-1111-1111-1111-111111111111",
|
||
|
|
"sub_block_code": "cluster-0",
|
||
|
|
"cluster_label": 0,
|
||
|
|
"temporal_extent": {
|
||
|
|
"start_date": "2026-04-12",
|
||
|
|
"end_date": "2026-05-12"
|
||
|
|
},
|
||
|
|
"cluster_block": {},
|
||
|
|
"satellite_metrics": {
|
||
|
|
"ndvi": 0.51,
|
||
|
|
"ndwi": 0.24,
|
||
|
|
"soil_vv": 0.13
|
||
|
|
},
|
||
|
|
"sensor_metrics": {},
|
||
|
|
"resolved_metrics": {
|
||
|
|
"ndvi": 0.51,
|
||
|
|
"ndwi": 0.24,
|
||
|
|
"soil_vv": 0.13
|
||
|
|
},
|
||
|
|
"candidate_plants": [],
|
||
|
|
"suggested_plant": {},
|
||
|
|
"source_metadata": {}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### ساختار هر آیتم `candidate_plants`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"plant_id": 101,
|
||
|
|
"plant_name": "Tomato",
|
||
|
|
"position": 0,
|
||
|
|
"stage": "vegetative",
|
||
|
|
"score": 150.0,
|
||
|
|
"predicted_yield": 150.0,
|
||
|
|
"predicted_yield_tons": 0.15,
|
||
|
|
"biomass": 300.0,
|
||
|
|
"max_lai": 4.2,
|
||
|
|
"simulation_engine": "pcse",
|
||
|
|
"simulation_model_name": "Wofost81_NWLP_CWB_CNB",
|
||
|
|
"simulation_warning": null,
|
||
|
|
"supporting_metrics": {}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### `400`
|
||
|
|
|
||
|
|
وقتی مزرعه گیاه ثبتشده نداشته باشد یا پیشنیاز simulation کامل نباشد:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 400,
|
||
|
|
"msg": "برای این مزرعه هنوز هیچ گیاهی در farm_data ثبت نشده است.",
|
||
|
|
"data": null
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### `404`
|
||
|
|
|
||
|
|
وقتی مزرعه یا خروجی KMeans پیدا نشود:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 404,
|
||
|
|
"msg": "برای این مزرعه هنوز خروجی KMeans در location_data ثبت نشده است.",
|
||
|
|
"data": null
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 9) `GET /api/location-data/remote-sensing/results/{result_id}/k-options/`
|
||
|
|
|
||
|
|
کاربرد:
|
||
|
|
|
||
|
|
- لیست همه Kهای ذخیرهشده برای یک subdivision result
|
||
|
|
|
||
|
|
### response موفق `200`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 200,
|
||
|
|
"msg": "success",
|
||
|
|
"data": {
|
||
|
|
"result_id": 5,
|
||
|
|
"active_requested_k": 3,
|
||
|
|
"recommended_requested_k": 4,
|
||
|
|
"options": []
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### توضیح فیلدها
|
||
|
|
|
||
|
|
- `result_id`: شناسه subdivision result
|
||
|
|
- `active_requested_k`: K فعال فعلی
|
||
|
|
- `recommended_requested_k`: K پیشنهادی سیستم
|
||
|
|
- `options`: لیست کامل گزینهها
|
||
|
|
|
||
|
|
### ساختار هر آیتم `options`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": 11,
|
||
|
|
"requested_k": 3,
|
||
|
|
"effective_cluster_count": 3,
|
||
|
|
"is_active": true,
|
||
|
|
"is_recommended": false,
|
||
|
|
"selection_source": "user",
|
||
|
|
"metadata": {},
|
||
|
|
"cluster_blocks": [],
|
||
|
|
"created_at": "2026-05-13T14:00:00Z",
|
||
|
|
"updated_at": "2026-05-13T14:00:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### ساختار هر `cluster_blocks` داخل option
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"cluster_label": 0,
|
||
|
|
"sub_block_code": "cluster-0",
|
||
|
|
"chunk_size_sqm": 900,
|
||
|
|
"centroid_lat": "35.689500",
|
||
|
|
"centroid_lon": "51.389500",
|
||
|
|
"center_cell_code": "cell-1",
|
||
|
|
"center_cell_lat": "35.689500",
|
||
|
|
"center_cell_lon": "51.389500",
|
||
|
|
"cell_count": 4,
|
||
|
|
"cell_codes": ["cell-1", "cell-2"],
|
||
|
|
"geometry": {},
|
||
|
|
"metadata": {}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### `404`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 404,
|
||
|
|
"msg": "subdivision result پیدا نشد.",
|
||
|
|
"data": null
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 10) `POST /api/location-data/remote-sensing/results/{result_id}/k-options/activate/`
|
||
|
|
|
||
|
|
کاربرد:
|
||
|
|
|
||
|
|
- فعالسازی یکی از Kهای ذخیرهشده
|
||
|
|
|
||
|
|
### response موفق `200`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 200,
|
||
|
|
"msg": "success",
|
||
|
|
"data": {
|
||
|
|
"result_id": 5,
|
||
|
|
"activated_requested_k": 4,
|
||
|
|
"subdivision_result": {}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### توضیح فیلدها
|
||
|
|
|
||
|
|
- `result_id`: شناسه result
|
||
|
|
- `activated_requested_k`: K که الان active شده
|
||
|
|
- `subdivision_result`: خروجی کامل subdivision بعد از sync شدن روی K جدید
|
||
|
|
|
||
|
|
### `400`
|
||
|
|
|
||
|
|
حالت اول: body نامعتبر
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 400,
|
||
|
|
"msg": "داده نامعتبر.",
|
||
|
|
"data": {
|
||
|
|
"requested_k": ["..."]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
حالت دوم: K داخل optionها وجود ندارد
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 400,
|
||
|
|
"msg": "K انتخابی برای این subdivision result موجود نیست.",
|
||
|
|
"data": {
|
||
|
|
"requested_k": [7]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### `404`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 404,
|
||
|
|
"msg": "subdivision result پیدا نشد.",
|
||
|
|
"data": null
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 11) `GET /api/location-data/remote-sensing/runs/{run_id}/status/`
|
||
|
|
|
||
|
|
کاربرد:
|
||
|
|
|
||
|
|
- polling وضعیت run
|
||
|
|
- دیدن stageهای pipeline
|
||
|
|
- اگر run کامل شده باشد، دیدن نتیجه نهایی
|
||
|
|
- اگر run از نوع cache-hit باشد، دیدن نتیجه کامل DB بلافاصله
|
||
|
|
|
||
|
|
### response موفق `200` در حالت pending/running
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 200,
|
||
|
|
"msg": "success",
|
||
|
|
"data": {
|
||
|
|
"status": "running",
|
||
|
|
"source": "database",
|
||
|
|
"run": {},
|
||
|
|
"task_id": "11111111-1111-1111-1111-111111111111",
|
||
|
|
"task": {
|
||
|
|
"current_stage": "fetching_remote_metrics",
|
||
|
|
"current_stage_details": {},
|
||
|
|
"timestamps": {},
|
||
|
|
"stages": [],
|
||
|
|
"metric_progress": {},
|
||
|
|
"celery": {
|
||
|
|
"state": "STARTED",
|
||
|
|
"ready": false,
|
||
|
|
"successful": false,
|
||
|
|
"failed": false,
|
||
|
|
"info": {}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### response موفق `200` در حالت completed
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 200,
|
||
|
|
"msg": "success",
|
||
|
|
"data": {
|
||
|
|
"status": "completed",
|
||
|
|
"source": "database",
|
||
|
|
"run": {},
|
||
|
|
"task_id": "11111111-1111-1111-1111-111111111111",
|
||
|
|
"task": {
|
||
|
|
"current_stage": "completed",
|
||
|
|
"current_stage_details": {},
|
||
|
|
"timestamps": {},
|
||
|
|
"stages": []
|
||
|
|
},
|
||
|
|
"location": {},
|
||
|
|
"block_code": "",
|
||
|
|
"chunk_size_sqm": 900,
|
||
|
|
"temporal_extent": {
|
||
|
|
"start_date": "2026-04-12",
|
||
|
|
"end_date": "2026-05-12"
|
||
|
|
},
|
||
|
|
"summary": {
|
||
|
|
"cell_count": 12,
|
||
|
|
"ndvi_mean": 0.54,
|
||
|
|
"ndwi_mean": 0.21,
|
||
|
|
"soil_vv_db_mean": -8.92
|
||
|
|
},
|
||
|
|
"cells": [],
|
||
|
|
"subdivision_result": {},
|
||
|
|
"pagination": {}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### توضیح فیلدهای `task`
|
||
|
|
|
||
|
|
- `current_stage`: stage فعلی pipeline
|
||
|
|
- `current_stage_details`: جزئیات همان stage
|
||
|
|
- `timestamps`: زمان ورود به stageها
|
||
|
|
- `stages`: تاریخچه stageها
|
||
|
|
- `metric_progress`: پیشرفت metricها هنگام fetch داده
|
||
|
|
- `retry`: اطلاعات retry اگر task در حال retry باشد
|
||
|
|
- `last_error`: آخرین خطا
|
||
|
|
- `failure_reason`: علت fail شدن task
|
||
|
|
- `celery.state`: وضعیت Celery مثل `PENDING`، `STARTED`، `RETRY`
|
||
|
|
- `celery.ready`: آیا task تمام شده
|
||
|
|
- `celery.successful`: آیا task موفق بوده
|
||
|
|
- `celery.failed`: آیا task fail شده
|
||
|
|
- `celery.info`: اطلاعات خام Celery
|
||
|
|
|
||
|
|
### مقادیر متداول `status`
|
||
|
|
|
||
|
|
- `pending`
|
||
|
|
- `running`
|
||
|
|
- `retrying`
|
||
|
|
- `completed`
|
||
|
|
- `failed`
|
||
|
|
|
||
|
|
### `404`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"code": 404,
|
||
|
|
"msg": "run با این task_id پیدا نشد.",
|
||
|
|
"data": null
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 12) نکات مهم برای فرانت
|
||
|
|
|
||
|
|
- در همه endpointها اول `code` و بعد `data` را چک کنید.
|
||
|
|
- در `POST /remote-sensing/` همیشه انتظار `task_id` داشته باشید.
|
||
|
|
- در `POST /remote-sensing/` اگر داده قبلا موجود باشد هم ممکن است `202` بگیرید، چون سیستم برای polling یک run قابل پیگیری میسازد.
|
||
|
|
- در `GET /remote-sensing/runs/{run_id}/status/` اگر `status = completed` شد، همان response نهایی را استفاده کنید و دیگر لازم نیست `GET /remote-sensing/` را دوباره صدا بزنید.
|
||
|
|
- در `GET /remote-sensing/cluster-blocks/{cluster_uuid}/live/` مقدار `source` مهم است:
|
||
|
|
- `database`: از cache
|
||
|
|
- `openeo`: از backend زنده
|
||
|
|
- در responseهای subdivision، pagination ممکن است هم برای `cells` باشد و هم برای `assignments`.
|
||
|
|
|
||
|
|
## 13) محل فایل
|
||
|
|
|
||
|
|
این مستند در این مسیر ذخیره شده است:
|
||
|
|
|
||
|
|
- `docs/location_data_api_responses_fa.md`
|