mirror of
https://github.com/HKUDS/AutoAgent.git
synced 2025-10-09 13:41:35 +03:00
208 lines
7.6 KiB
Python
208 lines
7.6 KiB
Python
from browsergym.utils.obs import _process_bid, IGNORED_AXTREE_ROLES, IGNORED_AXTREE_PROPERTIES
|
|
|
|
def flatten_md_axtree_to_str(
|
|
AX_tree,
|
|
extra_properties: dict = None,
|
|
with_visible: bool = False,
|
|
with_clickable: bool = False,
|
|
with_center_coords: bool = False,
|
|
with_bounding_box_coords: bool = False,
|
|
with_som: bool = False,
|
|
skip_generic: bool = True,
|
|
filter_visible_only: bool = False,
|
|
filter_with_bid_only: bool = False,
|
|
filter_som_only: bool = False,
|
|
coord_decimals: int = 0,
|
|
ignored_roles=IGNORED_AXTREE_ROLES,
|
|
ignored_properties=IGNORED_AXTREE_PROPERTIES,
|
|
remove_redundant_static_text: bool = True,
|
|
hide_bid_if_invisible: bool = False,
|
|
hide_all_children: bool = False,
|
|
hide_all_bids: bool = False,
|
|
) -> str:
|
|
"""Formats the accessibility tree into a string text"""
|
|
node_id_to_idx = {}
|
|
for idx, node in enumerate(AX_tree["nodes"]):
|
|
node_id_to_idx[node["nodeId"]] = idx
|
|
# print("******************************* AX_tree:", AX_tree)
|
|
|
|
def dfs(node_idx: int, depth: int, parent_node_filtered: bool, parent_node_name: str) -> str:
|
|
tree_str = ""
|
|
node = AX_tree["nodes"][node_idx]
|
|
# indent = "\t" * depth
|
|
indent = ""
|
|
skip_node = False # node will not be printed, with no effect on children nodes
|
|
filter_node = False # node will not be printed, possibly along with its children nodes
|
|
node_role = node["role"]["value"]
|
|
node_name = ""
|
|
|
|
if node_role in ignored_roles:
|
|
skip_node = True
|
|
pass
|
|
elif "name" not in node:
|
|
skip_node = True
|
|
pass
|
|
else:
|
|
node_name = node["name"]["value"]
|
|
if "value" in node and "value" in node["value"]:
|
|
node_value = node["value"]["value"]
|
|
else:
|
|
node_value = None
|
|
|
|
# extract bid
|
|
bid = node.get("browsergym_id", None)
|
|
|
|
# extract node attributes
|
|
attributes = []
|
|
for property in node.get("properties", []):
|
|
if not "value" in property:
|
|
continue
|
|
if not "value" in property["value"]:
|
|
continue
|
|
|
|
prop_name = property["name"]
|
|
prop_value = property["value"]["value"]
|
|
|
|
if prop_name in ignored_properties:
|
|
continue
|
|
elif prop_name in ("required", "focused", "atomic"):
|
|
if prop_value:
|
|
attributes.append(prop_name)
|
|
else:
|
|
attributes.append(f"{prop_name}={repr(prop_value)}")
|
|
|
|
if skip_generic and node_role == "generic" and not attributes:
|
|
skip_node = True
|
|
|
|
if hide_all_children and parent_node_filtered:
|
|
skip_node = True
|
|
|
|
if node_role == "StaticText":
|
|
if parent_node_filtered:
|
|
skip_node = True
|
|
elif remove_redundant_static_text and node_name in parent_node_name:
|
|
skip_node = True
|
|
else:
|
|
filter_node, extra_attributes_to_print = _process_bid(
|
|
bid,
|
|
extra_properties=extra_properties,
|
|
with_visible=with_visible,
|
|
with_clickable=with_clickable,
|
|
with_center_coords=with_center_coords,
|
|
with_bounding_box_coords=with_bounding_box_coords,
|
|
with_som=with_som,
|
|
filter_visible_only=filter_visible_only,
|
|
filter_with_bid_only=filter_with_bid_only,
|
|
filter_som_only=filter_som_only,
|
|
coord_decimals=coord_decimals,
|
|
)
|
|
|
|
# if either is True, skip the node
|
|
skip_node = skip_node or filter_node
|
|
|
|
# insert extra attributes before regular attributes
|
|
attributes = extra_attributes_to_print + attributes
|
|
|
|
# actually print the node string
|
|
if not skip_node:
|
|
if node_role == "generic" and not node_name:
|
|
node_str = f"{node_role}"
|
|
else:
|
|
node_str = f"{node_name.strip()}"
|
|
|
|
if not (
|
|
hide_all_bids
|
|
or bid is None
|
|
or (
|
|
hide_bid_if_invisible
|
|
and extra_properties.get(bid, {}).get("visibility", 0) < 0.5
|
|
)
|
|
):
|
|
node_str = node_str
|
|
|
|
if node_value is not None:
|
|
node_str += f' value={repr(node["value"]["value"])}'
|
|
|
|
if attributes:
|
|
node_str += ", ".join([""] + attributes)
|
|
|
|
tree_str += f"{indent}{node_str}"
|
|
|
|
for child_node_id in node["childIds"]:
|
|
if child_node_id not in node_id_to_idx or child_node_id == node["nodeId"]:
|
|
continue
|
|
# mark this to save some tokens
|
|
child_depth = depth if skip_node else (depth + 1)
|
|
child_str = dfs(
|
|
node_id_to_idx[child_node_id],
|
|
child_depth,
|
|
parent_node_filtered=filter_node,
|
|
parent_node_name=node_name,
|
|
)
|
|
if child_str:
|
|
if tree_str:
|
|
tree_str += "\n"
|
|
tree_str += child_str
|
|
|
|
return tree_str
|
|
|
|
tree_str = dfs(0, 1, False, "")
|
|
return tree_str
|
|
|
|
# def flatten_md_axtree_to_str(
|
|
# AX_tree,
|
|
# extra_properties: dict = None,
|
|
# with_visible: bool = False,
|
|
# with_clickable: bool = False,
|
|
# with_center_coords: bool = False,
|
|
# with_bounding_box_coords: bool = False,
|
|
# with_som: bool = False,
|
|
# skip_generic: bool = True,
|
|
# filter_visible_only: bool = False,
|
|
# filter_with_bid_only: bool = False,
|
|
# filter_som_only: bool = False,
|
|
# coord_decimals: int = 0,
|
|
# ignored_roles=IGNORED_AXTREE_ROLES,
|
|
# ignored_properties=IGNORED_AXTREE_PROPERTIES,
|
|
# remove_redundant_static_text: bool = True,
|
|
# hide_bid_if_invisible: bool = False,
|
|
# hide_all_children: bool = False,
|
|
# hide_all_bids: bool = False,
|
|
# ) -> str:
|
|
# """Formats the accessibility tree into a markdown string"""
|
|
# if not AX_tree or "nodes" not in AX_tree or not AX_tree["nodes"]:
|
|
# return "No content available"
|
|
|
|
# node_id_to_idx = {}
|
|
# for idx, node in enumerate(AX_tree["nodes"]):
|
|
# node_id_to_idx[node["nodeId"]] = idx
|
|
|
|
# def dfs(node_idx: int, depth: int, parent_node_filtered: bool, parent_node_name: str) -> str:
|
|
# tree_str = ""
|
|
# node = AX_tree["nodes"][node_idx]
|
|
|
|
# # 处理节点内容
|
|
# if "name" in node and "value" in node["name"]:
|
|
# content = node["name"]["value"].strip()
|
|
# if content:
|
|
# # 移除多余的空白字符
|
|
# content = ' '.join(content.split())
|
|
# # 添加到输出
|
|
# tree_str += content + "\n"
|
|
|
|
# # 递归处理子节点
|
|
# for child_node_id in node.get("childIds", []):
|
|
# if child_node_id in node_id_to_idx and child_node_id != node["nodeId"]:
|
|
# child_str = dfs(
|
|
# node_id_to_idx[child_node_id],
|
|
# depth + 1,
|
|
# parent_node_filtered=False,
|
|
# parent_node_name=node.get("name", {}).get("value", "")
|
|
# )
|
|
# if child_str:
|
|
# tree_str += child_str
|
|
|
|
# return tree_str
|
|
|
|
# tree_str = dfs(0, 0, False, "")
|
|
# return tree_str.strip() |