|
@@ -11,44 +11,14 @@ import logging
|
|
|
import io
|
|
|
import pandas as pd
|
|
|
from ..services.cd_prediction_service_v3 import CdPredictionServiceV3
|
|
|
+from ..services.cd_prediction_database_service import CdPredictionDatabaseService
|
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
# 设置日志
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
-# =============================================================================
|
|
|
-# 县市查询接口
|
|
|
-# =============================================================================
|
|
|
|
|
|
-@router.get("/supported-counties",
|
|
|
- summary="获取支持的县市列表",
|
|
|
- description="获取系统当前支持进行Cd预测的县市列表")
|
|
|
-async def get_supported_counties() -> Dict[str, Any]:
|
|
|
- """
|
|
|
- 获取支持的县市列表
|
|
|
-
|
|
|
- @returns {Dict[str, Any]} 支持的县市信息
|
|
|
- """
|
|
|
- try:
|
|
|
- service = CdPredictionServiceV3()
|
|
|
- counties = service.get_supported_counties_info()
|
|
|
-
|
|
|
- return {
|
|
|
- "success": True,
|
|
|
- "message": "获取支持县市列表成功",
|
|
|
- "data": {
|
|
|
- "counties": counties,
|
|
|
- "total_count": len(counties)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- except Exception as e:
|
|
|
- logger.error(f"获取支持县市列表失败: {str(e)}")
|
|
|
- raise HTTPException(
|
|
|
- status_code=500,
|
|
|
- detail=f"获取支持县市列表失败: {str(e)}"
|
|
|
- )
|
|
|
|
|
|
# =============================================================================
|
|
|
# 一键生成并获取地图接口
|
|
@@ -56,10 +26,12 @@ async def get_supported_counties() -> Dict[str, Any]:
|
|
|
|
|
|
@router.post("/crop-cd/generate-and-get-map",
|
|
|
summary="一键生成并获取作物Cd预测地图",
|
|
|
- description="根据县名和CSV数据生成作物Cd预测地图并直接返回图片文件")
|
|
|
+ description="根据区域名称和行政级别生成作物Cd预测地图并直接返回图片文件,优先使用数据库数据,也支持CSV文件上传")
|
|
|
async def generate_and_get_crop_cd_map(
|
|
|
- county_name: str = Form(..., description="县市名称,如:乐昌市"),
|
|
|
- data_file: UploadFile = File(..., description="CSV格式的环境因子数据文件,前两列为经纬度,后续列与areatest.csv结构一致"),
|
|
|
+ area: str = Form(..., description="区域名称,如:乐昌市"),
|
|
|
+ level: str = Form("auto", description="行政级别,如:county, city, province,默认为auto自动识别"),
|
|
|
+ use_database: Optional[bool] = Form(True, description="是否使用数据库数据,默认为True"),
|
|
|
+ data_file: Optional[UploadFile] = File(None, description="可选的CSV格式环境因子数据文件,仅在use_database=False时使用"),
|
|
|
enable_interpolation: Optional[bool] = Form(None, description="是否启用空间插值"),
|
|
|
interpolation_method: Optional[str] = Form(None, description="插值方法: nearest, linear, cubic"),
|
|
|
resolution_factor: Optional[float] = Form(None, description="分辨率因子,越大分辨率越高")
|
|
@@ -67,43 +39,14 @@ async def generate_and_get_crop_cd_map(
|
|
|
"""
|
|
|
一键生成并获取作物Cd预测地图
|
|
|
|
|
|
- @param county_name: 县市名称
|
|
|
- @param data_file: CSV数据文件,前两列为经纬度坐标,后面几列和areatest.csv的结构一致
|
|
|
+ @param area: 区域名称
|
|
|
+ @param level: 行政级别
|
|
|
+ @param use_database: 是否使用数据库数据
|
|
|
+ @param data_file: 可选的CSV数据文件,仅在use_database=False时使用
|
|
|
@returns {FileResponse} 预测地图文件
|
|
|
"""
|
|
|
try:
|
|
|
- logger.info(f"开始为{county_name}一键生成作物Cd预测地图")
|
|
|
-
|
|
|
- # 验证文件格式
|
|
|
- if not data_file.filename.endswith('.csv'):
|
|
|
- raise HTTPException(status_code=400, detail="仅支持CSV格式文件")
|
|
|
-
|
|
|
- # 读取CSV数据
|
|
|
- content = await data_file.read()
|
|
|
- df = pd.read_csv(io.StringIO(content.decode('utf-8')))
|
|
|
-
|
|
|
- # 验证数据格式
|
|
|
- if df.shape[1] < 3:
|
|
|
- raise HTTPException(
|
|
|
- status_code=400,
|
|
|
- detail="数据至少需要3列:前两列为经纬度,后续列为环境因子"
|
|
|
- )
|
|
|
-
|
|
|
- # 重命名前两列为标准的经纬度列名
|
|
|
- df.columns = ['longitude', 'latitude'] + list(df.columns[2:])
|
|
|
-
|
|
|
- service = CdPredictionServiceV3()
|
|
|
-
|
|
|
- # 验证数据
|
|
|
- validation_result = service.validate_input_data(df, county_name)
|
|
|
- if not validation_result['valid']:
|
|
|
- raise HTTPException(
|
|
|
- status_code=400,
|
|
|
- detail=f"数据验证失败: {', '.join(validation_result['errors'])}"
|
|
|
- )
|
|
|
-
|
|
|
- # 保存临时数据文件
|
|
|
- temp_file_path = service.save_temp_data(df, county_name)
|
|
|
+ logger.info(f"开始为{area}({level})一键生成作物Cd预测地图(数据源:{'数据库' if use_database else 'CSV文件'})")
|
|
|
|
|
|
# 构建栅格配置参数
|
|
|
raster_params = {}
|
|
@@ -114,81 +57,103 @@ async def generate_and_get_crop_cd_map(
|
|
|
if resolution_factor is not None:
|
|
|
raster_params['resolution_factor'] = resolution_factor
|
|
|
|
|
|
- # 生成预测结果
|
|
|
- result = await service.generate_crop_cd_prediction_for_county(
|
|
|
- county_name=county_name,
|
|
|
- data_file=temp_file_path,
|
|
|
- raster_config_override=raster_params if raster_params else None
|
|
|
- )
|
|
|
-
|
|
|
- if not result['map_path'] or not os.path.exists(result['map_path']):
|
|
|
- raise HTTPException(status_code=500, detail="地图文件生成失败")
|
|
|
+ if use_database:
|
|
|
+ # 使用数据库数据生成预测
|
|
|
+ db_service = CdPredictionDatabaseService()
|
|
|
+
|
|
|
+ result = await db_service.generate_crop_cd_prediction_from_database(
|
|
|
+ area=area,
|
|
|
+ level=level,
|
|
|
+ raster_config_override=raster_params if raster_params else None
|
|
|
+ )
|
|
|
+
|
|
|
+ if not result['map_path'] or not os.path.exists(result['map_path']):
|
|
|
+ raise HTTPException(status_code=500, detail="基于数据库数据的地图文件生成失败")
|
|
|
+
|
|
|
+ logger.info(f"使用数据库数据为{area}({level})生成作物Cd预测地图成功,处理{result.get('processed_records', 0)}条记录")
|
|
|
+
|
|
|
+ else:
|
|
|
+ # 使用上传的CSV文件生成预测
|
|
|
+ if not data_file:
|
|
|
+ raise HTTPException(status_code=400, detail="当use_database=False时,必须提供data_file")
|
|
|
+
|
|
|
+ # 验证文件格式
|
|
|
+ if not data_file.filename.endswith('.csv'):
|
|
|
+ raise HTTPException(status_code=400, detail="仅支持CSV格式文件")
|
|
|
+
|
|
|
+ # 读取CSV数据
|
|
|
+ content = await data_file.read()
|
|
|
+ df = pd.read_csv(io.StringIO(content.decode('utf-8')))
|
|
|
+
|
|
|
+ # 验证数据格式
|
|
|
+ if df.shape[1] < 3:
|
|
|
+ raise HTTPException(
|
|
|
+ status_code=400,
|
|
|
+ detail="数据至少需要3列:前两列为经纬度,后续列为环境因子"
|
|
|
+ )
|
|
|
+
|
|
|
+ # 重命名前两列为标准的经纬度列名
|
|
|
+ df.columns = ['longitude', 'latitude'] + list(df.columns[2:])
|
|
|
+
|
|
|
+ service = CdPredictionServiceV3()
|
|
|
+
|
|
|
+ # 验证数据
|
|
|
+ validation_result = service.validate_input_data(df, area)
|
|
|
+ if not validation_result['valid']:
|
|
|
+ raise HTTPException(
|
|
|
+ status_code=400,
|
|
|
+ detail=f"数据验证失败: {', '.join(validation_result['errors'])}"
|
|
|
+ )
|
|
|
+
|
|
|
+ # 保存临时数据文件
|
|
|
+ temp_file_path = service.save_temp_data(df, area)
|
|
|
+
|
|
|
+ # 生成预测结果
|
|
|
+ result = await service.generate_crop_cd_prediction_for_county(
|
|
|
+ county_name=area,
|
|
|
+ data_file=temp_file_path,
|
|
|
+ raster_config_override=raster_params if raster_params else None
|
|
|
+ )
|
|
|
+
|
|
|
+ if not result['map_path'] or not os.path.exists(result['map_path']):
|
|
|
+ raise HTTPException(status_code=500, detail="基于CSV文件的地图文件生成失败")
|
|
|
+
|
|
|
+ logger.info(f"使用CSV文件为{area}({level})生成作物Cd预测地图成功")
|
|
|
|
|
|
return FileResponse(
|
|
|
path=result['map_path'],
|
|
|
- filename=f"{county_name}_crop_cd_prediction_map.jpg",
|
|
|
+ filename=f"{area}_crop_cd_prediction_map.jpg",
|
|
|
media_type="image/jpeg"
|
|
|
)
|
|
|
|
|
|
except HTTPException:
|
|
|
raise
|
|
|
except Exception as e:
|
|
|
- logger.error(f"为{county_name}一键生成作物Cd预测地图失败: {str(e)}")
|
|
|
+ logger.error(f"为{area}({level})一键生成作物Cd预测地图失败: {str(e)}")
|
|
|
raise HTTPException(
|
|
|
status_code=500,
|
|
|
- detail=f"为{county_name}一键生成作物Cd预测地图失败: {str(e)}"
|
|
|
+ detail=f"为{area}({level})一键生成作物Cd预测地图失败: {str(e)}"
|
|
|
)
|
|
|
|
|
|
-@router.post("/effective-cd/generate-and-get-map",
|
|
|
- summary="一键生成并获取有效态Cd预测地图",
|
|
|
- description="根据县名和CSV数据生成有效态Cd预测地图并直接返回图片文件")
|
|
|
-async def generate_and_get_effective_cd_map(
|
|
|
- county_name: str = Form(..., description="县市名称,如:乐昌市"),
|
|
|
- data_file: UploadFile = File(..., description="CSV格式的环境因子数据文件,前两列为经纬度,后续列与areatest.csv结构一致"),
|
|
|
+@router.post("/crop-cd/generate-from-database",
|
|
|
+ summary="基于数据库数据生成作物Cd预测地图",
|
|
|
+ description="直接从数据库读取数据生成作物Cd预测地图")
|
|
|
+async def generate_crop_cd_map_from_database(
|
|
|
+ area: str = Form(..., description="区域名称,如:乐昌市"),
|
|
|
+ level: str = Form("auto", description="行政级别,如:county, city, province,默认为auto自动识别"),
|
|
|
enable_interpolation: Optional[bool] = Form(None, description="是否启用空间插值"),
|
|
|
interpolation_method: Optional[str] = Form(None, description="插值方法: nearest, linear, cubic"),
|
|
|
resolution_factor: Optional[float] = Form(None, description="分辨率因子,越大分辨率越高")
|
|
|
):
|
|
|
"""
|
|
|
- 一键生成并获取有效态Cd预测地图
|
|
|
+ 基于数据库数据生成作物Cd预测地图
|
|
|
|
|
|
- @param county_name: 县市名称
|
|
|
- @param data_file: CSV数据文件,前两列为经纬度坐标,后面几列和areatest.csv的结构一致
|
|
|
+ @param area: 区域名称
|
|
|
+ @param level: 行政级别
|
|
|
@returns {FileResponse} 预测地图文件
|
|
|
"""
|
|
|
try:
|
|
|
- logger.info(f"开始为{county_name}一键生成有效态Cd预测地图")
|
|
|
-
|
|
|
- # 验证文件格式
|
|
|
- if not data_file.filename.endswith('.csv'):
|
|
|
- raise HTTPException(status_code=400, detail="仅支持CSV格式文件")
|
|
|
-
|
|
|
- # 读取CSV数据
|
|
|
- content = await data_file.read()
|
|
|
- df = pd.read_csv(io.StringIO(content.decode('utf-8')))
|
|
|
-
|
|
|
- # 验证数据格式
|
|
|
- if df.shape[1] < 3:
|
|
|
- raise HTTPException(
|
|
|
- status_code=400,
|
|
|
- detail="数据至少需要3列:前两列为经纬度,后续列为环境因子"
|
|
|
- )
|
|
|
-
|
|
|
- # 重命名前两列为标准的经纬度列名
|
|
|
- df.columns = ['longitude', 'latitude'] + list(df.columns[2:])
|
|
|
-
|
|
|
- service = CdPredictionServiceV3()
|
|
|
-
|
|
|
- # 验证数据
|
|
|
- validation_result = service.validate_input_data(df, county_name)
|
|
|
- if not validation_result['valid']:
|
|
|
- raise HTTPException(
|
|
|
- status_code=400,
|
|
|
- detail=f"数据验证失败: {', '.join(validation_result['errors'])}"
|
|
|
- )
|
|
|
-
|
|
|
- # 保存临时数据文件
|
|
|
- temp_file_path = service.save_temp_data(df, county_name)
|
|
|
+ logger.info(f"开始基于数据库数据为{area}({level})生成作物Cd预测地图")
|
|
|
|
|
|
# 构建栅格配置参数
|
|
|
raster_params = {}
|
|
@@ -199,63 +164,58 @@ async def generate_and_get_effective_cd_map(
|
|
|
if resolution_factor is not None:
|
|
|
raster_params['resolution_factor'] = resolution_factor
|
|
|
|
|
|
- # 生成预测结果
|
|
|
- result = await service.generate_effective_cd_prediction_for_county(
|
|
|
- county_name=county_name,
|
|
|
- data_file=temp_file_path,
|
|
|
+ # 使用数据库数据生成预测
|
|
|
+ db_service = CdPredictionDatabaseService()
|
|
|
+
|
|
|
+ result = await db_service.generate_crop_cd_prediction_from_database(
|
|
|
+ area=area,
|
|
|
+ level=level,
|
|
|
raster_config_override=raster_params if raster_params else None
|
|
|
)
|
|
|
|
|
|
if not result['map_path'] or not os.path.exists(result['map_path']):
|
|
|
- raise HTTPException(status_code=500, detail="地图文件生成失败")
|
|
|
+ raise HTTPException(status_code=500, detail="基于数据库数据的地图文件生成失败")
|
|
|
+
|
|
|
+ logger.info(f"基于数据库数据为{area}({level})生成作物Cd预测地图成功,处理{result.get('processed_records', 0)}条记录")
|
|
|
|
|
|
return FileResponse(
|
|
|
path=result['map_path'],
|
|
|
- filename=f"{county_name}_effective_cd_prediction_map.jpg",
|
|
|
+ filename=f"{area}_crop_cd_prediction_map_database.jpg",
|
|
|
media_type="image/jpeg"
|
|
|
)
|
|
|
|
|
|
except HTTPException:
|
|
|
raise
|
|
|
except Exception as e:
|
|
|
- logger.error(f"为{county_name}一键生成有效态Cd预测地图失败: {str(e)}")
|
|
|
+ logger.error(f"基于数据库数据为{area}({level})生成作物Cd预测地图失败: {str(e)}")
|
|
|
raise HTTPException(
|
|
|
status_code=500,
|
|
|
- detail=f"为{county_name}一键生成有效态Cd预测地图失败: {str(e)}"
|
|
|
+ detail=f"基于数据库数据为{area}({level})生成作物Cd预测地图失败: {str(e)}"
|
|
|
)
|
|
|
|
|
|
-# =============================================================================
|
|
|
-# 基于数据库的有效态镉预测接口
|
|
|
-# =============================================================================
|
|
|
-
|
|
|
-@router.post("/effective-cd/generate-from-database",
|
|
|
- summary="基于数据库数据生成有效态Cd预测并更新结果表",
|
|
|
- description="从EffCd_input_data和Farmland_data表中读取数据,进行有效态Cd预测,并将结果保存到EffCd_output_data表")
|
|
|
-async def generate_effective_cd_from_database(
|
|
|
- area: str = Form(..., description="地区名称,如:乐昌市"),
|
|
|
- level: str = Form(..., description="行政级别,如:县级市、县、市辖区等"),
|
|
|
+@router.post("/effective-cd/generate-and-get-map",
|
|
|
+ summary="一键生成并获取有效态Cd预测地图",
|
|
|
+ description="根据区域名称和行政级别生成有效态Cd预测地图并直接返回图片文件,优先使用数据库数据,也支持CSV文件上传")
|
|
|
+async def generate_and_get_effective_cd_map(
|
|
|
+ area: str = Form(..., description="区域名称,如:乐昌市"),
|
|
|
+ level: str = Form("auto", description="行政级别,如:county, city, province,默认为auto自动识别"),
|
|
|
+ use_database: Optional[bool] = Form(True, description="是否使用数据库数据,默认为True"),
|
|
|
+ data_file: Optional[UploadFile] = File(None, description="可选的CSV格式环境因子数据文件,仅在use_database=False时使用"),
|
|
|
enable_interpolation: Optional[bool] = Form(None, description="是否启用空间插值"),
|
|
|
interpolation_method: Optional[str] = Form(None, description="插值方法: nearest, linear, cubic"),
|
|
|
resolution_factor: Optional[float] = Form(None, description="分辨率因子,越大分辨率越高")
|
|
|
):
|
|
|
"""
|
|
|
- 基于数据库数据生成有效态Cd预测并更新结果表
|
|
|
+ 一键生成并获取有效态Cd预测地图
|
|
|
|
|
|
- @param area: 地区名称
|
|
|
+ @param area: 区域名称
|
|
|
@param level: 行政级别
|
|
|
- @param enable_interpolation: 是否启用空间插值
|
|
|
- @param interpolation_method: 插值方法
|
|
|
- @param resolution_factor: 分辨率因子
|
|
|
- @returns {dict} 预测结果信息
|
|
|
+ @param use_database: 是否使用数据库数据
|
|
|
+ @param data_file: 可选的CSV数据文件,仅在use_database=False时使用
|
|
|
+ @returns {FileResponse} 预测地图文件
|
|
|
"""
|
|
|
try:
|
|
|
- from ..services.cd_prediction_service_v3 import CdPredictionServiceV3
|
|
|
- from ..services.cd_prediction_database_service import CdPredictionDatabaseService
|
|
|
-
|
|
|
- logger.info(f"开始基于数据库数据生成有效态Cd预测: {area} ({level})")
|
|
|
-
|
|
|
- # 初始化服务
|
|
|
- db_service = CdPredictionDatabaseService()
|
|
|
+ logger.info(f"开始为{area}({level})一键生成有效态Cd预测地图(数据源:{'数据库' if use_database else 'CSV文件'})")
|
|
|
|
|
|
# 构建栅格配置参数
|
|
|
raster_params = {}
|
|
@@ -266,69 +226,103 @@ async def generate_effective_cd_from_database(
|
|
|
if resolution_factor is not None:
|
|
|
raster_params['resolution_factor'] = resolution_factor
|
|
|
|
|
|
- # 执行基于数据库的有效态Cd预测
|
|
|
- result = await db_service.generate_effective_cd_prediction_from_database(
|
|
|
- area=area,
|
|
|
- level=level,
|
|
|
- raster_config_override=raster_params if raster_params else None
|
|
|
- )
|
|
|
+ if use_database:
|
|
|
+ # 使用数据库数据生成预测
|
|
|
+ db_service = CdPredictionDatabaseService()
|
|
|
+
|
|
|
+ result = await db_service.generate_effective_cd_prediction_from_database(
|
|
|
+ area=area,
|
|
|
+ level=level,
|
|
|
+ raster_config_override=raster_params if raster_params else None
|
|
|
+ )
|
|
|
+
|
|
|
+ if not result['map_path'] or not os.path.exists(result['map_path']):
|
|
|
+ raise HTTPException(status_code=500, detail="基于数据库数据的地图文件生成失败")
|
|
|
+
|
|
|
+ logger.info(f"使用数据库数据为{area}({level})生成有效态Cd预测地图成功,处理{result.get('processed_records', 0)}条记录")
|
|
|
+
|
|
|
+ else:
|
|
|
+ # 使用上传的CSV文件生成预测
|
|
|
+ if not data_file:
|
|
|
+ raise HTTPException(status_code=400, detail="当use_database=False时,必须提供data_file")
|
|
|
+
|
|
|
+ # 验证文件格式
|
|
|
+ if not data_file.filename.endswith('.csv'):
|
|
|
+ raise HTTPException(status_code=400, detail="仅支持CSV格式文件")
|
|
|
+
|
|
|
+ # 读取CSV数据
|
|
|
+ content = await data_file.read()
|
|
|
+ df = pd.read_csv(io.StringIO(content.decode('utf-8')))
|
|
|
+
|
|
|
+ # 验证数据格式
|
|
|
+ if df.shape[1] < 3:
|
|
|
+ raise HTTPException(
|
|
|
+ status_code=400,
|
|
|
+ detail="数据至少需要3列:前两列为经纬度,后续列为环境因子"
|
|
|
+ )
|
|
|
+
|
|
|
+ # 重命名前两列为标准的经纬度列名
|
|
|
+ df.columns = ['longitude', 'latitude'] + list(df.columns[2:])
|
|
|
+
|
|
|
+ service = CdPredictionServiceV3()
|
|
|
+
|
|
|
+ # 验证数据
|
|
|
+ validation_result = service.validate_input_data(df, area)
|
|
|
+ if not validation_result['valid']:
|
|
|
+ raise HTTPException(
|
|
|
+ status_code=400,
|
|
|
+ detail=f"数据验证失败: {', '.join(validation_result['errors'])}"
|
|
|
+ )
|
|
|
+
|
|
|
+ # 保存临时数据文件
|
|
|
+ temp_file_path = service.save_temp_data(df, area)
|
|
|
+
|
|
|
+ # 生成预测结果
|
|
|
+ result = await service.generate_effective_cd_prediction_for_county(
|
|
|
+ county_name=area,
|
|
|
+ data_file=temp_file_path,
|
|
|
+ raster_config_override=raster_params if raster_params else None
|
|
|
+ )
|
|
|
+
|
|
|
+ if not result['map_path'] or not os.path.exists(result['map_path']):
|
|
|
+ raise HTTPException(status_code=500, detail="基于CSV文件的地图文件生成失败")
|
|
|
+
|
|
|
+ logger.info(f"使用CSV文件为{area}({level})生成有效态Cd预测地图成功")
|
|
|
|
|
|
- logger.info(f"基于数据库数据的有效态Cd预测完成: {area} ({level})")
|
|
|
-
|
|
|
- return {
|
|
|
- "success": True,
|
|
|
- "message": f"成功为{area}生成有效态Cd预测",
|
|
|
- "area": area,
|
|
|
- "level": level,
|
|
|
- "processed_records": result.get('processed_records', 0),
|
|
|
- "updated_records": result.get('updated_records', 0),
|
|
|
- "map_path": result.get('map_path'),
|
|
|
- "histogram_path": result.get('histogram_path'),
|
|
|
- "timestamp": result.get('timestamp'),
|
|
|
- "validation": result.get('validation', {})
|
|
|
- }
|
|
|
+ return FileResponse(
|
|
|
+ path=result['map_path'],
|
|
|
+ filename=f"{area}_effective_cd_prediction_map.jpg",
|
|
|
+ media_type="image/jpeg"
|
|
|
+ )
|
|
|
|
|
|
except HTTPException:
|
|
|
raise
|
|
|
except Exception as e:
|
|
|
- logger.error(f"基于数据库数据的有效态Cd预测失败: {str(e)}")
|
|
|
+ logger.error(f"为{area}({level})一键生成有效态Cd预测地图失败: {str(e)}")
|
|
|
raise HTTPException(
|
|
|
status_code=500,
|
|
|
- detail=f"基于数据库数据的有效态Cd预测失败: {str(e)}"
|
|
|
+ detail=f"为{area}({level})一键生成有效态Cd预测地图失败: {str(e)}"
|
|
|
)
|
|
|
|
|
|
-# =============================================================================
|
|
|
-# 基于数据库的作物镉预测接口
|
|
|
-# =============================================================================
|
|
|
-
|
|
|
-@router.post("/crop-cd/generate-from-database",
|
|
|
- summary="基于数据库数据生成作物Cd预测并更新结果表",
|
|
|
- description="从CropCd_input_data和Farmland_data表中读取数据,进行作物Cd预测,并将结果保存到CropCd_output_data表")
|
|
|
-async def generate_crop_cd_from_database(
|
|
|
- area: str = Form(..., description="地区名称,如:乐昌市"),
|
|
|
- level: str = Form(..., description="行政级别,如:县级市、县、市辖区等"),
|
|
|
+@router.post("/effective-cd/generate-from-database",
|
|
|
+ summary="基于数据库数据生成有效态Cd预测地图",
|
|
|
+ description="直接从数据库读取数据生成有效态Cd预测地图")
|
|
|
+async def generate_effective_cd_map_from_database(
|
|
|
+ area: str = Form(..., description="区域名称,如:乐昌市"),
|
|
|
+ level: str = Form("auto", description="行政级别,如:county, city, province,默认为auto自动识别"),
|
|
|
enable_interpolation: Optional[bool] = Form(None, description="是否启用空间插值"),
|
|
|
interpolation_method: Optional[str] = Form(None, description="插值方法: nearest, linear, cubic"),
|
|
|
resolution_factor: Optional[float] = Form(None, description="分辨率因子,越大分辨率越高")
|
|
|
):
|
|
|
"""
|
|
|
- 基于数据库数据生成作物Cd预测并更新结果表
|
|
|
+ 基于数据库数据生成有效态Cd预测地图
|
|
|
|
|
|
- @param area: 地区名称
|
|
|
+ @param area: 区域名称
|
|
|
@param level: 行政级别
|
|
|
- @param enable_interpolation: 是否启用空间插值
|
|
|
- @param interpolation_method: 插值方法
|
|
|
- @param resolution_factor: 分辨率因子
|
|
|
- @returns {dict} 预测结果信息
|
|
|
+ @returns {FileResponse} 预测地图文件
|
|
|
"""
|
|
|
try:
|
|
|
- from ..services.cd_prediction_service_v3 import CdPredictionServiceV3
|
|
|
- from ..services.cd_prediction_database_service import CdPredictionDatabaseService
|
|
|
-
|
|
|
- logger.info(f"开始基于数据库数据生成作物Cd预测: {area} ({level})")
|
|
|
-
|
|
|
- # 初始化服务
|
|
|
- db_service = CdPredictionDatabaseService()
|
|
|
+ logger.info(f"开始基于数据库数据为{area}({level})生成有效态Cd预测地图")
|
|
|
|
|
|
# 构建栅格配置参数
|
|
|
raster_params = {}
|
|
@@ -339,65 +333,56 @@ async def generate_crop_cd_from_database(
|
|
|
if resolution_factor is not None:
|
|
|
raster_params['resolution_factor'] = resolution_factor
|
|
|
|
|
|
- # 执行基于数据库的作物Cd预测
|
|
|
- result = await db_service.generate_crop_cd_prediction_from_database(
|
|
|
+ # 使用数据库数据生成预测
|
|
|
+ db_service = CdPredictionDatabaseService()
|
|
|
+
|
|
|
+ result = await db_service.generate_effective_cd_prediction_from_database(
|
|
|
area=area,
|
|
|
level=level,
|
|
|
raster_config_override=raster_params if raster_params else None
|
|
|
)
|
|
|
|
|
|
- logger.info(f"基于数据库数据的作物Cd预测完成: {area} ({level})")
|
|
|
-
|
|
|
- return {
|
|
|
- "success": True,
|
|
|
- "message": f"成功为{area}生成作物Cd预测",
|
|
|
- "area": area,
|
|
|
- "level": level,
|
|
|
- "processed_records": result.get('processed_records', 0),
|
|
|
- "updated_records": result.get('updated_records', 0),
|
|
|
- "map_path": result.get('map_path'),
|
|
|
- "histogram_path": result.get('histogram_path'),
|
|
|
- "timestamp": result.get('timestamp'),
|
|
|
- "validation": result.get('validation', {})
|
|
|
- }
|
|
|
+ if not result['map_path'] or not os.path.exists(result['map_path']):
|
|
|
+ raise HTTPException(status_code=500, detail="基于数据库数据的地图文件生成失败")
|
|
|
+
|
|
|
+ logger.info(f"基于数据库数据为{area}({level})生成有效态Cd预测地图成功,处理{result.get('processed_records', 0)}条记录")
|
|
|
+
|
|
|
+ return FileResponse(
|
|
|
+ path=result['map_path'],
|
|
|
+ filename=f"{area}_effective_cd_prediction_map_database.jpg",
|
|
|
+ media_type="image/jpeg"
|
|
|
+ )
|
|
|
|
|
|
except HTTPException:
|
|
|
raise
|
|
|
except Exception as e:
|
|
|
- logger.error(f"基于数据库数据的作物Cd预测失败: {str(e)}")
|
|
|
+ logger.error(f"基于数据库数据为{area}({level})生成有效态Cd预测地图失败: {str(e)}")
|
|
|
raise HTTPException(
|
|
|
status_code=500,
|
|
|
- detail=f"基于数据库数据的作物Cd预测失败: {str(e)}"
|
|
|
+ detail=f"基于数据库数据为{area}({level})生成有效态Cd预测地图失败: {str(e)}"
|
|
|
)
|
|
|
|
|
|
# =============================================================================
|
|
|
# 获取最新预测结果接口(无需重新计算)
|
|
|
# =============================================================================
|
|
|
|
|
|
-@router.get("/crop-cd/latest-map/{county_name}",
|
|
|
+@router.get("/crop-cd/latest-map/{area_name}",
|
|
|
summary="获取作物Cd最新地图",
|
|
|
- description="直接返回指定县市的最新作物Cd预测地图,无需重新计算")
|
|
|
-async def get_latest_crop_cd_map(county_name: str):
|
|
|
+ description="直接返回指定区域的最新作物Cd预测地图,无需重新计算")
|
|
|
+async def get_latest_crop_cd_map(area_name: str):
|
|
|
"""
|
|
|
- 获取指定县市的最新作物Cd预测地图
|
|
|
+ 获取指定区域的最新作物Cd预测地图
|
|
|
|
|
|
- @param county_name: 县市名称,如:乐昌市
|
|
|
+ @param area_name: 区域名称,如:乐昌市
|
|
|
@returns {FileResponse} 最新的预测地图文件
|
|
|
"""
|
|
|
try:
|
|
|
- logger.info(f"获取{county_name}的最新作物Cd预测地图")
|
|
|
+ logger.info(f"获取{area_name}的最新作物Cd预测地图")
|
|
|
|
|
|
service = CdPredictionServiceV3()
|
|
|
|
|
|
- # 验证县市是否支持
|
|
|
- if not service.is_county_supported(county_name):
|
|
|
- raise HTTPException(
|
|
|
- status_code=404,
|
|
|
- detail=f"不支持的县市: {county_name}"
|
|
|
- )
|
|
|
-
|
|
|
# 查找最新的地图文件
|
|
|
- map_pattern = f"prediction_map_crop_cd_{county_name}_*.jpg"
|
|
|
+ map_pattern = f"prediction_map_crop_cd_{area_name}_*.jpg"
|
|
|
map_files = []
|
|
|
|
|
|
# 在输出目录中查找相关文件
|
|
@@ -409,7 +394,7 @@ async def get_latest_crop_cd_map(county_name: str):
|
|
|
if not map_files:
|
|
|
raise HTTPException(
|
|
|
status_code=404,
|
|
|
- detail=f"未找到{county_name}的作物Cd预测地图,请先执行预测"
|
|
|
+ detail=f"未找到{area_name}的作物Cd预测地图,请先执行预测"
|
|
|
)
|
|
|
|
|
|
# 选择最新的文件(按修改时间排序)
|
|
@@ -420,43 +405,36 @@ async def get_latest_crop_cd_map(county_name: str):
|
|
|
|
|
|
return FileResponse(
|
|
|
path=latest_map,
|
|
|
- filename=f"{county_name}_latest_crop_cd_map.jpg",
|
|
|
+ filename=f"{area_name}_latest_crop_cd_map.jpg",
|
|
|
media_type="image/jpeg"
|
|
|
)
|
|
|
|
|
|
except HTTPException:
|
|
|
raise
|
|
|
except Exception as e:
|
|
|
- logger.error(f"获取{county_name}最新作物Cd地图失败: {str(e)}")
|
|
|
+ logger.error(f"获取{area_name}最新作物Cd地图失败: {str(e)}")
|
|
|
raise HTTPException(
|
|
|
status_code=500,
|
|
|
- detail=f"获取{county_name}最新作物Cd地图失败: {str(e)}"
|
|
|
+ detail=f"获取{area_name}最新作物Cd地图失败: {str(e)}"
|
|
|
)
|
|
|
|
|
|
-@router.get("/effective-cd/latest-map/{county_name}",
|
|
|
+@router.get("/effective-cd/latest-map/{area_name}",
|
|
|
summary="获取有效态Cd最新地图",
|
|
|
- description="直接返回指定县市的最新有效态Cd预测地图,无需重新计算")
|
|
|
-async def get_latest_effective_cd_map(county_name: str):
|
|
|
+ description="直接返回指定区域的最新有效态Cd预测地图,无需重新计算")
|
|
|
+async def get_latest_effective_cd_map(area_name: str):
|
|
|
"""
|
|
|
- 获取指定县市的最新有效态Cd预测地图
|
|
|
+ 获取指定区域的最新有效态Cd预测地图
|
|
|
|
|
|
- @param county_name: 县市名称,如:乐昌市
|
|
|
+ @param area_name: 区域名称,如:乐昌市
|
|
|
@returns {FileResponse} 最新的预测地图文件
|
|
|
"""
|
|
|
try:
|
|
|
- logger.info(f"获取{county_name}的最新有效态Cd预测地图")
|
|
|
+ logger.info(f"获取{area_name}的最新有效态Cd预测地图")
|
|
|
|
|
|
service = CdPredictionServiceV3()
|
|
|
|
|
|
- # 验证县市是否支持
|
|
|
- if not service.is_county_supported(county_name):
|
|
|
- raise HTTPException(
|
|
|
- status_code=404,
|
|
|
- detail=f"不支持的县市: {county_name}"
|
|
|
- )
|
|
|
-
|
|
|
# 查找最新的地图文件
|
|
|
- map_pattern = f"prediction_map_effective_cd_{county_name}_*.jpg"
|
|
|
+ map_pattern = f"prediction_map_effective_cd_{area_name}_*.jpg"
|
|
|
map_files = []
|
|
|
|
|
|
# 在输出目录中查找相关文件
|
|
@@ -468,7 +446,7 @@ async def get_latest_effective_cd_map(county_name: str):
|
|
|
if not map_files:
|
|
|
raise HTTPException(
|
|
|
status_code=404,
|
|
|
- detail=f"未找到{county_name}的有效态Cd预测地图,请先执行预测"
|
|
|
+ detail=f"未找到{area_name}的有效态Cd预测地图,请先执行预测"
|
|
|
)
|
|
|
|
|
|
# 选择最新的文件(按修改时间排序)
|
|
@@ -479,43 +457,36 @@ async def get_latest_effective_cd_map(county_name: str):
|
|
|
|
|
|
return FileResponse(
|
|
|
path=latest_map,
|
|
|
- filename=f"{county_name}_latest_effective_cd_map.jpg",
|
|
|
+ filename=f"{area_name}_latest_effective_cd_map.jpg",
|
|
|
media_type="image/jpeg"
|
|
|
)
|
|
|
|
|
|
except HTTPException:
|
|
|
raise
|
|
|
except Exception as e:
|
|
|
- logger.error(f"获取{county_name}最新有效态Cd地图失败: {str(e)}")
|
|
|
+ logger.error(f"获取{area_name}最新有效态Cd地图失败: {str(e)}")
|
|
|
raise HTTPException(
|
|
|
status_code=500,
|
|
|
- detail=f"获取{county_name}最新有效态Cd地图失败: {str(e)}"
|
|
|
+ detail=f"获取{area_name}最新有效态Cd地图失败: {str(e)}"
|
|
|
)
|
|
|
|
|
|
-@router.get("/crop-cd/latest-histogram/{county_name}",
|
|
|
+@router.get("/crop-cd/latest-histogram/{area_name}",
|
|
|
summary="获取作物Cd最新直方图",
|
|
|
- description="直接返回指定县市的最新作物Cd预测直方图,无需重新计算")
|
|
|
-async def get_latest_crop_cd_histogram(county_name: str):
|
|
|
+ description="直接返回指定区域的最新作物Cd预测直方图,无需重新计算")
|
|
|
+async def get_latest_crop_cd_histogram(area_name: str):
|
|
|
"""
|
|
|
- 获取指定县市的最新作物Cd预测直方图
|
|
|
+ 获取指定区域的最新作物Cd预测直方图
|
|
|
|
|
|
- @param county_name: 县市名称,如:乐昌市
|
|
|
+ @param area_name: 区域名称,如:乐昌市
|
|
|
@returns {FileResponse} 最新的预测直方图文件
|
|
|
"""
|
|
|
try:
|
|
|
- logger.info(f"获取{county_name}的最新作物Cd预测直方图")
|
|
|
+ logger.info(f"获取{area_name}的最新作物Cd预测直方图")
|
|
|
|
|
|
service = CdPredictionServiceV3()
|
|
|
|
|
|
- # 验证县市是否支持
|
|
|
- if not service.is_county_supported(county_name):
|
|
|
- raise HTTPException(
|
|
|
- status_code=404,
|
|
|
- detail=f"不支持的县市: {county_name}"
|
|
|
- )
|
|
|
-
|
|
|
# 查找最新的直方图文件
|
|
|
- histogram_pattern = f"prediction_histogram_crop_cd_{county_name}_*.jpg"
|
|
|
+ histogram_pattern = f"prediction_histogram_crop_cd_{area_name}_*.jpg"
|
|
|
histogram_files = []
|
|
|
|
|
|
# 在输出目录中查找相关文件
|
|
@@ -527,7 +498,7 @@ async def get_latest_crop_cd_histogram(county_name: str):
|
|
|
if not histogram_files:
|
|
|
raise HTTPException(
|
|
|
status_code=404,
|
|
|
- detail=f"未找到{county_name}的作物Cd预测直方图,请先执行预测"
|
|
|
+ detail=f"未找到{area_name}的作物Cd预测直方图,请先执行预测"
|
|
|
)
|
|
|
|
|
|
# 选择最新的文件(按修改时间排序)
|
|
@@ -538,43 +509,36 @@ async def get_latest_crop_cd_histogram(county_name: str):
|
|
|
|
|
|
return FileResponse(
|
|
|
path=latest_histogram,
|
|
|
- filename=f"{county_name}_latest_crop_cd_histogram.jpg",
|
|
|
+ filename=f"{area_name}_latest_crop_cd_histogram.jpg",
|
|
|
media_type="image/jpeg"
|
|
|
)
|
|
|
|
|
|
except HTTPException:
|
|
|
raise
|
|
|
except Exception as e:
|
|
|
- logger.error(f"获取{county_name}最新作物Cd直方图失败: {str(e)}")
|
|
|
+ logger.error(f"获取{area_name}最新作物Cd直方图失败: {str(e)}")
|
|
|
raise HTTPException(
|
|
|
status_code=500,
|
|
|
- detail=f"获取{county_name}最新作物Cd直方图失败: {str(e)}"
|
|
|
+ detail=f"获取{area_name}最新作物Cd直方图失败: {str(e)}"
|
|
|
)
|
|
|
|
|
|
-@router.get("/effective-cd/latest-histogram/{county_name}",
|
|
|
+@router.get("/effective-cd/latest-histogram/{area_name}",
|
|
|
summary="获取有效态Cd最新直方图",
|
|
|
- description="直接返回指定县市的最新有效态Cd预测直方图,无需重新计算")
|
|
|
-async def get_latest_effective_cd_histogram(county_name: str):
|
|
|
+ description="直接返回指定区域的最新有效态Cd预测直方图,无需重新计算")
|
|
|
+async def get_latest_effective_cd_histogram(area_name: str):
|
|
|
"""
|
|
|
- 获取指定县市的最新有效态Cd预测直方图
|
|
|
+ 获取指定区域的最新有效态Cd预测直方图
|
|
|
|
|
|
- @param county_name: 县市名称,如:乐昌市
|
|
|
+ @param area_name: 区域名称,如:乐昌市
|
|
|
@returns {FileResponse} 最新的预测直方图文件
|
|
|
"""
|
|
|
try:
|
|
|
- logger.info(f"获取{county_name}的最新有效态Cd预测直方图")
|
|
|
+ logger.info(f"获取{area_name}的最新有效态Cd预测直方图")
|
|
|
|
|
|
service = CdPredictionServiceV3()
|
|
|
|
|
|
- # 验证县市是否支持
|
|
|
- if not service.is_county_supported(county_name):
|
|
|
- raise HTTPException(
|
|
|
- status_code=404,
|
|
|
- detail=f"不支持的县市: {county_name}"
|
|
|
- )
|
|
|
-
|
|
|
# 查找最新的直方图文件
|
|
|
- histogram_pattern = f"prediction_histogram_effective_cd_{county_name}_*.jpg"
|
|
|
+ histogram_pattern = f"prediction_histogram_effective_cd_{area_name}_*.jpg"
|
|
|
histogram_files = []
|
|
|
|
|
|
# 在输出目录中查找相关文件
|
|
@@ -586,7 +550,7 @@ async def get_latest_effective_cd_histogram(county_name: str):
|
|
|
if not histogram_files:
|
|
|
raise HTTPException(
|
|
|
status_code=404,
|
|
|
- detail=f"未找到{county_name}的有效态Cd预测直方图,请先执行预测"
|
|
|
+ detail=f"未找到{area_name}的有效态Cd预测直方图,请先执行预测"
|
|
|
)
|
|
|
|
|
|
# 选择最新的文件(按修改时间排序)
|
|
@@ -597,370 +561,15 @@ async def get_latest_effective_cd_histogram(county_name: str):
|
|
|
|
|
|
return FileResponse(
|
|
|
path=latest_histogram,
|
|
|
- filename=f"{county_name}_latest_effective_cd_histogram.jpg",
|
|
|
+ filename=f"{area_name}_latest_effective_cd_histogram.jpg",
|
|
|
media_type="image/jpeg"
|
|
|
)
|
|
|
|
|
|
except HTTPException:
|
|
|
raise
|
|
|
except Exception as e:
|
|
|
- logger.error(f"获取{county_name}最新有效态Cd直方图失败: {str(e)}")
|
|
|
+ logger.error(f"获取{area_name}最新有效态Cd直方图失败: {str(e)}")
|
|
|
raise HTTPException(
|
|
|
status_code=500,
|
|
|
- detail=f"获取{county_name}最新有效态Cd直方图失败: {str(e)}"
|
|
|
+ detail=f"获取{area_name}最新有效态Cd直方图失败: {str(e)}"
|
|
|
)
|
|
|
-
|
|
|
-@router.get("/latest-results/{county_name}",
|
|
|
- summary="获取县市最新预测结果概览",
|
|
|
- description="获取指定县市所有最新预测结果的概览信息")
|
|
|
-async def get_latest_results_overview(county_name: str):
|
|
|
- """
|
|
|
- 获取指定县市的最新预测结果概览
|
|
|
-
|
|
|
- @param county_name: 县市名称,如:乐昌市
|
|
|
- @returns {Dict[str, Any]} 最新预测结果的概览信息
|
|
|
- """
|
|
|
- try:
|
|
|
- logger.info(f"获取{county_name}的最新预测结果概览")
|
|
|
-
|
|
|
- service = CdPredictionServiceV3()
|
|
|
-
|
|
|
- # 验证县市是否支持
|
|
|
- if not service.is_county_supported(county_name):
|
|
|
- raise HTTPException(
|
|
|
- status_code=404,
|
|
|
- detail=f"不支持的县市: {county_name}"
|
|
|
- )
|
|
|
-
|
|
|
- import glob
|
|
|
- output_dir = service.output_figures_dir
|
|
|
-
|
|
|
- # 查找所有相关文件
|
|
|
- result_files = {
|
|
|
- "crop_cd_maps": [],
|
|
|
- "crop_cd_histograms": [],
|
|
|
- "effective_cd_maps": [],
|
|
|
- "effective_cd_histograms": []
|
|
|
- }
|
|
|
-
|
|
|
- # 作物Cd地图
|
|
|
- crop_map_pattern = os.path.join(output_dir, f"prediction_map_crop_cd_{county_name}_*.jpg")
|
|
|
- result_files["crop_cd_maps"] = glob.glob(crop_map_pattern)
|
|
|
-
|
|
|
- # 作物Cd直方图
|
|
|
- crop_hist_pattern = os.path.join(output_dir, f"prediction_histogram_crop_cd_{county_name}_*.jpg")
|
|
|
- result_files["crop_cd_histograms"] = glob.glob(crop_hist_pattern)
|
|
|
-
|
|
|
- # 有效态Cd地图
|
|
|
- eff_map_pattern = os.path.join(output_dir, f"prediction_map_effective_cd_{county_name}_*.jpg")
|
|
|
- result_files["effective_cd_maps"] = glob.glob(eff_map_pattern)
|
|
|
-
|
|
|
- # 有效态Cd直方图
|
|
|
- eff_hist_pattern = os.path.join(output_dir, f"prediction_histogram_effective_cd_{county_name}_*.jpg")
|
|
|
- result_files["effective_cd_histograms"] = glob.glob(eff_hist_pattern)
|
|
|
-
|
|
|
- # 构建结果概览
|
|
|
- overview = {
|
|
|
- "county_name": county_name,
|
|
|
- "available_results": {},
|
|
|
- "latest_files": {},
|
|
|
- "total_results": 0
|
|
|
- }
|
|
|
-
|
|
|
- for result_type, files in result_files.items():
|
|
|
- if files:
|
|
|
- # 按修改时间排序,获取最新文件
|
|
|
- latest_file = max(files, key=os.path.getmtime)
|
|
|
- file_stats = os.stat(latest_file)
|
|
|
-
|
|
|
- overview["available_results"][result_type] = {
|
|
|
- "count": len(files),
|
|
|
- "latest_timestamp": file_stats.st_mtime,
|
|
|
- "latest_size": file_stats.st_size
|
|
|
- }
|
|
|
-
|
|
|
- overview["latest_files"][result_type] = {
|
|
|
- "filename": os.path.basename(latest_file),
|
|
|
- "path": latest_file,
|
|
|
- "download_url": f"/api/cd-prediction/{result_type.replace('_', '-')}/latest-{'map' if 'map' in result_type else 'histogram'}/{county_name}"
|
|
|
- }
|
|
|
-
|
|
|
- overview["total_results"] += len(files)
|
|
|
-
|
|
|
- if overview["total_results"] == 0:
|
|
|
- raise HTTPException(
|
|
|
- status_code=404,
|
|
|
- detail=f"未找到{county_name}的任何预测结果,请先执行预测"
|
|
|
- )
|
|
|
-
|
|
|
- return {
|
|
|
- "success": True,
|
|
|
- "message": f"获取{county_name}预测结果概览成功",
|
|
|
- "data": overview
|
|
|
- }
|
|
|
-
|
|
|
- except HTTPException:
|
|
|
- raise
|
|
|
- except Exception as e:
|
|
|
- logger.error(f"获取{county_name}预测结果概览失败: {str(e)}")
|
|
|
- raise HTTPException(
|
|
|
- status_code=500,
|
|
|
- detail=f"获取{county_name}预测结果概览失败: {str(e)}"
|
|
|
- )
|
|
|
-
|
|
|
-# =============================================================================
|
|
|
-# 预测结果统计信息接口
|
|
|
-# =============================================================================
|
|
|
-
|
|
|
-@router.get("/crop-cd/statistics/{county_name}",
|
|
|
- summary="获取作物Cd预测统计信息",
|
|
|
- description="获取指定县市的作物Cd预测结果的详细统计信息")
|
|
|
-async def get_crop_cd_statistics(county_name: str):
|
|
|
- """
|
|
|
- 获取指定县市的作物Cd预测统计信息
|
|
|
-
|
|
|
- @param county_name: 县市名称,如:乐昌市
|
|
|
- @returns {Dict[str, Any]} 预测结果的统计信息
|
|
|
- """
|
|
|
- try:
|
|
|
- logger.info(f"获取{county_name}的作物Cd预测统计信息")
|
|
|
-
|
|
|
- service = CdPredictionServiceV3()
|
|
|
-
|
|
|
- # 验证县市是否支持
|
|
|
- if not service.is_county_supported(county_name):
|
|
|
- raise HTTPException(
|
|
|
- status_code=404,
|
|
|
- detail=f"不支持的县市: {county_name}"
|
|
|
- )
|
|
|
-
|
|
|
- # 获取预测结果数据
|
|
|
- stats = service.get_crop_cd_statistics(county_name)
|
|
|
-
|
|
|
- if not stats:
|
|
|
- raise HTTPException(
|
|
|
- status_code=404,
|
|
|
- detail=f"未找到{county_name}的作物Cd预测结果,请先执行预测"
|
|
|
- )
|
|
|
-
|
|
|
- return {
|
|
|
- "success": True,
|
|
|
- "message": f"获取{county_name}作物Cd预测统计信息成功",
|
|
|
- "data": stats
|
|
|
- }
|
|
|
-
|
|
|
- except HTTPException:
|
|
|
- raise
|
|
|
- except Exception as e:
|
|
|
- logger.error(f"获取{county_name}作物Cd预测统计信息失败: {str(e)}")
|
|
|
- raise HTTPException(
|
|
|
- status_code=500,
|
|
|
- detail=f"获取{county_name}作物Cd预测统计信息失败: {str(e)}"
|
|
|
- )
|
|
|
-
|
|
|
-@router.get("/effective-cd/statistics/{county_name}",
|
|
|
- summary="获取有效态Cd预测统计信息",
|
|
|
- description="获取指定县市的有效态Cd预测结果的详细统计信息")
|
|
|
-async def get_effective_cd_statistics(county_name: str):
|
|
|
- """
|
|
|
- 获取指定县市的有效态Cd预测统计信息
|
|
|
-
|
|
|
- @param county_name: 县市名称,如:乐昌市
|
|
|
- @returns {Dict[str, Any]} 预测结果的统计信息
|
|
|
- """
|
|
|
- try:
|
|
|
- logger.info(f"获取{county_name}的有效态Cd预测统计信息")
|
|
|
-
|
|
|
- service = CdPredictionServiceV3()
|
|
|
-
|
|
|
- # 验证县市是否支持
|
|
|
- if not service.is_county_supported(county_name):
|
|
|
- raise HTTPException(
|
|
|
- status_code=404,
|
|
|
- detail=f"不支持的县市: {county_name}"
|
|
|
- )
|
|
|
-
|
|
|
- # 获取预测结果数据
|
|
|
- stats = service.get_effective_cd_statistics(county_name)
|
|
|
-
|
|
|
- if not stats:
|
|
|
- raise HTTPException(
|
|
|
- status_code=404,
|
|
|
- detail=f"未找到{county_name}的有效态Cd预测结果,请先执行预测"
|
|
|
- )
|
|
|
-
|
|
|
- return {
|
|
|
- "success": True,
|
|
|
- "message": f"获取{county_name}有效态Cd预测统计信息成功",
|
|
|
- "data": stats
|
|
|
- }
|
|
|
-
|
|
|
- except HTTPException:
|
|
|
- raise
|
|
|
- except Exception as e:
|
|
|
- logger.error(f"获取{county_name}有效态Cd预测统计信息失败: {str(e)}")
|
|
|
- raise HTTPException(
|
|
|
- status_code=500,
|
|
|
- detail=f"获取{county_name}有效态Cd预测统计信息失败: {str(e)}"
|
|
|
- )
|
|
|
-
|
|
|
-@router.get("/combined-statistics/{county_name}",
|
|
|
- summary="获取综合预测统计信息",
|
|
|
- description="获取指定县市的作物Cd和有效态Cd预测结果的综合统计信息")
|
|
|
-async def get_combined_statistics(county_name: str):
|
|
|
- """
|
|
|
- 获取指定县市的综合预测统计信息
|
|
|
-
|
|
|
- @param county_name: 县市名称,如:乐昌市
|
|
|
- @returns {Dict[str, Any]} 综合预测结果的统计信息
|
|
|
- """
|
|
|
- try:
|
|
|
- logger.info(f"获取{county_name}的综合预测统计信息")
|
|
|
-
|
|
|
- service = CdPredictionServiceV3()
|
|
|
-
|
|
|
- # 验证县市是否支持
|
|
|
- if not service.is_county_supported(county_name):
|
|
|
- raise HTTPException(
|
|
|
- status_code=404,
|
|
|
- detail=f"不支持的县市: {county_name}"
|
|
|
- )
|
|
|
-
|
|
|
- # 获取综合统计信息
|
|
|
- stats = service.get_combined_statistics(county_name)
|
|
|
-
|
|
|
- if not stats:
|
|
|
- raise HTTPException(
|
|
|
- status_code=404,
|
|
|
- detail=f"未找到{county_name}的预测结果,请先执行预测"
|
|
|
- )
|
|
|
-
|
|
|
- return {
|
|
|
- "success": True,
|
|
|
- "message": f"获取{county_name}综合预测统计信息成功",
|
|
|
- "data": stats
|
|
|
- }
|
|
|
-
|
|
|
- except HTTPException:
|
|
|
- raise
|
|
|
- except Exception as e:
|
|
|
- logger.error(f"获取{county_name}综合预测统计信息失败: {str(e)}")
|
|
|
- raise HTTPException(
|
|
|
- status_code=500,
|
|
|
- detail=f"获取{county_name}综合预测统计信息失败: {str(e)}"
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-@router.get("/all-statistics",
|
|
|
- summary="获取所有县市统计概览",
|
|
|
- description="获取所有支持县市的预测结果统计概览")
|
|
|
-async def get_all_statistics():
|
|
|
- """
|
|
|
- 获取所有支持县市的预测结果统计概览
|
|
|
-
|
|
|
- @returns {Dict[str, Any]} 所有县市的统计概览
|
|
|
- """
|
|
|
- try:
|
|
|
- logger.info("获取所有县市统计概览")
|
|
|
-
|
|
|
- service = CdPredictionServiceV3()
|
|
|
-
|
|
|
- # 获取所有县市的统计概览
|
|
|
- all_stats = service.get_all_counties_statistics()
|
|
|
-
|
|
|
- return {
|
|
|
- "success": True,
|
|
|
- "message": "获取所有县市统计概览成功",
|
|
|
- "data": all_stats
|
|
|
- }
|
|
|
-
|
|
|
- except Exception as e:
|
|
|
- logger.error(f"获取所有县市统计概览失败: {str(e)}")
|
|
|
- raise HTTPException(
|
|
|
- status_code=500,
|
|
|
- detail=f"获取所有县市统计概览失败: {str(e)}"
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-# =============================================================================
|
|
|
-# 获取最终预测结果CSV文件接口
|
|
|
-# =============================================================================
|
|
|
-
|
|
|
-@router.get("/download-final-crop-cd-csv",
|
|
|
- summary="下载作物Cd最终预测结果CSV文件",
|
|
|
- description="获取系统最终的作物Cd预测结果CSV文件(Final_predictions_crop_cd.csv)")
|
|
|
-async def download_final_crop_cd_csv():
|
|
|
- """
|
|
|
- 下载作物Cd最终预测结果CSV文件
|
|
|
-
|
|
|
- @returns {FileResponse} CSV文件
|
|
|
- """
|
|
|
- try:
|
|
|
- logger.info("下载作物Cd最终预测结果CSV文件")
|
|
|
-
|
|
|
- service = CdPredictionServiceV3()
|
|
|
-
|
|
|
- # 构建CSV文件路径(适配你的实际路径)
|
|
|
- csv_path = "Cd_Prediction_Integrated_System/data/final/Final_predictions_crop_cd.csv"
|
|
|
-
|
|
|
- if not os.path.exists(csv_path):
|
|
|
- raise HTTPException(
|
|
|
- status_code=404,
|
|
|
- detail="未找到作物Cd最终预测结果文件,请先执行预测"
|
|
|
- )
|
|
|
-
|
|
|
- return FileResponse(
|
|
|
- path=csv_path,
|
|
|
- filename="Final_predictions_crop_cd.csv",
|
|
|
- media_type="text/csv"
|
|
|
- )
|
|
|
-
|
|
|
- except HTTPException:
|
|
|
- raise
|
|
|
- except Exception as e:
|
|
|
- logger.error(f"下载作物Cd最终预测结果CSV失败: {str(e)}")
|
|
|
- raise HTTPException(
|
|
|
- status_code=500,
|
|
|
- detail=f"下载作物Cd最终预测结果CSV失败: {str(e)}"
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
-@router.get("/download-final-effective-cd-csv",
|
|
|
- summary="下载有效态Cd最终预测结果CSV文件",
|
|
|
- description="获取系统最终的有效态Cd预测结果CSV文件(Final_predictions_effective_cd.csv)")
|
|
|
-async def download_final_effective_cd_csv():
|
|
|
- """
|
|
|
- 下载有效态Cd最终预测结果CSV文件
|
|
|
-
|
|
|
- @returns {FileResponse} CSV文件
|
|
|
- """
|
|
|
- try:
|
|
|
- logger.info("下载有效态Cd最终预测结果CSV文件")
|
|
|
-
|
|
|
- service = CdPredictionServiceV3()
|
|
|
-
|
|
|
- # 构建CSV文件路径
|
|
|
- csv_path = "Cd_Prediction_Integrated_System/data/final/Final_predictions_effective_cd.csv"
|
|
|
-
|
|
|
- if not os.path.exists(csv_path):
|
|
|
- raise HTTPException(
|
|
|
- status_code=404,
|
|
|
- detail="未找到有效态Cd最终预测结果文件,请先执行预测"
|
|
|
- )
|
|
|
-
|
|
|
- return FileResponse(
|
|
|
- path=csv_path,
|
|
|
- filename="Final_predictions_effective_cd.csv",
|
|
|
- media_type="text/csv"
|
|
|
- )
|
|
|
-
|
|
|
- except HTTPException:
|
|
|
- raise
|
|
|
- except Exception as e:
|
|
|
- logger.error(f"下载有效态Cd最终预测结果CSV失败: {str(e)}")
|
|
|
- raise HTTPException(
|
|
|
- status_code=500,
|
|
|
- detail=f"下载有效态Cd最终预测结果CSV失败: {str(e)}"
|
|
|
- )
|