3.2 KiB
3.2 KiB
Gemini Flow
1) 登录校验
最小校验项:
- 页面存在可输入提问的输入框
- 右上角有用户头像或账户入口
若未登录:提示用户先在 openclaw profile 浏览器中登录。
2) 模型策略
优先级:
- Gemini 3.1 Pro
- 当前页面可见的次优 Pro/Advanced 模型
若切换失败,保留默认并告知用户。
3) 按钮状态检测
.send-button-container 内的按钮通过 aria-label 区分三种状态:
- 空闲(idle):aria-label 为麦克风相关,按钮 disabled,输入框为空。
- 可发送(ready):aria-label 为"发送"/"Send",输入框有内容。
- 生成中(loading):aria-label 为"停止"/"Stop",Gemini 正在输出。
使用方式:
GeminiOps.getStatus()→ 返回{status: 'idle'|'ready'|'loading', label, disabled}GeminiOps.pollStatus()→ 返回{status, label, pageVisible, ts},毫秒级返回,供调用端分段轮询
CDP 保活轮询(重要)
禁止在页面内做长 Promise 等待(旧版 waitForComplete 已移除)。
正确做法:调用端每 8~10 秒 evaluate 一次 GeminiOps.pollStatus(),自行累计耗时并判断超时。
这确保 CDP WebSocket 通道持续有消息流量,避免被网关判定空闲而断开连接。
4) 生图结果获取
Gemini 一次只生成一张图片,流程上只关心最新生成的那张,历史图片不做处理。
调用 GeminiOps.getLatestImage() 获取最新一张生成图片。
DOM 结构
<div class="image-container ...">
<button class="image-button ...">
<img class="image loaded" src="https://lh3.googleusercontent.com/..." alt="AI 生成">
</button>
<div class="button-icon-wrapper">
<mat-icon fonticon="download" data-mat-icon-name="download" class="button-icon ..."></mat-icon>
</div>
</div>
图片定位
- 选择器:
img.image.loaded imageclass = Gemini 的图片元素loadedclass = 图片已渲染完成(未加载完的不会有此 class)- 两个 class 同时存在才算有效图片
- DOM 中可能存在多张历史图片,取最后一个即为最新生成
下载按钮定位
- 从
img向上找到最近的.image-container祖先容器 - 在容器内查找
mat-icon[fonticon="download"](即下载原图按钮) getLatestImage()返回hasDownloadBtn字段标识是否有下载按钮
API
GeminiOps.getLatestImage()→ 获取最新一张图片信息
{
"ok": true,
"src": "https://lh3.googleusercontent.com/...",
"alt": "AI 生成",
"width": 1024,
"height": 1024,
"hasDownloadBtn": true
}
GeminiOps.downloadLatestImage()→ 点击最新图片的下载原图按钮
{"ok": true, "src": "https://lh3.googleusercontent.com/..."}
回退
ok === false→ 页面可能还在渲染,等几秒再调一次- 连续两次失败 → 做 snapshot 排查页面状态
hasDownloadBtn: false→ 回退到直接用srcURL 下载
5) 用户提示文案(建议)
- 开始生图:
已收到,正在用 Gemini 给你绘图中 🎨
- 生成中超时:
还在渲染中,我继续盯着,马上回你。
- 完成:
画好了,给你发图啦~