autotrain/docs/device-adaptation.md
xinxin6623 9eb6778a6f feat: web UI enhancements, device calibration, phone control manual, and skills directory
- web_ui.py: major refactor with improved runner, mode selection, progress tracking
- scripts: add device_runtime, device_calibrate, calibration_trace, record_android_flow
- docs: add phone-control-manual, update device-adaptation and windows-migration
- invoice_tool: enhance H5 automation flow and visual fallback
- calibrate.py: expand calibration capabilities
- add skills/ and tests/ directories
- remove obsolete .opencode/skills/invoice-wrapup

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-12 22:14:56 +08:00

177 lines
11 KiB
Markdown
Raw Permalink 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.

# 换手机适配 · 截屏节点与适配清单
> 目的:换手机后开票流程报错时,按此清单逐节点排查。
>
> 配套工具:`scripts/calibrate.py`Web UI 的 `/calibrate` 页)+ `work/device_profiles.json`(按 ADB 序列号分设备保存)。
>
> 相关文档:[`screen-adaptation.md`](./screen-adaptation.md) 是理论全链路清单(按处理顺序列所有识图点);**本文是实操版**,标注实际运行中哪些节点真正触发截图、哪些是换手机的报错高发点。
## 新手机最短路径
1. 只连接并授权一台手机,打开 12306 的 H5 开票单列表。
2. 打开 Web UI 的「设备校准」,点「自动真实校准」,从当前屏待开票乘客中明确选择一人并确认。
3. 系统会完成一次真实开票全过程截图、XML 与页面提示保存到 `work/calibration/<ADB序列号>/<时间>/`,设备档案写入 `work/device_profiles.json`
4. 成功后该手机可启动正常批量;若屏幕密度、分辨率或方向变更,档案会要求重新校准。
## 当前自动化口径
主流程固定为**逐人开具**:只点击乘客行中的精确「开具」按钮,不会点击页面底部的「批量开具」。若页面只剩批量入口,脚本会停止并提示人工回到逐人列表。
## 一、换手机报错的根因
换手机后开票流程总报错,根因有三类:
| 类别 | 根因 | 影响 | 是否已解决 |
|---|---|---|---|
| **A. 硬编码像素坐标** | 防熄屏 tap `(630,1400)`、滑动 `start_y=2400` 等写死 1260×2800 | tap/swipe 落点错位,小屏 tap 到屏外,大屏滑太少 | 已由按设备 serial 保存的比例配置覆盖 |
| **B. 滑动幅度按绝对像素** | 幅度 1800px 写死,小屏占比过大跳行,大屏占比过小翻页慢 | 跳过乘客 / 重复行 / 签名去重失效 | 部分(同上,按比例计算) |
| **C. 视觉 fallback 找不到按钮** | 视觉 API 返回 found:false新手机页面布局/分辨率不同时模型识别失败 | 卡在子流程,走兜底 recover | 否(依赖模型识别能力,校准只能验证不能根治) |
**A、B 的解法已经写好**`calibrate.py` + `device_profiles.json` + `apply_speed_defaults`),但**每台新手机必须先跑一次校准**。配置按 ADB serial 隔离,不会被另一台手机覆盖。
**C 是模型识别能力问题**,校准只能提前发现"这个按钮在这台手机上模型认不认得",不能保证运行时不丢。解法是保留 XML 优先 + 视觉兜底的双通道,并接受一定比例的 recover。
## 二、实际运行中的截屏节点(按触发频率排序)
跟踪 `work/web_runner.log` 实测一次完整开票流程9 乘客/pass触发的截屏如下。**每个节点都是单文件覆盖式写入,无历史留档**。
### 节点 1 · 列表页识行 `vision_list_rows()` 【每轮必触发·高频】
- **触发**:每轮(每屏)开头,识别当前可见所有乘客行
- **代码**`invoice_tool.py:1248` -> `vision_fallback.py` `list-rows` 子命令
- **截图落盘**`work/last_screenshot.png`(覆盖)
- **输入**adb 截屏
- **输出**`rows[{masked_name, id_first, id_last, button_bbox, tap_point}]` + `scroll_position` + `page_ok`
- **坐标**0-1000 归一化 -> denormalize 到实际像素(屏幕无关)
- **换手机风险**:低(归一化坐标自动适配)。但**滑动幅度不对会导致识到的行不全/重复**,属于 A/B 类问题的连带症状。
- **实测频率**13 次/批9 乘客 + 滚动若干屏)
### 节点 2 · after_verify 超时纠偏 - 找「查看」`_vision_find_button("查看")` 【条件触发·报错高发】
- **触发**`wait_for_page_transition` 等 after_verify 超时返回 `other` 时,进阶段 7 纠偏
- **代码**`invoice_tool.py:1280` `_vision_find_button`
- **截图落盘**`work/_vision_find_tmp.png`(覆盖)
- **输入**adb 截屏
- **输出**:像素 (x,y) 或 None
- **实测**3 次,全部 `found:false`(页面实为 invoice_info不是发票管理页
- **换手机风险**:中。这个节点本身是"误判纠偏",新手机上 XML 文本可能更不稳定导致更频繁误判。
### 节点 3 · 纠偏后探测页面 `vision_detect_page()` 【条件触发】
- **触发**:节点 2 找不到「查看」后,调 `vision_detect_page()` 判断真实页面类型
- **代码**`invoice_tool.py:1116`
- **截图落盘**`work/last_screenshot.png`(覆盖,覆盖节点 1 的图)
- **输出**`{page, summary}`
- **实测**3 次,全部正确识别为 `invoice_info`summary="待开票页面显示车票信息及开具按钮"
- **换手机风险**:低(只返回页面类型,无坐标)。
### 节点 4 · 找「开具」`_vision_find_button("开具")` 【条件触发·关键】
- **触发**:节点 3 判定为 invoice_info 后,改找「开具」按钮
- **代码**`invoice_tool.py:1280`
- **截图落盘**`work/_vision_find_tmp.png`(覆盖)
- **输出**:像素 (x,y)
- **实测**3 次,全部 `found:true`,坐标 (1071,1047) / (1071,1044) 等
- **换手机风险**:中。模型识别能力依赖,新手机按钮样式/位置不同可能 found:false。
### 节点 5 · 找「确认」`_vision_find_button("确认")` 【高频·几乎必走视觉】
- **触发**发票确认页XML 找不到「确认」按钮时 fallback
- **代码**`_xml_or_vision_click` -> `_vision_find_button`
- **截图落盘**`work/_vision_find_tmp.png`(覆盖)
- **输出**:像素 (x,y)
- **实测**3 次,全部 `found:true`,坐标 (850,2153)
- **换手机风险****高**。H5 页面常无 text几乎必走视觉。新手机上 if found:false 会直接卡死子流程。
### 节点 6 · 找「继续开票」`_vision_find_button("继续开票")` 【条件触发·当前已失效】
- **触发**:成功页找「继续开票」回列表
- **代码**`_xml_or_vision_click`
- **截图落盘**`work/_vision_find_tmp.png`(覆盖)
- **输出**None
- **实测**3 次,**全部 `found:false`**XML 也找不到),走兜底 `click=download_done_ok` + `click=continue_invoice`
- **换手机风险**:高。当前机型就已经视觉找不到,新手机只会更糟。靠 XML 兜底 bounds 硬编码。
### 节点 7 · 进列表页 - 找「扫码开票」`_vision_find_button("扫码开票")` 【条件触发】
- **触发**precheck 不在列表页时,`auto_scan_qr_to_list` 自动扫码进入
- **代码**`invoice_tool.py:1280`
- **截图落盘**`work/_vision_find_tmp.png`(覆盖)
- **输出**:像素 (x,y)
- **实测**2 次,`found:true`,坐标 (1102,204) / (1097,204)
- **换手机风险**中。recover 路径依赖,新手机上 if found:false 会 recover 失败。
### 节点 8 · 相册找 QR 缩略图 `_vision_find_qr_thumbnail()` 【条件触发】
- **触发**auto_scan 扫码进相册选码时
- **代码**`invoice_tool.py:1610`
- **截图落盘**:见代码(未细查,应同 `last_screenshot.png`
- **输出**QR 缩略图坐标
- **换手机风险**:低(归一化坐标)。但相册布局不同可能影响识别。
## 三、校准工具(`calibrate.py`)对应这 8 个节点中的哪些
`calibrate.py``CALIBRATION_STEPS` 定义了 8 个校准状态,手动导航到对应页面后截图 + 视觉分析,验证"这个按钮在这台手机上模型认不认得"。对应关系:
| 校准 step_id | 校准状态 | 对应运行节点 | 校准验证的按钮 |
|---|---|---|---|
| `list_page` | H5 列表页 | 节点 1vision_list_rows | 「开具」 |
| `verify_page` | 身份核验页 | (运行时走 XML不视觉 | 「核验」 |
| `invoice_info` | 发票信息页 | 节点 4找「开具」+ 节点 2/3 纠偏 | 「提交」 |
| `invoice_confirm` | 发票确认页 | 节点 5找「确认」 | 「确认」 |
| `success_page` | 开票成功页 | 节点 6找「继续开票」 | 「发票预览/下载」「下载」「继续开票」 |
| `no_ticket` | 无票页 | (运行时走 XML 判断) | 无 |
| `loading` | 开具中 | (运行时走 XML 判断) | 无 |
| `album_qr` | 相册选码 | 节点 8找 QR 缩略图) | 无(找 QR 缩略图) |
**节点 7找「扫码开票」没有对应校准 step**--它是 recover 路径,校准时手机不在列表页才能触发,与 `list_page` 校准状态互斥。这是校准工具的一个缺口。
## 四、换手机适配操作步骤
### 步骤 1 · 生成 `device_profiles.json` 中当前设备的档案(解决 A/B 类硬编码问题)
1. Web UI 打开 `http://127.0.0.1:8765/calibrate`
2. 页面自动读 `adb shell wm size` 显示新手机分辨率
3. 点「💾 保存设备配置」--即使不逐状态截图,也会按分辨率比例计算滑动参数 + 防熄屏 tap写入 `work/device_profiles.json`
4. 之后 `invoice_tool.py``apply_speed_defaults` 会自动读这个 profile 覆盖硬编码默认值
**这一步就能解决大部分"滑动幅度不对导致跳行/重复"问题。**
### 步骤 2 · 逐状态截图校准(验证 C 类视觉识别问题)
1. 在新手机上手动导航到校准 step 对应的页面
2. 点该 step 的「截图」按钮 -> `work/calibration/<step_id>.png`
3. 点「分析」-> 跑视觉 API`page_ok` 和每个按钮的 `found`
4. 全绿点「保存设备配置」-> 把校准结果一并存进当前 serial 的设备档案
**重点验证这几个高风险按钮**(运行时几乎必走视觉、且当前机型已暴露问题):
- `invoice_confirm` 页的「确认」--运行时高频视觉 fallbackfound:false 直接卡死
- `success_page` 页的「继续开票」--当前机型已 found:false新手机大概率也不行需确认 XML 兜底 bounds 是否对得上
- `invoice_info` 页的「开具」--after_verify 超时纠偏链路的关键
### 步骤 3 · 跑一次 dry-run 验证
```bash
python3 scripts/invoice_tool.py android-h5-page-run --dry-run --max-actions 1
```
确认滑动、防熄屏 tap、列表识行正常后再正式跑。
## 五、当前已暴露的问题(非换手机专项,但换手机会放大)
跟踪当前日志1260×2800 原机型)发现的既有问题,换手机后会因视觉识别能力下降而放大:
1. **after_verify 必超时**:每个乘客都 `wait_page_more label=after_verify reason=network_or_loading extra=12.0s`XML 12s 内拿不到稳定文本,全靠视觉纠偏。新手机上 XML 可能更不稳。
2. **「继续开票」视觉恒 found:false**3/3 失败,靠 XML 硬编码 bounds 兜底。新手机 bounds 不同会直接失败。
3. **陈**杰「核验弹窗存在,但未解析出脱敏姓名」**:非截屏问题,是 XML 解析逻辑问题,连续两次报错走 recover。
## 六、截图留档建议(当前缺陷)
当前两个截图路径都是单文件覆盖,无法回溯:
- `work/last_screenshot.png` -- vision_list_rows / vision_detect_page 覆盖
- `work/_vision_find_tmp.png` -- _vision_find_button 覆盖
**换手机排错时建议**:在跑流程前手动备份,或改代码让每次视觉调用按 `work/screenshots/<timestamp>_<node>.png` 留档。否则报错时只能看 `last_screenshot.png`(已被后续节点覆盖)。
校准工具的 `work/calibration/<step_id>.png` 是按状态命名不覆盖,可用于静态比对,但不能反映运行时实际页面。