|
@@ -67,54 +67,55 @@ def get_default_file_path(filename: str) -> str:
|
|
|
return path
|
|
|
|
|
|
|
|
|
-@router.post("/calculate",
|
|
|
- summary="上传CSV文件更新数据并生成Cd通量可视化结果",
|
|
|
- description="上传包含镉通量数据的CSV文件,更新数据库,并生成空间分布图和直方图")
|
|
|
+@router.post("/calculate")
|
|
|
async def update_and_generate_fluxcd_visualization(
|
|
|
background_tasks: BackgroundTasks,
|
|
|
- csv_file: UploadFile = File(..., description="CSV文件,包含经纬度和通量数据"),
|
|
|
- boundary_shp: Optional[str] = Form(None, description="可选,边界SHP文件路径(如果使用默认则不提供)")
|
|
|
+ csv_file: Optional[UploadFile] = File(None),
|
|
|
+ boundary_shp: Optional[str] = Form(None)
|
|
|
) -> Dict[str, Any]:
|
|
|
try:
|
|
|
- logger.info("开始处理Cd通量数据更新和可视化")
|
|
|
- # 创建临时目录保存上传的CSV文件
|
|
|
- temp_dir = tempfile.mkdtemp()
|
|
|
- temp_csv_path = os.path.join(temp_dir, csv_file.filename)
|
|
|
-
|
|
|
- # 保存上传的文件
|
|
|
- with open(temp_csv_path, "wb") as f:
|
|
|
- content = await csv_file.read()
|
|
|
- f.write(content)
|
|
|
+ logger.info("开始处理Cd通量数据可视化")
|
|
|
|
|
|
# 初始化服务
|
|
|
service = FluxCdVisualizationService()
|
|
|
-
|
|
|
- # 步骤1: 更新数据
|
|
|
- update_result = service.update_from_csv(temp_csv_path)
|
|
|
- if not update_result.get("success"):
|
|
|
- logger.error(f"更新数据失败: {update_result.get('message')}")
|
|
|
- raise HTTPException(status_code=500, detail=update_result.get('message'))
|
|
|
-
|
|
|
- # 步骤2: 生成可视化结果
|
|
|
- # 使用静态目录作为输出目录
|
|
|
static_dir = get_static_dir()
|
|
|
os.makedirs(static_dir, exist_ok=True)
|
|
|
|
|
|
- # 生成三种通量结果
|
|
|
+ # 如果有上传文件,先更新数据
|
|
|
+ if csv_file:
|
|
|
+ logger.info("检测到上传文件,开始更新数据")
|
|
|
+ temp_dir = tempfile.mkdtemp()
|
|
|
+ temp_csv_path = os.path.join(temp_dir, csv_file.filename)
|
|
|
+
|
|
|
+ with open(temp_csv_path, "wb") as f:
|
|
|
+ content = await csv_file.read()
|
|
|
+ f.write(content)
|
|
|
+
|
|
|
+ update_result = service.update_from_csv(temp_csv_path)
|
|
|
+ if not update_result.get("success"):
|
|
|
+ logger.error(f"更新数据失败: {update_result.get('message')}")
|
|
|
+ raise HTTPException(status_code=500, detail=update_result.get('message'))
|
|
|
+
|
|
|
+ # 清理临时文件
|
|
|
+ background_tasks.add_task(shutil.rmtree, temp_dir, ignore_errors=True)
|
|
|
+
|
|
|
+ # 生成所有结果(直接从数据库获取数据)
|
|
|
input_result = service.generate_cd_input_flux_map(
|
|
|
output_dir=static_dir,
|
|
|
boundary_shp=boundary_shp
|
|
|
)
|
|
|
-
|
|
|
output_result = service.generate_cd_output_flux_map(
|
|
|
output_dir=static_dir,
|
|
|
boundary_shp=boundary_shp
|
|
|
)
|
|
|
-
|
|
|
net_result = service.generate_cd_net_flux_map(
|
|
|
output_dir=static_dir,
|
|
|
boundary_shp=boundary_shp
|
|
|
)
|
|
|
+ end_cd_result = service.generate_end_cd_map(
|
|
|
+ output_dir=static_dir,
|
|
|
+ boundary_shp=boundary_shp
|
|
|
+ )
|
|
|
|
|
|
# 保存最新结果信息
|
|
|
latest_result_path = os.path.join(static_dir, LATEST_RESULT_FILENAME)
|
|
@@ -122,13 +123,15 @@ async def update_and_generate_fluxcd_visualization(
|
|
|
json.dump({
|
|
|
"input": input_result,
|
|
|
"output": output_result,
|
|
|
- "net": net_result
|
|
|
+ "net": net_result,
|
|
|
+ "end_cd": end_cd_result
|
|
|
}, f, ensure_ascii=False, indent=2)
|
|
|
|
|
|
return {
|
|
|
"input": input_result,
|
|
|
"output": output_result,
|
|
|
- "net": net_result
|
|
|
+ "net": net_result,
|
|
|
+ "end_cd": end_cd_result
|
|
|
}
|
|
|
|
|
|
except HTTPException as he:
|
|
@@ -136,11 +139,84 @@ async def update_and_generate_fluxcd_visualization(
|
|
|
except Exception as e:
|
|
|
logger.error(f"处理过程中出错: {str(e)}", exc_info=True)
|
|
|
raise HTTPException(status_code=500, detail=f"服务器内部错误: {str(e)}")
|
|
|
- finally:
|
|
|
- # 清理临时目录(使用后台任务)
|
|
|
- background_tasks.add_task(shutil.rmtree, temp_dir, ignore_errors=True)
|
|
|
|
|
|
|
|
|
+# 添加常量定义
|
|
|
+DEFAULT_END_CD_MAP_FILENAME = "fluxcd_end_cd_map.jpg"
|
|
|
+DEFAULT_END_CD_HIST_FILENAME = "fluxcd_end_cd_histogram.jpg"
|
|
|
+DEFAULT_END_CD_CSV_FILENAME = "fluxcd_end_cd.csv"
|
|
|
+
|
|
|
+# 添加API路由
|
|
|
+@router.get("/end-cd/map",
|
|
|
+ summary="获取当年Cd浓度空间分布图",
|
|
|
+ description="返回当年Cd浓度的空间分布图")
|
|
|
+async def get_end_cd_map() -> FileResponse:
|
|
|
+ try:
|
|
|
+ map_path = get_default_file_path(DEFAULT_END_CD_MAP_FILENAME)
|
|
|
+ if os.path.exists(map_path):
|
|
|
+ return FileResponse(map_path, media_type="image/jpeg")
|
|
|
+ else:
|
|
|
+ raise HTTPException(status_code=404, detail="当年Cd浓度地图不存在,请先生成")
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"获取当年Cd浓度地图失败: {str(e)}")
|
|
|
+ raise HTTPException(status_code=500, detail=f"获取当年Cd浓度地图失败: {str(e)}")
|
|
|
+
|
|
|
+@router.get("/end-cd/histogram",
|
|
|
+ summary="获取当年Cd浓度直方图",
|
|
|
+ description="返回当年Cd浓度的直方图")
|
|
|
+async def get_end_cd_histogram() -> FileResponse:
|
|
|
+ try:
|
|
|
+ hist_path = get_default_file_path(DEFAULT_END_CD_HIST_FILENAME)
|
|
|
+ if os.path.exists(hist_path):
|
|
|
+ return FileResponse(hist_path, media_type="image/jpeg")
|
|
|
+ else:
|
|
|
+ raise HTTPException(status_code=404, detail="当年Cd浓度直方图不存在,请先生成")
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"获取当年Cd浓度直方图失败: {str(e)}")
|
|
|
+ raise HTTPException(status_code=500, detail=f"获取当年Cd浓度直方图失败: {str(e)}")
|
|
|
+
|
|
|
+@router.get("/end-cd/statistics",
|
|
|
+ summary="获取当年Cd浓度统计信息",
|
|
|
+ description="返回当年Cd浓度的统计信息")
|
|
|
+async def get_end_cd_statistics() -> JSONResponse:
|
|
|
+ try:
|
|
|
+ latest_result_path = os.path.join(STATIC_DIR, LATEST_RESULT_FILENAME)
|
|
|
+ if not os.path.exists(latest_result_path):
|
|
|
+ raise HTTPException(status_code=404, detail="无可用统计信息,请先生成")
|
|
|
+
|
|
|
+ with open(latest_result_path, "r", encoding="utf-8") as f:
|
|
|
+ result = json.load(f)
|
|
|
+
|
|
|
+ if not result.get("end_cd") or not result["end_cd"].get("success"):
|
|
|
+ raise HTTPException(status_code=404, detail="当年Cd浓度结果无效")
|
|
|
+
|
|
|
+ stats = result["end_cd"].get("data", {}).get("statistics")
|
|
|
+ if stats:
|
|
|
+ return JSONResponse(content=stats)
|
|
|
+ else:
|
|
|
+ raise HTTPException(status_code=404, detail="当年Cd浓度统计信息不存在")
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"获取当年Cd浓度统计信息失败: {str(e)}")
|
|
|
+ raise HTTPException(status_code=500, detail=f"获取当年Cd浓度统计信息失败: {str(e)}")
|
|
|
+
|
|
|
+@router.get("/end-cd/export-csv",
|
|
|
+ summary="导出当年Cd浓度CSV文件",
|
|
|
+ description="导出当年Cd浓度的CSV文件")
|
|
|
+async def export_end_cd_csv() -> FileResponse:
|
|
|
+ try:
|
|
|
+ csv_path = get_default_file_path(DEFAULT_END_CD_CSV_FILENAME)
|
|
|
+ if os.path.exists(csv_path):
|
|
|
+ return FileResponse(
|
|
|
+ csv_path,
|
|
|
+ filename="fluxcd_end_cd.csv",
|
|
|
+ media_type="text/csv"
|
|
|
+ )
|
|
|
+ else:
|
|
|
+ raise HTTPException(status_code=404, detail="当年Cd浓度CSV文件不存在,请先生成")
|
|
|
+ except Exception as e:
|
|
|
+ logger.error(f"导出当年Cd浓度CSV失败: {str(e)}")
|
|
|
+ raise HTTPException(status_code=500, detail=f"导出当年Cd浓度CSV失败: {str(e)}")
|
|
|
+
|
|
|
@router.get("/input/map",
|
|
|
summary="获取Cd输入通量空间分布图",
|
|
|
description="返回默认的Cd输入通量空间分布图")
|