diff --git a/sopel_modules/SpiceBot/AI.py b/sopel_modules/SpiceBot/AI.py index af6e560..b380ebc 100644 --- a/sopel_modules/SpiceBot/AI.py +++ b/sopel_modules/SpiceBot/AI.py @@ -5,12 +5,18 @@ This is the SpiceBot AI system. Based On Chatty cathy """ from sopel.tools import Identifier +from sopel.config.types import StaticSection, ListAttribute import os import tempfile import aiml from .Database import db as botdb +from .Logs import logs + + +class SpiceBot_AI_MainSection(StaticSection): + extra = ListAttribute('extra') class SpiceBot_AI(): @@ -18,17 +24,28 @@ class SpiceBot_AI(): def __init__(self): self.dict = { "counts": 0, + "failcounts": 0, "sessioncache": {} } # Load AIML kernel self.aiml_kernel = aiml.Kernel() + # aiml parser + self.aiml_parser = aiml.AimlParser.create_parser() + self.aiml_parser.setEncoding(None) + # Don't warn for no matches self.aiml_kernel._verboseMode = False # Learn responses self.load_brain() + if self.dict["counts"]: + logs.log('SpiceBot_AI', 'Registered %d %s files,' % (self.dict["counts"], 'aiml')) + logs.log('SpiceBot_AI', '%d %s files failed to load' % (self.dict["failcounts"], 'aiml'), True) + else: + logs.log('SpiceBot_AI', "Warning: Couldn't load any %s files" % ('aiml')) + def load_brain(self): import sopel_modules braindirs = [] @@ -37,9 +54,20 @@ class SpiceBot_AI(): aimldir = os.path.join(configsdir, "aiml") braindirs.append(aimldir) - # TODO add extra config + # for aimldir in bot.config.SpiceBot_AI.extra: + # braindirs.append(aimldir) + # learn directories + self.learn(braindirs) + + def load_extras(self, bot): + if len(bot.config.SpiceBot_AI.extra): + self.learn(self, bot.config.SpiceBot_AI.extra) + + def learn(self, braindirs): for braindir in braindirs: + for parsefile in os.listdir(braindir): + self.check_file_parse(parsefile) tempbrain = tempfile.mkstemp()[1] with open(tempbrain, 'w') as fileo: fileo.write( @@ -59,16 +87,36 @@ class SpiceBot_AI(): def on_message(self, bot, trigger, message): nick = Identifier(trigger.nick) - nick_id = bot.db.get_nick_id(nick, create=True) + nick_id = botdb.get_nick_id(nick, create=True) + self.check_user_import(nick, nick_id) + aiml_response = self.aiml_kernel.respond(message, nick_id) + self.save_nick_session(nick, nick_id) + return aiml_response + + def check_user_import(self, nick, nick_id=None): + if not nick_id: + nick = Identifier(nick) + nick_id = botdb.get_nick_id(nick, create=True) if nick_id not in self.dict["sessioncache"].keys(): self.dict["sessioncache"][nick_id] = botdb.get_nick_value(nick, 'botai') or {} for predicate in self.dict["sessioncache"][nick_id].keys(): predval = self.dict["sessioncache"][nick_id][predicate] self.aiml_kernel.setPredicate(predicate, predval, nick_id) - aiml_response = self.aiml_kernel.respond(message, nick_id) + + def save_nick_session(self, nick, nick_id=None): + if not nick_id: + nick = Identifier(nick) + nick_id = botdb.get_nick_id(nick, create=True) sessionData = self.aiml_kernel.getSessionData(nick_id) botdb.set_nick_value(nick, 'botai', sessionData) - return aiml_response + + def check_file_parse(self, parsefile): + try: + self.aiml_parser.parse(parsefile) + self.dict["counts"] += 1 + except Exception as e: + logs.log('SpiceBot_AI', "Error loading %s: %s (%s)" % ('aiml', e, parsefile)) + self.dict["failcounts"] += 1 botai = SpiceBot_AI() diff --git a/sopel_modules/SpiceBot/Config.py b/sopel_modules/SpiceBot/Config.py index dced9d4..3f0bcbf 100644 --- a/sopel_modules/SpiceBot/Config.py +++ b/sopel_modules/SpiceBot/Config.py @@ -24,6 +24,9 @@ class BotConfig(): opts = parser.parse_args(argv) self.config = get_configuration(opts) + self.config.core.prefix_list = str(self.config.core.prefix).replace("\\", '').split("|") + self.config.core.prefix_list.append("?") + self.config.basename = os.path.basename(self.config.filename).rsplit('.', 1)[0] self.config.core.logs_stdio = os.path.join(self.config.core.logdir, 'stdio.log') # self.config.core.logs_stdio = os.path.os.path.join(self.config.core.logdir, self.config.basename + '.stdio.log') diff --git a/sopel_modules/SpiceBot/configure.py b/sopel_modules/SpiceBot/configure.py index 7fb2352..dbcc464 100644 --- a/sopel_modules/SpiceBot/configure.py +++ b/sopel_modules/SpiceBot/configure.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals, absolute_import, division, print_functi """Configuration for SpiceBot""" from .Channels import SpiceBot_Channels_MainSection +from .AI import SpiceBot_AI_MainSection from .Update import SpiceBot_Update_MainSection from .Kick import SpiceBot_Kick from .osd import SpiceBot_OSD @@ -31,3 +32,6 @@ def configure(config): config.define_section("SpiceBot_Kick", SpiceBot_Kick, validate=False) config.SpiceBot_Kick.configure_setting('kick', 'MAXTARG limit for KICK') + + config.define_section("SpiceBot_AI", SpiceBot_AI_MainSection, validate=False) + config.SpiceBot_AI.configure_setting('extra', 'extra aiml directories to import matches from') diff --git a/sopel_modules/SpiceBot/setup.py b/sopel_modules/SpiceBot/setup.py index 251638e..3d240fe 100644 --- a/sopel_modules/SpiceBot/setup.py +++ b/sopel_modules/SpiceBot/setup.py @@ -15,6 +15,7 @@ from .Channels import SpiceBot_Channels_MainSection from .Update import SpiceBot_Update_MainSection from .osd import SopelWrapperOSD, ToolsOSD, SopelOSD, SpiceBot_OSD from .Kick import SopelWrapperKICK, SopelKICK, SpiceBot_Kick +from .AI import SpiceBot_AI_MainSection, botai def setup(bot): @@ -46,6 +47,9 @@ def setup(bot): bot.config.define_section("SpiceBot_Kick", SpiceBot_Kick, validate=False) botconfig.define_section("SpiceBot_Kick", SpiceBot_Kick, validate=False) + bot.config.core.prefix_list = str(bot.config.core.prefix).replace("\\", '').split("|") + bot.config.core.prefix_list.append("?") + logs.log('SpiceBot_Config', "Setting Up Configuration") bot.config.core.basename = os.path.basename(bot.config.filename).rsplit('.', 1)[0] bot.config.core.logs_stdio = os.path.join(bot.config.core.logdir, 'stdio.log') @@ -72,3 +76,7 @@ def setup(bot): events.BOT_STARTUPMONOLOGUE_CHANNELS, events.BOT_STARTUPMONOLOGUE_COMMANDS ]) + + logs.log('SpiceBot_AI', "Setting Up Configuration") + bot.config.define_section("SpiceBot_AI", SpiceBot_AI_MainSection, validate=False) + botai.load_extras(bot) diff --git a/sopel_modules/SpiceBot_AI/AI_aiml.py b/sopel_modules/SpiceBot_AI/AI_aiml.py index a29eb2a..dc98e5e 100644 --- a/sopel_modules/SpiceBot_AI/AI_aiml.py +++ b/sopel_modules/SpiceBot_AI/AI_aiml.py @@ -16,10 +16,12 @@ def bot_command_nick(bot, trigger): if not len(trigger.args): return - # TODO actual prefix - if str(trigger.args[1]).startswith((".", '?', '!')) or str(trigger.args[1]).lower().startswith(bot.nick.lower()): + message = trigger.args[1] + + # ignore text coming from a valid prefix + if str(message).startswith(tuple(bot.config.core.prefix_list)): return - returnmessage = SpiceBot.botai.on_message(bot, trigger, trigger.args[1]) - - bot.osd(str(returnmessage)) + returnmessage = SpiceBot.botai.on_message(bot, trigger, message) + if returnmessage: + bot.osd(str(returnmessage))