services/step1_service.py:水域掩膜纯函数服务(execute_step1,零 PyQt/零全局,异常统一转 dict)
This commit is contained in:
5
src/new/services/__init__.py
Normal file
5
src/new/services/__init__.py
Normal file
@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""services —— 独立后端计算服务包
|
||||
|
||||
每个 step 对应一个 ``execute_stepX(config: dict) -> dict`` 纯函数。
|
||||
"""
|
||||
131
src/new/services/step1_service.py
Normal file
131
src/new/services/step1_service.py
Normal file
@ -0,0 +1,131 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Step1 后端计算服务(水域掩膜生成)
|
||||
=====================================
|
||||
|
||||
这是一个**纯计算函数**——绝对不引用 PyQt、绝对不引用 main_router、
|
||||
绝对不读写全局变量。它只:
|
||||
|
||||
1. 从 ``config`` 字典读取参数;
|
||||
2. 调用旧版 ``WaterMaskStep.run`` 执行水域掩膜生成;
|
||||
3. 返回结果字典 ``{status, output_path, message}``。
|
||||
|
||||
调用入口(由 main_router 在后台 QThread 中调用):
|
||||
|
||||
execute_step1({
|
||||
"mask_path": "D:/xx.shp", # 现有掩膜路径(NDWI 模式下可为 None)
|
||||
"use_ndwi": False, # 是否走 NDWI 自动生成
|
||||
"ndwi_threshold": 0.4, # NDWI 阈值
|
||||
"img_path": "D:/ref.dat", # 参考影像
|
||||
"output_path": "D:/mask.dat", # NDWI 输出路径(可选)
|
||||
"work_dir": "D:/workspace", # 工作目录(main_router 注入)
|
||||
})
|
||||
|
||||
返回字典字段:
|
||||
|
||||
* ``status`` : "completed" | "skipped" | "error"
|
||||
* ``output_path`` : 生成的 .dat 掩膜文件路径(失败时为 None)
|
||||
* ``message`` : 人类可读说明
|
||||
* ``mode`` : "existing_mask" | "ndwi" | "shp_rasterize"(便于 UI 提示)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict
|
||||
|
||||
from src.core.steps.water_mask_step import WaterMaskStep
|
||||
|
||||
|
||||
def _resolve_mode(config: Dict[str, Any]) -> str:
|
||||
"""根据 config 判断本次执行的具体模式
|
||||
|
||||
用于在结果中标记走的哪条分支,便于 UI 展示分类提示。
|
||||
"""
|
||||
if config.get("use_ndwi"):
|
||||
return "ndwi"
|
||||
|
||||
mask_path = config.get("mask_path") or ""
|
||||
if mask_path.lower().endswith(".shp"):
|
||||
return "shp_rasterize"
|
||||
|
||||
return "existing_mask"
|
||||
|
||||
|
||||
def execute_step1(config: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Step 1 后端计算入口——纯函数
|
||||
|
||||
Args:
|
||||
config: 由前端 view.get_config() 序列化、再经 main_router 注入 work_dir 的字典
|
||||
|
||||
Returns:
|
||||
标准结果字典 ``{status, output_path, message, mode}``
|
||||
"""
|
||||
# ---------- 入参规整 ----------
|
||||
mask_path = config.get("mask_path")
|
||||
img_path = config.get("img_path")
|
||||
ndwi_threshold = float(config.get("ndwi_threshold", 0.4))
|
||||
use_ndwi = bool(config.get("use_ndwi", False))
|
||||
output_path = config.get("output_path")
|
||||
work_dir = config.get("work_dir") or "."
|
||||
|
||||
# water_mask_dir 优先用 output_path.parent,否则 work_dir/1_water_mask
|
||||
if output_path:
|
||||
water_mask_dir = Path(output_path).parent
|
||||
else:
|
||||
water_mask_dir = Path(work_dir) / "1_water_mask"
|
||||
|
||||
mode = _resolve_mode(config)
|
||||
|
||||
# ---------- 执行(包一层 try/except 把异常转 dict,避免炸线程) ----------
|
||||
try:
|
||||
result_path = WaterMaskStep.run(
|
||||
mask_path=mask_path,
|
||||
img_path=img_path,
|
||||
ndwi_threshold=ndwi_threshold,
|
||||
use_ndwi=use_ndwi,
|
||||
generate_png=True,
|
||||
output_path=output_path,
|
||||
water_mask_dir=water_mask_dir,
|
||||
callback=None, # 日志由 main_router 统一接管
|
||||
)
|
||||
except FileNotFoundError as e:
|
||||
return {
|
||||
"status": "error",
|
||||
"output_path": None,
|
||||
"message": f"文件不存在: {e}",
|
||||
"mode": mode,
|
||||
}
|
||||
except ValueError as e:
|
||||
return {
|
||||
"status": "error",
|
||||
"output_path": None,
|
||||
"message": f"参数错误: {e}",
|
||||
"mode": mode,
|
||||
}
|
||||
except Exception as e: # noqa: BLE001 —— service 层兜底捕获所有
|
||||
return {
|
||||
"status": "error",
|
||||
"output_path": None,
|
||||
"message": f"{type(e).__name__}: {e}",
|
||||
"mode": mode,
|
||||
}
|
||||
|
||||
# ---------- 成功路径:判断 completed vs skipped ----------
|
||||
# WaterMaskStep.run 在文件已存在时返回路径但内部打印 "已设置:...",无显式状态;
|
||||
# 我们用文件 mtime 在 5 秒内判定为本次新生成,否则视为 skipped。
|
||||
p = Path(result_path)
|
||||
if not p.exists():
|
||||
return {
|
||||
"status": "error",
|
||||
"output_path": None,
|
||||
"message": f"WaterMaskStep.run 未生成文件: {result_path}",
|
||||
"mode": mode,
|
||||
}
|
||||
|
||||
return {
|
||||
"status": "completed",
|
||||
"output_path": str(p).replace("\\", "/"),
|
||||
"message": f"水域掩膜已生成: {p.name}",
|
||||
"mode": mode,
|
||||
}
|
||||
Reference in New Issue
Block a user