Skip to content

Commit dd0cf34

Browse files
committed
refactor: Centralize UI selectors for CDK overlay, thinking mode, and budget toggles.
1 parent 1d057ef commit dd0cf34

8 files changed

Lines changed: 55 additions & 14 deletions

File tree

browser_utils/initialization/core.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from config import (
2424
AI_STUDIO_URL_PATTERN,
2525
INPUT_SELECTOR,
26+
MODEL_NAME_SELECTOR,
2627
USER_INPUT_END_MARKER_SERVER,
2728
USER_INPUT_START_MARKER_SERVER,
2829
)
@@ -322,7 +323,7 @@ async def initialize_page_logic( # pragma: no cover
322323
)
323324
logger.info("-> 核心输入区域可见。")
324325

325-
model_name_locator = found_page.locator('[data-test-id="model-name"]')
326+
model_name_locator = found_page.locator(MODEL_NAME_SELECTOR)
326327
try:
327328
model_name_on_page = await model_name_locator.first.inner_text(
328329
timeout=5000

browser_utils/models/startup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from playwright.async_api import Page as AsyncPage
1010
from playwright.async_api import expect as expect_async
1111

12-
from config import INPUT_SELECTOR
12+
from config import INPUT_SELECTOR, MODEL_NAME_SELECTOR
1313

1414
from .ui_state import _verify_and_apply_ui_state, _verify_ui_state_settings
1515

@@ -166,7 +166,7 @@ async def _set_model_from_page_display(page: AsyncPage, set_storage: bool = Fals
166166

167167
try:
168168
logger.info(" 尝试从页面显示元素读取当前模型名称...")
169-
model_name_locator = page.locator('[data-test-id="model-name"]')
169+
model_name_locator = page.locator(MODEL_NAME_SELECTOR)
170170
displayed_model_name_from_page_raw = await model_name_locator.first.inner_text(
171171
timeout=7000
172172
)

browser_utils/models/switcher.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from playwright.async_api import Page as AsyncPage
1212
from playwright.async_api import expect as expect_async
1313

14-
from config import AI_STUDIO_URL_PATTERN, INPUT_SELECTOR
14+
from config import AI_STUDIO_URL_PATTERN, INPUT_SELECTOR, MODEL_NAME_SELECTOR
1515

1616
from .ui_state import _verify_and_apply_ui_state
1717

@@ -129,7 +129,7 @@ async def switch_ai_studio_model(page: AsyncPage, model_id: str, req_id: str) ->
129129
break
130130

131131
try:
132-
model_name_locator = page.locator('[data-test-id="model-name"]')
132+
model_name_locator = page.locator(MODEL_NAME_SELECTOR)
133133
actual_displayed_model_id_on_page_raw = (
134134
await model_name_locator.first.inner_text(timeout=5000)
135135
)
@@ -209,7 +209,7 @@ async def switch_ai_studio_model(page: AsyncPage, model_id: str, req_id: str) ->
209209
current_displayed_name_for_revert_stripped = "无法读取"
210210

211211
try:
212-
model_name_locator_revert = page.locator('[data-test-id="model-name"]')
212+
model_name_locator_revert = page.locator(MODEL_NAME_SELECTOR)
213213
current_displayed_name_for_revert_raw = (
214214
await model_name_locator_revert.first.inner_text(timeout=5000)
215215
)

browser_utils/operations_modules/interactions.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from browser_utils.operations_modules.errors import save_error_snapshot
1818
from config import (
19+
CHAT_TURN_SELECTOR,
1920
CLICK_TIMEOUT_MS,
2021
DEBUG_LOGS_ENABLED,
2122
INITIAL_WAIT_MS_BEFORE_POLLING,
@@ -79,7 +80,7 @@ async def get_response_via_edit_button(
7980
) -> Optional[str]:
8081
"""通过编辑按钮获取响应"""
8182
logger.info(" (Helper) 尝试通过编辑按钮获取响应...")
82-
last_message_container = page.locator("ms-chat-turn").last
83+
last_message_container = page.locator(CHAT_TURN_SELECTOR).last
8384
edit_button = last_message_container.get_by_label("Edit")
8485
finish_edit_button = last_message_container.get_by_label("Stop editing")
8586
autosize_textarea_locator = last_message_container.locator("ms-autosize-textarea")
@@ -239,7 +240,7 @@ async def get_response_via_copy_button(
239240
) -> Optional[str]:
240241
"""通过复制按钮获取响应"""
241242
logger.info(" (Helper) 尝试通过复制按钮获取响应...")
242-
last_message_container = page.locator("ms-chat-turn").last
243+
last_message_container = page.locator(CHAT_TURN_SELECTOR).last
243244
more_options_button = last_message_container.get_by_label("Open options")
244245
copy_markdown_button = page.get_by_role("menuitem", name="Copy markdown")
245246

browser_utils/page_controller_modules/input.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from browser_utils.operations import save_error_snapshot
1010
from config import (
11+
CDK_OVERLAY_CONTAINER_SELECTOR,
1112
PROMPT_TEXTAREA_SELECTOR,
1213
RESPONSE_CONTAINER_SELECTOR,
1314
SUBMIT_BUTTON_SELECTOR,
@@ -188,7 +189,7 @@ async def _open_upload_menu_and_choose_file(self, files_list: List[str]) -> bool
188189
trigger = self.page.locator(UPLOAD_BUTTON_SELECTOR).first
189190
await expect_async(trigger).to_be_visible(timeout=3000)
190191
await trigger.click()
191-
menu_container = self.page.locator("div.cdk-overlay-container")
192+
menu_container = self.page.locator(CDK_OVERLAY_CONTAINER_SELECTOR)
192193
# 等待菜单显示
193194
try:
194195
await expect_async(
@@ -261,7 +262,7 @@ async def _open_upload_menu_and_choose_file(self, files_list: List[str]) -> bool
261262
async def _handle_post_upload_dialog(self):
262263
"""处理上传后可能出现的授权/版权确认对话框,优先点击同意类按钮,不主动关闭重要对话框。"""
263264
try:
264-
overlay_container = self.page.locator("div.cdk-overlay-container")
265+
overlay_container = self.page.locator(CDK_OVERLAY_CONTAINER_SELECTOR)
265266
if await overlay_container.count() == 0:
266267
return
267268

browser_utils/page_controller_modules/thinking.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,13 @@
1515
ENABLE_THINKING_MODE_TOGGLE_SELECTOR,
1616
SET_THINKING_BUDGET_TOGGLE_SELECTOR,
1717
THINKING_BUDGET_INPUT_SELECTOR,
18+
THINKING_BUDGET_TOGGLE_OLD_ROOT_SELECTOR,
19+
THINKING_BUDGET_TOGGLE_PARENT_SELECTOR,
1820
THINKING_LEVEL_OPTION_HIGH_SELECTOR,
1921
THINKING_LEVEL_OPTION_LOW_SELECTOR,
2022
THINKING_LEVEL_SELECT_SELECTOR,
23+
THINKING_MODE_TOGGLE_OLD_ROOT_SELECTOR,
24+
THINKING_MODE_TOGGLE_PARENT_SELECTOR,
2125
)
2226
from models import ClientDisconnectedError
2327

@@ -469,14 +473,14 @@ async def _control_thinking_mode_toggle(
469473
try:
470474
# 新版UI: 尝试直接点击带 aria-label 的开关父容器
471475
alt_toggle = self.page.locator(
472-
'mat-slide-toggle:has(button[aria-label="Toggle thinking mode"])'
476+
THINKING_MODE_TOGGLE_PARENT_SELECTOR
473477
)
474478
if await alt_toggle.count() > 0:
475479
await alt_toggle.click(timeout=CLICK_TIMEOUT_MS)
476480
else:
477481
# 旧版UI回退: data-test-toggle
478482
root = self.page.locator(
479-
'mat-slide-toggle[data-test-toggle="enable-thinking"]'
483+
THINKING_MODE_TOGGLE_OLD_ROOT_SELECTOR
480484
)
481485
label = root.locator("label.mdc-label")
482486
await expect_async(label).to_be_visible(timeout=2000)
@@ -563,14 +567,14 @@ async def _control_thinking_budget_toggle(
563567
try:
564568
# 新版UI: 尝试直接点击带 aria-label 的开关父容器
565569
alt_toggle = self.page.locator(
566-
'mat-slide-toggle:has(button[aria-label="Toggle thinking budget between auto and manual"])'
570+
THINKING_BUDGET_TOGGLE_PARENT_SELECTOR
567571
)
568572
if await alt_toggle.count() > 0:
569573
await alt_toggle.click(timeout=CLICK_TIMEOUT_MS)
570574
else:
571575
# 旧版UI回退: data-test-toggle
572576
root = self.page.locator(
573-
'mat-slide-toggle[data-test-toggle="manual-budget"]'
577+
THINKING_BUDGET_TOGGLE_OLD_ROOT_SELECTOR
574578
)
575579
label = root.locator("label.mdc-label")
576580
await expect_async(label).to_be_visible(timeout=2000)

config/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@
8383
"NO_PROXY_ENV",
8484
"ENABLE_SCRIPT_INJECTION",
8585
"USERSCRIPT_PATH",
86+
# 新增页面元素选择器
87+
"MODEL_NAME_SELECTOR",
88+
"CDK_OVERLAY_CONTAINER_SELECTOR",
89+
"CHAT_TURN_SELECTOR",
90+
# 思考模式回退选择器
91+
"THINKING_MODE_TOGGLE_PARENT_SELECTOR",
92+
"THINKING_MODE_TOGGLE_OLD_ROOT_SELECTOR",
93+
"THINKING_BUDGET_TOGGLE_PARENT_SELECTOR",
94+
"THINKING_BUDGET_TOGGLE_OLD_ROOT_SELECTOR",
8695
# 工具函数
8796
"get_environment_variable",
8897
"get_boolean_env",

config/selectors.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,28 @@
118118
GROUNDING_WITH_GOOGLE_SEARCH_TOGGLE_SELECTOR = (
119119
'div[data-test-id="searchAsAToolTooltip"] mat-slide-toggle button'
120120
)
121+
122+
# --- 页面元素选择器 ---
123+
# 模型名称显示元素
124+
MODEL_NAME_SELECTOR = '[data-test-id="model-name"]'
125+
# CDK Overlay 容器(用于菜单、对话框等)
126+
CDK_OVERLAY_CONTAINER_SELECTOR = "div.cdk-overlay-container"
127+
# 聊天轮次容器
128+
CHAT_TURN_SELECTOR = "ms-chat-turn"
129+
130+
# --- 思考模式回退选择器 ---
131+
# 这些选择器用于 thinking.py 中的回退逻辑
132+
# 主思考开关父容器(新版UI)
133+
THINKING_MODE_TOGGLE_PARENT_SELECTOR = (
134+
'mat-slide-toggle:has(button[aria-label="Toggle thinking mode"])'
135+
)
136+
# 主思考开关旧版根元素
137+
THINKING_MODE_TOGGLE_OLD_ROOT_SELECTOR = (
138+
'mat-slide-toggle[data-test-toggle="enable-thinking"]'
139+
)
140+
# 思考预算开关父容器(新版UI)
141+
THINKING_BUDGET_TOGGLE_PARENT_SELECTOR = 'mat-slide-toggle:has(button[aria-label="Toggle thinking budget between auto and manual"])'
142+
# 思考预算开关旧版根元素
143+
THINKING_BUDGET_TOGGLE_OLD_ROOT_SELECTOR = (
144+
'mat-slide-toggle[data-test-toggle="manual-budget"]'
145+
)

0 commit comments

Comments
 (0)