Skip to content

Commit 0675824

Browse files
committed
fix: 跟随前端更新-2
1 parent b71e751 commit 0675824

File tree

2 files changed

+91
-41
lines changed

2 files changed

+91
-41
lines changed

src/browser/page_controller.py

Lines changed: 85 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import re
66
import os
77
from playwright.async_api import Page as AsyncPage, expect as expect_async, TimeoutError, Locator
8-
from config import TEMPERATURE_INPUT_SELECTOR, MAX_OUTPUT_TOKENS_SELECTOR, STOP_SEQUENCE_INPUT_SELECTOR, MAT_CHIP_REMOVE_BUTTON_SELECTOR, TOP_P_INPUT_SELECTOR, SUBMIT_BUTTON_SELECTOR, OVERLAY_SELECTOR, PROMPT_TEXTAREA_SELECTOR, RESPONSE_CONTAINER_SELECTOR, RESPONSE_TEXT_SELECTOR, EDIT_MESSAGE_BUTTON_SELECTOR, USE_URL_CONTEXT_SELECTOR, UPLOAD_BUTTON_SELECTOR, INSERT_BUTTON_SELECTOR, THINKING_MODE_TOGGLE_SELECTOR, SET_THINKING_BUDGET_TOGGLE_SELECTOR, THINKING_BUDGET_INPUT_SELECTOR, GROUNDING_WITH_GOOGLE_SEARCH_TOGGLE_SELECTOR, ZERO_STATE_SELECTOR, SYSTEM_INSTRUCTIONS_BUTTON_SELECTOR, SYSTEM_INSTRUCTIONS_TEXTAREA_SELECTOR, SKIP_PREFERENCE_VOTE_BUTTON_SELECTOR, CLICK_TIMEOUT_MS, WAIT_FOR_ELEMENT_TIMEOUT_MS, CLEAR_CHAT_VERIFY_TIMEOUT_MS, DEFAULT_TEMPERATURE, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_STOP_SEQUENCES, DEFAULT_TOP_P, ENABLE_URL_CONTEXT, ENABLE_THINKING_BUDGET, DEFAULT_THINKING_BUDGET, ENABLE_GOOGLE_SEARCH, THINKING_LEVEL_SELECT_SELECTOR, THINKING_LEVEL_OPTION_HIGH_SELECTOR, THINKING_LEVEL_OPTION_LOW_SELECTOR, DEFAULT_THINKING_LEVEL
8+
from config import TEMPERATURE_INPUT_SELECTOR, MAX_OUTPUT_TOKENS_SELECTOR, STOP_SEQUENCE_INPUT_SELECTOR, MAT_CHIP_REMOVE_BUTTON_SELECTOR, TOP_P_INPUT_SELECTOR, SUBMIT_BUTTON_SELECTOR, OVERLAY_SELECTOR, PROMPT_TEXTAREA_SELECTOR, RESPONSE_CONTAINER_SELECTOR, RESPONSE_TEXT_SELECTOR, EDIT_MESSAGE_BUTTON_SELECTOR, USE_URL_CONTEXT_SELECTOR, UPLOAD_BUTTON_SELECTOR, INSERT_BUTTON_SELECTOR, THINKING_MODE_TOGGLE_SELECTOR, SET_THINKING_BUDGET_TOGGLE_SELECTOR, THINKING_BUDGET_INPUT_SELECTOR, GROUNDING_WITH_GOOGLE_SEARCH_TOGGLE_SELECTOR, ZERO_STATE_SELECTOR, SYSTEM_INSTRUCTIONS_BUTTON_SELECTOR, SYSTEM_INSTRUCTIONS_TEXTAREA_SELECTOR, SKIP_PREFERENCE_VOTE_BUTTON_SELECTOR, CLICK_TIMEOUT_MS, WAIT_FOR_ELEMENT_TIMEOUT_MS, CLEAR_CHAT_VERIFY_TIMEOUT_MS, DEFAULT_TEMPERATURE, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_STOP_SEQUENCES, DEFAULT_TOP_P, ENABLE_URL_CONTEXT, ENABLE_THINKING_BUDGET, DEFAULT_THINKING_BUDGET, ENABLE_GOOGLE_SEARCH, THINKING_LEVEL_SELECT_SELECTOR, THINKING_LEVEL_OPTION_HIGH_SELECTOR, THINKING_LEVEL_OPTION_LOW_SELECTOR, DEFAULT_THINKING_LEVEL, ADVANCED_SETTINGS_EXPANDER_SELECTOR
99
from models import ClientDisconnectedError, ElementClickError
1010
from .operations import save_error_snapshot, _wait_for_response_completion, _get_final_response_content, click_element
1111
from .thinking_normalizer import parse_reasoning_param, describe_config
@@ -54,6 +54,8 @@ async def adjust_parameters(self, request_params: Dict[str, Any], page_params_ca
5454
stop_to_set = request_params.get('stop', DEFAULT_STOP_SEQUENCES)
5555
top_p_to_set = request_params.get('top_p', DEFAULT_TOP_P)
5656

57+
await self._ensure_advanced_settings_expanded(check_client_disconnected)
58+
5759
async def handle_tools_panel():
5860
await self._ensure_tools_panel_expanded(check_client_disconnected)
5961
if ENABLE_URL_CONTEXT:
@@ -354,6 +356,60 @@ async def _adjust_google_search(self, request_params: Dict[str, Any], check_clie
354356
await asyncio.sleep(0.3)
355357
self.logger.error(f"[{self.req_id}] ❌ Google Search 設定失敗,已重試 {max_retries} 次")
356358

359+
360+
async def _ensure_advanced_settings_expanded(self, check_client_disconnected: Callable):
361+
max_retries = 3
362+
expander_locator = self.page.locator(ADVANCED_SETTINGS_EXPANDER_SELECTOR)
363+
364+
async def is_expanded() -> bool:
365+
try:
366+
grandparent = expander_locator.locator('xpath=../..')
367+
class_str = await grandparent.get_attribute('class', timeout=2000)
368+
return class_str and 'expanded' in class_str.split()
369+
except Exception:
370+
return False
371+
372+
for attempt in range(1, max_retries + 1):
373+
try:
374+
await self._check_disconnect(check_client_disconnected, f'高级设置展开 - 尝试 {attempt}')
375+
376+
if await expander_locator.count() == 0:
377+
self.logger.info(f'[{self.req_id}] 高级设置展开按钮不存在,可能已是新版布局,跳过。')
378+
return
379+
380+
if await is_expanded():
381+
self.logger.info(f'[{self.req_id}] ✅ 高级设置面板已展开。')
382+
return
383+
384+
self.logger.info(f'[{self.req_id}] 🔧 (尝试 {attempt}/{max_retries}) 正在展开高级设置面板...')
385+
386+
try:
387+
await click_element(self.page, expander_locator, '高级设置展开按钮', self.req_id)
388+
except ElementClickError as e:
389+
self.logger.warning(f'[{self.req_id}] 高级设置展开按钮点击失败: {e}')
390+
if attempt < max_retries:
391+
await asyncio.sleep(0.3)
392+
continue
393+
394+
await asyncio.sleep(0.3)
395+
396+
if await is_expanded():
397+
self.logger.info(f'[{self.req_id}] ✅ 高级设置面板已展开。')
398+
return
399+
400+
self.logger.warning(f'[{self.req_id}] 高级设置展开验证失败 (尝试 {attempt})')
401+
if attempt < max_retries:
402+
await asyncio.sleep(0.3)
403+
404+
except Exception as e:
405+
if isinstance(e, ClientDisconnectedError):
406+
raise
407+
self.logger.warning(f'[{self.req_id}] 展开高级设置失败 (尝试 {attempt}): {e}')
408+
if attempt < max_retries:
409+
await asyncio.sleep(0.3)
410+
411+
self.logger.error(f'[{self.req_id}] ❌ 高级设置展开失败,已重试 {max_retries} 次')
412+
357413
async def _ensure_tools_panel_expanded(self, check_client_disconnected: Callable):
358414
max_retries = 3
359415
for attempt in range(1, max_retries + 1):
@@ -646,64 +702,56 @@ async def _verify_chat_cleared(self, check_client_disconnected: Callable):
646702
self.logger.warning(f'[{self.req_id}] 警告: 清空聊天验证失败,但将继续执行。后续操作可能会受影响。')
647703

648704
async def _robust_click_insert_assets(self, check_client_disconnected: Callable) -> bool:
649-
self.logger.info(f"[{self.req_id}] 开始寻找并点击 'Insert assets' 按钮...")
705+
self.logger.info(f"[{self.req_id}] 开始寻找并点击媒体添加按钮...")
650706

651707
trigger_selectors = [
652-
'button[aria-label*="Insert assets"]',
708+
INSERT_BUTTON_SELECTOR,
709+
'button[aria-label*="Insert"]',
653710
'button[iconname="add_circle"]',
654-
'.ms-button-icon[iconname="add_circle"]'
711+
'button[iconname="note_add"]'
655712
]
656713

657714
trigger_btn = None
658715
for sel in trigger_selectors:
659716
if await self.page.locator(sel).count() > 0:
660717
trigger_btn = self.page.locator(sel).first
718+
self.logger.info(f"[{self.req_id}] 找到媒体按钮: {sel}")
661719
break
662720

663721
if not trigger_btn:
664-
self.logger.warning(f"[{self.req_id}] 未找到 'Insert assets' 按钮。")
665-
return False
666-
667-
async def is_menu_open():
668-
try:
669-
count = await self.page.locator('button[aria-label="Upload File"]').count()
670-
if count > 0 and await self.page.locator('button[aria-label="Upload File"]').first.is_visible():
671-
return True
672-
except Exception:
673-
pass
722+
self.logger.warning(f"[{self.req_id}] 未找到媒体添加按钮。")
674723
return False
675724

725+
upload_menu_locator = self.page.locator(UPLOAD_BUTTON_SELECTOR)
726+
676727
max_attempts = 3
677-
for attempt in range(max_attempts):
678-
await self._check_disconnect(check_client_disconnected, f'点击Insert Assets - 尝试 {attempt+1}')
728+
for attempt in range(1, max_attempts + 1):
729+
await self._check_disconnect(check_client_disconnected, f'点击媒体按钮 - 尝试 {attempt}')
730+
731+
self.logger.info(f"[{self.req_id}] (尝试 {attempt}/{max_attempts}) 点击媒体添加按钮...")
679732

680-
self.logger.info(f"[{self.req_id}] (尝试 {attempt+1}) 发送 'click' 事件到 Insert Assets 按钮...")
681733
try:
682-
await trigger_btn.dispatch_event('click')
683-
except Exception as e:
684-
self.logger.warning(f"[{self.req_id}] dispatch_event 失败: {e}")
734+
await click_element(self.page, trigger_btn, '媒体添加按钮', self.req_id)
735+
except ElementClickError as e:
736+
self.logger.warning(f"[{self.req_id}] 媒体按钮点击失败: {e}")
737+
if attempt < max_attempts:
738+
await asyncio.sleep(0.5)
739+
continue
685740

686741
for _ in range(10):
687-
if await is_menu_open():
688-
self.logger.info(f"[{self.req_id}] 'Upload File' 菜单项已检测到开启。")
689-
return True
742+
try:
743+
if await upload_menu_locator.count() > 0 and await upload_menu_locator.first.is_visible():
744+
self.logger.info(f"[{self.req_id}] ✅ 'Upload file' 菜单项已检测到开启。")
745+
return True
746+
except Exception:
747+
pass
690748
await asyncio.sleep(0.2)
691749

692-
self.logger.info(f"[{self.req_id}] (尝试 {attempt+1}) 菜单未开,尝试 JS click...")
693-
try:
694-
await trigger_btn.evaluate('e => e.click()')
695-
except Exception as e:
696-
self.logger.warning(f"[{self.req_id}] JS click 失败: {e}")
697-
698-
for _ in range(5):
699-
if await is_menu_open():
700-
self.logger.info(f"[{self.req_id}] 'Upload File' 菜单项已检测到开启 (JS click 后)。")
701-
return True
702-
await asyncio.sleep(0.2)
703-
704-
self.logger.warning(f"[{self.req_id}] (尝试 {attempt+1}) 菜单仍未开启。")
750+
self.logger.warning(f"[{self.req_id}] (尝试 {attempt}/{max_attempts}) 菜单仍未开启。")
751+
if attempt < max_attempts:
752+
await asyncio.sleep(0.3)
705753

706-
self.logger.error(f"[{self.req_id}] 多次尝试后仍无法打开 'Insert assets' 菜单。")
754+
self.logger.error(f"[{self.req_id}] 多次尝试后仍无法打开媒体菜单。")
707755
return False
708756

709757
async def _upload_images_via_file_input(self, images: List[Dict[str, str]], check_client_disconnected: Callable) -> bool:

src/config/selectors.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
PROMPT_TEXTAREA_SELECTOR = 'ms-prompt-box textarea'
22
INPUT_SELECTOR = PROMPT_TEXTAREA_SELECTOR
33
INPUT_SELECTOR2 = PROMPT_TEXTAREA_SELECTOR
4-
SUBMIT_BUTTON_SELECTOR = 'button[aria-label="Run"].run-button'
5-
INSERT_BUTTON_SELECTOR = 'button[aria-label="Insert assets such as images, videos, files, or audio"]'
6-
UPLOAD_BUTTON_SELECTOR = 'button[aria-label="Upload File"]'
4+
SUBMIT_BUTTON_SELECTOR = 'ms-prompt-box ms-run-button button'
5+
INSERT_BUTTON_SELECTOR = 'button[data-test-id="add-media-button"]'
6+
UPLOAD_BUTTON_SELECTOR = 'button[role="menuitem"]:has-text("Upload file")'
7+
HIDDEN_FILE_INPUT_SELECTOR = 'input.file-input[type="file"]'
78
SKIP_PREFERENCE_VOTE_BUTTON_SELECTOR = 'button[data-test-id="skip-button"][aria-label="Skip preference vote"]'
89
RESPONSE_CONTAINER_SELECTOR = 'ms-chat-turn .chat-turn-container.model'
910
RESPONSE_TEXT_SELECTOR = 'ms-cmark-node.cmark-node'
10-
LOADING_SPINNER_SELECTOR = 'button[aria-label="Run"].run-button svg .stoppable-spinner'
11+
LOADING_SPINNER_SELECTOR = 'ms-prompt-box ms-run-button button svg .stoppable-spinner'
1112
OVERLAY_SELECTOR = '.mat-mdc-dialog-inner-container'
1213
ZERO_STATE_SELECTOR = 'ms-zero-state'
1314
ERROR_TOAST_SELECTOR = 'div.toast.warning, div.toast.error'
@@ -17,6 +18,7 @@
1718
MORE_OPTIONS_BUTTON_SELECTOR = 'button[aria-label="Open options"]'
1819
COPY_MARKDOWN_BUTTON_SELECTOR = 'button[role="menuitem"]:has-text("Copy markdown")'
1920
COPY_MARKDOWN_BUTTON_SELECTOR_ALT = 'div[role="menu"] button:has-text("Copy Markdown")'
21+
ADVANCED_SETTINGS_EXPANDER_SELECTOR = 'button[aria-label="Expand or collapse advanced settings"]'
2022
MAX_OUTPUT_TOKENS_SELECTOR = 'input[aria-label="Maximum output tokens"]'
2123
STOP_SEQUENCE_INPUT_SELECTOR = 'input[aria-label="Add stop token"]'
2224
MAT_CHIP_REMOVE_BUTTON_SELECTOR = 'mat-chip-set mat-chip-row button[aria-label*="Remove"]'

0 commit comments

Comments
 (0)