api_tempdiag.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. # main.py
  2. import os, glob
  3. import pandas as pd
  4. from fastapi import FastAPI, HTTPException
  5. from fastapi.responses import JSONResponse
  6. from pydantic import BaseModel, model_validator
  7. from typing import List
  8. from Temp_Diag import MSET_Temp
  9. app = FastAPI(title="Temperature Diagnosis API")
  10. # 全局:{ windCode: { turbine: { channel: model, … }, … }, … }
  11. MODEL_STORE: dict[str, dict[str, dict[str, MSET_Temp]]] = {}
  12. # 英文→中文映射
  13. cn_map = {
  14. 'main_bearing_temperature': '主轴承温度',
  15. 'gearbox_oil_temperature': '齿轮箱油温',
  16. 'generatordrive_end_bearing_temperature': '发电机驱动端轴承温度',
  17. 'generatornon_drive_end_bearing_temperature': '发电机非驱动端轴承温度'
  18. }
  19. class TemperatureInput(BaseModel):
  20. windCode: str
  21. windTurbineNumberList: List[str]
  22. startTime: str
  23. endTime: str
  24. @model_validator(mode='before')
  25. def ensure_list(cls, v):
  26. raw = v.get('windTurbineNumberList')
  27. if isinstance(raw, str):
  28. v['windTurbineNumberList'] = [raw]
  29. return v
  30. class TemperatureThresholdInput(TemperatureInput):
  31. pageNo: int
  32. pageSize: int
  33. @app.on_event("startup")
  34. def load_all_models():
  35. for f in glob.glob("models/*/*/*.pkl"):
  36. _, wc, turbine, fname = f.split(os.sep)
  37. ch = os.path.splitext(fname)[0]
  38. MODEL_STORE.setdefault(wc, {}).setdefault(turbine, {})[ch] = MSET_Temp.load_model(f)
  39. print("模型加载完成:", {k: list(v.keys()) for k,v in MODEL_STORE.items()})
  40. @app.post("/temperature/threshold")
  41. async def route_threshold(inp: TemperatureThresholdInput):
  42. """
  43. 输入:
  44. {
  45. "windCode": "WOF091200030",
  46. "windTurbineNumberList": ["WOG01355"],
  47. "startTime": "2024-06-01 00:00",
  48. "endTime": "2024-06-05 01:00",
  49. "pageNo": 1,
  50. "pageSize": 10
  51. }
  52. 输出:
  53. {
  54. "data": {
  55. "type": "temperature_threshold",
  56. "records": [
  57. {
  58. "wind_turbine_number": "WOG01355",
  59. "time_stamp": "2025-06-01 00:05:00",
  60. "temp_channel": "主轴承温度",
  61. "SPRT_score": 0.12,
  62. "status": "正常"
  63. },
  64. ...
  65. ],
  66. "totalSize": 42
  67. },
  68. "code": 200,
  69. "message": "success"
  70. }
  71. """
  72. # 1) 校验模型是否存在
  73. if inp.windCode not in MODEL_STORE:
  74. raise HTTPException(404, f"无模型:{inp.windCode}")
  75. # 2) 为每台待分析风机,拉数据并推理
  76. records = []
  77. for turbine in inp.windTurbineNumberList:
  78. if turbine not in MODEL_STORE[inp.windCode]:
  79. continue
  80. analyzer = MSET_Temp(inp.windCode, [turbine], inp.startTime, inp.endTime)
  81. df = analyzer._get_data_by_filter()
  82. if df.empty:
  83. continue
  84. df['time_stamp'] = pd.to_datetime(df['time_stamp'])
  85. for eng, cn in cn_map.items():
  86. if eng not in df.columns:
  87. continue
  88. sub = df[['time_stamp', eng]].dropna()
  89. arr = sub[eng].values.reshape(-1,1)
  90. ts = sub['time_stamp'].dt.strftime("%Y-%m-%d %H:%M:%S").tolist()
  91. model = MODEL_STORE[inp.windCode][turbine].get(eng)
  92. if not model:
  93. continue
  94. flags = model.predict_SPRT(arr, decisionGroup=1)
  95. for i, sc in enumerate(flags):
  96. records.append({
  97. "wind_turbine_number": turbine,
  98. "time_stamp": ts[i],
  99. "temp_channel": cn,
  100. "SPRT_score": sc,
  101. "status": "危险" if sc>0.99 else "正常"
  102. })
  103. # 分页返回
  104. total = len(records)
  105. start = (inp.pageNo-1)*inp.pageSize
  106. end = start+inp.pageSize
  107. return {
  108. "data": {
  109. "type": "temperature_threshold",
  110. "records": records[start:end],
  111. "totalSize": total
  112. },
  113. "code": 200,
  114. "message": "success"
  115. }
  116. @app.post("/SPRT/trend")
  117. async def route_trend(inp: TemperatureInput):
  118. """
  119. 输入:
  120. {
  121. "windCode": "WOF091200030",
  122. "windTurbineNumberList": ["WOG01355"],
  123. "startTime": "2024-06-01 00:00",
  124. "endTime": "2024-06-05 01:00"
  125. }
  126. 输出:
  127. {
  128. "data": {
  129. "type": "SPRT_trend",
  130. "main_bearing": {"timestamps": [...], "values": [...]},
  131. "gearbox_oil": {"timestamps": [...], "values": [...]},
  132. "generator_drive_end": {"timestamps": [...], "values": [...]},
  133. "generator_nondrive_end": {"timestamps": [...], "values": [...]}
  134. },
  135. "code": 200,
  136. "message": "success"
  137. }
  138. """
  139. if inp.windCode not in MODEL_STORE:
  140. raise HTTPException(404, f"无模型:{inp.windCode}")
  141. turbines_out = []
  142. for turbine in inp.windTurbineNumberList:
  143. if turbine not in MODEL_STORE[inp.windCode]:
  144. continue
  145. analyzer = MSET_Temp(inp.windCode, [turbine], inp.startTime, inp.endTime)
  146. df = analyzer._get_data_by_filter()
  147. if df.empty:
  148. continue
  149. df['time_stamp'] = pd.to_datetime(df['time_stamp'])
  150. ch_data = {}
  151. for eng, key in {
  152. 'main_bearing_temperature':'main_bearing',
  153. 'gearbox_oil_temperature':'gearbox_oil',
  154. 'generatordrive_end_bearing_temperature':'generator_drive_end',
  155. 'generatornon_drive_end_bearing_temperature':'generator_nondrive_end'
  156. }.items():
  157. if eng not in df.columns:
  158. ch_data[key] = {"timestamps": [], "values": []}
  159. continue
  160. sub = df[['time_stamp', eng]].dropna()
  161. ts = sub['time_stamp'].dt.strftime("%Y-%m-%d %H:%M:%S").tolist()
  162. arr = sub[eng].values.reshape(-1,1)
  163. model = MODEL_STORE[inp.windCode][turbine].get(eng)
  164. vals = model.predict_SPRT(arr, decisionGroup=1) if model else []
  165. ch_data[key] = {"timestamps": ts, "values": vals}
  166. # turbines_out.append({
  167. # "wind_turbine_number": turbine,
  168. # **ch_data
  169. # })
  170. return {
  171. "data": {
  172. "type": "SPRT_trend",
  173. **ch_data
  174. },
  175. "code": 200,
  176. "message": "success"
  177. }
  178. if __name__ == "__main__":
  179. import uvicorn
  180. uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)