"""Real private API regression. Run on the service host with synthetic speech/mix WAVs. Environment AUDIO_QA_ENV names a private service env file. --restart exercises recovery. """ import sys,os,json,time,hashlib,urllib.request,urllib.error,subprocess from pathlib import Path import numpy as np import soundfile as sf env=dict(l.split('=',1) for l in Path(os.environ['AUDIO_QA_ENV']).read_text().splitlines() if '=' in l and not l.startswith('#')) base=os.environ.get('AUDIO_QA_URL','http://127.0.0.1:18342');token=env['AUDIO_API_TOKEN'] root=Path(sys.argv[3]);root.mkdir(parents=True,exist_ok=True) def call(route,body=None,method=None): data=json.dumps(body).encode() if isinstance(body,dict) else body r=urllib.request.Request(base+route,data=data,method=method,headers={'Authorization':'Bearer '+token,'Content-Type':'application/json' if isinstance(body,dict) else 'audio/wav'}) with urllib.request.urlopen(r,timeout=60) as response:return response.read() def state(route,body=None,method=None):return json.loads(call(route,body,method)) def rejects(code,route,body=None,method=None): try:call(route,body,method) except urllib.error.HTTPError as e:assert e.code==code,(e.code,code);return raise AssertionError('Expected HTTP '+str(code)) try:urllib.request.urlopen(base+'/health',timeout=10);raise AssertionError('Missing authentication') except urllib.error.HTTPError as e:assert e.code==401 report={} for operation,file in [('transcribe',Path(sys.argv[1])),('separate',Path(sys.argv[2]))]: data=file.read_bytes();digest=hashlib.sha256(data).hexdigest() jid=hashlib.sha256(('real-audio-qa-v1:'+operation+digest).encode()).hexdigest() body={'id':jid,'tenant':hashlib.sha256(b'audio-qa').hexdigest(),'plan':{'operation':operation,'sha256':digest,'bytes':len(data)}} job=state('/v1/audio-jobs',body) rejects(409,'/v1/audio-jobs',{**body,'plan':{**body['plan'],'bytes':len(data)+1}}) if job['status']=='awaiting-input': rejects(400,'/v1/audio-jobs/'+jid+'/input',b'wrong','PUT') job=state('/v1/audio-jobs/'+jid+'/input',data,'PUT') restarted=False;start=time.monotonic() for i in range(600): job=state('/v1/audio-jobs/'+jid) if operation=='separate' and '--restart' in sys.argv and job['status']=='running' and not restarted: subprocess.run(['systemctl','restart','audio-processing'],check=True);time.sleep(3);restarted=True;continue if job['status'] in ('succeeded','failed'):break time.sleep(1) assert job['status']=='succeeded',job assert state('/v1/audio-jobs',body)['attempts']==job['attempts'] if restarted:assert job['attempts']==2,job if operation=='transcribe': subs=job['result']['subtitles'];text=''.join(s['text'] for s in subs) assert '智能剪辑' in text and '人声分离' in text,text assert len(subs)>=2 and all(0<=s['start']