"""Export causal, continuous MaAI scores for EOT Studio (no label gating).""" import csv import hashlib import json from smoke_run import HERE, ROOT, EXPECTED, WEIGHTS, CPC, np, sf, soxr, torch from evaluate_can_reply import model def main(): torch.set_num_threads(4) torch.set_num_interop_threads(1) for p in (WEIGHTS, CPC): assert hashlib.sha256(p.read_bytes()).hexdigest() == EXPECTED[p.name] with (HERE/'results/work-data-can-reply/predictions.csv').open(encoding='utf-8-sig') as f: checkpoints = list(csv.DictReader(f)) calls = [] for call in sorted({r['call_id'] for r in checkpoints}): path = ROOT/'data/韩泰机器人抢话/音频'/f'{call}.mp3' pcm, sr = sf.read(path, dtype='float32', always_2d=True) assert pcm.shape[1] == 2 maai = model() maai.CALC_PROCESS_TIME_INTERVAL = 10**9 resampler = soxr.ResampleStream(sr,16000,2,dtype='float32',quality='HQ') pending = np.empty((0,2),dtype=np.float32) points = [] # Streaming resampling never reads the next input block. Timestamp each # result when its audio is actually available, including filter delay. for start in range(0,len(pcm),sr//10): end = min(len(pcm),start+sr//10) block = resampler.resample_chunk(pcm[start:end],last=end==len(pcm)) pending = np.concatenate([pending,block]) score = None while len(pending)>=1600: frame,pending = pending[:1600],pending[1600:] maai.process(np.ascontiguousarray(frame[:,0]),np.ascontiguousarray(frame[:,1])) result = maai.result_dict_queue.get_nowait() score = 1-float(result['p_now'][0]) assert np.isfinite(score) and 0<=score<=1 if score is not None: points.append([round(end*1000/sr,3),round(score,7)]) calls.append(dict(call_id=call,audio_path=f'韩泰机器人抢话/音频/{call}.mp3', audio_sha256=hashlib.sha256(path.read_bytes()).hexdigest(), duration_ms=round(len(pcm)*1000/sr,3),points=points, checkpoints=sorted([[int(r['decision_ms']),round(1-float(r['p_now_user']),7)] for r in checkpoints if r['call_id']==call]))) del maai print(f'{call[:8]}: {len(points)} timeline scores',flush=True) output = dict(schema_version=1,model='maai',name='MaAI',sample_interval_ms=100, score='1 - p_now[user]', method='Continuous stereo replay, 16kHz, 10Hz, CPC + ch_kyoto noise-robust VAP, 20s KV cache. Causal streaming resampler; timestamps denote input availability. Checkpoints retain the earlier independent <=20s point evaluation.', model_sha256=EXPECTED,script_sha256=hashlib.sha256((HERE/'export_timeline.py').read_bytes()).hexdigest(),calls=calls) (HERE/'results/score-timeline.json').write_text(json.dumps(output,ensure_ascii=False,separators=(',',':'))+'\n') if __name__=='__main__': main()