feat(investigations): refine report authoring and replay flushing
This commit is contained in:
@@ -1067,6 +1067,8 @@ class OperationalTaskService:
|
||||
run_id=row["metadata"]["run_id"],
|
||||
execution_generation=row["metadata"]["execution_generation"],
|
||||
command=row["metadata"]["command"],
|
||||
narration=row["metadata"].get("narration"),
|
||||
purpose=row["metadata"].get("purpose"),
|
||||
) for row in rows[:limit]]
|
||||
return TaskPresentationHistoryPage(
|
||||
task_id=task_id, event_cursor=boundary, items=items,
|
||||
@@ -1097,6 +1099,9 @@ class OperationalTaskService:
|
||||
now = self._now()
|
||||
self._require_active_run_lease(run, now)
|
||||
payload = _json(command.command)
|
||||
if command.narration is not None:
|
||||
known = {item["evidence_id"] for item in await self.repo.list_evidence(str(task_id))}
|
||||
self._require_evidence_refs(command.narration.evidence_refs, known)
|
||||
await self._record_scada_presentation(task, run, payload, now)
|
||||
if command.command.action == "open_chart":
|
||||
validate_time_comparison_chart(payload["chart"], allow_missing_current=bool(
|
||||
@@ -1122,6 +1127,10 @@ class OperationalTaskService:
|
||||
payload["data"] = resolved
|
||||
metadata = {"task_id": str(task_id), "run_id": str(run["run_id"]),
|
||||
"execution_generation": run["generation"], "command": payload}
|
||||
if command.narration is not None:
|
||||
metadata["narration"] = _json(command.narration)
|
||||
if command.purpose is not None:
|
||||
metadata["purpose"] = command.purpose
|
||||
try:
|
||||
size = len(json.dumps(metadata, ensure_ascii=False, allow_nan=False).encode("utf-8"))
|
||||
except (ValueError, TypeError) as exc:
|
||||
|
||||
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
from datetime import datetime, timedelta, timezone
|
||||
import json
|
||||
from uuid import NAMESPACE_URL, uuid4, uuid5
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from fastapi import HTTPException
|
||||
from app.core.config import settings
|
||||
@@ -531,35 +532,24 @@ class ScadaReplayService:
|
||||
external = incident["external_id"]
|
||||
pressure = monitoring["pressure"]
|
||||
flow = monitoring["outlet_flow"]
|
||||
detector = monitoring["burst_detection"]
|
||||
score = detector.get("target_score")
|
||||
score_text = f"{score:.4f}" if score is not None else "数据不足"
|
||||
summary = (
|
||||
f"SCADA 数据诊断发现指标异常,进入异常调查与爆管诊断。"
|
||||
f"爆管侦测得分 {score_text};"
|
||||
f"压力下降测点 {len(pressure.get('hit_device_ids', []))} 个;"
|
||||
f"出厂边界流量增加测点 {len(flow.get('hit_device_ids', []))} 个。"
|
||||
"任一指标异常即启动调查,加权分用于评估爆管嫌疑;达到门槛后继续候选定位、隔离与影响分析。"
|
||||
)
|
||||
findings = []
|
||||
if pressure.get("hit_device_ids"):
|
||||
findings.append(f"{len(pressure['hit_device_ids'])} 个压力测点下降")
|
||||
if flow.get("hit_device_ids"):
|
||||
findings.append(f"{len(flow['hit_device_ids'])} 个出厂边界流量测点增加")
|
||||
summary = f"SCADA 监测发现{'、'.join(findings) or '指标异常'},已启动调查。"
|
||||
if monitoring.get("anomaly_signals"):
|
||||
signals = monitoring["anomaly_signals"]
|
||||
devices = {device for item in signals for device in item.get("device_ids", [])}
|
||||
summary += f" 单项异常 {len(signals)} 项,涉及 {len(devices)} 个测点;明细通过冻结 SCADA 查询核验。"
|
||||
if monitoring.get("weighted"):
|
||||
weighted = monitoring["weighted"]
|
||||
weights = weighted["weights"]
|
||||
summary += (
|
||||
f" 综合评分 {weighted['score']:.2f},爆管嫌疑门槛 {weighted['threshold']:.2f}"
|
||||
f"(侦测 {weights['burst_detection']:.0%}、压力 {weights['pressure']:.0%}、"
|
||||
f"流量 {weights['outlet_flow']:.0%})。"
|
||||
)
|
||||
if detector.get("score_threshold") is not None:
|
||||
summary += f" 侦测动态阈值 {detector['score_threshold']:.4f}。"
|
||||
summary += f"本次异常涉及 {len(devices)} 个测点。"
|
||||
summary += ("现有监测结果提示爆管嫌疑,需结合管网与现场核验。"
|
||||
if monitoring["status"] == "suspected_burst" else "异常原因及影响范围待核查。")
|
||||
event_time = parse_time(monitoring["period_end"]).astimezone(ZoneInfo("Asia/Shanghai"))
|
||||
command = OperationalTaskCreate(
|
||||
request_id=uuid5(NAMESPACE_URL, external),
|
||||
task_type="event_investigation",
|
||||
workflow="scada_anomaly",
|
||||
title=f"SCADA 异常调查 · {monitoring['period_end']}",
|
||||
title=f"SCADA 异常调查 · {event_time:%Y-%m-%d %H:%M}",
|
||||
summary=summary,
|
||||
source=TaskSource(
|
||||
kind="external_system",
|
||||
|
||||
@@ -316,6 +316,7 @@ def flushing_analysis(
|
||||
valve_control: dict[str, dict] = None,
|
||||
_temporary_project: str | None = None,
|
||||
persist_results: bool = True,
|
||||
scada_mappings: ScadaElementMappings | None = None,
|
||||
) -> dict | str | None:
|
||||
"""
|
||||
管道冲洗模拟
|
||||
@@ -445,6 +446,7 @@ def flushing_analysis(
|
||||
modify_total_duration=modify_total_duration,
|
||||
modify_valve_opening=modify_valve_opening,
|
||||
valve_control=valve_control,
|
||||
scada_mappings=scada_mappings,
|
||||
scheme_type="flushing_analysis",
|
||||
scheme_name=scheme_name,
|
||||
result_db_name=name,
|
||||
|
||||
Reference in New Issue
Block a user