fix: address verify findings - add visualize subcommand, curl healthcheck, IoU in JSON, 50KB threshold

This commit is contained in:
张宗平
2026-06-11 18:31:14 +08:00
parent 7e6915ade6
commit ad2a8ef687
5 changed files with 67 additions and 6 deletions
+37
View File
@@ -79,6 +79,33 @@ def cmd_e2e(args):
return run_e2e(args)
def cmd_visualize(args):
"""visualize 子命令:渲染双栏对比图。"""
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
from ts_anomaly_td.io_csv import read_csv
from ts_anomaly_td.visualize import render_contrast
ts, vals, labels = read_csv(args.gt_csv)
conn = TDConnection(args.url)
try:
db = args.db or "ts_anomaly"
conn.execute_no_result(f"USE {db}")
if args.algos:
from ts_anomaly_td.detection import detect_all_algos
results = detect_all_algos(conn, args.stable, algos=args.algos.split(","))
else:
from ts_anomaly_td.detection import detect_all_algos
results = detect_all_algos(conn, args.stable)
render_contrast(ts, vals, labels, results, args.output, title=args.stable)
logger.info("visualize: %s", args.output)
finally:
conn.close()
def cmd_watch(args):
"""watch 子命令:TMQ 准实时监控。"""
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
@@ -132,6 +159,15 @@ def build_parser() -> argparse.ArgumentParser:
p_e2e.add_argument("--log-dir", default="logs", help="JSON 日志目录 (default: logs)")
p_e2e.add_argument("--url", default="ws://root:taosdata@localhost:6041", help="TDengine WebSocket URL")
# visualize
p_viz = sub.add_parser("visualize", help="渲染 GT 对比可视化图")
p_viz.add_argument("--gt-csv", required=True, help="GT CSV 文件路径")
p_viz.add_argument("--stable", required=True, help="supertable 名称")
p_viz.add_argument("--db", default="ts_anomaly", help="数据库名")
p_viz.add_argument("--algos", default=None, help="逗号分隔算法列表 (默认全 6 个)")
p_viz.add_argument("--output", required=True, help="PNG 输出路径")
p_viz.add_argument("--url", default="ws://root:taosdata@localhost:6041", help="TDengine WebSocket URL")
# watch (Iter-2)
p_watch = sub.add_parser("watch", help="TMQ 准实时异常监控")
p_watch.add_argument("--stable", required=True, help="supertable 名称")
@@ -151,6 +187,7 @@ def main():
"detect-batch": cmd_detect_batch,
"forecast-anomaly": cmd_forecast_anomaly,
"e2e": cmd_e2e,
"visualize": cmd_visualize,
"watch": cmd_watch,
}
+25 -1
View File
@@ -11,7 +11,7 @@ from ts_anomaly_td.schema import setup_schema
from ts_anomaly_td.io_csv import read_csv
from ts_anomaly_td.detection import detect_all_algos, ALL_ALGOS
from ts_anomaly_td.forecast import forecast_anomaly
from ts_anomaly_td.visualize import render_contrast
from ts_anomaly_td.visualize import render_contrast, _compute_iou
logger = logging.getLogger(__name__)
@@ -94,7 +94,31 @@ def run_e2e(args):
"anomaly_count": fc_anom_count,
},
"png": str(png_path),
"iou": None,
}
# 计算 GT windows(从 labels 提取)
gt_windows_for_iou = []
in_anom = False
anom_start = None
for i, l in enumerate(labels):
if l == 1 and not in_anom:
in_anom = True
anom_start = ts[i]
elif l == 0 and in_anom:
in_anom = False
gt_windows_for_iou.append((anom_start, ts[i]))
if in_anom:
gt_windows_for_iou.append((anom_start, ts[-1]))
# 收集检测 windows
all_det_windows = []
for r in det_results.values():
if not r.get("error"):
all_det_windows.extend(r.get("windows", []))
iou = _compute_iou(gt_windows_for_iou, all_det_windows)
ds_summary["iou"] = round(iou, 3)
for algo, r in det_results.items():
ds_summary["algorithms"][algo] = {
"window_count": len(r["windows"]),
+1 -1
View File
@@ -24,7 +24,7 @@ def create_supertable(conn, stable: str) -> None:
"""
sql = (
f"CREATE STABLE IF NOT EXISTS ds_{stable} "
f"(ts TIMESTAMP, `value` DOUBLE, is_anomaly INT) "
f"(ts TIMESTAMP, `value` DOUBLE, `label` INT) "
f"TAGS (series_id INT)"
)
conn.execute_no_result(sql)