Files
behavior-tree/robobrain/robot_robobrain/intent.py
T

31 lines
1.8 KiB
Python
Raw Normal View History

"""Conservative independent intent gate for instructions without confirmed slots.
Only registered aliases and explicit quantities are accepted. Other language asks
for structured clarification; this parser is not claimed to cover arbitrary NLP.
"""
import re
COUNTS={'一':1,'二':2,'两':2,'三':3,'四':4,'五':5,'六':6,'七':7,'八':8,'九':9,'十':10,'one':1,'two':2,'three':3}
def matches(instruction,registry,aliases):
candidates=[]
for key in registry:
for term in [key]+list(aliases.get(key,[])):
if not term:continue
for m in re.finditer(re.escape(term),instruction):candidates.append((m.start(),m.end(),key))
chosen=[]
for item in sorted(candidates,key=lambda x:(-(x[1]-x[0]),x[0])):
if not any(item[0]<q[1] and q[0]<item[1] for q in chosen):chosen.append(item)
return sorted(chosen)
def extract(instruction,site):
names=site.get('object_locations',{}) or site.get('object_aliases',{})
objects=matches(instruction,names,site.get('object_aliases',{}))
sources=matches(instruction,site.get('sources',{}),site.get('source_aliases',{}))
destinations=matches(instruction,site.get('destinations',{}),site.get('destination_aliases',{}))
if not objects or len({x[2] for x in sources})!=1 or len({x[2] for x in destinations})!=1:return None
items=[]
for start,end,name in objects:
m=re.search(r'(\d+|一|二|两|三|四|五|六|七|八|九|十|one|two|three)\s*(?:瓶|个|件|盒|袋)?\s*$',instruction[:start])
if not m:return None
count=COUNTS.get(m[1],int(m[1]) if m[1].isdigit() else 0)
if not 1<=count<=20:return None
items.append(dict(target_name=name,quantity=count,source_location=sources[0][2]))
return dict(items=items,destination=destinations[0][2])