From 7a548e44047d1143c82ceb52f378f4c4f604c802 Mon Sep 17 00:00:00 2001 From: WJZ_P <110795301+WJZ-P@users.noreply.github.com> Date: Sun, 22 Mar 2026 18:31:09 +0800 Subject: [PATCH] =?UTF-8?q?fix(gemini-ops):=20=E6=B3=A8=E9=87=8A=E4=B8=B4?= =?UTF-8?q?=E6=97=B6=E4=BC=9A=E8=AF=9D=E9=80=BB=E8=BE=91=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E5=9B=BE=E7=89=87=E4=B8=8A=E4=BC=A0=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E5=92=8C=E8=B6=85=E6=97=B6=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/demo.js | 14 +++++++------- src/gemini-ops.js | 18 +++++++++++++----- src/mcp-server.js | 12 +++++++----- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/demo.js b/src/demo.js index 62b0ac0..979438c 100644 --- a/src/demo.js +++ b/src/demo.js @@ -34,13 +34,13 @@ async function main() { try { // 1. 进入临时会话(不留聊天记录,保持账号干净) - console.log('[1] 进入临时会话...'); - const tempResult = await ops.clickTempChat(); - if (!tempResult.ok) { - console.warn('[1] 临时会话按钮未找到,跳过(可能已在临时模式或页面结构变化)'); - } else { - console.log('[1] 已进入临时会话'); - } + // console.log('[1] 进入临时会话...'); + // const tempResult = await ops.clickTempChat(); + // if (!tempResult.ok) { + // console.warn('[1] 临时会话按钮未找到,跳过(可能已在临时模式或页面结构变化)'); + // } else { + // console.log('[1] 已进入临时会话'); + // } // 2. 探测页面状态 console.log('\n[2] 探测页面元素...'); diff --git a/src/gemini-ops.js b/src/gemini-ops.js index 90eba4d..84dc447 100644 --- a/src/gemini-ops.js +++ b/src/gemini-ops.js @@ -8,7 +8,8 @@ import { createOperator } from './operator.js'; import { sleep } from './util.js'; import config from './config.js'; -import { mkdirSync } from 'node:fs'; +import { mkdirSync, existsSync } from 'node:fs'; +import { resolve as pathResolve, normalize as pathNormalize } from 'node:path'; import { removeWatermarkFromFile, removeWatermarkFromDataUrl } from './watermark-remover.js'; // ── Gemini 页面元素选择器 ── @@ -923,6 +924,13 @@ export function createOps(page) { */ async uploadImage(filePath) { try { + // 路径规范化(兼容 Windows 反斜杠、混合斜杠等) + filePath = pathResolve(pathNormalize(filePath)); + + if (!existsSync(filePath)) { + return { ok: false, error: 'file_not_found', detail: `文件不存在: ${filePath}` }; + } + // 1. 点击加号面板按钮,展开上传菜单 const panelClick = await this.click('uploadPanelBtn'); if (!panelClick.ok) { @@ -934,7 +942,7 @@ export function createOps(page) { // 3. Promise.all 是精髓:一边开始监听文件选择器弹窗,一边点击"上传文件"按钮 const [fileChooser] = await Promise.all([ - page.waitForFileChooser({ timeout: 3_000 }), + page.waitForFileChooser({ timeout: 5_000 }), this.click('uploadFileBtn'), ]); @@ -943,8 +951,8 @@ export function createOps(page) { console.log(`[ops] 文件已塞入,等待 Gemini 加载图片...`); // 5. 等待图片加载完成(.image-preview.loading 消失) - const loadTimeout = 10_000; - const loadInterval = 250; + const loadTimeout = 15_000; + const loadInterval = 500; const loadStart = Date.now(); await sleep(500); // 短暂等待 UI 响应 while (Date.now() - loadStart < loadTimeout) { @@ -953,7 +961,7 @@ export function createOps(page) { return !!el; }); if (!loading) { - console.log(`[ops] 图片加载完成 (${Date.now() - loadStart}ms): ${filePath}`); + console.log(`[ops] 图片上传成功 (${Date.now() - loadStart}ms): ${filePath}`); return { ok: true, elapsed: Date.now() - loadStart }; } await sleep(loadInterval); diff --git a/src/mcp-server.js b/src/mcp-server.js index 3cfb498..3d58321 100644 --- a/src/mcp-server.js +++ b/src/mcp-server.js @@ -48,16 +48,18 @@ server.registerTool( isError: true, }; } + // 检查是否需要新建会话 + if (newSession) { + await ops.click('newChatBtn'); + await sleep(250); + } // 确保是 pro 模型(生图需要 Pro) await ops.ensureModelPro(); - // 如果有参考图,需要先新建会话再上传,最后 generateImage 不再新建 + // 如果有参考图,需要上传参考图 if (referenceImages.length > 0) { - if (newSession) { - await ops.click('newChatBtn'); - await sleep(250); - } + for (const imgPath of referenceImages) { console.error(`[mcp] 正在上传参考图: ${imgPath}`); const uploadResult = await ops.uploadImage(imgPath);