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

11 KiB
Raw Blame History

换手机适配 · 截屏节点与适配清单

目的:换手机后开票流程报错时,按此清单逐节点排查。

配套工具:scripts/calibrate.pyWeb UI 的 /calibrate 页)+ work/device_profiles.json(按 ADB 序列号分设备保存)。

相关文档: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_infosummary="待开票页面显示车票信息及开具按钮"
  • 换手机风险:低(只返回页面类型,无坐标)。

节点 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:falseXML 也找不到),走兜底 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.pyCALIBRATION_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.pyapply_speed_defaults 会自动读这个 profile 覆盖硬编码默认值

这一步就能解决大部分"滑动幅度不对导致跳行/重复"问题。

步骤 2 · 逐状态截图校准(验证 C 类视觉识别问题)

  1. 在新手机上手动导航到校准 step 对应的页面
  2. 点该 step 的「截图」按钮 -> work/calibration/<step_id>.png
  3. 点「分析」-> 跑视觉 APIpage_ok 和每个按钮的 found
  4. 全绿点「保存设备配置」-> 把校准结果一并存进当前 serial 的设备档案

重点验证这几个高风险按钮(运行时几乎必走视觉、且当前机型已暴露问题):

  • invoice_confirm 页的「确认」--运行时高频视觉 fallbackfound:false 直接卡死
  • success_page 页的「继续开票」--当前机型已 found:false新手机大概率也不行需确认 XML 兜底 bounds 是否对得上
  • invoice_info 页的「开具」--after_verify 超时纠偏链路的关键

步骤 3 · 跑一次 dry-run 验证

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.0sXML 12s 内拿不到稳定文本,全靠视觉纠偏。新手机上 XML 可能更不稳。
  2. 「继续开票」视觉恒 found:false3/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 是按状态命名不覆盖,可用于静态比对,但不能反映运行时实际页面。