Skip to content

Commit 56ee2eb

Browse files
MAX-TABMAX-TAB
authored andcommitted
修复
1 parent af21fb6 commit 56ee2eb

5 files changed

Lines changed: 44 additions & 134 deletions

File tree

browser_utils/initialization.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ async def _initialize_page_logic(browser: AsyncBrowser):
416416
await expect_async(found_page.locator(INPUT_SELECTOR)).to_be_visible(timeout=10000)
417417
logger.info("-> ✅ 核心输入区域可见。")
418418

419-
model_name_locator = found_page.locator('mat-select[data-test-ms-model-selector] .model-option-content span')
419+
model_name_locator = found_page.locator('[data-test-id="model-name"]')
420420
try:
421421
model_name_on_page = await model_name_locator.first.inner_text(timeout=5000)
422422
logger.info(f"-> 🤖 页面检测到的当前模型: {model_name_on_page}")

browser_utils/model_management.py

Lines changed: 26 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -274,26 +274,25 @@ async def switch_ai_studio_model(page: AsyncPage, model_id: str, req_id: str) ->
274274
if m_obj.get("id") == model_id:
275275
expected_display_name_for_target_id = m_obj.get("display_name")
276276
break
277+
278+
try:
279+
model_name_locator = page.locator('[data-test-id="model-name"]')
280+
actual_displayed_model_id_on_page_raw = await model_name_locator.first.inner_text(timeout=5000)
281+
actual_displayed_model_id_on_page = actual_displayed_model_id_on_page_raw.strip()
282+
283+
target_model_id = model_id
284+
285+
if actual_displayed_model_id_on_page == target_model_id:
286+
page_display_match = True
287+
logger.info(f"[{req_id}] ✅ 页面显示模型ID ('{actual_displayed_model_id_on_page}') 与期望ID ('{target_model_id}') 一致。")
288+
else:
289+
page_display_match = False
290+
logger.error(f"[{req_id}] ❌ 页面显示模型ID ('{actual_displayed_model_id_on_page}') 与期望ID ('{target_model_id}') 不一致。")
277291

278-
if not expected_display_name_for_target_id:
279-
logger.warning(f"[{req_id}] 无法在parsed_model_list中找到目标ID '{model_id}' 的显示名称,跳过页面显示名称验证。这可能不准确。")
280-
page_display_match = True
281-
else:
282-
try:
283-
model_name_locator = page.locator('mat-select[data-test-ms-model-selector] .model-option-content span')
284-
actual_displayed_model_name_on_page_raw = await model_name_locator.first.inner_text(timeout=5000)
285-
actual_displayed_model_name_on_page = actual_displayed_model_name_on_page_raw.strip()
286-
normalized_actual_display = actual_displayed_model_name_on_page.lower()
287-
normalized_expected_display = expected_display_name_for_target_id.strip().lower()
288-
289-
if normalized_actual_display == normalized_expected_display:
290-
page_display_match = True
291-
logger.info(f"[{req_id}] ✅ 页面显示模型 ('{actual_displayed_model_name_on_page}') 与期望 ('{expected_display_name_for_target_id}') 一致。")
292-
else:
293-
logger.error(f"[{req_id}] ❌ 页面显示模型 ('{actual_displayed_model_name_on_page}') 与期望 ('{expected_display_name_for_target_id}') 不一致。(Raw page: '{actual_displayed_model_name_on_page_raw}')")
294-
except Exception as e_disp:
295-
logger.warning(f"[{req_id}] 读取页面显示的当前模型名称时出错: {e_disp}。将无法验证页面显示。")
296-
292+
except Exception as e_disp:
293+
page_display_match = False # 读取失败则认为不匹配
294+
logger.warning(f"[{req_id}] 读取页面显示的当前模型ID时出错: {e_disp}。将无法验证页面显示。")
295+
297296
if page_display_match:
298297
return True
299298
else:
@@ -306,7 +305,7 @@ async def switch_ai_studio_model(page: AsyncPage, model_id: str, req_id: str) ->
306305
current_displayed_name_for_revert_stripped = "无法读取"
307306

