Files
gemini-skill/references/gemini-flow.md

181 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Gemini Flow
## 1) 登录校验
最小校验项:
- 页面存在可输入提问的输入框
- 右上角有用户头像或账户入口
若未登录:提示用户先在 Daemon 托管的浏览器中手动登录 Google 账号Daemon 未运行时会自动后台拉起)。
## 2) 模型策略
优先级:
1. Gemini 3.1 Pro
2. 当前页面可见的次优 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) 生图结果获取
> ⚠️ **严禁使用浏览器截图screenshot获取生成图片。**
> - **默认流程**:通过 `src` URL 右键另存为Save Image As保存到本地再发送给用户。
> - **高清流程**:仅当用户明确要求高清/原图时,才调用 `downloadLatestImage()` 点击原图下载按钮。
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`
- `image` class = Gemini 的图片元素
- `loaded` class = 图片已渲染完成(未加载完的不会有此 class
- 两个 class 同时存在才算有效图片
- DOM 中可能存在多张历史图片,**取最后一个**即为最新生成
### 下载按钮定位
-`img` 向上找到最近的 `.image-container` 祖先容器
- 在容器内查找 `mat-icon[fonticon="download"]`(即下载原图按钮)
- `getLatestImage()` 返回 `hasDownloadBtn` 字段标识是否有下载按钮
### API
所有操作函数的返回值都包含 `debug` 字段,记录该次调用每一步的日志(含时间戳、步骤名、成功/失败、上下文详情),方便排查问题和改进策略。
- `GeminiOps.getLatestImage()` → 获取最新一张图片信息
```json
{
"ok": true,
"src": "https://lh3.googleusercontent.com/...",
"alt": "AI 生成",
"width": 1024,
"height": 1024,
"hasDownloadBtn": true,
"debug": [
{"ts": 1710000000000, "fn": "getLatestImage", "step": "start", "ok": true},
{"ts": 1710000000001, "fn": "getLatestImage", "step": "query_imgs", "ok": true, "detail": {"totalFound": 1}},
{"ts": 1710000000002, "fn": "getLatestImage", "step": "picked_latest", "ok": true, "detail": {"index": 0, "src": "https://lh3.google..."}},
{"ts": 1710000000003, "fn": "getLatestImage", "step": "find_container", "ok": true},
{"ts": 1710000000004, "fn": "getLatestImage", "step": "find_download_btn", "ok": true}
]
}
```
- `GeminiOps.downloadLatestImage()` → 点击最新图片的下载原图按钮(仅用户要求高清时)
```json
{"ok": true, "src": "https://lh3.googleusercontent.com/...", "debug": [...]}
```
- `GeminiOps.extractImageBase64()`**默认图片获取方式**,从 DOM 直接提取 Base64
```json
{
"ok": true,
"dataUrl": "data:image/png;base64,iVBORw0KGgo...",
"width": 1024,
"height": 1024,
"method": "canvas",
"debug": [...]
}
```
提取策略(自动选择,无需调用端干预):
1. **Canvas 提取**(优先):将已渲染的 `<img>` 绘制到虚拟 Canvas同步导出 `toDataURL('image/png')`。零网络请求,毫秒级完成。`method` 返回 `"canvas"`
2. **Fetch fallback**:若 Canvas 因跨域 tainted 而报错,自动回退到页面内 `fetch(img.src)``blob``FileReader.readAsDataURL()``method` 返回 `"fetch"`
> ⚠️ 该函数返回 **Promise**。CDP 调用时必须设置 `awaitPromise: true`
> ```js
> // CDP Runtime.evaluate 示例
> { expression: "GeminiOps.extractImageBase64()", awaitPromise: true, returnByValue: true }
> ```
调用端拿到 `dataUrl` 后,去掉 `data:image/png;base64,` 前缀,解码为二进制存为 `.png` 文件即可。
- `GeminiOps.probe()` / `click()` / `fillPrompt()` / `pollStatus()` → 同样携带 `debug` 字段
- `GeminiOps.getDebugLog()` → 获取完整累积日志(不清空),用于事后排查
```json
{"log": [...], "count": 15}
```
### debug 日志格式
每条日志条目:
| 字段 | 类型 | 说明 |
|---|---|---|
| `ts` | number | 毫秒级时间戳 |
| `fn` | string | 函数名,如 `click``getLatestImage` |
| `step` | string | 步骤名,如 `start``find_container``clicked` |
| `ok` | boolean | 该步骤是否成功 |
| `detail` | object? | 可选,上下文信息(匹配的选择器、找到的元素数量等) |
调用端应将 `debug` 数组回传给用户,便于分析定位失败原因和优化选择器策略。
```
### 图片交付流程(重要)
**默认流程Base64 提取):**
1. 调用 `GeminiOps.getLatestImage()` 确认图片已渲染完成(`ok: true`
2. 调用 `GeminiOps.extractImageBase64()` 提取图片数据(需 `awaitPromise: true`
3. 去掉 `dataUrl` 的 `data:image/png;base64,` 前缀,解码为二进制,保存为 `.png` 文件
4. 将本地图片文件发送给用户
**高清流程(仅用户要求时):**
1. 调用 `GeminiOps.getLatestImage()` 确认图片已渲染完成
2. 调用 `GeminiOps.downloadLatestImage()` 点击原图下载按钮
3. 将下载到本地的高清原图文件发送给用户
> **严禁**在任何环节使用浏览器截图screenshot代替保存图片。
### 回退
- `ok === false` → 页面可能还在渲染,等几秒再调一次
- 连续两次失败 → 做 snapshot 排查页面状态snapshot 仅用于排查,不用于交付图片)
## 5) 用户提示文案(建议)
- 开始生图:
- `已收到,正在用 Gemini 给你绘图中 🎨`
- 生成中超时:
- `还在渲染中,我继续盯着,马上回你。`
- 完成:
- `画好了,给你发图啦~`