class ElizaDeducer:
"""
This class populates a special chat dictionary
based on the matches added via its add_phrase_matcher function.
See subclass ElizaDeducerInitializer for example:
ed = ElizaDeducerInitializer(2) # 2 = limit of replies per input
"""
def __init__(self, lim: int):
self.babble2: list['PhraseMatcher'] = []
self.pattern_index: dict[str, list['PhraseMatcher']] = {}
self.response_cache: dict[str, list['AXKeyValuePair']] = {}
self.ec2 = EventChatV2(lim) # Chat dictionary, use getter for access. Hardcoded replies can also be added
def get_ec2(self) -> 'EventChatV2':
return self.ec2
def learn(self, msg: str) -> None:
# Populate EventChat dictionary
# Check cache first
if msg in self.response_cache:
self.ec2.add_key_values(list(self.response_cache[msg]))
# Search for matching patterns
potential_matchers = self.get_potential_matchers(msg)
for pm in potential_matchers:
if pm.matches(msg):
response = pm.respond(msg)
self.response_cache[msg] = response
self.ec2.add_key_values(response)
def learned_bool(self, msg: str) -> bool:
# Same as learn method but returns true if it learned new replies
learned = False
# Populate EventChat dictionary
# Check cache first
if msg in self.response_cache:
self.ec2.add_key_values(list(self.response_cache[msg]))
learned = True
# Search for matching patterns
potential_matchers = self.get_potential_matchers(msg)
for pm in potential_matchers:
if pm.matches(msg):
response = pm.respond(msg)
self.response_cache[msg] = response
self.ec2.add_key_values(response)
learned = True
return learned
def respond(self, str1: str) -> str:
return self.ec2.response(str1)
def respond_latest(self, str1: str) -> str:
# Get most recent reply/data
return self.ec2.response_latest(str1)
def get_potential_matchers(self, msg: str) -> list['PhraseMatcher']:
potential_matchers = []
for key in self.pattern_index:
if key in msg:
potential_matchers.extend(self.pattern_index[key])
return potential_matchers
def add_phrase_matcher(self, pattern: str, *kv_pairs: str) -> None:
kvs = [AXKeyValuePair(kv_pairs[i], kv_pairs[i + 1]) for i in range(0, len(kv_pairs), 2)]
matcher = PhraseMatcher(pattern, kvs)
self.babble2.append(matcher)
self.index_pattern(pattern, matcher)
def index_pattern(self, pattern: str, matcher: 'PhraseMatcher') -> None:
for word in pattern.split():
self.pattern_index.setdefault(word, []).append(matcher)
class PhraseMatcher:
def __init__(self, matcher: str, responses: list['AXKeyValuePair']):
self.matcher = re.compile(matcher)
self.responses = responses
def matches(self, str: str) -> bool:
m = self.matcher.match(str)
return m is not None
def respond(self, str: str) -> list['AXKeyValuePair']:
m = self.matcher.match(str)
result = []
if m:
tmp = len(m.groups())
for kv in self.responses:
temp_kv = AXKeyValuePair(kv.key, kv.value)
for i in range(tmp):
s = m.group(i + 1)
temp_kv.key = temp_kv.key.replace("{" + str(i) + "}", s).lower()
temp_kv.value = temp_kv.value.replace("{" + str(i) + "}", s).lower()
result.append(temp_kv)
return result