class PatternMatcherBaseClass(PatternTestBaseClass): @classmethod def setUpClass(cls): logging.getLogger().setLevel(logging.DEBUG) PatternMatcherBaseClass.bot = TestBot() PatternMatcherBaseClass.clientid = "matcher_test" def setUp(self): self._dump_graph = True self.graph = PatternGraph() self.matcher = AIMLParser() def dump_graph(self): if self._dump_graph is True: self.graph.dump() def add_pattern_to_graph(self, pattern, topic="*", that="*", template="test"): pattern_element = ET.fromstring("<pattern>%s</pattern>" % (pattern)) topic_element = ET.fromstring("<topic>%s</topic>" % (topic)) that_element = ET.fromstring("<that>%s</that>" % (that)) template_node = TemplateWordNode(template) self.matcher.pattern_parser.add_pattern_to_graph( pattern_element, topic_element, that_element, template_node) def match_sentence(self, sentence, topic="*", that="*"): return self.matcher.match_sentence(PatternMatcherBaseClass.bot, PatternMatcherBaseClass.clientid, Sentence(sentence), topic, that)
class PatternMatcherBaseClass(PatternTestBaseClass): @classmethod def setUpClass(cls): logging.getLogger().setLevel(logging.DEBUG) PatternMatcherBaseClass.bot = TestBot() PatternMatcherBaseClass.clientid = "matcher_test" def setUp(self): self._dump_graph = True self.graph = PatternGraph() self.matcher = AIMLParser() def dump_graph(self): if self._dump_graph is True: self.graph.dump() def add_pattern_to_graph(self, pattern, topic="*", that="*", template="test"): pattern_element = ET.fromstring("<pattern>%s</pattern>"%(pattern)) topic_element = ET.fromstring("<topic>%s</topic>"%(topic)) that_element = ET.fromstring("<that>%s</that>"%(that)) template_node = TemplateWordNode(template) self.matcher.pattern_parser.add_pattern_to_graph(pattern_element, topic_element, that_element, template_node) def match_sentence(self, sentence, topic="*", that="*"): return self.matcher.match_sentence( PatternMatcherBaseClass.bot, PatternMatcherBaseClass.clientid, Sentence(sentence), topic, that)
class AIMLParserTests(unittest.TestCase): def setUp(self): self.parser = AIMLParser() self.assertIsNotNone(self.parser) def test_tag_name_from_namespace(self): tag, namespace = self.parser.tag_and_namespace_from_text("aiml") self.assertEquals("aiml", tag) self.assertIsNone(namespace) tag, namespace = self.parser.tag_and_namespace_from_text("{http://alicebot.org/2001/AIML}aiml") self.assertEquals("aiml", tag) self.assertEquals("{http://alicebot.org/2001/AIML}", namespace) def test_parse_from_file_valid(self): filename = os.path.dirname(__file__)+ '/valid.aiml' self.parser.parse_from_file(filename) def test_aiml_with_namespace(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="ISO-8859-1"?> <aiml version="1.01" xmlns="http://alicebot.org/2001/AIML" xmlns:aiml="http://alicebot.org/2001/AIML" xmlns:html="http://www.w3.org/TR/REC-html40"> <category> <pattern>*</pattern> <template>RESPONSE</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") template = that.star.template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE") def test_base_aiml_topic_category_template(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> <category> <pattern>*</pattern> <template>RESPONSE</template> </category> </topic> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") template = that.star.template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE") def test_base_aiml_topic_category_template_multi_line(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> <category> <pattern>*</pattern> <template> RESPONSE1, RESPONSE2. RESPONSE3 </template> </category> </topic> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") template = that.star.template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE1, RESPONSE2. RESPONSE3") def test_base_aiml_category_template(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>*</pattern> <template>RESPONSE</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") template = that.star.template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE") def test_base_aiml_category_template_that(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>*</pattern> <that>something</that> <template>RESPONSE</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertEqual(len(that.children), 1) self.assertIsNotNone(that.children[0]) self.assertIsInstance(that.children[0], PatternWordNode) self.assertEqual(that.children[0].word, "something") template = that.children[0].template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE") def test_base_aiml_category_template_topic(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>*</pattern> <topic>something</topic> <template>RESPONSE</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "something") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") template = that.star.template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE") def test_base_aiml_category_template_topic_that(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>*</pattern> <that>something</that> <topic>other</topic> <template>RESPONSE</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "other") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertEqual(len(that.children), 1) self.assertIsNotNone(that.children[0]) self.assertIsInstance(that.children[0], PatternWordNode) self.assertEqual(that.children[0].word, "something") template = that.children[0].template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE") def test_base_aiml_multiple_categories(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>Hello</pattern> <template>Hiya</template> </category> <category> <pattern>Goodbye</pattern> <template>See ya</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertEqual(2, len(self.parser.pattern_parser.root.children)) node = self.parser.pattern_parser.root.children[1] self.assertIsNotNone(node) self.assertIsInstance(node, PatternWordNode) self.assertEquals(node.word, "Hello") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") node = self.parser.pattern_parser.root.children[0] self.assertIsNotNone(node) self.assertIsInstance(node, PatternWordNode) self.assertEquals(node.word, "Goodbye") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") def test_base_aiml_multiple_categories_in_a_topic(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> <category> <pattern>Hello</pattern> <template>Hiya</template> </category> <category> <pattern>Goodbye</pattern> <template>See ya</template> </category> </topic> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertEqual(2, len(self.parser.pattern_parser.root.children)) node = self.parser.pattern_parser.root.children[1] self.assertIsNotNone(node) self.assertIsInstance(node, PatternWordNode) self.assertEquals(node.word, "Hello") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") node = self.parser.pattern_parser.root.children[0] self.assertIsNotNone(node) self.assertIsInstance(node, PatternWordNode) self.assertEquals(node.word, "Goodbye") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") def test_base_aiml_multiple_categories_in_and_out_of_topic(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>Welcome</pattern> <template>Hello there</template> </category> <topic name="test"> <category> <pattern>Hello</pattern> <template>Hiya</template> </category> <category> <pattern>Goodbye</pattern> <template>See ya</template> </category> </topic> <category> <pattern>Interesting</pattern> <template>Yes</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertEqual(4, len(self.parser.pattern_parser.root.children)) node1 = self.parser.pattern_parser.root.children[0] self.assertIsNotNone(node1) self.assertIsInstance(node1, PatternWordNode) self.assertEquals(node1.word, "Interesting") topic = node1.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") node2 = self.parser.pattern_parser.root.children[1] self.assertIsNotNone(node2) self.assertIsInstance(node2, PatternWordNode) self.assertEquals(node2.word, "Goodbye") topic = node2.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") node3 = self.parser.pattern_parser.root.children[2] self.assertIsNotNone(node3) self.assertIsInstance(node3, PatternWordNode) self.assertEquals(node3.word, "Hello") topic = node3.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") node4 = self.parser.pattern_parser.root.children[3] self.assertIsNotNone(node4) self.assertIsInstance(node4, PatternWordNode) self.assertEquals(node4.word, "Welcome") topic = node4.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") def test_match_sentence(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>HELLO</pattern> <template>Hiya</template> </category> </aiml> """) self.parser.pattern_parser.dump() bot = Bot(Brain(BrainConfiguration()), config=BotConfiguration()) context = self.parser.match_sentence(bot, "test", Sentence("HELLO"), "*", "*") self.assertIsNotNone(context) self.assertEqual("Hiya", context.template_node().template.resolve(None, None)) def test_inline_br_html(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>HELLO</pattern> <template>Hello <br/> World</template> </category> </aiml> """) def test_inline_bold_html(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>HELLO</pattern> <template>Hello <bold>You</bold> World</template> </category> </aiml> """) def test_iset(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>Hello</pattern> <template>Hi There</template> </category> <category> <pattern># <iset>who, what</iset> are you</pattern> <template>OK thanks</template> </category> <category> <pattern># <iset>who, what</iset> is he</pattern> <template>OK thanks</template> </category> </aiml> """) def test_duplicate_topics(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="TOPIC1"> <category> <pattern>*</pattern> <template> Test Text </template> </category> </topic> <topic name="TOPIC2"> <category> <pattern>*</pattern> <template> Test Text </template> </category> </topic> </aiml> """)
class AIMLParserTests(unittest.TestCase): def setUp(self): self.parser = AIMLParser(supress_warnings=True, stop_on_invalid=True) self.assertIsNotNone(self.parser) def test_parse_from_file_valid(self): filename = os.path.dirname(__file__) + '/valid.aiml' self.parser.parse_from_file(filename) def test_parse_from_file_invalid(self): filename = os.path.dirname(__file__) + '/invalid.aiml' self.parser.parse_from_file(filename) def test_crud(self): with self.assertRaises(ParseError) as raised: self.parser.parse_from_text("""Blah Blah Blah """) def test_no_aiml(self): with self.assertRaises(ParseError) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> """) self.assertTrue(str(raised.exception).startswith("no element found:")) def test_no_content(self): with self.assertRaises(ParseError) as raised: self.parser.parse_from_text(""" """) self.assertTrue(str(raised.exception).startswith("no element found:")) def test_base_aiml_no_content(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> </aiml> """) self.assertEqual(raised.exception.message, "Error, no categories in aiml file") def test_base_aiml_topic_no_name(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic> </topic> </aiml> """) self.assertEqual(raised.exception.message, "Error, missing name attribute for topic") def test_base_aiml_topic_no_category(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> </topic> </aiml> """) self.assertEqual(raised.exception.message, "Error, no categories in topic") def test_base_aiml_topic_category_no_content(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> <category> </category> </topic> </aiml> """) self.assertEqual(raised.exception.message, "Error, no template node found in category") def test_base_aiml_topic_at_multiple_levels(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> <category> <topic name="test2" /> <pattern>*</pattern> <template>RESPONSE</template> </category> </topic> </aiml> """) self.assertEqual(raised.exception.message, "Error, topic exists in category AND as parent node") def test_base_aiml_topic_category_no_template(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> <category> <pattern>*</pattern> </category> </topic> </aiml> """) self.assertEqual(raised.exception.message, "Error, no template node found in category") def test_base_aiml_category_no_content(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> </category> </aiml> """) self.assertEqual(raised.exception.message, "Error, no template node found in category") def test_base_aiml_category_no_template(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>*</pattern> </category> </aiml> """) self.assertEqual(raised.exception.message, "Error, no template node found in category") def test_base_aiml_topic_empty_parent_node(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name=""> <category> <pattern>*</pattern> <template>RESPONSE</template> </category> </topic> </aiml> """) self.assertEqual(raised.exception.message, "Topic name empty or null") def test_base_aiml_topic_with_something_else(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> <xxxx> <pattern>*</pattern> <template>RESPONSE</template> </xxxx> </topic> </aiml> """) self.assertEqual(raised.exception.message, "Error unknown child node of topic, xxxx") def test_base_aiml_topic_empty_child_node1(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <topic name="" /> <pattern>*</pattern> <template>RESPONSE</template> </category> </aiml> """) self.assertEqual(raised.exception.message, "Topic node text is empty") def test_base_aiml_topic_empty_child_node2(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <topic></topic> <pattern>*</pattern> <template>RESPONSE</template> </category> </aiml> """) self.assertEqual(raised.exception.message, "Topic node text is empty") def test_base_aiml_that_empty_child_node(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <that></that> <pattern>*</pattern> <template>RESPONSE</template> </category> </aiml> """) self.assertEqual(raised.exception.message, "That node text is empty") def test_base_aiml_topic_category_template(self): self.parser.parse_from_text("""<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> <category> <pattern>*</pattern> <template>RESPONSE</template> </category> </topic> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") template = that.star.template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE") def test_base_aiml_topic_category_template_multi_line(self): self.parser.parse_from_text("""<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> <category> <pattern>*</pattern> <template> RESPONSE1, RESPONSE2. RESPONSE3 </template> </category> </topic> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") template = that.star.template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE1, RESPONSE2. RESPONSE3") def test_base_aiml_category_template(self): self.parser.parse_from_text("""<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>*</pattern> <template>RESPONSE</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") template = that.star.template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE") def test_base_aiml_category_template_that(self): self.parser.parse_from_text("""<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>*</pattern> <that>something</that> <template>RESPONSE</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertEqual(len(that.children), 1) self.assertIsNotNone(that.children[0]) self.assertIsInstance(that.children[0], PatternWordNode) self.assertEqual(that.children[0].word, "something") template = that.children[0].template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE") def test_base_aiml_category_template_topic(self): self.parser.parse_from_text("""<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>*</pattern> <topic>something</topic> <template>RESPONSE</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "something") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") template = that.star.template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE") def test_base_aiml_category_template_topic_that(self): self.parser.parse_from_text("""<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>*</pattern> <that>something</that> <topic>other</topic> <template>RESPONSE</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "other") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertEqual(len(that.children), 1) self.assertIsNotNone(that.children[0]) self.assertIsInstance(that.children[0], PatternWordNode) self.assertEqual(that.children[0].word, "something") template = that.children[0].template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE") def test_base_aiml_multiple_categories(self): self.parser.parse_from_text("""<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>Hello</pattern> <template>Hiya</template> </category> <category> <pattern>Goodbye</pattern> <template>See ya</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertEqual(2, len(self.parser.pattern_parser.root.children)) node = self.parser.pattern_parser.root.children[1] self.assertIsNotNone(node) self.assertIsInstance(node, PatternWordNode) self.assertEquals(node.word, "Hello") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") node = self.parser.pattern_parser.root.children[0] self.assertIsNotNone(node) self.assertIsInstance(node, PatternWordNode) self.assertEquals(node.word, "Goodbye") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") def test_base_aiml_multiple_categories_in_a_topic(self): self.parser.parse_from_text("""<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> <category> <pattern>Hello</pattern> <template>Hiya</template> </category> <category> <pattern>Goodbye</pattern> <template>See ya</template> </category> </topic> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertEqual(2, len(self.parser.pattern_parser.root.children)) node = self.parser.pattern_parser.root.children[1] self.assertIsNotNone(node) self.assertIsInstance(node, PatternWordNode) self.assertEquals(node.word, "Hello") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") node = self.parser.pattern_parser.root.children[0] self.assertIsNotNone(node) self.assertIsInstance(node, PatternWordNode) self.assertEquals(node.word, "Goodbye") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") def test_base_aiml_multiple_categories_in_and_out_of_topic(self): self.parser.parse_from_text("""<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>Welcome</pattern> <template>Hello there</template> </category> <topic name="test"> <category> <pattern>Hello</pattern> <template>Hiya</template> </category> <category> <pattern>Goodbye</pattern> <template>See ya</template> </category> </topic> <category> <pattern>Interesting</pattern> <template>Yes</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertEqual(4, len(self.parser.pattern_parser.root.children)) node1 = self.parser.pattern_parser.root.children[0] self.assertIsNotNone(node1) self.assertIsInstance(node1, PatternWordNode) self.assertEquals(node1.word, "Interesting") topic = node1.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") node2 = self.parser.pattern_parser.root.children[1] self.assertIsNotNone(node2) self.assertIsInstance(node2, PatternWordNode) self.assertEquals(node2.word, "Goodbye") topic = node2.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") node3 = self.parser.pattern_parser.root.children[2] self.assertIsNotNone(node3) self.assertIsInstance(node3, PatternWordNode) self.assertEquals(node3.word, "Hello") topic = node3.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") node4 = self.parser.pattern_parser.root.children[3] self.assertIsNotNone(node4) self.assertIsInstance(node4, PatternWordNode) self.assertEquals(node4.word, "Welcome") topic = node4.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") def test_match_sentence(self): self.parser.parse_from_text("""<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>HELLO</pattern> <template>Hiya</template> </category> </aiml> """) self.parser.pattern_parser.dump() context = self.parser.match_sentence(None, "test", Sentence("HELLO"), "*", "*") self.assertIsNotNone(context) self.assertEqual("Hiya", context.template_node().template.resolve(None, None)) def test_inline_br_html(self): self.parser.parse_from_text("""<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>HELLO</pattern> <template>Hello <br/> World</template> </category> </aiml> """) self.parser.pattern_parser.dump(output_func=print) def test_inline_bold_html(self): self.parser.parse_from_text("""<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>HELLO</pattern> <template>Hello <bold>You</bold> World</template> </category> </aiml> """) self.parser.pattern_parser.dump(output_func=print) def test_iset(self): self.parser.parse_from_text("""<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>Hello</pattern> <template>Hi There</template> </category> <category> <pattern># <iset>who, what</iset> are you</pattern> <template>OK thanks</template> </category> <category> <pattern># <iset>who, what</iset> is he</pattern> <template>OK thanks</template> </category> </aiml> """) self.parser.pattern_parser.dump(output_func=print)
class Brain(object): def __init__(self, configuration: BrainConfiguration): self._configuration = configuration self._aiml_parser = AIMLParser() self._denormal_collection = DenormalCollection() self._normal_collection = NormalCollection() self._gender_collection = GenderCollection() self._person_collection = PersonCollection() self._person2_collection = PersonCollection() self._predicates_collection = PredicatesCollection() self._pronouns_collection = PronounsCollection() self._triples_collection = TriplesCollection() self._sets_collection = SetCollection() self._maps_collection = MapCollection() self._properties_collection = PropertiesCollection() self._preprocessors = ProcessorLoader() self._postprocessors = ProcessorLoader() self.load(self._configuration) @property def configuration(self): return self._configuration @property def aiml_parser(self): return self._aiml_parser @property def denormals(self): return self._denormal_collection @property def normals(self): return self._normal_collection @property def genders(self): return self._gender_collection @property def persons(self): return self._person_collection @property def person2s(self): return self._person2_collection @property def predicates(self): return self._predicates_collection @property def pronounds(self): return self._pronouns_collection @property def triples(self): return self._triples_collection @property def sets(self): return self._sets_collection @property def maps(self): return self._maps_collection @property def properties(self): return self._properties_collection @property def preprocessors(self): return self._preprocessors @property def postprocessors(self): return self._postprocessors def load(self, brain_configuration: BrainConfiguration): self._aiml_parser.load_aiml(brain_configuration) self.load_collections(brain_configuration) self.load_services(brain_configuration) def _load_denormals(self, brain_configuration): if brain_configuration.denormal is not None: total = self._denormal_collection.load_from_filename( brain_configuration.denormal) logging.info("Loaded a total of %d denormalisations", total) else: logging.warning("No configuration setting for denormal") def _load_normals(self, brain_configuration): if brain_configuration.normal is not None: total = self._normal_collection.load_from_filename( brain_configuration.normal) logging.info("Loaded a total of %d normalisations", total) else: logging.warning("No configuration setting for normal") def _load_genders(self, brain_configuration): if brain_configuration.gender is not None: total = self._gender_collection.load_from_filename( brain_configuration.gender) logging.info("Loaded a total of %d genderisations", total) else: logging.warning("No configuration setting for gender") def _load_persons(self, brain_configuration): if brain_configuration.person is not None: total = self._person_collection.load_from_filename( brain_configuration.person) logging.info("Loaded a total of %d persons", total) else: logging.warning("No configuration setting for person") def _load_person2s(self, brain_configuration): if brain_configuration.person2 is not None: total = self._person2_collection.load_from_filename( brain_configuration.person2) logging.info("Loaded a total of %d person2s", total) else: logging.warning("No configuration setting for person2") def _load_predicates(self, brain_configuration): if brain_configuration.predicates is not None: total = self._predicates_collection.load_from_filename( brain_configuration.predicates) logging.info("Loaded a total of %d predicates", total) else: logging.warning("No configuration setting for predicates") def _load_pronouns(self, brain_configuration): if brain_configuration.pronouns is not None: total = self._pronouns_collection.load_from_filename( brain_configuration.pronouns) logging.info("Loaded a total of %d pronouns", total) else: logging.warning("No configuration setting for pronouns") def _load_properties(self, brain_configuration): if brain_configuration.properties is not None: total = self._properties_collection.load_from_filename( brain_configuration.properties) logging.info("Loaded a total of %d properties", total) else: logging.warning("No configuration setting for properties") def _load_triples(self, brain_configuration): if brain_configuration.triples is not None: total = self._properties_collection.load_from_filename( brain_configuration.triples) logging.info("Loaded a total of %d triples", total) else: logging.warning("No configuration setting for triples") def _load_sets(self, brain_configuration): if brain_configuration.set_files is not None: total = self._sets_collection.load(brain_configuration.set_files) logging.info("Loaded a total of %d sets files", total) else: logging.warning("No configuration setting for set files") def _load_maps(self, brain_configuration): if brain_configuration.map_files is not None: total = self._maps_collection.load(brain_configuration.map_files) logging.info("Loaded a total of %d maps files", total) else: logging.warning("No configuration setting for map files") def _load_preprocessors(self, brain_configuration): if brain_configuration.preprocessors is not None: total = self._preprocessors.load(brain_configuration.preprocessors) logging.info("Loaded a total of %d pre processors", total) else: logging.warning("No configuration setting for pre processors") def _load_postprocessors(self, brain_configuration): if brain_configuration.postprocessors is not None: total = self._postprocessors.load( brain_configuration.postprocessors) logging.info("Loaded a total of %d post processors", total) else: logging.warning("No configuration setting for post processors") def load_collections(self, brain_configuration): self._load_denormals(brain_configuration) self._load_normals(brain_configuration) self._load_genders(brain_configuration) self._load_persons(brain_configuration) self._load_person2s(brain_configuration) self._load_predicates(brain_configuration) self._load_pronouns(brain_configuration) self._load_properties(brain_configuration) self._load_triples(brain_configuration) self._load_sets(brain_configuration) self._load_maps(brain_configuration) self._load_preprocessors(brain_configuration) self._load_postprocessors(brain_configuration) def load_services(self, brain_configuration): ServiceFactory.preload_services(brain_configuration.services) def pre_process_question(self, bot, clientid, question): return self.preprocessors.process(bot, clientid, question) def ask_question(self, bot, clientid, sentence) -> str: conversation = bot.get_conversation(clientid) topic_pattern = conversation.predicate("topic") if topic_pattern is None: logging.info("No Topic pattern default to [*]") topic_pattern = "*" else: logging.info("Topic pattern = [%s]", topic_pattern) try: that_question = conversation.nth_question(2) that_sentence = that_question.current_sentence() # If the last response was valid, i.e not none and not empty string, then use # that as the that_pattern, otherwise we default to '*' as pattern if that_sentence.response is not None and that_sentence.response != '': that_pattern = that_sentence.response logging.info("That pattern = [%s]", that_pattern) else: logging.info("That pattern, no response, default to [*]") that_pattern = "*" except Exception: logging.info("No That pattern default to [*]") that_pattern = "*" match_context = self._aiml_parser.match_sentence( bot, clientid, sentence, topic_pattern=topic_pattern, that_pattern=that_pattern) if match_context is not None: template_node = match_context.template_node() logging.debug("AIML Parser evaluating template [%s]", template_node.to_string()) return template_node.template.resolve(bot, clientid) return None def post_process_response(self, bot, clientid, response: str): return self.postprocessors.process(bot, clientid, response) def dump_tree(self): self._aiml_parser.pattern_parser.root.dump(tabs="") def write_learnf_to_file(self, bot, clientid, pattern, topic, that, template): learnf_path = "%s/learnf%s" % ( self._configuration.aiml_files.files, self._configuration.aiml_files.extension) logging.debug("Writing learnf to %s", learnf_path) if os.path.isfile(learnf_path) is False: file = open(learnf_path, "w+") file.write('<?xml version="1.0" encoding="UTF-8"?>\n') file.write('<aiml>\n') file.write('</aiml>\n') file.close() tree = ET.parse(learnf_path) root = tree.getroot() # Add our new element child = ET.Element("category") child.append(pattern) child.append(topic) child.append(that) child.append(template.xml_tree(bot, clientid)) root.append(child) tree.write(learnf_path, method="xml")
class Brain(object): def __init__(self, configuration: BrainConfiguration): self._configuration = configuration self._aiml_parser = AIMLParser() self._denormal_collection = DenormalCollection() self._normal_collection = NormalCollection() self._gender_collection = GenderCollection() self._person_collection = PersonCollection() self._person2_collection = PersonCollection() self._predicates_collection = PredicatesCollection() self._pronouns_collection = PronounsCollection() self._triples_collection = TriplesCollection() self._sets_collection = SetCollection() self._maps_collection = MapCollection() self._properties_collection = PropertiesCollection() self._preprocessors = ProcessorLoader() self._postprocessors = ProcessorLoader() self.load(self._configuration) @property def aiml_parser(self): return self._aiml_parser @property def denormals(self): return self._denormal_collection @property def normals(self): return self._normal_collection @property def genders(self): return self._gender_collection @property def persons(self): return self._person_collection @property def person2s(self): return self._person2_collection @property def predicates(self): return self._predicates_collection @property def pronounds(self): return self._pronouns_collection @property def triples(self): return self._triples_collection @property def sets(self): return self._sets_collection @property def maps(self): return self._maps_collection @property def properties(self): return self._properties_collection @property def preprocessors(self): return self._preprocessors @property def postprocessors(self): return self._postprocessors def load(self, brain_configuration: BrainConfiguration): self._aiml_parser.load_aiml(brain_configuration) self.load_collections(brain_configuration) def load_collections(self, brain_configuration): if brain_configuration.denormal is not None: total = self._denormal_collection.load_from_filename( brain_configuration.denormal) logging.info("Loaded a total of %d denormalisations" % (total)) else: logging.warning("No configuration setting for denormal") if brain_configuration.normal is not None: total = self._normal_collection.load_from_filename( brain_configuration.normal) logging.info("Loaded a total of %d normalisations" % (total)) else: logging.warning("No configuration setting for normal") if brain_configuration.gender is not None: total = self._gender_collection.load_from_filename( brain_configuration.gender) logging.info("Loaded a total of %d genderisations" % (total)) else: logging.warning("No configuration setting for gender") if brain_configuration.person is not None: total = self._person_collection.load_from_filename( brain_configuration.person) logging.info("Loaded a total of %d persons" % (total)) else: logging.warning("No configuration setting for person") if brain_configuration.person2 is not None: total = self._person2_collection.load_from_filename( brain_configuration.person2) logging.info("Loaded a total of %d person2s" % (total)) else: logging.warning("No configuration setting for person2") if brain_configuration.predicates is not None: total = self._predicates_collection.load_from_filename( brain_configuration.predicates) logging.info("Loaded a total of %d predicates" % (total)) else: logging.warning("No configuration setting for predicates") if brain_configuration.pronouns is not None: total = self._pronouns_collection.load_from_filename( brain_configuration.pronouns) logging.info("Loaded a total of %d pronouns" % (total)) else: logging.warning("No configuration setting for pronouns") if brain_configuration.properties is not None: total = self._properties_collection.load_from_filename( brain_configuration.properties) logging.info("Loaded a total of %d properties" % (total)) else: logging.warning("No configuration setting for properties") if brain_configuration.triples is not None: total = self._properties_collection.load_from_filename( brain_configuration.triples) logging.info("Loaded a total of %d triples" % (total)) else: logging.warning("No configuration setting for triples") if brain_configuration.set_files is not None: total = self._sets_collection.load(brain_configuration.set_files) logging.info("Loaded a total of %d sets files" % (total)) else: logging.warning("No configuration setting for set files") if brain_configuration.map_files is not None: total = self._maps_collection.load(brain_configuration.map_files) logging.info("Loaded a total of %d maps files" % (total)) else: logging.warning("No configuration setting for map files") if brain_configuration.preprocessors is not None: total = self._preprocessors.load(brain_configuration.preprocessors) logging.info("Loaded a total of %d pre processors" % (total)) else: logging.warning("No configuration setting for pre processors") if brain_configuration.postprocessors is not None: total = self._postprocessors.load( brain_configuration.postprocessors) logging.info("Loaded a total of %d post processors" % (total)) else: logging.warning("No configuration setting for post processors") def pre_process_question(self, question): return self.preprocessors.process(question) def ask_question(self, bot, clientid, sentence) -> str: conversation = bot.get_conversation(clientid) try: topic_pattern = conversation.predicate("topic") except: topic_pattern = "*" try: that_question = conversation.nth_question(2) that_sentence = that_question.current_sentence() that_pattern = that_sentence.text() except: that_pattern = "*" return self._aiml_parser.match_sentence(bot, clientid, sentence, topic_pattern=topic_pattern, that_pattern=that_pattern) def post_process_response(self, response: str): return self.postprocessors.process(response) def dump_tree(self): self._aiml_parser.pattern_parser.root.dump(tabs="") def write_learnf_to_file(self, bot, clientid, pattern, topic, that, template): learnf_path = "%s/learnf%s" % ( self._configuration.aiml_files.files, self._configuration.aiml_files.extension) logging.debug("Writing learnf to %s" % learnf_path) import os.path if os.path.isfile(learnf_path) is False: file = open(learnf_path, "w+") file.write('<?xml version="1.0" encoding="UTF-8"?>\n') file.write('<aiml>\n') file.write('</aiml>\n') file.close() tree = ET.parse(learnf_path) root = tree.getroot() # Add our new element child = ET.Element("category") child.append(pattern) child.append(topic) child.append(that) child.append(template.xml_tree(bot, clientid)) root.append(child) tree.write(learnf_path, method="xml")
class AIMLParserTests(unittest.TestCase): def setUp(self): self.parser = AIMLParser(supress_warnings=True, stop_on_invalid=True) self.assertIsNotNone(self.parser) def test_parse_from_file_valid(self): filename = os.path.dirname(__file__)+ '/valid.aiml' self.parser.parse_from_file(filename) def test_parse_from_file_invalid(self): filename = os.path.dirname(__file__)+ '/invalid.aiml' self.parser.parse_from_file(filename) def test_crud(self): with self.assertRaises(ParseError) as raised: self.parser.parse_from_text( """Blah Blah Blah """) def test_no_aiml(self): with self.assertRaises(ParseError) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> """) self.assertTrue(str(raised.exception).startswith("no element found:")) def test_no_content(self): with self.assertRaises(ParseError) as raised: self.parser.parse_from_text( """ """) self.assertTrue(str(raised.exception).startswith("no element found:")) def test_base_aiml_no_content(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> </aiml> """) self.assertEqual(raised.exception.message, "Error, no categories in aiml file") def test_base_aiml_topic_no_name(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic> </topic> </aiml> """) self.assertEqual(raised.exception.message, "Error, missing name attribute for topic") def test_base_aiml_topic_no_category(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> </topic> </aiml> """) self.assertEqual(raised.exception.message, "Error, no categories in topic") def test_base_aiml_topic_category_no_content(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> <category> </category> </topic> </aiml> """) self.assertEqual(raised.exception.message, "Error, no template node found in category") def test_base_aiml_topic_at_multiple_levels(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> <category> <topic name="test2" /> <pattern>*</pattern> <template>RESPONSE</template> </category> </topic> </aiml> """) self.assertEqual(raised.exception.message, "Error, topic exists in category AND as parent node") def test_base_aiml_topic_category_no_template(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> <category> <pattern>*</pattern> </category> </topic> </aiml> """) self.assertEqual(raised.exception.message, "Error, no template node found in category") def test_base_aiml_category_no_content(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> </category> </aiml> """) self.assertEqual(raised.exception.message, "Error, no template node found in category") def test_base_aiml_category_no_template(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>*</pattern> </category> </aiml> """) self.assertEqual(raised.exception.message, "Error, no template node found in category") def test_base_aiml_topic_empty_parent_node(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name=""> <category> <pattern>*</pattern> <template>RESPONSE</template> </category> </topic> </aiml> """) self.assertEqual(raised.exception.message, "Topic name empty or null") def test_base_aiml_topic_with_something_else(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> <xxxx> <pattern>*</pattern> <template>RESPONSE</template> </xxxx> </topic> </aiml> """) self.assertEqual(raised.exception.message, "Error unknown child node of topic, xxxx") def test_base_aiml_topic_empty_child_node1(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <topic name="" /> <pattern>*</pattern> <template>RESPONSE</template> </category> </aiml> """) self.assertEqual(raised.exception.message, "Topic node text is empty") def test_base_aiml_topic_empty_child_node2(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <topic></topic> <pattern>*</pattern> <template>RESPONSE</template> </category> </aiml> """) self.assertEqual(raised.exception.message, "Topic node text is empty") def test_base_aiml_that_empty_child_node(self): with self.assertRaises(ParserException) as raised: self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <that></that> <pattern>*</pattern> <template>RESPONSE</template> </category> </aiml> """) self.assertEqual(raised.exception.message, "That node text is empty") def test_base_aiml_topic_category_template(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> <category> <pattern>*</pattern> <template>RESPONSE</template> </category> </topic> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") template = that.star.template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE") def test_base_aiml_topic_category_template_multi_line(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> <category> <pattern>*</pattern> <template> RESPONSE1, RESPONSE2. RESPONSE3 </template> </category> </topic> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") template = that.star.template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE1, RESPONSE2. RESPONSE3") def test_base_aiml_category_template(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>*</pattern> <template>RESPONSE</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") template = that.star.template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE") def test_base_aiml_category_template_that(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>*</pattern> <that>something</that> <template>RESPONSE</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertEqual(len(that.children), 1) self.assertIsNotNone(that.children[0]) self.assertIsInstance(that.children[0], PatternWordNode) self.assertEqual(that.children[0].word, "something") template = that.children[0].template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE") def test_base_aiml_category_template_topic(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>*</pattern> <topic>something</topic> <template>RESPONSE</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "something") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") template = that.star.template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE") def test_base_aiml_category_template_topic_that(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>*</pattern> <that>something</that> <topic>other</topic> <template>RESPONSE</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertTrue(self.parser.pattern_parser.root.has_one_or_more()) node = self.parser.pattern_parser.root.star self.assertIsNotNone(node) self.assertIsInstance(node, PatternOneOrMoreWildCardNode) self.assertEquals(node.wildcard, "*") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "other") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertEqual(len(that.children), 1) self.assertIsNotNone(that.children[0]) self.assertIsInstance(that.children[0], PatternWordNode) self.assertEqual(that.children[0].word, "something") template = that.children[0].template self.assertIsNotNone(template) self.assertIsInstance(template, PatternTemplateNode) self.assertEqual(template.template.resolve(bot=None, clientid="test"), "RESPONSE") def test_base_aiml_multiple_categories(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>Hello</pattern> <template>Hiya</template> </category> <category> <pattern>Goodbye</pattern> <template>See ya</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertIsInstance(self.parser.pattern_parser.root, PatternRootNode) self.assertEqual(2, len(self.parser.pattern_parser.root.children)) node = self.parser.pattern_parser.root.children[1] self.assertIsNotNone(node) self.assertIsInstance(node, PatternWordNode) self.assertEquals(node.word, "Hello") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") node = self.parser.pattern_parser.root.children[0] self.assertIsNotNone(node) self.assertIsInstance(node, PatternWordNode) self.assertEquals(node.word, "Goodbye") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") def test_base_aiml_multiple_categories_in_a_topic(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <topic name="test"> <category> <pattern>Hello</pattern> <template>Hiya</template> </category> <category> <pattern>Goodbye</pattern> <template>See ya</template> </category> </topic> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertEqual(2, len(self.parser.pattern_parser.root.children)) node = self.parser.pattern_parser.root.children[1] self.assertIsNotNone(node) self.assertIsInstance(node, PatternWordNode) self.assertEquals(node.word, "Hello") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") node = self.parser.pattern_parser.root.children[0] self.assertIsNotNone(node) self.assertIsInstance(node, PatternWordNode) self.assertEquals(node.word, "Goodbye") topic = node.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") def test_base_aiml_multiple_categories_in_and_out_of_topic(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>Welcome</pattern> <template>Hello there</template> </category> <topic name="test"> <category> <pattern>Hello</pattern> <template>Hiya</template> </category> <category> <pattern>Goodbye</pattern> <template>See ya</template> </category> </topic> <category> <pattern>Interesting</pattern> <template>Yes</template> </category> </aiml> """) self.assertIsNotNone(self.parser.pattern_parser.root) self.assertEqual(4, len(self.parser.pattern_parser.root.children)) node1 = self.parser.pattern_parser.root.children[0] self.assertIsNotNone(node1) self.assertIsInstance(node1, PatternWordNode) self.assertEquals(node1.word, "Interesting") topic = node1.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") node2 = self.parser.pattern_parser.root.children[1] self.assertIsNotNone(node2) self.assertIsInstance(node2, PatternWordNode) self.assertEquals(node2.word, "Goodbye") topic = node2.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") node3 = self.parser.pattern_parser.root.children[2] self.assertIsNotNone(node3) self.assertIsInstance(node3, PatternWordNode) self.assertEquals(node3.word, "Hello") topic = node3.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertEqual(len(topic.children), 1) self.assertIsNotNone(topic.children[0]) self.assertIsInstance(topic.children[0], PatternWordNode) self.assertEqual(topic.children[0].word, "test") that = topic.children[0].that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") node4 = self.parser.pattern_parser.root.children[3] self.assertIsNotNone(node4) self.assertIsInstance(node4, PatternWordNode) self.assertEquals(node4.word, "Welcome") topic = node4.topic self.assertIsNotNone(topic) self.assertIsInstance(topic, PatternTopicNode) self.assertTrue(topic.has_one_or_more()) self.assertIsInstance(topic.star, PatternOneOrMoreWildCardNode) self.assertEquals(topic.star.wildcard, "*") that = topic.star.that self.assertIsNotNone(that) self.assertIsInstance(that, PatternThatNode) self.assertTrue(that.has_one_or_more()) self.assertIsInstance(that.star, PatternOneOrMoreWildCardNode) self.assertEquals(that.star.wildcard, "*") def test_match_sentence(self): self.parser.parse_from_text( """<?xml version="1.0" encoding="UTF-8"?> <aiml> <category> <pattern>HELLO</pattern> <template>Hiya</template> </category> </aiml> """) self.parser.pattern_parser.dump() context = self.parser.match_sentence(None, "test", Sentence("HELLO"), "*", "*") self.assertIsNotNone(context) self.assertEqual("Hiya", context.template_node().template.resolve(None, None))
class Brain(object): def __init__(self, configuration: BrainConfiguration): self._configuration = configuration self._aiml_parser = AIMLParser() self._denormal_collection = DenormalCollection() self._normal_collection = NormalCollection() self._gender_collection = GenderCollection() self._person_collection = PersonCollection() self._person2_collection = PersonCollection() self._predicates_collection = PredicatesCollection() self._pronouns_collection = PronounsCollection() self._triples_collection = TriplesCollection() self._sets_collection = SetCollection() self._maps_collection = MapCollection() self._properties_collection = PropertiesCollection() self._preprocessors = ProcessorLoader() self._postprocessors = ProcessorLoader() self.load(self._configuration) @property def configuration(self): return self._configuration @property def aiml_parser(self): return self._aiml_parser @property def denormals(self): return self._denormal_collection @property def normals(self): return self._normal_collection @property def genders(self): return self._gender_collection @property def persons(self): return self._person_collection @property def person2s(self): return self._person2_collection @property def predicates(self): return self._predicates_collection @property def pronounds(self): return self._pronouns_collection @property def triples(self): return self._triples_collection @property def sets(self): return self._sets_collection @property def maps(self): return self._maps_collection @property def properties(self): return self._properties_collection @property def preprocessors(self): return self._preprocessors @property def postprocessors(self): return self._postprocessors def load(self, brain_configuration: BrainConfiguration): self._aiml_parser.load_aiml(brain_configuration) self.load_collections(brain_configuration) self.load_services(brain_configuration) def _load_denormals(self, brain_configuration): if brain_configuration.denormal is not None: total = self._denormal_collection.load_from_filename(brain_configuration.denormal) logging.info("Loaded a total of %d denormalisations", total) else: logging.warning("No configuration setting for denormal") def _load_normals(self, brain_configuration): if brain_configuration.normal is not None: total = self._normal_collection.load_from_filename(brain_configuration.normal) logging.info("Loaded a total of %d normalisations", total) else: logging.warning("No configuration setting for normal") def _load_genders(self, brain_configuration): if brain_configuration.gender is not None: total = self._gender_collection.load_from_filename(brain_configuration.gender) logging.info("Loaded a total of %d genderisations", total) else: logging.warning("No configuration setting for gender") def _load_persons(self, brain_configuration): if brain_configuration.person is not None: total = self._person_collection.load_from_filename(brain_configuration.person) logging.info("Loaded a total of %d persons", total) else: logging.warning("No configuration setting for person") def _load_person2s(self, brain_configuration): if brain_configuration.person2 is not None: total = self._person2_collection.load_from_filename(brain_configuration.person2) logging.info("Loaded a total of %d person2s", total) else: logging.warning("No configuration setting for person2") def _load_predicates(self, brain_configuration): if brain_configuration.predicates is not None: total = self._predicates_collection.load_from_filename(brain_configuration.predicates) logging.info("Loaded a total of %d predicates", total) else: logging.warning("No configuration setting for predicates") def _load_pronouns(self, brain_configuration): if brain_configuration.pronouns is not None: total = self._pronouns_collection.load_from_filename(brain_configuration.pronouns) logging.info("Loaded a total of %d pronouns", total) else: logging.warning("No configuration setting for pronouns") def _load_properties(self, brain_configuration): if brain_configuration.properties is not None: total = self._properties_collection.load_from_filename(brain_configuration.properties) logging.info("Loaded a total of %d properties", total) else: logging.warning("No configuration setting for properties") def _load_triples(self, brain_configuration): if brain_configuration.triples is not None: total = self._properties_collection.load_from_filename(brain_configuration.triples) logging.info("Loaded a total of %d triples", total) else: logging.warning("No configuration setting for triples") def _load_sets(self, brain_configuration): if brain_configuration.set_files is not None: total = self._sets_collection.load(brain_configuration.set_files) logging.info("Loaded a total of %d sets files", total) else: logging.warning("No configuration setting for set files") def _load_maps(self, brain_configuration): if brain_configuration.map_files is not None: total = self._maps_collection.load(brain_configuration.map_files) logging.info("Loaded a total of %d maps files", total) else: logging.warning("No configuration setting for map files") def _load_preprocessors(self, brain_configuration): if brain_configuration.preprocessors is not None: total = self._preprocessors.load(brain_configuration.preprocessors) logging.info("Loaded a total of %d pre processors", total) else: logging.warning("No configuration setting for pre processors") def _load_postprocessors(self, brain_configuration): if brain_configuration.postprocessors is not None: total = self._postprocessors.load(brain_configuration.postprocessors) logging.info("Loaded a total of %d post processors", total) else: logging.warning("No configuration setting for post processors") def load_collections(self, brain_configuration): self._load_denormals(brain_configuration) self._load_normals(brain_configuration) self._load_genders(brain_configuration) self._load_persons(brain_configuration) self._load_person2s(brain_configuration) self._load_predicates(brain_configuration) self._load_pronouns(brain_configuration) self._load_properties(brain_configuration) self._load_triples(brain_configuration) self._load_sets(brain_configuration) self._load_maps(brain_configuration) self._load_preprocessors(brain_configuration) self._load_postprocessors(brain_configuration) def load_services(self, brain_configuration): ServiceFactory.preload_services(brain_configuration.services) def pre_process_question(self, bot, clientid, question): return self.preprocessors.process(bot, clientid, question) def ask_question(self, bot, clientid, sentence) -> str: conversation = bot.get_conversation(clientid) topic_pattern = conversation.predicate("topic") if topic_pattern is None: logging.info("No Topic pattern default to [*]") topic_pattern = "*" else: logging.info("Topic pattern = [%s]", topic_pattern) try: that_question = conversation.nth_question(2) that_sentence = that_question.current_sentence() # If the last response was valid, i.e not none and not empty string, then use # that as the that_pattern, otherwise we default to '*' as pattern if that_sentence.response is not None and that_sentence.response != '': that_pattern = TextUtils.strip_all_punctuation(that_sentence.response) logging.info("That pattern = [%s]", that_pattern) else: logging.info("That pattern, no response, default to [*]") that_pattern = "*" except Exception: logging.info("No That pattern default to [*]") that_pattern = "*" match_context = self._aiml_parser.match_sentence(bot, clientid, sentence, topic_pattern=topic_pattern, that_pattern=that_pattern) if match_context is not None: template_node = match_context.template_node() logging.debug("AIML Parser evaluating template [%s]", template_node.to_string()) return template_node.template.resolve(bot, clientid) return None def post_process_response(self, bot, clientid, response: str): return self.postprocessors.process(bot, clientid, response) def dump_tree(self): self._aiml_parser.pattern_parser.root.dump(tabs="") def write_learnf_to_file(self, bot, clientid, pattern, topic, that, template): learnf_path = "%s/learnf%s" % (self._configuration.aiml_files.files, self._configuration.aiml_files.extension) logging.debug("Writing learnf to %s", learnf_path) if os.path.isfile(learnf_path) is False: file = open(learnf_path, "w+") file.write('<?xml version="1.0" encoding="UTF-8"?>\n') file.write('<aiml>\n') file.write('</aiml>\n') file.close() tree = ET.parse(learnf_path) root = tree.getroot() # Add our new element child = ET.Element("category") child.append(pattern) child.append(topic) child.append(that) child.append(template.xml_tree(bot, clientid)) root.append(child) tree.write(learnf_path, method="xml")
class Brain(object): def __init__(self, configuration: BrainConfiguration): self._configuration = configuration self._aiml_parser = AIMLParser(self) self._denormal_collection = DenormalCollection() self._normal_collection = NormalCollection() self._gender_collection = GenderCollection() self._person_collection = PersonCollection() self._person2_collection = PersonCollection() self._rdf_collection = RDFCollection() self._sets_collection = SetCollection() self._maps_collection = MapCollection() self._properties_collection = PropertiesCollection() self._preprocessors = ProcessorLoader() self._postprocessors = ProcessorLoader() self._authentication = None self._authorisation = None self._default_oob = None self._oob = {} self._regex_templates = {} self._dynamics_collection = DynamicsCollection() self.load(self._configuration) @property def configuration(self): return self._configuration @property def aiml_parser(self): return self._aiml_parser @property def denormals(self): return self._denormal_collection @property def normals(self): return self._normal_collection @property def genders(self): return self._gender_collection @property def persons(self): return self._person_collection @property def person2s(self): return self._person2_collection @property def rdf(self): return self._rdf_collection @property def sets(self): return self._sets_collection @property def maps(self): return self._maps_collection @property def properties(self): return self._properties_collection @property def preprocessors(self): return self._preprocessors @property def postprocessors(self): return self._postprocessors @property def authentication(self): return self._authentication @property def authorisation(self): return self._authorisation @property def default_oob(self): return self._default_oob @property def oobs(self): return self._oob @property def regex_templates(self): return self._regex_templates @property def dynamics(self): return self._dynamics_collection def load_binary(self, brain_configuration): if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loading binary brain from [%s]" % brain_configuration.binaries.binary_filename) try: start = datetime.datetime.now() gc.disable() f = open(brain_configuration.binaries.binary_filename, "rb") self._aiml_parser = pickle.load(f) gc.enable() f.close() stop = datetime.datetime.now() diff = stop - start if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Brain load took a total of %.2f sec" % diff.total_seconds()) load_aiml = False except Exception as e: logging.exception(e) if brain_configuration.binaries.load_aiml_on_binary_fail is True: load_aiml = True else: raise e def load_aiml(self, brain_configuration): if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loading aiml source brain") self._aiml_parser.load_aiml(brain_configuration) def save_binary(self, brain_configuration): if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Saving binary brain to [%s]" % brain_configuration.binaries.binary_filename) start = datetime.datetime.now() f = open(brain_configuration.binaries.binary_filename, "wb") pickle.dump(self._aiml_parser, f) f.close() stop = datetime.datetime.now() diff = stop - start if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Brain save took a total of %.2f sec" % diff.total_seconds()) def load(self, brain_configuration: BrainConfiguration): if brain_configuration.binaries.load_binary is True: self.load_binary(brain_configuration) self.load_aiml(brain_configuration) if brain_configuration.binaries.save_binary is True: self.save_binary(brain_configuration) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loading collections") self.load_collections(brain_configuration) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loading services") self.load_services(brain_configuration) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loading security services") self.load_security_services(brain_configuration) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loading oob processors") self.load_oob_processors(brain_configuration) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loading regex templates") self.load_regex_templates(brain_configuration) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loading dynamics sets, maps and vars") self.load_dynamics(brain_configuration) def _load_denormals(self, brain_configuration): if brain_configuration.files.denormal is not None: total = self._denormal_collection.load_from_filename( brain_configuration.files.denormal) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loaded a total of %d denormalisations", total) else: if logging.getLogger().isEnabledFor(logging.WARNING): logging.warning("No configuration setting for denormal") def _load_normals(self, brain_configuration): if brain_configuration.files.normal is not None: total = self._normal_collection.load_from_filename( brain_configuration.files.normal) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loaded a total of %d normalisations", total) else: if logging.getLogger().isEnabledFor(logging.WARNING): logging.warning("No configuration setting for normal") def _load_genders(self, brain_configuration): if brain_configuration.files.gender is not None: total = self._gender_collection.load_from_filename( brain_configuration.files.gender) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loaded a total of %d genderisations", total) else: if logging.getLogger().isEnabledFor(logging.WARNING): logging.warning("No configuration setting for gender") def _load_persons(self, brain_configuration): if brain_configuration.files.person is not None: total = self._person_collection.load_from_filename( brain_configuration.files.person) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loaded a total of %d persons", total) else: if logging.getLogger().isEnabledFor(logging.WARNING): logging.warning("No configuration setting for person") def _load_person2s(self, brain_configuration): if brain_configuration.files.person2 is not None: total = self._person2_collection.load_from_filename( brain_configuration.files.person2) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loaded a total of %d person2s", total) else: if logging.getLogger().isEnabledFor(logging.WARNING): logging.warning("No configuration setting for person2") def _load_properties(self, brain_configuration): if brain_configuration.files.properties is not None: total = self._properties_collection.load_from_filename( brain_configuration.files.properties) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loaded a total of %d properties", total) else: if logging.getLogger().isEnabledFor(logging.WARNING): logging.warning("No configuration setting for properties") def _load_rdf(self, brain_configuration): if brain_configuration.files.rdf_files is not None and brain_configuration.files.rdf_files.files is not None: total = self._rdf_collection.load( brain_configuration.files.rdf_files) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loaded a total of %d rdf files", total) elif brain_configuration.files.triples is not None: total = self._rdf_collection.load_from_filename( brain_configuration.files.triples) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loaded a total of %d triples", total) else: if logging.getLogger().isEnabledFor(logging.WARNING): logging.warning("No configuration setting for triples") def _load_sets(self, brain_configuration): total = self._sets_collection.load(brain_configuration.files.set_files) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loaded a total of %d sets files", total) def _load_maps(self, brain_configuration): total = self._maps_collection.load(brain_configuration.files.map_files) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loaded a total of %d maps files", total) def _load_preprocessors(self, brain_configuration): if brain_configuration.files.preprocessors is not None: total = self._preprocessors.load( brain_configuration.files.preprocessors) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loaded a total of %d pre processors", total) else: if logging.getLogger().isEnabledFor(logging.WARNING): logging.warning("No configuration setting for pre processors") def _load_postprocessors(self, brain_configuration): if brain_configuration.files.postprocessors is not None: total = self._postprocessors.load( brain_configuration.files.postprocessors) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loaded a total of %d post processors", total) else: if logging.getLogger().isEnabledFor(logging.WARNING): logging.warning("No configuration setting for post processors") def load_collections(self, brain_configuration): self._load_denormals(brain_configuration) self._load_normals(brain_configuration) self._load_genders(brain_configuration) self._load_persons(brain_configuration) self._load_person2s(brain_configuration) self._load_properties(brain_configuration) self._load_rdf(brain_configuration) self._load_sets(brain_configuration) self._load_maps(brain_configuration) self._load_preprocessors(brain_configuration) self._load_postprocessors(brain_configuration) def load_services(self, brain_configuration): ServiceFactory.preload_services(brain_configuration.services) def load_security_services(self, brain_configuration): if brain_configuration.security is not None: if brain_configuration.security.authentication is not None: if brain_configuration.security.authentication.classname is not None: try: classobject = ClassLoader.instantiate_class( brain_configuration.security.authentication. classname) self._authentication = classobject( brain_configuration.security.authentication) except Exception as excep: logging.exception(excep) else: if logging.getLogger().isEnabledFor(logging.DEBUG): logging.debug("No authentication configuration defined") if brain_configuration.security.authorisation is not None: if brain_configuration.security.authorisation.classname is not None: try: classobject = ClassLoader.instantiate_class( brain_configuration.security.authorisation. classname) self._authorisation = classobject( brain_configuration.security.authorisation) except Exception as excep: logging.exception(excep) else: if logging.getLogger().isEnabledFor(logging.DEBUG): logging.debug("No authorisation configuration defined") else: if logging.getLogger().isEnabledFor(logging.DEBUG): logging.debug( "No security configuration defined, running open...") def load_dynamics(self, brain_configuration): if brain_configuration.dynamics is not None: self._dynamics_collection.load_from_configuration( brain_configuration.dynamics) else: if logging.getLogger().isEnabledFor(logging.DEBUG): logging.debug("No dynamics configuration defined...") def pre_process_question(self, bot, clientid, question): return self.preprocessors.process(bot, clientid, question) def parse_last_sentences_from_response(self, response): response = re.sub(r'<\s*br\s*/>\s*', ".", response) response = re.sub(r'<br></br>*', ".", response) sentences = response.split(".") sentences = [x for x in sentences if x] last_sentence = sentences[-1] that_pattern = TextUtils.strip_all_punctuation(last_sentence) that_pattern = that_pattern.strip() return that_pattern def load_oob_processors(self, brain_configuration): if brain_configuration.oob is not None: if brain_configuration.oob.default() is not None: try: if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loading default oob") classobject = ClassLoader.instantiate_class( brain_configuration.oob.default().classname) self._default_oob = classobject() except Exception as excep: logging.exception(excep) for oob_name in brain_configuration.oob.oobs(): try: if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loading oob: %s" % oob_name) classobject = ClassLoader.instantiate_class( brain_configuration.oob.oob(oob_name).classname) self._oob[oob_name] = classobject() except Exception as excep: logging.exception(excep) def load_regex_templates(self, brain_configuration): if brain_configuration.files.regex_templates is not None: collection = PropertiesCollection() total = collection.load_from_filename( brain_configuration.files.regex_templates) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Loaded a total of %d regex templates", total) for pair in collection.pairs: name = pair[0] pattern = pair[1] try: self._regex_templates[name] = re.compile(pattern) except Exception: if logging.getLogger().isEnabledFor(logging.INFO): logging.error("Invalid regex template [%s]" % pattern) def regex_template(self, name): if name in self._regex_templates: return self._regex_templates[name] else: return None def strip_oob(self, response): m = re.compile("(.*)(<\s*oob\s*>.*<\/\s*oob\s*>)(.*)") g = m.match(response) if g is not None: front = g.group(1).strip() back = g.group(3).strip() response = "" if front != "": response = front + " " response += back oob = g.group(2) return response, oob return response, None def process_oob(self, bot, clientid, oob_command): oob_content = ET.fromstring(oob_command) if oob_content.tag == 'oob': for child in oob_content.findall('./'): if child.tag in self._oob: oob_class = self._oob[child.tag] return oob_class.process_out_of_bounds( bot, clientid, child) else: return self._default_oob.process_out_of_bounds( bot, clientid, child) return "" def post_process_response(self, bot, clientid, response: str): return self.postprocessors.process(bot, clientid, response) def dump_tree(self): self._aiml_parser.pattern_parser.root.dump(tabs="") def ask_question(self, bot, clientid, sentence, srai=False, brain_question_context=None): if brain_question_context is not None: brain_question_context.clientid = clientid brain_question_context.srai = srai brain_question_context.sentence = sentence if self.authentication is not None: if self.authentication.authenticate(clientid) is False: if logging.getLogger().isEnabledFor(logging.ERROR): logging.error("[%s] failed authentication!") return self.authentication.configuration.denied_srai conversation = bot.get_conversation(clientid) topic_pattern = conversation.property("topic") if topic_pattern is None: if logging.getLogger().isEnabledFor(logging.INFO): logging.info("No Topic pattern default to [*]") topic_pattern = "*" else: if logging.getLogger().isEnabledFor(logging.INFO): logging.info("Topic pattern = [%s]", topic_pattern) if brain_question_context is not None: brain_question_context.topic = topic_pattern try: that_question = conversation.previous_nth_question(1) that_sentence = that_question.current_sentence() # If the last response was valid, i.e not none and not empty string, then use # that as the that_pattern, otherwise we default to '*' as pattern if that_sentence.response is not None and that_sentence.response != '': that_pattern = self.parse_last_sentences_from_response( that_sentence.response) if logging.getLogger().isEnabledFor(logging.INFO): logging.info("That pattern = [%s]", that_pattern) else: if logging.getLogger().isEnabledFor(logging.INFO): logging.info("That pattern, no response, default to [*]") that_pattern = "*" except Exception: if logging.getLogger().isEnabledFor(logging.INFO): logging.info("No That pattern default to [*]") that_pattern = "*" if brain_question_context is not None: brain_question_context.that = that_pattern match_context = self._aiml_parser.match_sentence( bot, clientid, sentence, topic_pattern=topic_pattern, that_pattern=that_pattern) if match_context is not None: if brain_question_context is not None: brain_question_context.match_context = match_context template_node = match_context.template_node() if logging.getLogger().isEnabledFor(logging.DEBUG): logging.debug("AIML Parser evaluating template [%s]", template_node.to_string()) response = template_node.template.resolve(bot, clientid) if brain_question_context is not None: brain_question_context.raw_response = response if "<oob>" in response: response, oob = self.strip_oob(response) if oob is not None: oob_response = self.process_oob(bot, clientid, oob) if brain_question_context is not None: brain_question_context.raw_response = response brain_question_context.oob_response = oob_response response = response + " " + oob_response return response return None
class Brain(object): def __init__(self, configuration: BrainConfiguration): self._configuration = configuration self._aiml_parser = AIMLParser(self) self._denormal_collection = DenormalCollection() self._normal_collection = NormalCollection() self._gender_collection = GenderCollection() self._person_collection = PersonCollection() self._person2_collection = PersonCollection() self._predicates_collection = PredicatesCollection() self._pronouns_collection = PronounsCollection() self._triples_collection = TriplesCollection() self._sets_collection = SetCollection() self._maps_collection = MapCollection() self._properties_collection = PropertiesCollection() self._preprocessors = ProcessorLoader() self._postprocessors = ProcessorLoader() self._authentication = None self._authorisation = None self._default_oob = None self._oob = {} self.load(self._configuration) @property def configuration(self): return self._configuration @property def aiml_parser(self): return self._aiml_parser @property def denormals(self): return self._denormal_collection @property def normals(self): return self._normal_collection @property def genders(self): return self._gender_collection @property def persons(self): return self._person_collection @property def person2s(self): return self._person2_collection @property def predicates(self): return self._predicates_collection @property def pronouns(self): return self._pronouns_collection @property def triples(self): return self._triples_collection @property def sets(self): return self._sets_collection @property def maps(self): return self._maps_collection @property def properties(self): return self._properties_collection @property def preprocessors(self): return self._preprocessors @property def postprocessors(self): return self._postprocessors @property def authentication(self): return self._authentication @property def authorisation(self): return self._authorisation @property def default_oob(self): return self._default_oob @property def oobs(self): return self._oob def load_binary(self, brain_configuration): logging.info("Loading binary brain from [%s]" % brain_configuration.binaries.binary_filename) try: start = datetime.datetime.now() gc.disable() f = open(brain_configuration.binaries.binary_filename, "rb") self._aiml_parser = pickle.load(f) gc.enable() f.close() stop = datetime.datetime.now() diff = stop - start logging.info("Brain load took a total of %.2f sec" % diff.total_seconds()) load_aiml = False except Exception as e: logging.exception(e) if brain_configuration.binaries.load_aiml_on_binary_fail is True: load_aiml = True else: raise e def load_aiml(self, brain_configuration): logging.info("Loading aiml source brain") self._aiml_parser.load_aiml(brain_configuration) def save_binary(self, brain_configuration): logging.info("Saving binary brain to [%s]" % brain_configuration.binaries.binary_filename) start = datetime.datetime.now() f = open(brain_configuration.binaries.binary_filename, "wb") pickle.dump(self._aiml_parser, f) f.close() stop = datetime.datetime.now() diff = stop - start logging.info("Brain save took a total of %.2f sec" % diff.total_seconds()) def load(self, brain_configuration: BrainConfiguration): if brain_configuration.binaries.load_binary is True: self.load_binary(brain_configuration) self.load_aiml(brain_configuration) if brain_configuration.binaries.save_binary is True: self.save_binary(brain_configuration) logging.info("Loading collections") self.load_collections(brain_configuration) logging.info("Loading services") self.load_services(brain_configuration) logging.info("Loading security services") self.load_security_services(brain_configuration) logging.info("Loading oob processors") self.load_oob_processors(brain_configuration) def _load_denormals(self, brain_configuration): if brain_configuration.files.denormal is not None: total = self._denormal_collection.load_from_filename( brain_configuration.files.denormal) logging.info("Loaded a total of %d denormalisations", total) else: logging.warning("No configuration setting for denormal") def _load_normals(self, brain_configuration): if brain_configuration.files.normal is not None: total = self._normal_collection.load_from_filename( brain_configuration.files.normal) logging.info("Loaded a total of %d normalisations", total) else: logging.warning("No configuration setting for normal") def _load_genders(self, brain_configuration): if brain_configuration.files.gender is not None: total = self._gender_collection.load_from_filename( brain_configuration.files.gender) logging.info("Loaded a total of %d genderisations", total) else: logging.warning("No configuration setting for gender") def _load_persons(self, brain_configuration): if brain_configuration.files.person is not None: total = self._person_collection.load_from_filename( brain_configuration.files.person) logging.info("Loaded a total of %d persons", total) else: logging.warning("No configuration setting for person") def _load_person2s(self, brain_configuration): if brain_configuration.files.person2 is not None: total = self._person2_collection.load_from_filename( brain_configuration.files.person2) logging.info("Loaded a total of %d person2s", total) else: logging.warning("No configuration setting for person2") def _load_predicates(self, brain_configuration): if brain_configuration.files.predicates is not None: total = self._predicates_collection.load_from_filename( brain_configuration.files.predicates) logging.info("Loaded a total of %d predicates", total) else: logging.warning("No configuration setting for predicates") def _load_pronouns(self, brain_configuration): if brain_configuration.files.pronouns is not None: total = self._pronouns_collection.load_from_filename( brain_configuration.files.pronouns) logging.info("Loaded a total of %d pronouns", total) else: logging.warning("No configuration setting for pronouns") def _load_properties(self, brain_configuration): if brain_configuration.files.properties is not None: total = self._properties_collection.load_from_filename( brain_configuration.files.properties) logging.info("Loaded a total of %d properties", total) else: logging.warning("No configuration setting for properties") def _load_triples(self, brain_configuration): if brain_configuration.files.triples is not None: total = self._properties_collection.load_from_filename( brain_configuration.files.triples) logging.info("Loaded a total of %d triples", total) else: logging.warning("No configuration setting for triples") def _load_sets(self, brain_configuration): total = self._sets_collection.load(brain_configuration.files.set_files) logging.info("Loaded a total of %d sets files", total) def _load_maps(self, brain_configuration): total = self._maps_collection.load(brain_configuration.files.map_files) logging.info("Loaded a total of %d maps files", total) def _load_preprocessors(self, brain_configuration): if brain_configuration.files.preprocessors is not None: total = self._preprocessors.load( brain_configuration.files.preprocessors) logging.info("Loaded a total of %d pre processors", total) else: logging.warning("No configuration setting for pre processors") def _load_postprocessors(self, brain_configuration): if brain_configuration.files.postprocessors is not None: total = self._postprocessors.load( brain_configuration.files.postprocessors) logging.info("Loaded a total of %d post processors", total) else: logging.warning("No configuration setting for post processors") def load_collections(self, brain_configuration): self._load_denormals(brain_configuration) self._load_normals(brain_configuration) self._load_genders(brain_configuration) self._load_persons(brain_configuration) self._load_person2s(brain_configuration) self._load_predicates(brain_configuration) self._load_pronouns(brain_configuration) self._load_properties(brain_configuration) self._load_triples(brain_configuration) self._load_sets(brain_configuration) self._load_maps(brain_configuration) self._load_preprocessors(brain_configuration) self._load_postprocessors(brain_configuration) def load_services(self, brain_configuration): ServiceFactory.preload_services(brain_configuration.services) def load_security_services(self, brain_configuration): if brain_configuration.security is not None: if brain_configuration.security.authentication is not None: if brain_configuration.security.authentication.classname is not None: try: classobject = ClassLoader.instantiate_class( brain_configuration.security.authentication. classname) self._authentication = classobject( brain_configuration.security.authentication) except Exception as excep: logging.exception(excep) else: logging.debug("No authentication configuration defined") if brain_configuration.security.authorisation is not None: if brain_configuration.security.authorisation.classname is not None: try: classobject = ClassLoader.instantiate_class( brain_configuration.security.authorisation. classname) self._authorisation = classobject( brain_configuration.security.authorisation) except Exception as excep: logging.exception(excep) else: logging.debug("No authorisation configuration defined") else: logging.debug("No security configuration defined, running open...") def pre_process_question(self, bot, clientid, question): return self.preprocessors.process(bot, clientid, question) def ask_question(self, bot, clientid, sentence) -> str: if self.authentication is not None: if self.authentication.authenticate(clientid) is False: logging.error("[%s] failed authentication!") return self.authentication.configuration.denied_srai conversation = bot.get_conversation(clientid) topic_pattern = conversation.predicate("topic") if topic_pattern is None: logging.info("No Topic pattern default to [*]") topic_pattern = "*" else: logging.info("Topic pattern = [%s]", topic_pattern) try: that_question = conversation.nth_question(2) that_sentence = that_question.current_sentence() # If the last response was valid, i.e not none and not empty string, then use # that as the that_pattern, otherwise we default to '*' as pattern if that_sentence.response is not None and that_sentence.response != '': that_pattern = TextUtils.strip_all_punctuation( that_sentence.response) logging.info("That pattern = [%s]", that_pattern) else: logging.info("That pattern, no response, default to [*]") that_pattern = "*" except Exception: logging.info("No That pattern default to [*]") that_pattern = "*" match_context = self._aiml_parser.match_sentence( bot, clientid, sentence, topic_pattern=topic_pattern, that_pattern=that_pattern) if match_context is not None: template_node = match_context.template_node() logging.debug("AIML Parser evaluating template [%s]", template_node.to_string()) response = template_node.template.resolve(bot, clientid) if "<oob>" in response: response, oob = self.strip_oob(response) if oob is not None: oob_response = self.process_oob(bot, clientid, oob) response = response + " " + oob_response return response return None def load_oob_processors(self, brain_configuration): if brain_configuration.oob is not None: if brain_configuration.oob.default() is not None: try: logging.info("Loading default oob") classobject = ClassLoader.instantiate_class( brain_configuration.oob.default().classname) self._default_oob = classobject() except Exception as excep: logging.exception(excep) for oob_name in brain_configuration.oob.oobs(): try: logging.info("Loading oob: %s" % oob_name) classobject = ClassLoader.instantiate_class( brain_configuration.oob.oob(oob_name).classname) self._oob[oob_name] = classobject() except Exception as excep: logging.exception(excep) def strip_oob(self, response): m = re.compile("(.*)(<\s*oob\s*>.*<\/\s*oob\s*>)(.*)") g = m.match(response) if g is not None: front = g.group(1).strip() back = g.group(3).strip() response = "" if front != "": response = front + " " response += back oob = g.group(2) return response, oob return response, None def process_oob(self, bot, clientid, oob_command): oob_content = ET.fromstring(oob_command) if oob_content.tag == 'oob': for tag in oob_content: if tag in self._oob: oob_class = self._oob[tag] return oob_class.process_out_of_bounds(bot, clientid, tag) else: return self._default_oob.process_out_of_bounds( bot, clientid, tag) return "" def post_process_response(self, bot, clientid, response: str): return self.postprocessors.process(bot, clientid, response) def dump_tree(self): self._aiml_parser.pattern_parser.root.dump(tabs="")