啟用條件
當使用者想要一個有語音解說的影片來說明功能或重現錯誤,或者當純截圖無法展示流程(時序、步驟順序、狀態變化)時載入。對於單一靜態狀態,截圖就足夠:請不要錄製影片。
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、非同步任務):在錄製的影格中檢查結果。如果應用程式執行的結果與旁白所述不同,請重新錄製;絕對不要發布語音與畫面內容矛盾的影片。
決策關卡
| 情境 | 動作 |
|---|---|
| 錯誤報告 | assets/bug-template.json:contexto → pasos → actual(紅色標註)→ esperado(綠色)→ evidencia → impacto |
| 功能 / 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)及 waitFor 來等待 UI 結果 |
| gdigrab 執行失敗,顯示「never became visible on screen」 | 工作空間視窗被隱藏或遮擋。請使用者在 ego 中選擇該空間並重新執行;不要聲稱或重複使用使用者自己的空間或分頁 |
| 需要模擬或複雜步驟 | actionsModule 搭配匯出的 async (page, ctx) 函式,透過 { "call": "name" } 呼叫 |
| 錯誤的證據步驟 | 從第一次執行讀取 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 會對原始 CSS 選擇器使用 page.evaluate/waitForFunction。
場景欄位: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)。