308307
try:
309-
model_name_locator_revert = page.locator('mat-select[data-test-ms-model-selector] .model-option-content span')
308+
model_name_locator_revert = page.locator('[data-test-id="model-name"]')
310309
current_displayed_name_for_revert_raw = await model_name_locator_revert.first.inner_text(timeout=5000)
311310
current_displayed_name_for_revert_stripped = current_displayed_name_for_revert_raw.strip()
312311
logger.info(f"[{req_id}] 恢复:页面当前显示的模型名称 (原始: '{current_displayed_name_for_revert_raw}', 清理后: '{current_displayed_name_for_revert_stripped}')")
@@ -324,17 +323,9 @@ async def switch_ai_studio_model(page: AsyncPage, model_id: str, req_id: str) ->
324323
return False
325324

326325
model_id_to_revert_to = None
327-
if parsed_model_list and current_displayed_name_for_revert_stripped != "无法读取":
328-
normalized_current_display_for_revert = current_displayed_name_for_revert_stripped.lower()
329-
for m_obj in parsed_model_list:
330-
parsed_list_display_name = m_obj.get("display_name", "").strip().lower()
331-
if parsed_list_display_name == normalized_current_display_for_revert:
332-
model_id_to_revert_to = m_obj.get("id")
333-
logger.info(f"[{req_id}] 恢复:页面显示名称 '{current_displayed_name_for_revert_stripped}' 对应模型ID: {model_id_to_revert_to}")
334-
break
335-
336-
if not model_id_to_revert_to:
337-
logger.warning(f"[{req_id}] 恢复:无法在 parsed_model_list 中找到与页面显示名称 '{current_displayed_name_for_revert_stripped}' 匹配的模型ID。")
326+
if current_displayed_name_for_revert_stripped != "无法读取":
327+
model_id_to_revert_to = current_displayed_name_for_revert_stripped
328+
logger.info(f"[{req_id}] 恢复:页面当前显示的ID是 '{model_id_to_revert_to}',将直接用于恢复。")
338329
else:
339330
if current_displayed_name_for_revert_stripped == "无法读取":
340331
logger.warning(f"[{req_id}] 恢复:因无法读取页面显示名称,故不能从 parsed_model_list 转换ID。")
@@ -529,7 +520,7 @@ async def _set_model_from_page_display(page: AsyncPage, set_storage: bool = Fals
529520

530521
try:
531522
logger.info(" 尝试从页面显示元素读取当前模型名称...")
532-
model_name_locator = page.locator('mat-select[data-test-ms-model-selector] .model-option-content span')
523+
model_name_locator = page.locator('[data-test-id="model-name"]')
533524
displayed_model_name_from_page_raw = await model_name_locator.first.inner_text(timeout=7000)
534525
displayed_model_name = displayed_model_name_from_page_raw.strip()
535526
logger.info(f" 页面当前显示模型名称 (原始: '{displayed_model_name_from_page_raw}', 清理后: '{displayed_model_name}')")
@@ -542,19 +533,10 @@ async def _set_model_from_page_display(page: AsyncPage, set_storage: bool = Fals
542533
except asyncio.TimeoutError:
543534
logger.warning(" 等待模型列表超时,可能无法准确转换显示名称为ID。")
544535

545-
if parsed_model_list:
546-
for model_obj in parsed_model_list:
547-
if model_obj.get("display_name") and model_obj.get("display_name").strip() == displayed_model_name:
548-
found_model_id_from_display = model_obj.get("id")
549-
logger.info(f" 显示名称 '{displayed_model_name}' 对应模型 ID: {found_model_id_from_display}")
550-
break
551-
552-
if not found_model_id_from_display:
553-
logger.warning(f" 未在已知模型列表中找到与显示名称 '{displayed_model_name}' 匹配的 ID。")
554-
else:
555-
logger.warning(" 模型列表尚不可用,无法将显示名称转换为ID。")
536+
found_model_id_from_display = displayed_model_name
537+
logger.info(f" 页面显示的直接是模型ID: '{found_model_id_from_display}'")
556538

557-
new_model_value = found_model_id_from_display if found_model_id_from_display else displayed_model_name
539+
new_model_value = found_model_id_from_display
558540
if server.current_ai_studio_model_id != new_model_value:
559541
server.current_ai_studio_model_id = new_model_value
560542
logger.info(f" 全局 current_ai_studio_model_id 已更新为: {server.current_ai_studio_model_id}")

browser_utils/page_controller.py

Lines changed: 11 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -580,78 +580,21 @@ async def clear_chat_history(self, check_client_disconnected: Callable):
580580
raise
581581

582582
async def _execute_chat_clear(self, clear_chat_button_locator, confirm_button_locator, overlay_locator, check_client_disconnected: Callable):
583-
"""执行清空聊天操作"""
584-
overlay_initially_visible = False
583+
"""执行清空聊天操作 (适配新版UI,无确认对话框)"""
584+
self.logger.info(f"[{self.req_id}] 点击\"清空聊天\"按钮: {CLEAR_CHAT_BUTTON_SELECTOR}")
585+
585586
try:
586-
if await overlay_locator.is_visible(timeout=1000):
587-
overlay_initially_visible = True
588-
self.logger.info(f"[{self.req_id}] 清空聊天确认遮罩层已可见。直接点击\"继续\"。")
589-
except TimeoutError:
590-
self.logger.info(f"[{self.req_id}] 清空聊天确认遮罩层初始不可见 (检查超时或未找到)。")
591-
overlay_initially_visible = False
592-
except Exception as e_vis_check:
593-
self.logger.warning(f"[{self.req_id}] 检查遮罩层可见性时发生错误: {e_vis_check}。假定不可见。")
594-
overlay_initially_visible = False
595-
596-
await self._check_disconnect(check_client_disconnected, "清空聊天 - 初始遮罩层检查后")
597-
598-
if overlay_initially_visible:
599-
self.logger.info(f"[{self.req_id}] 点击\"继续\"按钮 (遮罩层已存在): {CLEAR_CHAT_CONFIRM_BUTTON_SELECTOR}")
600-
await confirm_button_locator.click(timeout=CLICK_TIMEOUT_MS)
601-
else:
602-
self.logger.info(f"[{self.req_id}] 点击\"清空聊天\"按钮: {CLEAR_CHAT_BUTTON_SELECTOR}")
603587
await clear_chat_button_locator.click(timeout=CLICK_TIMEOUT_MS)
604588
await self._check_disconnect(check_client_disconnected, "清空聊天 - 点击\"清空聊天\"后")
589+
590+
await asyncio.sleep(0.5)
591+
592+
self.logger.info(f"[{self.req_id}] ✅ '清空聊天'按钮已点击。新版UI无确认步骤,操作完成。")
605593

606-
try:
607-
self.logger.info(f"[{self.req_id}] 等待清空聊天确认遮罩层出现: {OVERLAY_SELECTOR}")
608-
await expect_async(overlay_locator).to_be_visible(timeout=WAIT_FOR_ELEMENT_TIMEOUT_MS)
609-
self.logger.info(f"[{self.req_id}] 清空聊天确认遮罩层已出现。")
610-
except TimeoutError:
611-
error_msg = f"等待清空聊天确认遮罩层超时 (点击清空按钮后)。请求 ID: {self.req_id}"
612-
self.logger.error(error_msg)
613-
await save_error_snapshot(f"clear_chat_overlay_timeout_{self.req_id}")
614-
raise Exception(error_msg)
615-
616-
await self._check_disconnect(check_client_disconnected, "清空聊天 - 遮罩层出现后")
617-
self.logger.info(f"[{self.req_id}] 点击\"继续\"按钮 (在对话框中): {CLEAR_CHAT_CONFIRM_BUTTON_SELECTOR}")
618-
await confirm_button_locator.click(timeout=CLICK_TIMEOUT_MS)
619-
620-
await self._check_disconnect(check_client_disconnected, "清空聊天 - 点击\"继续\"后")
621-
622-
# 等待对话框消失
623-
max_retries_disappear = 3
624-
for attempt_disappear in range(max_retries_disappear):
625-
try:
626-
self.logger.info(f"[{self.req_id}] 等待清空聊天确认按钮/对话框消失 (尝试 {attempt_disappear + 1}/{max_retries_disappear})...")
627-
await expect_async(confirm_button_locator).to_be_hidden(timeout=CLEAR_CHAT_VERIFY_TIMEOUT_MS)
628-
await expect_async(overlay_locator).to_be_hidden(timeout=1000)
629-
self.logger.info(f"[{self.req_id}] ✅ 清空聊天确认对话框已成功消失。")
630-
break
631-
except TimeoutError:
632-
self.logger.warning(f"[{self.req_id}] ⚠️ 等待清空聊天确认对话框消失超时 (尝试 {attempt_disappear + 1}/{max_retries_disappear})。")
633-
if attempt_disappear < max_retries_disappear - 1:
634-
await asyncio.sleep(1.0)
635-
await self._check_disconnect(check_client_disconnected, f"清空聊天 - 重试消失检查 {attempt_disappear + 1} 前")
636-
continue
637-
else:
638-
error_msg = f"达到最大重试次数。清空聊天确认对话框未消失。请求 ID: {self.req_id}"
639-
self.logger.error(error_msg)
640-
await save_error_snapshot(f"clear_chat_dialog_disappear_timeout_{self.req_id}")
641-
raise Exception(error_msg)
642-
except ClientDisconnectedError:
643-
self.logger.info(f"[{self.req_id}] 客户端在等待清空确认对话框消失时断开连接。")
644-
raise
645-
except Exception as other_err:
646-
self.logger.warning(f"[{self.req_id}] 等待清空确认对话框消失时发生其他错误: {other_err}")
647-
if attempt_disappear < max_retries_disappear - 1:
648-
await asyncio.sleep(1.0)
649-
continue
650-
else:
651-
raise
652-
653-
await self._check_disconnect(check_client_disconnected, f"清空聊天 - 消失检查尝试 {attempt_disappear + 1} 后")
654-
594+
except Exception as e:
595+
self.logger.error(f"[{self.req_id}] 点击'清空聊天'按钮时发生错误: {e}")
596+
raise
597+
655598
async def _verify_chat_cleared(self, check_client_disconnected: Callable):
656599
"""验证聊天已清空"""
657600
last_response_container = self.page.locator(RESPONSE_CONTAINER_SELECTOR).last

config/selectors.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010

1111
# --- 按钮选择器 ---
1212
SUBMIT_BUTTON_SELECTOR = 'button[aria-label="Run"].run-button'
13-
CLEAR_CHAT_BUTTON_SELECTOR = 'button[data-test-clear="outside"][aria-label="Clear chat"]'
13+
CLEAR_CHAT_BUTTON_SELECTOR = 'button[data-test-clear="outside"][aria-label="New chat"]'
1414
CLEAR_CHAT_CONFIRM_BUTTON_SELECTOR = 'button.ms-button-primary:has-text("Continue")'
15-
UPLOAD_BUTTON_SELECTOR = 'button[aria-label="Upload File"]'
15+
UPLOAD_BUTTON_SELECTOR = 'button[aria-label^="Insert assets"]'
1616

1717
# --- 响应相关选择器 ---
1818
RESPONSE_CONTAINER_SELECTOR = 'ms-chat-turn .chat-turn-container.model'

deprecated_javascript_version/server.cjs

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -989,47 +989,32 @@ async function processQueue() {
989989
console.log(`[${reqId}] 检测到可能是新对话 (消息数: ${messages.length}),尝试清空聊天记录...`);
990990
try {
991991
const clearButton = page.locator(CLEAR_CHAT_BUTTON_SELECTOR);
992-
console.log(`[${reqId}] - 查找并点击"Clear chat"按钮...`);
992+
console.log(`[${reqId}] - 查找并点击"Clear chat" (New chat) 按钮...`);
993993
await clearButton.waitFor({ state: 'visible', timeout: 7000 });
994994
await clearButton.click({ timeout: 5000 });
995-
console.log(`[${reqId}] - "Clear chat"按钮已点击。`);
995+
console.log(`[${reqId}] - "Clear chat"按钮已点击。新版UI无确认步骤,开始验证清空效果...`);
996996

997-
console.log(`[${reqId}] - 等待确认对话框及"Continue"按钮出现...`);
998-
const confirmButton = page.locator(CLEAR_CHAT_CONFIRM_BUTTON_SELECTOR);
999-
await confirmButton.waitFor({ state: 'visible', timeout: 5000 });
1000-
1001-
console.log(`[${reqId}] - 点击"Continue"按钮...`);
1002-
await confirmButton.click({ timeout: 5000 });
1003-
console.log(`[${reqId}] - "Continue"按钮已点击。开始验证清空效果...`);
1004-
1005-
// --- 新增:验证清空效果 ---
1006997
const checkStartTime = Date.now();
1007998
let cleared = false;
1008999
while (Date.now() - checkStartTime < CLEAR_CHAT_VERIFY_TIMEOUT_MS) {
1009-
// 定位所有 AI 回复容器
10101000
const modelTurns = page.locator(RESPONSE_CONTAINER_SELECTOR);
10111001
const count = await modelTurns.count();
10121002
if (count === 0) {
10131003
console.log(`[${reqId}] ✅ 验证成功: 页面上未找到之前的 AI 回复元素 (耗时 ${Date.now() - checkStartTime}ms)。`);
10141004
cleared = true;
1015-
break; // 验证成功,退出循环
1005+
break;
10161006
}
1017-
// 稍微等待后再次检查
10181007
await page.waitForTimeout(CLEAR_CHAT_VERIFY_INTERVAL_MS);
10191008
}
10201009

10211010
if (!cleared) {
1022-
// 如果超时后仍然找到 AI 回复元素
10231011
console.warn(`[${reqId}] ⚠️ 验证超时: 在 ${CLEAR_CHAT_VERIFY_TIMEOUT_MS}ms 内仍能检测到之前的 AI 回复元素。上下文可能未完全清空。`);
1024-
// 保存快照以供调试
10251012
await saveErrorSnapshot(`clear_chat_verify_fail_${reqId}`);
10261013
}
1027-
// --- 结束:验证清空效果 ---
1028-
10291014
} catch (clearChatError) {
10301015
console.warn(`[${reqId}] ⚠️ 清空聊天记录或验证时出错: ${clearChatError.message.split('\n')[0]}. 将继续执行请求,但上下文可能未被清除。`);
10311016
if (clearChatError.message.includes('selector')) {
1032-
console.warn(` (请仔细检查选择器是否仍然有效: CLEAR_CHAT_BUTTON_SELECTOR='${CLEAR_CHAT_BUTTON_SELECTOR}', CLEAR_CHAT_CONFIRM_BUTTON_SELECTOR='${CLEAR_CHAT_CONFIRM_BUTTON_SELECTOR}')`);
1017+
console.warn(` (请仔细检查选择器是否仍然有效: CLEAR_CHAT_BUTTON_SELECTOR='${CLEAR_CHAT_BUTTON_SELECTOR}')`);
10331018
}
10341019
await saveErrorSnapshot(`clear_chat_fail_or_verify_${reqId}`);
10351020
}

0 commit comments

Comments
 (0)