WechatOnCloud/bridge/woc_bridge/ui/locators/base.py

111 lines
3.6 KiB
Python
Raw Normal View History

"""L2 Locator 抽象层基类GeomSpec + RoiSpec + Selector + ElementHandle。
GeomSpec几何定位规格relative_to / ratio / offset
RoiSpec图像匹配感兴趣区域相对窗口的比例矩形缩小 OpenCV 搜索范围
SelectorUI 元素选择器kind / by_image / by_geom / roi / threshold / require_image
ElementHandle定位结果句柄绝对坐标 + 置信度 + 策略
L3 Actions 通过 Selector 描述要找的元素LocatorRegistry 解析为
ElementHandle图像命中或几何兜底Actions 据此调 Backend 执行点击
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Optional
@dataclass
class GeomSpec:
"""几何定位规格。
relative_to 取值window / window_top_left / window_bottom_right语义占位
实际计算统一用 ratio + offsetoffset 已含正负号区分方向
所有字段带默认值避免构造时必填字段顺序问题
"""
relative_to: str = "window"
x_ratio: float = 0.0
y_ratio: float = 0.0
x_offset: int = 0
y_offset: int = 0
@dataclass
class RoiSpec:
"""图像匹配感兴趣区域ROI相对窗口的比例矩形。
用于将 OpenCV 模板匹配限制在窗口的某个子区域避免误匹配到
窗口内其他视觉相似的 UI 元素例如 input_box 只在聊天区右下角查找
即使模板图像有缺陷也不会匹配到窗口中部
所有字段为相对窗口宽/高的比例0.0~1.0 Actions 按当前窗口几何
转换为绝对像素 ROI 传给 OpenCVBackend.find_template
字段
x_ratio: ROI 左上角相对窗口左上角的 X 比例
y_ratio: ROI 左上角相对窗口左上角的 Y 比例
w_ratio: ROI 宽度相对窗口宽度的比例
h_ratio: ROI 高度相对窗口高度的比例
边界由 Actions/opencv.py 做裁剪保护YAML 中可略微宽松
"""
x_ratio: float = 0.0
y_ratio: float = 0.0
w_ratio: float = 1.0
h_ratio: float = 1.0
@dataclass
class Selector:
"""UI 元素选择器。
kind元素类别键 search_box / send_button / input_box
by_image图像模板名P2 启用非空时优先图像匹配
by_geom几何规格非空时图像失败或 P1 阶段走几何兜底
roi图像匹配感兴趣区域可选非空时限制 OpenCV 搜索范围
为空时使用全窗口用于防止模板误匹配到窗口其他相似元素
threshold图像匹配置信度阈值默认 0.80
require_image高风险操作为 True 图像失败即拒绝执行
description人类可读描述
所有字段带默认值
"""
kind: str = ""
by_image: Optional[str] = None
by_geom: Optional[GeomSpec] = None
roi: Optional[RoiSpec] = None
threshold: float = 0.80
require_image: bool = False
description: str = ""
@dataclass
class ElementHandle:
"""定位结果句柄。
selector来源 Selector回溯用
x / y元素中心绝对坐标点击点
w / h元素宽高图像匹配时返回几何兜底为 0
confidence匹配置信度图像命中时为模型分数几何兜底为 1.0
strategy定位策略 image / geom
所有字段带默认值
"""
selector: Optional[Selector] = None
x: int = 0
y: int = 0
w: int = 0
h: int = 0
confidence: float = 1.0
strategy: str = "geom"
@property
def center(self) -> tuple[int, int]:
"""返回元素中心点x, y"""
return (self.x, self.y)