Files
CyberGril/samples/companion/tools/baseline.py
T

51 lines
3.2 KiB
Python

import asyncio
import json
import pathlib
from playwright.async_api import async_playwright
OUT = pathlib.Path(__file__).resolve().parents[1] / "evidence"
OUT.mkdir(exist_ok=True)
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch(
args=["--no-sandbox", "--autoplay-policy=no-user-gesture-required"]
)
page = await browser.new_page()
await page.goto("http://192.168.200.12:8010")
await page.evaluate("""async () => {
document.body.innerHTML='<video id="v" autoplay playsinline></video><canvas id="c" width="768" height="768"></canvas>';
const v=document.querySelector('video'), c=document.querySelector('canvas'), ctx=c.getContext('2d');
const ac=new AudioContext(), dest=ac.createMediaStreamDestination();
const pc=window.pc=new RTCPeerConnection({iceServers:[]});
const stream=new MediaStream(); v.srcObject=stream;
pc.ontrack=e=>stream.addTrack(e.track);
pc.addTransceiver('audio',{direction:'recvonly'}); pc.addTransceiver('video',{direction:'recvonly'});
await pc.setLocalDescription(await pc.createOffer());
await new Promise(r=>{if(pc.iceGatheringState==='complete')r();else pc.onicegatheringstatechange=()=>{if(pc.iceGatheringState==='complete')r()}});
const a=await (await fetch('/offer',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(pc.localDescription)})).json();
window.sid=a.sessionid; await pc.setRemoteDescription(a);
await new Promise(r=>v.onloadeddata=r); await v.play();
v.muted=true; const source=ac.createMediaStreamSource(stream); source.connect(ac.destination); source.connect(dest);
await ac.resume(); const recorded=c.captureStream(25); dest.stream.getAudioTracks().forEach(t=>recorded.addTrack(t));
window.metrics=[]; const analyser=ac.createAnalyser();source.connect(analyser);let buffer=new Float32Array(analyser.fftSize);
function draw(){ctx.drawImage(v,0,0,768,768);ctx.fillStyle='white';ctx.font='20px sans-serif';ctx.fillText((performance.now()/1000).toFixed(3),20,750);analyser.getFloatTimeDomainData(buffer);metrics.push([performance.now(),Math.sqrt(buffer.reduce((s,x)=>s+x*x,0)/buffer.length)]);window.raf=requestAnimationFrame(draw)}draw();
window.chunks=[];window.rec=new MediaRecorder(recorded,{mimeType:'video/webm;codecs=vp8,opus'});rec.ondataavailable=e=>chunks.push(e.data);rec.start(1000);
}""")
await page.wait_for_timeout(1500)
await page.evaluate(
"""async()=>{window.sent=performance.now();await fetch('/human',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({sessionid:sid,type:'echo',text:'你好。八百标兵奔北坡,炮兵并排北边跑。现在我停下来听你说话。'})})}"""
)
await page.wait_for_timeout(18000)
data = await page.evaluate(
"""async()=>{await new Promise(r=>{rec.onstop=r;rec.stop()});const b=new Blob(chunks);return Array.from(new Uint8Array(await b.arrayBuffer()))}"""
)
(OUT / "baseline-browser-av.webm").write_bytes(bytes(data))
(OUT / "baseline.json").write_text(json.dumps(await page.evaluate("({sent,metrics})")))
await browser.close()
asyncio.run(main())