Download code/browser_checks.py from laion/tyger-speaker-predictor: direct link, hf CLI and curl.
- Browser
- Download file 5.84 kB
-
https://huggingface.co/laion/tyger-speaker-predictor/resolve/main/code/browser_checks.py
- Command line
-
hf download hf://laion/tyger-speaker-predictor/code/browser_checks.py
-
curl -L -o browser_checks.py https://huggingface.co/laion/tyger-speaker-predictor/resolve/main/code/browser_checks.py
5.84 kB
| """Reproducible browser clock checks; optional actual API/voice and camera QA. | |
| uv run --no-project --with playwright --with numpy==1.26.4 --python /path/to/python browser_checks.py [--live] [--camera] | |
| The live fixture is synthetic text; microphone input is generated silence. | |
| """ | |
| import argparse | |
| import asyncio | |
| import json | |
| from pathlib import Path | |
| import subprocess | |
| import tempfile | |
| import numpy as np | |
| from playwright.async_api import async_playwright | |
| async def run(args): | |
| logs=Path(__file__).parent/'logs';logs.mkdir(exist_ok=True) | |
| with tempfile.TemporaryDirectory(prefix='robby-browser-') as temporary: | |
| silence=Path(temporary)/'synthetic-silence.wav' | |
| subprocess.run(['ffmpeg','-nostdin','-v','error','-f','lavfi','-i','anullsrc=r=48000:cl=mono', | |
| '-t','30',str(silence)],check=True) | |
| async with async_playwright() as playwright: | |
| browser=await playwright.chromium.launch(executable_path=args.chrome,headless=True, | |
| args=['--no-sandbox','--use-fake-device-for-media-stream','--use-fake-ui-for-media-stream', | |
| '--use-file-for-fake-audio-capture='+str(silence),'--autoplay-policy=no-user-gesture-required']) | |
| try: | |
| page=await browser.new_page(viewport={'width':1440,'height':1000}) | |
| errors=[];page.on('pageerror',lambda e:errors.append(str(e))) | |
| await page.goto(args.url);await page.wait_for_function('window.robo') | |
| clock=await page.evaluate('''async()=>{ | |
| const {PlaybackClock}=await import('/static/clock.js');let before=[],after=[]; | |
| for(const output of [.005,.02,.055,.15,.25])for(const input of [.005,.04,.12])for(const network of [0,.1,.5,.9]){ | |
| const context={currentTime:10.1,getOutputTimestamp:()=>({contextTime:10.1-output,performanceTime:10000})}; | |
| const c=new PlaybackClock(context);c.inputLatency=input;c.add(1,8,240000,0); | |
| const actual=Math.floor((10-output-input-8)*24000),tag=c.tag(10,10000)[1]; | |
| after.push(Math.abs(tag-actual)/24);before.push(Math.abs(output+input+network-.15)*1000); | |
| } | |
| const ctx={currentTime:9,baseLatency:0,outputLatency:0};const c=new PlaybackClock(ctx);c.inputLatency=0; | |
| c.add(1,9.005,240,0);const parts=c.pieces(9,320,16000,10000); | |
| if(JSON.stringify(parts.map(p=>[p.first,p.end,p.id]))!==JSON.stringify([[0,80,0],[80,240,1],[240,320,0]]))throw Error('Playback-edge split failed'); | |
| const d=new PlaybackClock({currentTime:9,baseLatency:.1,outputLatency:0});d.inputLatency=.02;d.add(2,8,48000,0);d.stop(9); | |
| const kept=d.tag(9.05,10000)[0]===2,cut=d.tag(9.5,10000)[1]===-1;if(!kept||!cut)throw Error('Cancel history failed'); | |
| return {before,after,playback_edge_split:true,cancel_keeps_history:kept,cancel_removes_future:cut}; | |
| }''') | |
| result={'protocol':'clock-v3 explicit latency grid','scenarios':len(clock['before']), | |
| 'before_p50_ms':float(np.median(clock['before'])),'before_p95_ms':float(np.percentile(clock['before'],95)), | |
| 'after_p50_ms':float(np.median(clock['after'])),'after_max_ms':max(clock['after']), | |
| **{k:v for k,v in clock.items() if k not in ('before','after')}, | |
| 'hardware_accuracy':'Ideal-clock simulation, not physical audio-device measurement'} | |
| await page.screenshot(path=str(logs/'robo-desktop.png')) | |
| await page.set_viewport_size({'width':390,'height':844});await page.screenshot(path=str(logs/'robo-mobile.png')) | |
| result['mobile_no_overflow']=await page.evaluate('document.documentElement.scrollWidth<=innerWidth') | |
| if args.camera: | |
| await page.click('.settings summary');await page.click('#camera') | |
| await page.wait_for_function('''()=>{let t=document.querySelector('#camera-status').textContent;return t.startsWith('Tracking locally')||t.startsWith('No face visible')||t.includes('unavailable')}''',timeout=60000) | |
| await page.wait_for_timeout(1000) | |
| result['camera_status']=await page.locator('#camera-status').text_content() | |
| result['camera_video_running']=await page.evaluate('document.querySelector("#video").readyState>=2') | |
| await page.click('#camera') | |
| if args.live: | |
| await page.click('#call');await page.wait_for_function('window.robo.ws?.readyState===1') | |
| await page.fill('#message','Say hello in just four words.');await page.click('button[type=submit]') | |
| await page.wait_for_function('window.robo.metrics.tagged_blocks>0',timeout=90000) | |
| await page.wait_for_function('document.querySelector("#phase-text").textContent==="Listening to you"',timeout=30000) | |
| result['live']=await page.evaluate('({...window.robo.metrics,clock:window.robo.clock.report()})') | |
| await page.evaluate('window.robo.stop()') | |
| result['page_errors']=errors | |
| assert not errors and result['mobile_no_overflow'] and result['after_max_ms']<.05,result | |
| (logs/'browser-checks.json').write_text(json.dumps(result,indent=2)) | |
| print(json.dumps(result,indent=2)) | |
| finally:await browser.close() | |
| if __name__=='__main__': | |
| parser=argparse.ArgumentParser();parser.add_argument('--url',default='http://127.0.0.1:8793') | |
| parser.add_argument('--chrome',default='/usr/bin/google-chrome');parser.add_argument('--live',action='store_true') | |
| parser.add_argument('--camera',action='store_true');asyncio.run(run(parser.parse_args())) | |