|
- import fs from 'node:fs';
- import { execFileSync } from 'node:child_process';
- import { chromium } from '@playwright/test';
- const silence = process.argv.includes('--silence');
- const dir = `reports/bridge-lipsync-diagnosis-20260914${silence ? '-silence' : ''}`; fs.mkdirSync(dir, { recursive: true });
- const input = 'reports/bridge-digital-video-20260914/TASK-VIRTUAL-005-step-03.mp4';
- execFileSync('ffmpeg', ['-hide_banner','-loglevel','error','-y','-i',input,'-vn','-ar','16000','-ac','1','-c:a','pcm_s16le',`${dir}/sample.wav`]);
- if (silence) execFileSync('ffmpeg', ['-hide_banner','-loglevel','error','-y','-f','lavfi','-i','anullsrc=r=16000:cl=mono','-t','8.241','-c:a','pcm_s16le',`${dir}/sample.wav`]);
- const origin = 'http://1.14.103.234:8123';
- const browser = await chromium.launch({ channel:'msedge', headless:true, args:['--autoplay-policy=no-user-gesture-required','--use-gl=angle','--use-angle=swiftshader','--enable-unsafe-swiftshader',`--unsafely-treat-insecure-origin-as-secure=${origin}`] });
- try {
- const context=await browser.newContext({ viewport:{width:480,height:640},acceptDownloads:true });
- await context.route(`${origin}/__open-render__`,r=>r.fulfill({contentType:'text/html',body:'<iframe src="/viewer/a1000000000000000000000000000005" allow="autoplay" style="width:100vw;height:100vh"></iframe>'}));
- const page=await context.newPage(), errors=[];page.on('pageerror',e=>errors.push(e.message));
- await page.goto(`${origin}/__open-render__`);
- const frame=page.frames().find(f=>f.url().includes('/viewer/'));
- await frame.waitForFunction(()=>window.DH_RUNTIME_READY,{},{timeout:120000});
- await frame.evaluate(()=>{
- window.lipDiagnostic={frames:[],start:performance.now(),events:[]};
- const bs=Module._updateBlendShape, set=Module._setAudioBuffer;
- Module._updateBlendShape=function(p,n){const t=performance.now(),r=bs(p,n);window.lipDiagnostic.frames.push({t:t-window.lipDiagnostic.start,ms:performance.now()-t,values:Array.from(new Float32Array(Module.HEAPU8.buffer,p,12))});return r;};
- Module._setAudioBuffer=function(p,n){const r=set(p,n);window.lipDiagnostic.events.push({type:'setAudio',t:performance.now()-window.lipDiagnostic.start,n,result:r});return r;};
- });
- const capture=fs.readFileSync('../../ai_person/ai_person_api/app/services/open_render_capture.js','utf8');
- await page.evaluate(({ script, args }) => eval(`(${script}\n)`)(args), { script: capture, args: {audio:fs.readFileSync(`${dir}/sample.wav`).toString('base64'),background:null,backgroundVideo:false,width:480,height:640,text:'口型同步诊断',subtitles:false,maxSeconds:120} });
- await page.waitForFunction(()=>['done','error'].includes(window.openCapture?.status),{},{timeout:120000});
- const result=await frame.evaluate(()=>window.lipDiagnostic);
- result.capture=await page.evaluate(()=>window.openCapture);result.errors=errors;
- if (result.capture.status === 'done') {
- const downloadPromise = page.waitForEvent('download');
- await page.evaluate(()=>{const a=document.createElement('a');a.href=window.openCapture.url;a.download='diagnostic.webm';a.click();});
- await (await downloadPromise).saveAs(`${dir}/diagnostic.webm`);
- }
- const active=result.frames.filter(f=>f.t>=result.events[0]?.t);
- result.summary={frameCount:active.length,elapsedMs:active.at(-1)?.t-active[0]?.t,fps:active.length/((active.at(-1)?.t-active[0]?.t)/1000),maxBlend:Math.max(...active.flatMap(f=>f.values.map(Math.abs))),nonZeroFrames:active.filter(f=>f.values.some(v=>Math.abs(v)>.001)).length};
- fs.writeFileSync(`${dir}/runtime.json`,JSON.stringify(result,null,2));console.log(JSON.stringify({summary:result.summary,events:result.events,capture:result.capture.status,errors}));
- } finally {await browser.close();}
|