Files
story/firmware/echoear-platform-agent/tools/com6_voice_acceptance.py
T

52 lines
4.1 KiB
Python
Raw Normal View History

"""COM6-only fixed-sentence smoke test; retain numeric/audio-state evidence only."""
import datetime,json,pathlib,re,serial,subprocess,time
probe = """
import json,subprocess
p=json.loads(subprocess.check_output(['docker','inspect','data-terminal-cloud-postgres-1']))[0]
e=dict(x.split('=',1) for x in p['Config']['Env'] if '=' in x)
q=\"SELECT json_build_object('bound',(SELECT count(*) FROM device_binding WHERE device_id=d.id AND unbound_at IS NULL),'busy',EXISTS(SELECT 1 FROM call_session WHERE device_id=d.id AND call_state IN ('PREPARING','STARTING','TALKING','STOPPING')) OR EXISTS(SELECT 1 FROM conversation WHERE device_id=d.id AND status NOT IN ('COMPLETED','FAILED','EXPIRED')) OR EXISTS(SELECT 1 FROM fleet_ota WHERE device_id=d.id AND status IN ('pending','accepted'))) FROM device d WHERE public_id='623a4e54-bdc4-4c98-b03e-27267d3ff360' AND factory_device_id='KP01-020026091601' AND status='registered'\"
print(subprocess.check_output(['docker','exec',p['Id'],'psql','-U',e['POSTGRES_USER'],'-d',e['POSTGRES_DB'],'-At','-v','ON_ERROR_STOP=1','-c',q],text=True).strip())
"""
result=subprocess.run(['ssh','-i','E:/Codex/story/.local-evidence/account-reset-18642041700-20260916/migration-key.pem','-o','BatchMode=yes','-o','ConnectTimeout=10','root@82.157.201.114','python3 -'],input=probe,text=True,capture_output=True,check=True)
state=json.loads(result.stdout)
if state['busy'] or state['bound']!=1:raise SystemExit('COM6 is busy or binding changed; test not started')
port=serial.Serial();port.port='COM6';port.baudrate=115200;port.timeout=.2;port.dtr=False;port.rts=False
port.open()
patterns=[r'RTC diagnostic: .*',r'USB diagnostic: .*',r'chat end acknowledged=\d+',
r'Network diagnostic: sockets=\d+ limit=\d+',
r'mbedtls_net_connect error, return -0x[0-9a-f]+ errno=\d+',
r'platform_conversation_begin failed, ret: -?\d+',r'volc_start failed, ret: -?\d+',
r'PLATFORM_HTTP method=\w+ status=\d+ elapsed_ms=\d+ new_connection=\d+',
r'Failed to allocate \d+ bytes',r'Cannot allocate memory',
r'get rtc config failed',r'engine start failed: -?\d+',r'engine is not in CREATED state',r'bot id is invalid',
r'engine handle\([a-zA-Z0-9()]+\) or bot id\([a-zA-Z0-9()]+\) is NULL',r'rtc instance is NULL',
r'connect failed, https client (?:context|connect) return: -0x[0-9a-f]+',
r'RTC configuration request prepared',
r'Failed to join room: -?\d+',r'Failed to get response from server',
r'webclient POST request failed, response\(-?\d+\) error',
r'RTC config rejected code=[A-Za-z_0-9.]+ fields room=\d user=\d token=\d task=\d',
r'PLAYBACK (?:stats .*|start .*|idle .*|diagnostic sentence requested ret=-?\d+|feeder write failed|queue overflow.*)',
r'DOWNLINK span_ms=.*',r'AUDIO conversation status=-?\d+',r'device_control: state .*',
r'Platform error code: [A-Z_0-9]+',r'Guru Meditation.*',r'Stack canary.*',r'CORRUPT HEAP.*']
allow=re.compile('|'.join('('+p+')' for p in patterns))
lines=[];stopped=False
try:
port.write(b'\ndiag-say\n');start=time.monotonic()
print('COM6 fixed-sentence test started; no transcript captured',flush=True)
diagnosed=False
while time.monotonic()-start<55:
if not diagnosed and time.monotonic()-start>=15:port.write(b'diag-state\n');diagnosed=True
if not stopped and time.monotonic()-start>=40:port.write(b'diag-stop\n');stopped=True
raw=port.readline().decode('utf-8','replace').strip()
found=allow.search(raw)
if found:
line=found.group(0)[:700];lines.append(line);print(line,flush=True)
finally:
if not stopped:port.write(b'diag-stop\n')
port.close()
stamp=datetime.datetime.now(datetime.timezone.utc).strftime('%Y%m%dT%H%M%SZ')
path=pathlib.Path('E:/Codex/story/.local-evidence/com6-controls-20260922')/('voice-'+stamp+'.log')
path.write_text('\n'.join(lines)+'\n',encoding='utf-8')
print(json.dumps({'evidence':str(path),'lines':len(lines),'downlink':any(x.startswith('DOWNLINK ') for x in lines),'playback':any(x.startswith('PLAYBACK stats ') for x in lines),'hangup_ack':any('chat end acknowledged=1' in x for x in lines)}),flush=True)