Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 

38 Zeilen
3.7 KiB

  1. import fs from 'node:fs';
  2. import { execFileSync } from 'node:child_process';
  3. import { chromium } from '@playwright/test';
  4. const silence = process.argv.includes('--silence');
  5. const dir = `reports/bridge-lipsync-diagnosis-20260914${silence ? '-silence' : ''}`; fs.mkdirSync(dir, { recursive: true });
  6. const input = 'reports/bridge-digital-video-20260914/TASK-VIRTUAL-005-step-03.mp4';
  7. execFileSync('ffmpeg', ['-hide_banner','-loglevel','error','-y','-i',input,'-vn','-ar','16000','-ac','1','-c:a','pcm_s16le',`${dir}/sample.wav`]);
  8. 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`]);
  9. const origin = 'http://1.14.103.234:8123';
  10. 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}`] });
  11. try {
  12. const context=await browser.newContext({ viewport:{width:480,height:640},acceptDownloads:true });
  13. 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>'}));
  14. const page=await context.newPage(), errors=[];page.on('pageerror',e=>errors.push(e.message));
  15. await page.goto(`${origin}/__open-render__`);
  16. const frame=page.frames().find(f=>f.url().includes('/viewer/'));
  17. await frame.waitForFunction(()=>window.DH_RUNTIME_READY,{},{timeout:120000});
  18. await frame.evaluate(()=>{
  19. window.lipDiagnostic={frames:[],start:performance.now(),events:[]};
  20. const bs=Module._updateBlendShape, set=Module._setAudioBuffer;
  21. 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;};
  22. 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;};
  23. });
  24. const capture=fs.readFileSync('../../ai_person/ai_person_api/app/services/open_render_capture.js','utf8');
  25. 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} });
  26. await page.waitForFunction(()=>['done','error'].includes(window.openCapture?.status),{},{timeout:120000});
  27. const result=await frame.evaluate(()=>window.lipDiagnostic);
  28. result.capture=await page.evaluate(()=>window.openCapture);result.errors=errors;
  29. if (result.capture.status === 'done') {
  30. const downloadPromise = page.waitForEvent('download');
  31. await page.evaluate(()=>{const a=document.createElement('a');a.href=window.openCapture.url;a.download='diagnostic.webm';a.click();});
  32. await (await downloadPromise).saveAs(`${dir}/diagnostic.webm`);
  33. }
  34. const active=result.frames.filter(f=>f.t>=result.events[0]?.t);
  35. 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};
  36. 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}));
  37. } finally {await browser.close();}