fix(gemini-ops): 修复 CDP IO.read 分块返回的 base64 拼接问题,优化图片下载交互等待时间

This commit is contained in:
WJZ_P
2026-03-22 16:32:50 +08:00
parent 120e00b188
commit 1dacede9b1

View File

@@ -639,7 +639,11 @@ export function createOps(page) {
return { ok: false, error: 'cdp_no_stream' };
}
const chunks = [];
// 【关键修复】CDP IO.read 分块返回的 base64 不能直接拼接字符串!
// 每个 chunk 是独立编码的 base64末尾可能有 '=' 填充符,
// 直接 join 会导致中间插入非法字符 → 解码后数据损坏。
// 正确做法:先把每个 chunk 解码为 Buffer拼接 Buffer最后统一编码。
const bufferChunks = [];
let eof = false;
while (!eof) {
const { data, base64Encoded, eof: done } = await client.send('IO.read', {
@@ -647,13 +651,14 @@ export function createOps(page) {
size: 1024 * 1024, // 每次读 1MB
});
if (data) {
chunks.push(base64Encoded ? data : Buffer.from(data).toString('base64'));
bufferChunks.push(base64Encoded ? Buffer.from(data, 'base64') : Buffer.from(data));
}
eof = done;
}
await client.send('IO.close', { handle: streamHandle });
const base64Full = chunks.join('');
const fullBuffer = Buffer.concat(bufferChunks);
const base64Full = fullBuffer.toString('base64');
// 从 response headers 推断 MIMECDP 有时不提供,默认用 image/png
const mime = (resource.headers?.['content-type'] || resource.headers?.['Content-Type'] || 'image/png').split(';')[0].trim();
const dataUrl = `data:${mime};base64,${base64Full}`;
@@ -743,7 +748,7 @@ export function createOps(page) {
if (!scrollResult.ok) return scrollResult;
// 1b. 等待滚动和重排完成后,再获取准确的坐标
await sleep(250);
await sleep(500);
const imgInfo = await op.query((targetIndex) => {
const imgs = [...document.querySelectorAll('img.image.loaded')];
@@ -811,12 +816,16 @@ export function createOps(page) {
});
// 4. hover 到图片上,触发工具栏显示
console.log(`[downloadFullSizeImage] hover 到 (${imgInfo.x}, ${imgInfo.y})...`);
await page.mouse.move(imgInfo.x, imgInfo.y);
await sleep(500);
await sleep(800);
// 5. 点击"下载完整尺寸"按钮带重试hover 可能需要更长时间触发工具栏)
const btnSelector = 'button[data-test-id="download-generated-image-button"]';
const clickResult = await op.click(btnSelector);
// 先检查按钮是否出现
let clickResult = await op.click(btnSelector);
console.log(`[downloadFullSizeImage] 第1次点击下载按钮: ok=${clickResult.ok}, error=${clickResult.error || 'none'}`);
if (!clickResult.ok) {
return { ok: false, error: 'full_size_download_btn_not_found', src: imgInfo.src, index: imgInfo.index, total: imgInfo.total };