File size: 3,427 Bytes
0690c04 | 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 | """Bounded prompt-development experiment on frozen synthetic cases (not held-out)."""
import asyncio,argparse,json,time,sys
from pathlib import Path
import numpy as np
from duplex_cases import CASES
from coreai_d3 import D3CoreAI
from d3_format import render
from d3_runtime import normalize_question
VARIANTS={
'short_cn':dict(type='choice',instructions='根据对话状态判断如何处理用户刚说的话。注意:对问题的简短回答也是有效输入;附和不需要回复。',criteria={
'interrupt':'助手还在说话,用户要求停下、暂停、取消,纠正助手,或必须立即改变当前话题。',
'discard':'噪声、助手回声、对别人说话、单纯附和或感谢。助手正说话时要求继续,或空闲无任务时要求停止,也忽略。',
'enqueue':'其他有意义的问题、请求、补充或回答;保留并稍后处理。助手空闲时也接纳。',}),
'short_en':dict(type='choice',instructions='How should a voice assistant handle the latest user utterance? Use the playback state and preceding question. Short answers to a question are meaningful.',criteria={
'interrupt':'While the assistant is speaking: stop/pause/cancel it, correct what it is saying, urgently switch tasks, or warn of danger.',
'discard':'Noise, confirmed echo, speech to another person, or acknowledgment needing no reply. Also continue when already speaking, or stop when idle with no task.',
'enqueue':'A meaningful question, request, information, or answer that can be processed next. When idle, accept meaningful input this way.',}),
}
def state_text(c):
s=c['state']
return '助手状态:'+('正在播报' if s['assistant_speaking'] else '当前没有播报')+'\n助手最近说:'+s['last_assistant_utterance']+'\n输入来源:'+{'user':'用户对助手说话','non_speech':'非语音噪声','confirmed_assistant_echo':'已确认是助手回声','not_addressed_to_assistant':'对其他人说话'}[s['input_origin']]+'\n用户本次说:'+s['user_transcript']
def summary(rows):
labels=['interrupt','discard','enqueue'];conf={x:{y:0 for y in labels} for x in labels}
for r in rows:conf[r['expected']][r['choice']]+=1
return dict(cases=len(rows),correct=sum(r['expected']==r['choice'] for r in rows),confusion=conf,false_discard=sum(r['choice']=='discard' and r['expected']!='discard' for r in rows),false_interrupt=sum(r['choice']=='interrupt' and r['expected']!='interrupt' for r in rows),missed_interrupt=sum(r['choice']!='interrupt' and r['expected']=='interrupt' for r in rows),median_seconds=float(np.median([r['seconds'] for r in rows])))
async def main(a):
engine=await D3CoreAI.load(a.bundle);results={}
for name,q in VARIANTS.items():
rows=[]
for c in CASES:
s=state_text(c);t=time.perf_counter();logits,keys,encoded=await engine.logits(s,q)
p=np.exp(logits-logits.max());p/=p.sum()
r=dict(id=c['id'],expected=c['expected'],choice=keys[int(p.argmax())],probabilities=p.tolist(),seconds=time.perf_counter()-t,tokens=int(len(encoded['input_ids'][0])))
rows.append(r)
results[name]=dict(question=q,summary=summary(rows),records=rows)
Path(a.output).write_text(json.dumps(results,ensure_ascii=False,indent=2)+'\n');print(name,results[name]['summary'],flush=True)
if __name__=='__main__':
p=argparse.ArgumentParser();p.add_argument('--bundle',default='.');p.add_argument('--output',required=True);a=p.parse_args();asyncio.run(main(a))
|