speaker-verification
audio
nemotron
tyger
experimental
File size: 4,443 Bytes
0efd0f1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
"""Sequential, fail-closed final QA. One live slot; never stop other sessions.

Uses only public synthetic fixtures/fake browser devices. Does not start/stop
services, publish files remotely, or change model weights.
"""
import argparse,hashlib,json,subprocess,sys,time
from pathlib import Path

ROOT=Path(__file__).resolve().parent

def runtime_signature():
    files=[ROOT/n for n in ('server.py','speaker_session.py','speaker_turns.py','speaker_runtime.py','speaker_teacher.py',
        'speaker_names.py','identity.py','audio_sync.py','feature_tap.py','paths.py','tts_bridge.py','shared_turn.py')]
    for pattern in ('*.js','*.css','emotion-catalog.json','index.html','robby.svg'):files+=sorted((ROOT/'static').glob(pattern))
    return hashlib.sha256(b''.join(p.read_bytes() for p in files)).hexdigest()

def main(url,max_repeats=0):
    py=sys.executable
    browser=['uv','run','--no-project','--with','playwright','--python',py]
    stages=[('unit',[py,'run_unit_checks.py'],60),
        ('fixture_asr',[py,'-m','speaker_live.fixture_qa'],120),
        ('three_people',[py,'-m','speaker_live.multi_test','--extended','--background-shift','0','--max-repeats',str(max_repeats)],360),
        ('three_people_shifted',[py,'-m','speaker_live.multi_test','--extended','--background-shift','2.3','--max-repeats',str(max_repeats)],360),
        ('streamed_echo',[py,'-m','speaker_live.echo_test'],180),
        ('browser_original',browser+['browser_mic_checks.py','--url',url],180),
        ('browser_desk',browser+['browser_mic_checks.py','--url',url.rstrip('/')+'/desk-robot/'],180),
        ('microphone_lifecycle',browser+['browser_lifecycle_checks.py'],60),
        ('desk_cpu',browser+['desk_robot_checks.py','--url',url.rstrip('/')+'/desk-robot/'],90),
        ('clock_camera',['uv','run','--no-project','--with','playwright','--with','numpy==1.26.4','--python',py,
            'browser_checks.py','--url',url.rstrip('/')+'/desk-robot/','--camera'],90),
        ('native_features',[py,'-m','speaker_v4.preflight'],90),
        ('selective_dataset_safety',[py,'-m','pytest','-q','speaker_v2/test_dataset_pipeline.py'],60)]
    source_hash=runtime_signature()
    report={'started':time.time(),'synthetic_only':True,'physical_microphone_used':False,
        'runtime_source_sha256':source_hash,'url':url,'max_explicit_repeats_per_turn':max_repeats,
        'first_pass_guaranteed':False,'stages':[],'passed':False}
    target=ROOT/'logs/final-verification.json'
    def save():target.write_text(json.dumps(report,indent=2))
    save()
    for name,command,timeout in stages:
        print('START '+name,flush=True);start=time.monotonic()
        record={'name':name,'passed':False,'started':time.time()};report['stages'].append(record);save()
        with (ROOT/'logs'/('verify-'+name+'.log')).open('w') as output:
            try:
                result=subprocess.run(command,cwd=ROOT,stdout=output,stderr=subprocess.STDOUT,timeout=timeout)
                record.update(exit_code=result.returncode,passed=result.returncode==0)
            except subprocess.TimeoutExpired:record.update(exit_code=None,timed_out=True)
        record['seconds']=time.monotonic()-start;save()
        print(json.dumps(record),flush=True)
        if not record['passed']:raise SystemExit('Final QA stopped at '+name+'; see its synthetic-only test log')
        if name=='three_people':
            # Keep both independently timed conversation receipts, not only
            # the shifted-background rerun that uses the same output filename.
            import shutil
            source=Path('/mnt/nvme/robo-speaker-studies/speaker-live-results/three-user-live.json')
            shutil.copyfile(source,source.with_name('three-user-unshifted.json'))
    final_hash=runtime_signature()
    report.update(finished=time.time(),passed=source_hash==final_hash,source_unchanged=source_hash==final_hash);save()
    if not report['passed']:raise SystemExit('Runtime source changed during final QA; results are not a frozen-source pass')
    print('All final checks passed on unchanged runtime source.',flush=True)

if __name__=='__main__':
    p=argparse.ArgumentParser();p.add_argument('--url',default='https://diane-asylum-understood-invoice.trycloudflare.com/')
    p.add_argument('--max-repeats',type=int,choices=(0,1),default=0,help='0: strict first pass; 1: explicitly reported bounded-recovery test')
    args=p.parse_args();main(args.url,args.max_repeats)