water.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. from fastapi import APIRouter, Form, HTTPException, BackgroundTasks, Query
  2. from fastapi.responses import FileResponse, JSONResponse
  3. import os
  4. import logging
  5. import tempfile
  6. import shutil
  7. from typing import Dict, Any, Optional
  8. from datetime import datetime
  9. import json
  10. from pathlib import Path
  11. # 导入服务层函数
  12. from ..services.water_service import (
  13. process_land_to_visualization,
  14. get_land_statistics,
  15. get_base_dir
  16. )
  17. # 配置日志
  18. logger = logging.getLogger(__name__)
  19. logger.setLevel(logging.INFO)
  20. handler = logging.StreamHandler()
  21. formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  22. handler.setFormatter(formatter)
  23. logger.addHandler(handler)
  24. router = APIRouter()
  25. # 清理临时路径的函数
  26. def cleanup_temp_path(path: str) -> None:
  27. """删除临时文件或整个临时目录"""
  28. try:
  29. if os.path.exists(path):
  30. if os.path.isfile(path):
  31. os.unlink(path)
  32. elif os.path.isdir(path):
  33. shutil.rmtree(path)
  34. except Exception as e:
  35. logger.warning(f"清理临时路径失败: {path}, 错误: {e}")
  36. @router.get("/default-map",
  37. summary="获取默认地图图片",
  38. description="返回指定土地类型的默认地图图片")
  39. async def get_default_map(
  40. land_type: str = Query("水田", description="土地类型,如:'水田'、'旱地'或'水浇地'")
  41. ) -> FileResponse:
  42. """返回默认地图图片"""
  43. try:
  44. logger.info(f"获取默认地图: {land_type}")
  45. # 获取基础目录
  46. base_dir = get_base_dir()
  47. raster_dir = os.path.join(base_dir, "..", "static", "water", "Raster")
  48. map_path = os.path.join(raster_dir, f"{land_type}_Cd含量地图.jpg")
  49. if not os.path.exists(map_path):
  50. logger.warning(f"默认地图文件不存在: {map_path}")
  51. raise HTTPException(status_code=404, detail="地图文件不存在")
  52. return FileResponse(
  53. path=map_path,
  54. filename=f"{land_type}_Cd含量地图.jpg",
  55. media_type="image/jpeg"
  56. )
  57. except HTTPException:
  58. raise
  59. except Exception as e:
  60. logger.error(f"获取默认地图失败: {str(e)}")
  61. raise HTTPException(
  62. status_code=500,
  63. detail=f"获取默认地图失败: {str(e)}"
  64. )
  65. @router.get("/default-histogram",
  66. summary="获取默认直方图",
  67. description="返回指定土地类型的默认直方图图片")
  68. async def get_default_histogram(
  69. land_type: str = Query("水田", description="土地类型,如:'水田'、'旱地'或'水浇地'")
  70. ) -> FileResponse:
  71. """返回默认直方图图片"""
  72. try:
  73. logger.info(f"获取默认直方图: {land_type}")
  74. # 获取基础目录
  75. base_dir = get_base_dir()
  76. raster_dir = os.path.join(base_dir, "..", "static", "water", "Raster")
  77. hist_path = os.path.join(raster_dir, f"{land_type}_Cd含量直方图.jpg")
  78. if not os.path.exists(hist_path):
  79. logger.warning(f"默认直方图文件不存在: {hist_path}")
  80. raise HTTPException(status_code=404, detail="直方图文件不存在")
  81. return FileResponse(
  82. path=hist_path,
  83. filename=f"{land_type}_Cd含量直方图.jpg",
  84. media_type="image/jpeg"
  85. )
  86. except HTTPException:
  87. raise
  88. except Exception as e:
  89. logger.error(f"获取默认直方图失败: {str(e)}")
  90. raise HTTPException(
  91. status_code=500,
  92. detail=f"获取默认直方图失败: {str(e)}"
  93. )
  94. @router.post("/calculate",
  95. summary="重新计算土地数据",
  96. description="根据输入的土地类型和系数重新计算土地数据")
  97. async def recalculate_land_data(
  98. background_tasks: BackgroundTasks,
  99. land_type: str = Form(..., description="土地类型,如:'水田'、'旱地'或'水浇地'"),
  100. param1: float = Form(711, description="土地类型系数的第一个参数"),
  101. param2: float = Form(0.524, description="土地类型系数的第二个参数"),
  102. color_map_name: str = Form("绿-黄-红-紫", description="使用的色彩方案"),
  103. output_size: int = Form(8, description="输出图片的尺寸")
  104. ) -> Dict[str, Any]:
  105. """重新计算土地数据并返回结果路径"""
  106. try:
  107. logger.info(f"重新计算土地数据: {land_type}")
  108. # 获取默认目录
  109. base_dir = get_base_dir()
  110. raster_dir = os.path.join(base_dir, "..", "static", "water", "Raster")
  111. # 确保目录存在
  112. os.makedirs(raster_dir, exist_ok=True)
  113. # 构建系数参数
  114. coefficient_params = {
  115. land_type: (param1, param2)
  116. }
  117. # 调用服务层函数处理土地数据
  118. results = process_land_to_visualization(
  119. land_type=land_type,
  120. coefficient_params=coefficient_params,
  121. color_map_name=color_map_name,
  122. output_size=output_size
  123. )
  124. if not results or any(r is None for r in results):
  125. logger.error(f"重新计算土地数据失败: {land_type}")
  126. raise HTTPException(
  127. status_code=500,
  128. detail=f"重新计算土地数据失败: {land_type}"
  129. )
  130. cleaned_csv, shapefile, tif_file, map_output, hist_output, used_coeff = results
  131. # 定义默认路径
  132. default_map_path = os.path.join(raster_dir, f"{land_type}_Cd含量地图.jpg")
  133. default_hist_path = os.path.join(raster_dir, f"{land_type}_Cd含量直方图.jpg")
  134. # 移动文件到默认目录(覆盖旧文件)
  135. shutil.move(map_output, default_map_path)
  136. shutil.move(hist_output, default_hist_path)
  137. return {
  138. "map_path": default_map_path,
  139. "histogram_path": default_hist_path,
  140. "used_coeff": used_coeff
  141. }
  142. except HTTPException:
  143. raise
  144. except Exception as e:
  145. logger.error(f"重新计算土地数据失败: {str(e)}")
  146. raise HTTPException(
  147. status_code=500,
  148. detail=f"重新计算土地数据失败: {str(e)}"
  149. )
  150. @router.get("/statistics",
  151. summary="获取土地类型统计数据",
  152. description="返回指定土地类型的Cd预测结果统计信息")
  153. async def get_land_statistics_endpoint(
  154. land_type: str = Query("水田", description="土地类型,如:'水田'、'旱地'或'水浇地'")
  155. ) -> JSONResponse:
  156. """返回土地类型Cd预测结果的统计信息"""
  157. try:
  158. logger.info(f"获取土地类型统计数据: {land_type}")
  159. # 调用服务层函数获取统计数据
  160. stats = get_land_statistics(land_type)
  161. if not stats:
  162. logger.warning(f"未找到{land_type}的土地类型统计数据")
  163. raise HTTPException(status_code=404, detail="统计数据不存在")
  164. return JSONResponse(content=stats)
  165. except HTTPException:
  166. raise
  167. except Exception as e:
  168. logger.error(f"获取土地类型统计数据失败: {str(e)}")
  169. raise HTTPException(
  170. status_code=500,
  171. detail=f"获取土地类型统计数据失败: {str(e)}"
  172. )