|
- import fs from 'node:fs';
- import path from 'node:path';
- import { chromium } from '@playwright/test';
-
- const root = path.resolve('../..');
- const sourceReport = path.resolve('reports/instructors-v2-20260914');
- const report = path.resolve(process.env.REPORT_DIR || sourceReport);
- fs.mkdirSync(report,{recursive:true});
- const stable = process.argv.includes('--stable');
- const jobs = JSON.parse(fs.readFileSync(`${sourceReport}/jobs.json`, 'utf8'));
- const origin = process.env.BASE_URL || 'http://127.0.0.1:8003';
- const audio = fs.readFileSync(`${root}/unreal_tran/ute2e/reports/bridge-lipsync-diagnosis-20260914/sample.wav`).toString('base64');
- 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'] });
- const results = [];
- try {
- for (const job of jobs) {
- const id = stable ? job.stable_id : job.avatar_id;
- const context = await browser.newContext({ viewport: { width: 560, height: 760 } });
- await context.route(`${origin}/__instructor-v2-check`, route => route.fulfill({ contentType: 'text/html', body:
- `<html><meta charset="utf-8"><body style="margin:16px;background:#f3f8f7;font:16px sans-serif"><h3>教员${job.number} · v2 语音驱动预览</h3><iframe style="border:0;width:480px;height:640px" src="/human/viewer/${id}" allow="autoplay"></iframe><script>window.events=[];addEventListener('message',e=>{if(e.origin===location.origin&&e.data?.type?.startsWith('digital-human.'))window.events.push(e.data)});</script></body></html>` }));
- const page = await context.newPage();
- const errors = [];
- page.on('pageerror', error => errors.push(error.message));
- await page.goto(`${origin}/__instructor-v2-check`);
- const frame = page.frames().find(frame => frame.url().includes('/human/viewer/'));
- await frame.waitForFunction(() => window.DH_RUNTIME_READY, {}, { timeout: 120000 });
- await frame.evaluate(() => {
- window.v2Check = { frames: 0, active: 0, maxBlend: 0 };
- const original = Module._updateBlendShape;
- Module._updateBlendShape = function(pointer, count) {
- const result = original(pointer, count);
- const max = Math.max(...Array.from(new Float32Array(Module.HEAPU8.buffer, pointer, 12)).map(Math.abs));
- window.v2Check.frames++;
- window.v2Check.maxBlend = Math.max(window.v2Check.maxBlend, max);
- if (max > .001) window.v2Check.active++;
- return result;
- };
- });
- await page.screenshot({ path: `${report}/${stable ? 'stable' : 'generated'}-${job.number}-idle.png` });
- await page.evaluate(audioBase64 => document.querySelector('iframe').contentWindow.postMessage({
- type: 'digital-human.play-audio', requestId: 'v2-validation', audioBase64,
- }, location.origin), audio);
- await page.waitForFunction(() => window.events.some(event => event.type === 'digital-human.speaking-start'), {}, { timeout: 15000 });
- await frame.waitForFunction(() => window.v2Check.active > 30, {}, { timeout: 15000 });
- await page.screenshot({ path: `${report}/${stable ? 'stable' : 'generated'}-${job.number}-speaking.png` });
- await page.waitForFunction(() => window.events.some(event => event.type === 'digital-human.speaking-end'), {}, { timeout: 20000 });
- const events = await page.evaluate(() => window.events);
- const driver = await frame.evaluate(() => window.v2Check);
- if (errors.length || events.some(event => event.type === 'digital-human.error')) throw new Error(JSON.stringify({ errors, events }));
- const result = { number: job.number, avatarId: id, driver, events, errors };
- results.push(result);
- console.log(JSON.stringify(result));
- fs.writeFileSync(`${report}/${stable ? 'stable' : 'generated'}-viewer-validation.json`, JSON.stringify(results, null, 2));
- await context.close();
- }
- } finally { await browser.close(); }
|