from fastapi import APIRouter, Depends, HTTPException, Query from datetime import datetime from psycopg import AsyncConnection from app.services.timeseries_analysis import TimeseriesAnalysisService from app.domain.schemas.timeseries_history import ( ElementHistoryQuery, ElementHistoryResponse, ) from app.services.timeseries_history import TimeseriesHistoryService from .dependencies import get_timescale_connection, get_postgres_connection router = APIRouter() @router.post( "/timeseries/views/element-history/query", summary="批量查询管网元素历史数据", response_model=ElementHistoryResponse, ) async def query_element_history( payload: ElementHistoryQuery, timescale_conn: AsyncConnection = Depends(get_timescale_connection), postgres_conn: AsyncConnection = Depends(get_postgres_connection), ) -> ElementHistoryResponse: try: return await TimeseriesHistoryService.query( timescale_conn, postgres_conn, payload ) except ValueError as exc: raise HTTPException(status_code=422, detail=str(exc)) from exc @router.post("/timeseries/scada-cleaning-runs", summary="清洗SCADA监测数据") async def clean_scada_data( device_ids: str = Query(..., description="设备ID列表或 'all' 表示清洗所有设备"), start_time: datetime = Query(..., description="清洗数据的开始时间"), end_time: datetime = Query(..., description="清洗数据的结束时间"), timescale_conn: AsyncConnection = Depends(get_timescale_connection), postgres_conn: AsyncConnection = Depends(get_postgres_connection), ): """ 清洗SCADA监测数据 根据device_ids查询monitored_value,清洗后更新cleaned_value。 支持清洗指定设备或所有设备的数据。 Args: device_ids: 设备ID列表,用逗号分隔,或 'all' 表示清洗所有设备 start_time: 清洗数据的开始时间 end_time: 清洗数据的结束时间 timescale_conn: TimescaleDB连接 postgres_conn: PostgreSQL连接 Returns: 清洗结果信息 Raises: HTTPException: 当清洗过程出现错误时返回400错误 """ try: if device_ids == "all": device_ids_list = [] else: device_ids_list = ( [id.strip() for id in device_ids.split(",") if id.strip()] if device_ids else [] ) return await TimeseriesAnalysisService.clean_scada_data( timescale_conn, postgres_conn, device_ids_list, start_time, end_time ) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) @router.get("/pipeline-health-predictions", summary="预测管道健康状况") async def predict_pipeline_health( query_time: datetime = Query(..., description="查询时间"), timescale_conn: AsyncConnection = Depends(get_timescale_connection), postgres_conn: AsyncConnection = Depends(get_postgres_connection), ): """ 预测管道健康状况 根据管网名称和当前时间,查询管道信息和实时数据, 使用随机生存森林模型预测管道的生存概率。 Args: query_time: 查询时间 timescale_conn: TimescaleDB连接 Returns: 预测结果列表,每个元素包含 link_id 和对应的生存函数 Raises: HTTPException: 当模型文件不存在返回404错误,其他错误返回400或500错误 """ try: return await TimeseriesAnalysisService.predict_pipeline_health( timescale_conn, postgres_conn, query_time ) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except FileNotFoundError as e: raise HTTPException(status_code=404, detail=str(e)) except Exception as e: raise HTTPException(status_code=500, detail=f"内部服务器错误: {str(e)}")