激活协议
当用户想要一个带有语音解说的视频来解释功能或重现 Bug 时加载,或者当静态截图无法展示流程(时序、顺序、状态变化)时加载。对于单一静态状态,截图即可满足需求,请勿录制。
CLI 位于 C:\Users\DESARROLLADORES\Documents\personal\ai-video-evidence (node bin/narrate.mjs)。需要 Node 22+、PATH 中包含 ffmpeg/ffprobe、Google Chrome 以及 pip install edge-tts。
硬性规则
- 先编写脚本(
narration.json),验证通过后再录制。切勿手动录制和解说。 - 一个场景 = 一个想法,配一句话或两句话。语音必须描述该场景屏幕上的内容,绝不描述后续内容。
- 解说语言需与目标观众匹配(Trip2 PR 使用西班牙语)。默认语音:
es-CO-SalomeNeural;男声:es-CO-GonzaloNeural。 - 切勿输入密码。对于需要认证的应用,用户运行
narrate login <url>并登录,然后将browser.storageState指向保存的文件。录制完成后删除该文件,并确保其不被纳入 git。 - 仅使用用户确认过的测试数据。新记录添加
QA_前缀;切勿编辑或删除现有记录。 - 输出文件不要纳入 git(
out/、pr-assets/)。 - 非确定性流程(LLM、异步任务):在录制的帧中检查结果。如果应用执行了与解说内容不符的操作,则重新录制;切勿发布语音与画面矛盾的视频。
决策门
| 情况 | 操作 |
|---|---|
| Bug 报告 | assets/bug-template.json:上下文 → 步骤 → 实际结果(红色标注) → 预期结果(绿色) → 证据 → 影响 |
| 功能 / PR 演示 | assets/feature-template.json:解决了什么 → 操作流程 → 边界情况 |
| 后端等待或缓慢加载 | 将其设为独立场景,并添加 "speedup": 4;仅加速解说之后的部分 |
原生 <select> 弹出框、操作系统对话框,或应用需要用户的真实 ego 会话(Trip2 已登录) | "recorder": "gdigrab"(仅 Windows)。运行前:用户登录到应用的 ego 会话,保持显示器 1 空闲,并在运行器要求时准备好将 ego 切换到任务空间 narrate-<name>(ego 会隐藏 Agent 窗口;运行器会通过 Win32 将其升起,但 ego 仅绘制选中的空间)。无人值守运行 = 使用 playwright |
gdigrab 脚本使用了 call/actionsModule 或 waitForResponse | 不支持(验证错误):使用真实后端或本地服务器(examples/bug-demo/server.mjs)以及基于 UI 结果的 waitFor |
| gdigrab 运行失败并提示“never became visible on screen” | 任务空间窗口被隐藏或遮挡。要求用户在 ego 中选择该空间并重新运行;不要声明或重用用户自己的空间或标签页 |
| 需要模拟或复杂步骤 | 使用导出的 actionsModule,包含 async (page, ctx) 函数,通过 { "call": "name" } 调用 |
| Bug 的证据步骤 | 从第一次运行中读取 out/<name>/evidence.json(失败的响应、控制台错误),并在 evidencia 标注中放入真实的请求/状态 |
执行步骤
- 将匹配的模板复制到工作目录旁(Trip2:
pr-assets/<name>.json),填写title、baseUrl、场景和选择器。 - 运行
node bin/narrate.mjs validate <file>;修复所有报告的错误。 - 如果应用需要会话:对于
playwright,让用户运行node bin/narrate.mjs login <url> --save pr-assets/state.json,然后设置browser.storageState。对于gdigrab,用户需预先在 ego 中登录应用(Trip2 路径:baseUrl= 本地 Trip2 URL,recorder: "gdigrab",场景简短,无call)。 - 运行
node bin/narrate.mjs run <file>(也可分开运行tts、record、assemble;单独运行assemble可在不重新录制的情况下重新渲染)。 - 检查结果:使用
ffmpeg -ss <t> -frames:v 1从场景起始处(scenes.json)提取帧并查看;使用volumedetect确认音频;阅读evidence.json(gdigrab 模式下为空)。对于 gdigrab,确认帧中仅显示页面(没有桌面、任务栏或其他窗口位于上层)。 - 交付
<name>.mp4(H.264 + AAC + 软字幕)和<name>.srt。对于 Trip2 PR,请遵循trip2-pr-delivery:工件放在pr-assets/中,附加到 PR,并在描述中列出。
动作参考
goto(相对于 baseUrl)、click、hover、check(选择器)、fill/select {selector, value}、press {key, selector?}、scroll {selector? | y?}、wait(毫秒)、waitFor(选择器或 {selector, state, timeoutMs})、waitForResponse(URL 子串,也接受该场景中已看到的响应)、overlay {kind: actual|expected|info, title?, text | html, durationMs?}、screenshot(名称)、call(actionsModule 的导出)。选择器是 Playwright 定位器(#id、text=Guardar、role=button[name="Guardar"])。当使用 recorder: "gdigrab" 时,选择器原样传递给 ego:原始 CSS、text=...、loc=role:button[name='Guardar']、@ref;拒绝 call 和 waitForResponse;check、scroll {selector} 和 waitFor 使用 page.evaluate/waitForFunction 配合原始 CSS 选择器。
场景字段:id(slug)、say、chapter {title, description?, durationMs?}、actions、speedup。顶层字段:title、baseUrl、recorder(playwright | gdigrab)、gdigrab {framerate: 25, drawMouse: true, tab: "new"}、viewport(仅 Playwright)、tts {engine: edge|deepgram|sapi, voice, rate, fallback}、browser {channel, headless, locale, storageState}、captions、showActions、gapMs、actionsModule、output。
输出协议
返回:视频路径及时长、SRT 路径、使用的 TTS 引擎(及任何回退)、场景及其开始时间、evidence.json 捕获到的内容,以及任何无法显示的内容(原生弹出框、不稳定的步骤)。
参考资料
assets/bug-template.json、assets/feature-template.json— 脚本骨架。- 仓库
README.md— 安装、命令、同步方式。 examples/bug-demo/— 完整的可运行示例,包含模拟后端(narration.json,Playwright)及其 gdigrab 变体(narration-ego.json+server.mjs)。