Files
next-tjwater-server/app/api/v1/endpoints/timeseries/composite.py
T
jiang be6317eb48 feat(server): integrate MCP queries and investigation messaging
Add project-bound OAuth MCP queries and controlled analysis with scoped evidence,
limits, timeouts and a nearby-model spatial query using EPSG:4326 inputs.
Default nearby searches to 200 meters and five results.

Integrate investigation messaging/presentation, health/readiness and typed history;
remove duplicate web search and fix online simulation and compressed baseline writes.
Include project migrations 023-025; keep local credentials and demo seeding excluded.

Validation: 319 focused pytest checks; real PostGIS temporary-table regression;
read-only Jinqian bridge radius comparison; cross-language MCP discovery/calls.
2026-10-19 18:46:58 +08:00

110 lines
3.9 KiB
Python

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()
history_router = APIRouter()
@history_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)}")