agricultural_input.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. """
  2. 农业投入Cd通量计算API接口
  3. @description: 提供各个地区的农业投入输入Cd通量预测计算功能
  4. """
  5. from fastapi import APIRouter, HTTPException, Query, Body
  6. from pydantic import BaseModel, Field
  7. from typing import Dict, Any, Optional
  8. import logging
  9. from ..services.agricultural_input_service import AgriculturalInputService
  10. router = APIRouter()
  11. # =============================================================================
  12. # 数据模型定义
  13. # =============================================================================
  14. class CdFluxCalculationRequest(BaseModel):
  15. """
  16. 农业投入Cd通量计算请求模型
  17. @description: 用户提供的计算参数
  18. """
  19. # 镉含量参数 (mg/kg)
  20. f3_nitrogen_cd_content: float = Field(..., description="氮肥镉含量平均值 (mg/kg)", ge=0)
  21. f4_phosphorus_cd_content: float = Field(..., description="磷肥镉含量平均值 (mg/kg)", ge=0)
  22. f5_potassium_cd_content: float = Field(..., description="钾肥镉含量平均值 (mg/kg)", ge=0)
  23. f6_compound_cd_content: float = Field(..., description="复合肥镉含量平均值 (mg/kg)", ge=0)
  24. f7_organic_cd_content: float = Field(..., description="有机肥镉含量平均值 (mg/kg)", ge=0)
  25. f8_pesticide_cd_content: float = Field(..., description="农药镉含量 (mg/kg)", ge=0)
  26. f9_farmyard_cd_content: float = Field(..., description="农家肥镉含量 (mg/kg)", ge=0)
  27. f10_film_cd_content: float = Field(..., description="农膜镉含量 (mg/kg)", ge=0)
  28. # 使用量参数 (t/ha/a)
  29. nf_nitrogen_usage: float = Field(..., description="氮肥单位面积使用量 (t/ha/a)", ge=0)
  30. pf_phosphorus_usage: float = Field(..., description="磷肥单位面积使用量 (t/ha/a)", ge=0)
  31. kf_potassium_usage: float = Field(..., description="钾肥单位面积使用量 (t/ha/a)", ge=0)
  32. cf_compound_usage: float = Field(..., description="复合肥单位面积使用量 (t/ha/a)", ge=0)
  33. of_organic_usage: float = Field(..., description="有机肥单位面积使用量 (t/ha/a)", ge=0)
  34. p_pesticide_usage: float = Field(..., description="农药单位面积使用量 (t/ha/a)", ge=0)
  35. ff_farmyard_usage: float = Field(..., description="农家肥单位面积使用量 (t/ha/a)", ge=0)
  36. af_film_usage: float = Field(..., description="农膜(存留)单位面积使用量 (t/ha/a)", ge=0)
  37. # 可选的标识信息
  38. description: Optional[str] = Field(None, description="计算描述信息")
  39. model_config = {
  40. "json_schema_extra": {
  41. "example": {
  42. "f3_nitrogen_cd_content": 0.12,
  43. "f4_phosphorus_cd_content": 0.85,
  44. "f5_potassium_cd_content": 0.05,
  45. "f6_compound_cd_content": 0.45,
  46. "f7_organic_cd_content": 0.22,
  47. "f8_pesticide_cd_content": 0.08,
  48. "f9_farmyard_cd_content": 0.15,
  49. "f10_film_cd_content": 0.03,
  50. "nf_nitrogen_usage": 0.25,
  51. "pf_phosphorus_usage": 0.15,
  52. "kf_potassium_usage": 0.12,
  53. "cf_compound_usage": 0.30,
  54. "of_organic_usage": 2.50,
  55. "p_pesticide_usage": 0.02,
  56. "ff_farmyard_usage": 1.80,
  57. "af_film_usage": 0.05,
  58. "description": "测试地区农业投入Cd通量计算"
  59. }
  60. }
  61. }
  62. # 设置日志
  63. logger = logging.getLogger(__name__)
  64. # =============================================================================
  65. # 农业投入Cd通量计算接口
  66. # =============================================================================
  67. @router.get("/calculate-by-area",
  68. summary="根据地区计算农业投入Cd通量",
  69. description="根据指定地区从Parameters表中获取数据并计算农业投入输入Cd通量")
  70. async def calculate_cd_flux_by_area(
  71. area: str = Query(..., description="地区名称,如:韶关")
  72. ) -> Dict[str, Any]:
  73. """
  74. 根据地区计算农业投入输入Cd通量
  75. @param area: 地区名称
  76. @returns: 计算结果包括总通量和各项明细
  77. 计算公式:农业投入输入Cd(g/ha/a) = F3*NF + F4*PF + F5*KF + F6*CF + F7*OF + F8*P + F9*FF + F10*AF
  78. """
  79. try:
  80. service = AgriculturalInputService()
  81. result = service.calculate_cd_flux_by_area(area)
  82. if not result["success"]:
  83. raise HTTPException(
  84. status_code=404,
  85. detail=result["message"]
  86. )
  87. return result
  88. except HTTPException:
  89. raise
  90. except Exception as e:
  91. logger.error(f"计算地区 '{area}' 的Cd通量失败: {str(e)}")
  92. raise HTTPException(
  93. status_code=500,
  94. detail=f"计算失败: {str(e)}"
  95. )
  96. @router.get("/calculate-all-areas",
  97. summary="计算所有地区的农业投入Cd通量",
  98. description="计算数据库中所有地区的农业投入输入Cd通量,并提供统计汇总")
  99. async def calculate_all_areas_cd_flux() -> Dict[str, Any]:
  100. """
  101. 计算所有地区的农业投入输入Cd通量
  102. @returns: 所有地区的计算结果,按通量从高到低排序,包含统计汇总
  103. """
  104. try:
  105. service = AgriculturalInputService()
  106. result = service.calculate_all_areas_cd_flux()
  107. if not result["success"]:
  108. raise HTTPException(
  109. status_code=500,
  110. detail=result["message"]
  111. )
  112. return result
  113. except HTTPException:
  114. raise
  115. except Exception as e:
  116. logger.error(f"计算所有地区Cd通量失败: {str(e)}")
  117. raise HTTPException(
  118. status_code=500,
  119. detail=f"计算失败: {str(e)}"
  120. )
  121. @router.get("/available-areas",
  122. summary="获取可用地区列表",
  123. description="获取数据库中所有可用于计算的地区列表")
  124. async def get_available_areas() -> Dict[str, Any]:
  125. """
  126. 获取数据库中所有可用的地区列表
  127. @returns: 可用地区列表
  128. """
  129. try:
  130. service = AgriculturalInputService()
  131. result = service.get_available_areas()
  132. if not result["success"]:
  133. raise HTTPException(
  134. status_code=500,
  135. detail=result["message"]
  136. )
  137. return result
  138. except HTTPException:
  139. raise
  140. except Exception as e:
  141. logger.error(f"获取可用地区列表失败: {str(e)}")
  142. raise HTTPException(
  143. status_code=500,
  144. detail=f"获取失败: {str(e)}"
  145. )
  146. @router.post("/calculate-with-custom-data",
  147. summary="使用自定义数据计算农业投入Cd通量",
  148. description="接收用户提供的参数数据,直接进行农业投入输入Cd通量计算")
  149. async def calculate_cd_flux_with_custom_data(
  150. request: CdFluxCalculationRequest = Body(..., description="计算所需的参数数据")
  151. ) -> Dict[str, Any]:
  152. """
  153. 使用用户提供的自定义数据计算农业投入输入Cd通量
  154. @param request: 包含所有计算参数的请求体
  155. @returns: 计算结果包括总通量和各项明细
  156. 计算公式:农业投入输入Cd(g/ha/a) = F3*NF + F4*PF + F5*KF + F6*CF + F7*OF + F8*P + F9*FF + F10*AF
  157. """
  158. try:
  159. service = AgriculturalInputService()
  160. result = service.calculate_cd_flux_with_custom_data(request)
  161. if not result["success"]:
  162. raise HTTPException(
  163. status_code=400,
  164. detail=result["message"]
  165. )
  166. return result
  167. except HTTPException:
  168. raise
  169. except Exception as e:
  170. logger.error(f"使用自定义数据计算Cd通量失败: {str(e)}")
  171. raise HTTPException(
  172. status_code=500,
  173. detail=f"计算失败: {str(e)}"
  174. )
  175. @router.get("/calculation-formula",
  176. summary="获取计算公式说明",
  177. description="获取农业投入Cd通量的计算公式和参数说明")
  178. async def get_calculation_formula() -> Dict[str, Any]:
  179. """
  180. 获取农业投入Cd通量的计算公式和参数说明
  181. @returns: 公式和参数详细说明
  182. """
  183. try:
  184. formula_info = {
  185. "success": True,
  186. "message": "农业投入Cd通量计算公式",
  187. "data": {
  188. "formula": "农业投入输入Cd(g/ha/a) = F3*NF + F4*PF + F5*KF + F6*CF + F7*OF + F8*P + F9*FF + F10*AF",
  189. "unit": "g/ha/a",
  190. "parameters": {
  191. "F3": "氮肥镉含量平均值(mg/kg)",
  192. "F4": "磷肥镉含量平均值(mg/kg)",
  193. "F5": "钾肥镉含量平均值(mg/kg)",
  194. "F6": "复合肥镉含量平均值(mg/kg)",
  195. "F7": "有机肥镉含量平均值(mg/kg)",
  196. "F8": "农药镉含量(mg/kg)",
  197. "F9": "农家肥镉含量(mg/kg)",
  198. "F10": "农膜镉含量(mg/kg)",
  199. "NF": "氮肥单位面积使用量(t/ha/a)",
  200. "PF": "磷肥单位面积使用量(t/ha/a)",
  201. "KF": "钾肥单位面积使用量(t/ha/a)",
  202. "CF": "复合肥单位面积使用量(t/ha/a)",
  203. "OF": "有机肥单位面积使用量(t/ha/a)",
  204. "P": "农药单位面积使用量(t/ha/a)",
  205. "FF": "农家肥单位面积使用量(t/ha/a)",
  206. "AF": "农膜(存留)单位面积使用量(t/ha/a)"
  207. },
  208. "components": {
  209. "nitrogen_fertilizer": "氮肥贡献量 = F3 × NF",
  210. "phosphorus_fertilizer": "磷肥贡献量 = F4 × PF",
  211. "potassium_fertilizer": "钾肥贡献量 = F5 × KF",
  212. "compound_fertilizer": "复合肥贡献量 = F6 × CF",
  213. "organic_fertilizer": "有机肥贡献量 = F7 × OF",
  214. "pesticide": "农药贡献量 = F8 × P",
  215. "farmyard_manure": "农家肥贡献量 = F9 × FF",
  216. "agricultural_film": "农膜贡献量 = F10 × AF"
  217. }
  218. }
  219. }
  220. return formula_info
  221. except Exception as e:
  222. logger.error(f"获取计算公式失败: {str(e)}")
  223. raise HTTPException(
  224. status_code=500,
  225. detail=f"获取失败: {str(e)}"
  226. )