Ejemplo n.º 1
0
    def _reply(self, irc, msg, channel, text):
        """Send a response to text"""
        
        cobeBrain = Brain(self._getBrainDirectoryForChannel(channel))
        response = cobeBrain.reply(text).encode('utf-8')
        response = self._strip_nick(irc, msg, response)
        
        for i in range(response.lower().count(self.magicnick.lower())):
            # If first word is nick, switch with the callers nick.
            if self.magicnick in response:
                response = response.replace(self.magicnick, random.choice(list(irc.state.channels[msg.args[0]].users)))
            if self.magicnick.lower() in response:
                response = response.replace(self.magicnick.lower(), random.choice(list(irc.state.channels[msg.args[0]].users)))

        
        cobeBrain.learn(response) # Let's have the bot learn the wacky things it says
        
        self.log.info("Attempting to respond in {0} with message: {1}".format(channel, response))
        
        # delay the response here so we look real?
        if self.registryValue('responseDelay', channel):
            self.log.info("Delayed the response in %s." % channel)
            delayseconds = time.time() + random.randint(2, 5)
            schedule.addEvent(irc.queueMsg(ircmsgs.privmsg(channel, response)), delayseconds)
        else:
            irc.queueMsg(ircmsgs.privmsg(channel, response))
Ejemplo n.º 2
0
 def _learn(self, irc, channel, text, probability):
     """Internal method for learning phrases."""
     
     if os.path.exists(self._getBrainDirectoryForChannel(channel)):
         # Does this channel have a directory for the brain file stored and does this file exist?
         
         text = self._cleanText(text)
         
         if text and len(text) > 1 and not text.isspace():
     
             self.log.debug("Learning: {0}".format(text))
             cobeBrain = Brain(self._getBrainDirectoryForChannel(channel))
             cobeBrain.learn(text)
             
             if random.randint(0, 10000) <= probability:
                 self._reply(irc, channel, text)
             
     else: # Nope, let's make it!
                     
         commands.getoutput('{0} {1}'.format(self._doCommand(channel), 'init'))
         
         text = self._cleanText(text)
         
         if text and len(text) > 1 and not text.isspace():
     
             self.log.debug("Learning: {0}".format(text))
             cobeBrain = Brain(self._getBrainDirectoryForChannel(channel))
             cobeBrain.learn(text)
             
             if random.randint(0, 10000) <= probability:
                 self._reply(irc, channel, text)
Ejemplo n.º 3
0
def learn_text(text, brain_name):
    brain = Brain(brain_name)
    if not os.path.isfile(brain_name):
        print("- Training...")
        for sent in text:
            brain.learn(sent)
    return brain
Ejemplo n.º 4
0
    def _learn(self, irc, msg, channel, text, probability):
        """Internal method for learning phrases."""

        if os.path.exists(self._getBrainDirectoryForChannel(channel)):
            # Does this channel have a directory for the brain file stored and does this file exist?

            text = self._cleanText(text)

            if text and len(text) > 1 and not text.isspace():

                self.log.debug("Learning: {0}".format(text))
                cobeBrain = Brain(self._getBrainDirectoryForChannel(channel))
                cobeBrain.learn(text)

                if random.randint(0, 10000) <= probability:
                    self._reply(irc, msg, channel, text)

        else:  # Nope, let's make it!

            commands.getoutput('{0} {1}'.format(self._doCommand(channel),
                                                'init'))

            text = self._cleanText(text)

            if text and len(text) > 1 and not text.isspace():

                self.log.debug("Learning: {0}".format(text))
                cobeBrain = Brain(self._getBrainDirectoryForChannel(channel))
                cobeBrain.learn(text)

                if random.randint(0, 10000) <= probability:
                    self._reply(irc, msg, channel, text)
Ejemplo n.º 5
0
    def _reply(self, irc, msg, channel, text):
        """Send a response to text"""

        cobeBrain = Brain(self._getBrainDirectoryForChannel(channel))
        response = cobeBrain.reply(text).encode('utf-8')
        response = self._strip_nick(irc, msg, response)

        for i in range(response.lower().count(self.magicnick.lower())):
            # If first word is nick, switch with the callers nick.
            if self.magicnick in response:
                response = response.replace(
                    self.magicnick,
                    random.choice(list(irc.state.channels[msg.args[0]].users)))
            if self.magicnick.lower() in response:
                response = response.replace(
                    self.magicnick.lower(),
                    random.choice(list(irc.state.channels[msg.args[0]].users)))

        cobeBrain.learn(
            response)  # Let's have the bot learn the wacky things it says

        self.log.info("Attempting to respond in {0} with message: {1}".format(
            channel, response))

        # delay the response here so we look real?
        if self.registryValue('responseDelay', channel):
            self.log.info("Delayed the response in %s." % channel)
            delayseconds = time.time() + random.randint(2, 5)
            schedule.addEvent(irc.queueMsg(ircmsgs.privmsg(channel, response)),
                              delayseconds)
        else:
            irc.queueMsg(ircmsgs.privmsg(channel, response))
Ejemplo n.º 6
0
class Markov:
    def __init__(self, brain_id):
        self.brain_id = brain_id
        brain_path = f'data/cobe/{brain_id}'
        os.makedirs('data/cobe/', exist_ok=True)

        self.brain = Brain(brain_path)

    def filter(self, message):
        message = re.sub('\<@[A-Z0-9a-z]{9}\>', '', message)  # remove mentions
        message = re.sub('\s{2,}', ' ', message)  #remove double spaces
        message = re.sub('\<[^\<]+\>', '', message)  #remove shit like links
        message = message.strip()  # remove unneeded spaces
        valid = False
        if len(message) > 5:
            valid = True
        return [valid, message]

    def learn(self, message):
        valid, message = self.filter(message)
        if not valid:
            return
        self.brain.learn(message)

    def speak(self, message):
        response = self.brain.reply(message)
        valid, response = self.filter(response)
        if not valid:
            return None
        return response
Ejemplo n.º 7
0
def handle(msg):
    print msg
    content_type, chat_type, chat_id = telepot.glance(msg)
    if content_type == 'text':
        brain = Brain(config.get('Brain', 'path') + str(chat_id) + ".brain")
        brain.learn(msg['text'])
        if 'braulio' in msg['text'].lower():
            bot.sendMessage(chat_id,brain.reply(msg['text']))
Ejemplo n.º 8
0
def handle(msg):
    print msg
    content_type, chat_type, chat_id = telepot.glance(msg)
    if content_type == 'text':
        brain = Brain(config.get('Brain', 'path') + str(chat_id) + ".brain")
        brain.learn(msg['text'])
        if 'braulio' in msg['text'].lower():
            bot.sendMessage(chat_id, brain.reply(msg['text']))
Ejemplo n.º 9
0
def handle(msg):
    content_type, chat_type, chat_id = telepot.glance(msg)
    if content_type == 'text':
        brain = Brain(config.get('Brain', 'path') + str(chat_id) + ".brain")
        brain.learn(msg['text'])
        if 'reply_to_message' in msg and msg['reply_to_message']['from']['username'] == "Braulio_bot":
            bot.sendMessage(chat_id,brain.reply(msg['text']),reply_to_message_id=msg['message_id'])
        elif 'braulio' in msg['text'].lower():
            bot.sendMessage(chat_id,brain.reply(msg['text']).replace("Braulio",msg['from']['first_name']))
Ejemplo n.º 10
0
    def _learn_corpus(self, corpus_file, brain_name, questions=False):
        if not os.path.isfile(brain_name):
            brain = Brain(brain_name)
            print("- Training...")
            corpus = read_file(corpus_file)
            corpus = clean_text(corpus, get_questions=questions)

            for sent in corpus:
                brain.learn(sent)

        return Brain(brain_name)
Ejemplo n.º 11
0
 def _learn(self, irc, channel, text, probability):
     text = self._cleantext(text)
     if text:
         if len(text) > 0 and not text.isspace():
             b = Brain(self._brainfile)
             b.learn(text)
     # determine probability to respond.
     if random.randint(0, 100) < probability:
         # if we've randomly determined to talk, check the update time.
         sentinel = self._updatesentinel(channel)
         if sentinel:
             self._reply(irc, channel, text)
Ejemplo n.º 12
0
    def corpuslearn(self, irc, msg, args, text):
        """<text>

        Manually teach the corpus <text>
        """

        text = self._cleantext(text)
        if text and len(text) > 1 and not text.isspace():
            irc.reply("I am learning: {0}".format(text))
            b = Brain(self._brainfile)
            b.learn(text)
        else:
            irc.reply("After sanitizing, I did not have any text to learn.")
Ejemplo n.º 13
0
def fun(message):
    print message.text
    brain = Brain("/db/" + str(message.chat.id)[1:] + ".br")
    # Telegram understands UTF-8, so encode text for unicode compatibility
    brain.learn(message.text)
    if "tagueul" in message.text.lower() or "tg" in message.text.lower() or "ta gueule" in message.text.lower():
        bot.reply_to(message, "Non, toi ta gueule.")
    elif (randint(1, 100) < percent):
        if violence : 
          bot.reply_to(message, brain.reply(message.text.upper(), 3000))
        else :
          bot.reply_to(message, brain.reply(message.text, 3000))
    return 'ok'
Ejemplo n.º 14
0
    def testLearnStems(self):
        Brain.init(TEST_BRAIN_FILE, order=2)

        brain = Brain(TEST_BRAIN_FILE)
        brain.set_stemmer("english")
        stem = brain.stemmer.stem

        brain.learn("this is testing")

        c = brain.graph.cursor()
        stem_count = c.execute("SELECT count(*) FROM token_stems").fetchone()

        self.assertEqual(3, stem_count[0])
        self.assertEqual(brain.graph.get_token_stem_id(stem("test")),
                          brain.graph.get_token_stem_id(stem("testing")))
Ejemplo n.º 15
0
Archivo: server.py Proyecto: happz/viki
class Chatter(object):
  def __init__(self):
    self.brain = Brain('cobe.brain')

    with open('seed.txt', 'r') as f:
      text = [l.strip() for l in f.read().replace('\n', ' ').replace('.', '\n').replace('?', '\n').replace('\xa0', ' - ').split('\n') if l.strip()]

      for line in text:
        self.brain.learn(line)

  def reply(self, message):
    return self.brain.reply(message)

  def learn(self, line):
    self.brain.learn(line)
Ejemplo n.º 16
0
    def testLearnStems(self):
        Brain.init(TEST_BRAIN_FILE, order=2)

        brain = Brain(TEST_BRAIN_FILE)
        brain.set_stemmer("english")
        stem = brain.stemmer.stem

        brain.learn("this is testing")

        c = brain.graph.cursor()
        stem_count = c.execute("SELECT count(*) FROM token_stems").fetchone()

        self.assertEqual(3, stem_count[0])
        self.assertEqual(brain.graph.get_token_stem_id(stem("test")),
                          brain.graph.get_token_stem_id(stem("testing")))
Ejemplo n.º 17
0
def handle(msg):
    content_type, chat_type, chat_id = telepot.glance(msg)
    if content_type == 'text':
        brain = Brain(config.get('Brain', 'path') + str(chat_id) + ".brain")
        brain.learn(msg['text'])
        if 'reply_to_message' in msg and msg['reply_to_message']['from'][
                'username'] == "Braulio_bot":
            bot.sendMessage(chat_id,
                            brain.reply(msg['text']),
                            reply_to_message_id=msg['message_id'])
        elif 'braulio' in msg['text'].lower():
            bot.sendMessage(
                chat_id,
                brain.reply(msg['text']).replace("Braulio",
                                                 msg['from']['first_name']))
Ejemplo n.º 18
0
 def _reply(self, irc, channel, text):
     """Send a response to text"""
     
     cobeBrain = Brain(self._getBrainDirectoryForChannel(channel))
     response = cobeBrain.reply(text).encode('utf-8')
     
     cobeBrain.learn(response) # Let's have the bot learn the wacky things it says
     
     self.log.info("Attempting to respond in {0} with message: {1}".format(channel, response))
     
     # delay the response here so we look real?
     if self.registryValue('responseDelay', channel):
         self.log.info("Delayed the response in %s." % channel)
         delayseconds = time.time() + random.randint(2, 5)
         schedule.addEvent(irc.queueMsg(ircmsgs.privmsg(channel, response)), delayseconds)
     else:
         irc.queueMsg(ircmsgs.privmsg(channel, response))
Ejemplo n.º 19
0
def learn(archivepath, brain, **kwargs):
    # start brain. Batch saves us from lots of I/O
    brain = Brain(brain)
    brain.set_stemmer(kwargs.get('language', 'english'))

    brain.start_batch_learning()

    tweets = tweet_generator(archivepath, **kwargs)
    count = 0

    for text in tweets:
        count = count + 1
        brain.learn(text)

    brain.stop_batch_learning()

    return count
Ejemplo n.º 20
0
    def train_brain(self, channel):
        """
        create a cobe brain file based on the db.

        This file is used by cobe to generate responses.
        """

        logger.debug('starting training')
        logger.debug('ignored: {}'.format(IGNORED))

        # replace the current brain
        try:
            os.remove('brain.ai')
        except:
            pass

        BRAIN = Brain('brain.ai')

        logger.debug('created brain.ai')

        start = time.time()

        BRAIN.start_batch_learning()

        logger_lines = db.logger.find({
            'channel': channel,
            'nick': {
                '$nin': IGNORED
            },
            'message': {
                '$regex': '^(?!\.|\,|\!)'
            },
        })

        logger.debug('log total: {}'.format(logger_lines.count()))

        for line in logger_lines:
            BRAIN.learn(line['message'])

        BRAIN.stop_batch_learning()

        logger.debug('learned stuff. Took {:.2f}s'.format(time.time() - start))
Ejemplo n.º 21
0
def chatbot(botname, remotebot, out=sys.stdout):
	mem = Brain(botname + ".brain")
	mem.learn("This is the only thing I know!")

	msg = "Hello!"
	out.write("BEGIN LOG: %s\n" % time.ctime())
	try:
		while True:
			out.write("Local: %s\n" % msg)
			msg = remotebot.think(msg)
			out.write("Remote: %s\n" % msg)
			if LEARN == True:
				mem.learn(msg)
			msg = mem.reply(msg)
			out.flush()

	except (KeyboardInterrupt, SystemExit, EOFError):
		print "Saving..."
		out.write("END LOG: %s\n" % time.ctime())
		out.close()
Ejemplo n.º 22
0
    def _reply(self, irc, msg, channel, text):
        """Send a response to text"""

        cobeBrain = Brain(self._getBrainDirectoryForChannel(channel))
        response = cobeBrain.reply(text).encode('utf-8')
        response = self._strip_nick(irc, msg, response)

        cobeBrain.learn(
            response)  # Let's have the bot learn the wacky things it says

        self.log.info("Attempting to respond in {0} with message: {1}".format(
            channel, response))

        # delay the response here so we look real?
        if self.registryValue('responseDelay', channel):
            self.log.info("Delayed the response in %s." % channel)
            delayseconds = time.time() + random.randint(2, 5)
            schedule.addEvent(irc.queueMsg(ircmsgs.privmsg(channel, response)),
                              delayseconds)
        else:
            irc.queueMsg(ircmsgs.privmsg(channel, response))
Ejemplo n.º 23
0
class Markov(ModuleInterface):
    help = "Markov - Yeah I'm sentient, what of it?"

    def onEnable(self):
        self.brain = Brain(os.path.join("hubbot", "data", "{}.brain".format(self.bot.server)))

    def addToBrain(self, msg):
        if "://" not in msg and len(msg) > 1:
            self.brain.learn(msg)

    def shouldTrigger(self, message):
        """
        @type message: hubbot.message.IRCMessage
        """
        if message.Type in self.acceptedTypes:
            return True
        return False

    def onTrigger(self, message):
        """
        @type message: hubbot.message.IRCMessage
        """
        if message.User.Name == self.bot.nickname:
            return
        elif message.TargetType is TargetTypes.USER and not message.MessageString.startswith(self.bot.commandChar):
            reply = self.brain.reply(message.MessageString, max_len=100)
            return IRCResponse(ResponseType.Say, reply.capitalize(), message.ReplyTo)
        elif self.bot.nickname.lower() in message.MessageString.lower() and len(message.MessageList) > 1:
            messageList = [item.lower() for item in message.MessageList if item.lower() != self.bot.nickname.lower()]
            reply = self.brain.reply(" ".join(messageList), max_len=100)

            nickList = [nick.lower() for nick in self.bot.channels[message.ReplyTo].Users.keys()]
            for word in reply.split():
                if word.lower() in nickList:
                    reply.replace(word, message.User.Name)
            return IRCResponse(ResponseType.Say, reply.capitalize(), message.ReplyTo)
        else:
            messageList = [item.lower() for item in message.MessageList if item.lower() != self.bot.nickname.lower()]
            self.addToBrain(" ".join(messageList))
Ejemplo n.º 24
0
from os import path
from cobe.brain import Brain

b = Brain("%s/shakespeare.sqlite" % path.split(path.abspath(__file__))[0])

b.start_batch_learning()

with open("shakespeare.txt") as f:
    for l in f:
        b.learn(l)

b.stop_batch_learning()
Ejemplo n.º 25
0
    def testLearn(self):
        Brain.init(TEST_BRAIN_FILE, order=2)
        brain = Brain(TEST_BRAIN_FILE)

        brain.learn("this is a test")
        brain.learn("this is also a test")
Ejemplo n.º 26
0
        'screen_name': account,
        'count': 200,
        'exclude_replies': True,
        'include_rts': False
    }

    if account in state['accounts']:
        last_tweet = long(state['accounts'][account])
        params['since_id'] = last_tweet
    else:
        last_tweet = 0

    timeline = api.statuses.user_timeline(**params)

    for tweet in timeline:
        b.learn(tweet['text'])
        #add it to the db
        db_manager.insert_tweet(tweet['text'].encode('utf-8', 'replace'),
                                False)
        last_tweet = max(tweet['id'], last_tweet)
        tweets += 1

    print "%d found..." % tweets
    state['accounts'][account] = str(last_tweet)

print "Learning %d tweets" % tweets
b.stop_batch_learning()
#close the learned txt
open(os.path.join(os.path.dirname(__file__), '.state'),
     'w').write(dumps(state))
Ejemplo n.º 27
0
    def teach(self, irc, msg, args, channel, text):
        """[<channel>] <text>

        Teaches the bot <text>. If the channel is not given, the current channel is used.
        """
        if not channel:  # Did the user enter in a channel? If not, set the current channel
            channel = msg.args[0]

        if not irc.isChannel(msg.args[0]) and irc.isChannel(channel):
            # Are we in a channel and is the channel supplied a channel?

            if os.path.exists(self._getBrainDirectoryForChannel(channel)):
                # Does this channel have a brain file?

                text = self._cleanText(text)
                if text and len(text) > 1 and not text.isspace():

                    irc.reply("Learning text: {0}".format(text))
                    cobeBrain = Brain(
                        self._getBrainDirectoryForChannel(channel))
                    cobeBrain.learn(text)

                else:

                    irc.error(_("No text to learn!"), Raise=True)

            else:
                # Nope, create one!

                self.log.info("Non-existent brainfile in {0}!".format(channel))
                self.log.info("Creating a brainfile now in {0}".format(
                    self._getBrainDirectoryForChannel(channel)))

                commands.getoutput('{0} {1}'.format(self._doCommand(channel),
                                                    'init'))

                text = self._cleanText(text)
                if text and len(text) > 1 and not text.isspace():

                    irc.reply("Learning text: {0}".format(text))
                    cobeBrain = Brain(
                        self._getBrainDirectoryForChannel(channel))
                    cobeBrain.learn(text)

        elif os.path.exists(self._getBrainDirectoryForChannel(
                channel)) and irc.isChannel(channel):
            # We are in a channel! Does the brain file exist and are we supplied a channel?

            text = self._cleanText(text)
            if text and len(text) > 1 and not text.isspace():

                irc.reply("Learning text: {0}".format(text))
                cobeBrain = Brain(self._getBrainDirectoryForChannel(channel))
                cobeBrain.learn(text)

            else:

                irc.error(_("No text to learn!"), Raise=True)

        elif not os.path.exists(self._getBrainDirectoryForChannel(
                channel)) and irc.isChannel(channel):
            # Nope, create one!

            self.log.info("Non-existent brainfile in {0}!".format(channel))
            self.log.info("Creating a brainfile now in {0}".format(
                self._getBrainDirectoryForChannel(channel)))

            commands.getoutput('{0} {1}'.format(self._doCommand(channel),
                                                'init'))

            text = self._cleanText(text)
            if text and len(text) > 1 and not text.isspace():

                irc.reply("Learning text: {0}".format(text))
                cobeBrain = Brain(self._getBrainDirectoryForChannel(channel))
                cobeBrain.learn(text)

        else:
            irc.error(_("Improper channel given!"), Raise=True)
Ejemplo n.º 28
0
    def respond(self, irc, msg, args, channel, text):
        """[<channel>] <text>

        Replies to <text>. If the channel is not given, the current channel is used.
        """
        if not channel:  # Did the user enter in a channel? If not, set the current channel
            channel = msg.args[0]

        if not irc.isChannel(msg.args[0]) and irc.isChannel(channel):
            # Are we in a channel and is the channel supplied a channel?

            if os.path.exists(self._getBrainDirectoryForChannel(channel)):
                # Does this channel have a brain file?

                text = self._cleanText(text)
                if text and len(text) > 1 and not text.isspace():

                    cobeBrain = Brain(self.brainDirectories[channel])
                    response = cobeBrain.reply(text).encode('utf-8')
                    response = self._strip_nick(irc, msg, response)
                    for i in range(response.lower().count(
                            self.magicnick.lower())):
                        # If first word is nick, switch with the callers nick.
                        if self.magicnick in response:
                            response = response.replace(
                                self.magicnick,
                                re.sub(
                                    r'[Kk]', r'κ',
                                    re.sub(r'^(.)',
                                           r'\1​',
                                           random.choice(
                                               list(irc.state.channels[
                                                   msg.args[0]].users)),
                                           count=1)))
                        if self.magicnick.lower() in response:
                            response = response.replace(
                                self.magicnick,
                                re.sub(
                                    r'[Kk]', r'κ',
                                    re.sub(r'^(.)',
                                           r'\1​',
                                           random.choice(
                                               list(irc.state.channels[
                                                   msg.args[0]].users)),
                                           count=1)))
                        if self.magicnick in response:
                            response = response.replace(
                                self.magicnick,
                                re.sub(
                                    r'[Ee]', r'ε',
                                    re.sub(r'^(.)',
                                           r'\1​',
                                           random.choice(
                                               list(irc.state.channels[
                                                   msg.args[0]].users)),
                                           count=1)))
                        if self.magicnick.lower() in response:
                            response = response.replace(
                                self.magicnick.lower(),
                                re.sub(
                                    r'[Ee]', r'ε',
                                    re.sub(r'^(.)',
                                           r'\1​',
                                           random.choice(
                                               list(irc.state.channels[
                                                   msg.args[0]].users)),
                                           count=1)))

                else:

                    irc.error(_("No text to reply to!"), Raise=True)

            else:
                # Nope, create one!

                self.log.info("Non-existent brainfile in {0}!".format(channel))
                self.log.info("Creating a brainfile now in {0}".format(
                    self._getBrainDirectoryForChannel(channel)))

                commands.getoutput('{0} {1}'.format(self._doCommand(channel),
                                                    'init'))

                text = self._cleanText(text)
                if text and len(text) > 1 and not text.isspace():

                    cobeBrain = Brain(
                        self._getBrainDirectoryForChannel(channel))
                    response = cobeBrain.reply(text).encode('utf-8')
                    response = self._strip_nick(irc, msg, response)
                    for i in range(response.lower().count(
                            self.magicnick.lower())):
                        # If first word is nick, switch with the callers nick.
                        if self.magicnick in response:
                            response = response.replace(
                                self.magicnick,
                                re.sub(
                                    r'[Kk]', r'κ',
                                    re.sub(r'^(.)',
                                           r'\1​',
                                           random.choice(
                                               list(irc.state.channels[
                                                   msg.args[0]].users)),
                                           count=1)))
                        if self.magicnick.lower() in response:
                            response = response.replace(
                                self.magicnick,
                                re.sub(
                                    r'[Kk]', r'κ',
                                    re.sub(r'^(.)',
                                           r'\1​',
                                           random.choice(
                                               list(irc.state.channels[
                                                   msg.args[0]].users)),
                                           count=1)))
                        if self.magicnick in response:
                            response = response.replace(
                                self.magicnick,
                                re.sub(
                                    r'[Ee]', r'ε',
                                    re.sub(r'^(.)',
                                           r'\1​',
                                           random.choice(
                                               list(irc.state.channels[
                                                   msg.args[0]].users)),
                                           count=1)))
                        if self.magicnick.lower() in response:
                            response = response.replace(
                                self.magicnick.lower(),
                                re.sub(
                                    r'[Ee]', r'ε',
                                    re.sub(r'^(.)',
                                           r'\1​',
                                           random.choice(
                                               list(irc.state.channels[
                                                   msg.args[0]].users)),
                                           count=1)))

                    # lowercase first letter of the string.
                    response = response[0].lower() + response[1:]

                    irc.reply(response)

                else:
                    irc.error(_("No text to reply to!"), Raise=True)

        elif os.path.exists(self._getBrainDirectoryForChannel(
                channel)) and irc.isChannel(channel):
            # We are in a channel! Does the brain file exist and is this a channel?

            text = self._cleanText(text)
            if text and len(text) > 1 and not text.isspace():

                cobeBrain = Brain(self._getBrainDirectoryForChannel(channel))
                response = cobeBrain.reply(text).encode('utf-8')
                response = self._strip_nick(irc, msg, response)
                # If first word is nick, switch with the callers nick.
                if self.magicnick in response:
                    response = response.replace(
                        self.magicnick,
                        re.sub(
                            r'[Kk]', r'κ',
                            re.sub(r'^(.)',
                                   r'\1​',
                                   random.choice(
                                       list(irc.state.channels[
                                           msg.args[0]].users)),
                                   count=1)))
                if self.magicnick.lower() in response:
                    response = response.replace(
                        self.magicnick,
                        re.sub(
                            r'[Kk]', r'κ',
                            re.sub(r'^(.)',
                                   r'\1​',
                                   random.choice(
                                       list(irc.state.channels[
                                           msg.args[0]].users)),
                                   count=1)))
                if self.magicnick in response:
                    response = response.replace(
                        self.magicnick,
                        re.sub(
                            r'[Ee]', r'ε',
                            re.sub(r'^(.)',
                                   r'\1​',
                                   random.choice(
                                       list(irc.state.channels[
                                           msg.args[0]].users)),
                                   count=1)))
                if self.magicnick.lower() in response:
                    response = response.replace(
                        self.magicnick.lower(),
                        re.sub(
                            r'[Ee]', r'ε',
                            re.sub(r'^(.)',
                                   r'\1​',
                                   random.choice(
                                       list(irc.state.channels[
                                           msg.args[0]].users)),
                                   count=1)))

                # lowercase first letter of the string.
                response = response[0].lower() + response[1:]

                irc.reply(response)

            else:
                irc.error(_("No text to reply to!"), Raise=True)

        elif not os.path.exists(self._getBrainDirectoryForChannel(
                channel)) and irc.isChannel(channel):
            # Nope, create one!

            self.log.info("Non-existent brainfile in {0}!".format(channel))
            self.log.info("Creating a brainfile now in {0}".format(
                self._getBrainDirectoryForChannel(channel)))

            commands.getoutput('{0} {1}'.format(self._doCommand(channel),
                                                'init'))

            text = self._cleanText(text)
            if text and len(text) > 1 and not text.isspace():

                irc.reply("Learning text: {0}".format(text))
                cobeBrain = Brain(self._getBrainDirectoryForChannel(channel))
                response = self._strip_nick(irc, msg, response)
                # If first word is nick, switch with the callers nick.
                if self.magicnick in response:
                    response = response.replace(
                        self.magicnick,
                        re.sub(
                            r'[Kk]', r'κ',
                            re.sub(r'^(.)',
                                   r'\1​',
                                   random.choice(
                                       list(irc.state.channels[
                                           msg.args[0]].users)),
                                   count=1)))

                if self.magicnick.lower() in response:
                    response = response.replace(
                        self.magicnick,
                        re.sub(
                            r'[Kk]', r'κ',
                            re.sub(r'^(.)',
                                   r'\1​',
                                   random.choice(
                                       list(irc.state.channels[
                                           msg.args[0]].users)),
                                   count=1)))
                if self.magicnick in response:
                    response = response.replace(
                        self.magicnick,
                        re.sub(
                            r'[Ee]', r'ε',
                            re.sub(r'^(.)',
                                   r'\1​',
                                   random.choice(
                                       list(irc.state.channels[
                                           msg.args[0]].users)),
                                   count=1)))
                if self.magicnick.lower() in response:
                    response = response.replace(
                        self.magicnick.lower(),
                        re.sub(
                            r'[Ee]', r'ε',
                            re.sub(r'^(.)',
                                   r'\1​',
                                   random.choice(
                                       list(irc.state.channels[
                                           msg.args[0]].users)),
                                   count=1)))

                cobeBrain.learn(text)

            else:
                irc.error(_("No text to reply to!"), Raise=True)

        else:
            irc.error(_("Improper channel given!"), Raise=True)
Ejemplo n.º 29
0
class wormgas(SingleServerIRCBot):

    channel_ids = {
        u'rw': 1,
        u'game': 1,
        u'oc': 2,
        u'ocr': 2,
        u'vw': 3,
        u'mw': 3,
        u'cover': 3,
        u'covers': 3,
        u'bw': 4,
        u'chip': 4,
        u'ch': 4,
        u'ow': 5,
        u'omni': 5,
        u'all': 5
    }

    def __init__(self):
        self.path, self.file = os.path.split(_abspath)
        self.brain = Brain(u'{}/brain.sqlite'.format(self.path))

        config_json = u'{}/config.json'.format(self.path)
        rps_json = u'{}/rps.json'.format(self.path)
        keys_json = u'{}/keys.json'.format(self.path)
        self.config = dbaccess.Config(config_json, rps_json, keys_json)

        # Load plugins
        for plug_name in self.config.get(u'plugins', list())[:]:
            public, private = self.handle_load([u'!load', plug_name])
            for m in private:
                log.info(m)

        self.mb = util.CollectionOfNamedLists(u'{}/mb.json'.format(self.path))
        self.tf = util.TitleFetcher()

        args = sys.argv[1:]
        for arg in args:
            if arg.startswith(u'--set-'):
                key, value = arg[6:].split(u'=', 1)
                print u'Setting \'{}\' to \'{}\'.'.format(key, value)
                self.config.set(key, value)

        # Set up ignore if the ignore list is non-empty.
        ignore = self.config.get(u'msg:ignore', u'')
        self.reignore = None
        if ignore:
            self.reignore = re.compile(ignore, re.IGNORECASE)

        server = self.config.get(u'irc:server')
        nick = self.config.get(u'irc:nick')
        name = self.config.get(u'irc:name')
        SingleServerIRCBot.__init__(self, [(server, 6667)], nick, name)
        self.connection.buffer_class.errors = u'replace'

    def stop(self):
        '''Save all data and shut down the bot.'''
        del self.config
        del self.brain

    def _dispatcher(self, c, e):
        et = e.type
        if et not in self._events_not_logged():
            s = e.source
            t = e.target
            log.debug(u'{}, {}, {} -- {}'.format(et, s, t, e.arguments))
        SingleServerIRCBot._dispatcher(self, c, e)

    def _aux_wa(self, query):
        '''Auxilliary function that does the Wolfram API magic.'''

        apikey = self.config.get(u'wa:apikey', None)
        if apikey is None:
            return [u'Wolfram Alpha API key not configured, cannot use !wa.']
        try:
            url = u'http://api.wolframalpha.com/v2/query'
            payload = {
                u'appid': apikey,
                u'input': query,
                u'format': u'plaintext'
            }
            r = requests.get(url, timeout=10, params=payload)
            root = xml.etree.ElementTree.fromstring(r.text.encode(u'utf-8'))
            if root.get(u'success') != u'true':
                return [u'Wolfram Alpha found no answer.']
            plaintext = root.find(u'./pod[@primary="true"]/subpod/plaintext')
            if plaintext is None:
                for pod in root.findall(u'./pod'):
                    if pod.get(u'title') != u'Input interpretation':
                        plaintext = pod.find(u'./subpod/plaintext')
                        if plaintext is not None:
                            break
            if plaintext is None:
                return [u'Error: could not find response.']
            if plaintext.text is None:
                return [u'Error: empty response.']
            return plaintext.text.splitlines()
        except requests.exceptions.Timeout:
            return [u'Error: Wolfram Alpha timed out.']
        except xml.etree.ElementTree.ParseError:
            return [u'Error: could not parse response.']
        except Exception as e:
            log.exception(e)
            return [u'Error: An unknown error occurred.']

    @command_handler(u'!wa (?P<query>.+)')
    def handle_wa(self, nick, channel, query=None):
        '''Ask something of the Wolfram Alpha API.'''

        log.info(u'{} used !wa'.format(nick))
        self.mb.clear(nick)
        result = self._aux_wa(query)

        # Private messages always get the full result
        if channel == PRIVMSG:
            self.mb.set(nick, result)
            return

        # Otherwise, check for the cooldown and respond accordingly.
        ltw = int(self.config.get(u'lasttime:wa', 0))
        ww = int(self.config.get(u'wait:wa', 0))
        if ltw < time.time() - ww:
            # If sending to the channel, send at most 5 lines.
            self.mb.set(channel, result[:5])
            self.config.set(u'lasttime:wa', time.time())
        else:
            self.mb.set(nick, result)
            wait = ltw + ww - int(time.time())
            r = u'I am cooling down. You cannot use !wa in '
            r += u'{} for another {} seconds.'.format(channel, wait)
            self.mb.add(nick, r)

    @command_handler(u'!8ball')
    def handle_8ball(self, nick, channel):
        '''Ask a question of the magic 8ball.'''

        log.info(u'{} used !8ball'.format(nick))
        self.mb.clear(nick)

        result = random.choice(self._answers_8ball())
        # Private messages always get the result.
        if channel == PRIVMSG:
            self.mb.add(nick, result)
            return

        # Otherwise, check for the cooldown and respond accordingly.
        ltb = int(self.config.get(u'lasttime:8ball', 0))
        wb = int(self.config.get(u'wait:8ball', 0))
        if ltb < time.time() - wb:
            self.mb.add(channel, result)
            if u'again' not in result:
                self.config.set(u'lasttime:8ball', time.time())
        else:
            self.mb.add(nick, result)
            wait = ltb + wb - int(time.time())
            r = u'I am cooling down. You cannot use !8ball in '
            r += u'{} for another {} seconds.'.format(channel, wait)
            self.mb.add(nick, r)

    @command_handler(r'^!$')
    def handle_bang(self, nick, channel):
        '''Get messages from the message buffer.'''

        log.info(u'{} used !'.format(nick))
        pass

    @command_handler(u'^!help(\s(?P<topic>\w+))?')
    def handle_help(self, nick, channel, topic=None):
        '''Look up help about a topic'''

        log.info(u'{} used !help'.format(nick))

        self.mb.clear(nick)
        self._help(nick, topic)

    def _help(self, nick, topic):
        is_admin = self._is_admin(nick)
        rs = list()

        chan_code_ls = u'\x02, \x02'.join(self.channel_ids.keys())
        channelcodes = (u'Channel codes are \x02{}\x02.'.format(chan_code_ls))
        notpermitted = u'You are not permitted to use this command.'
        wiki = (u'More help is available at '
                u'https://github.com/williamjacksn/wormgas/wiki')

        if topic in [u'all', None]:
            rs.append(u'Use \x02!help [<topic>]\x02 with one of these topics: '
                      u'8ball, flip, id, key, nowplaying, prevplayed, roll, '
                      u'rps, rq, wa.')
            if is_admin:
                rs.append(u'Administration topics: restart, set, stop, unset.')
            rs.append(wiki)
        elif topic == u'8ball':
            rs.append(u'Use \x02!8ball\x02 to ask a question of the magic '
                      u'8ball.')
        elif topic == u'wa':
            rs.append(u'Use \x02!wa <query>\x02 to query Wolfram Alpha.')
        elif topic == u'flip':
            rs.append(u'Use \x02!flip\x02 to flip a coin.')
        elif topic == u'id':
            rs.append(u'Look up your Rainwave user id at '
                      u'http://rainwave.cc/auth/ and use \x02!id add <id>\x02 '
                      u'to tell me about it.')
            rs.append(u'Use \x02!id drop\x02 to delete your user id and '
                      u'\x02!id show\x02 to see it.')
        elif topic == u'key':
            rs.append(u'Get an API key from http://rainwave.cc/auth/ and use '
                      u'\x02!key add <key>\x02 to tell me about it.')
            rs.append(u'Use \x02!key drop\x02 to delete your key and \x02!key '
                      u'show\x02 to see it.')
        elif topic in [u'nowplaying', u'np']:
            rs.append(u'Use \x02!nowplaying <channel>\x02 to show what is now '
                      u'playing on the radio.')
            rs.append(u'Short version is \x02!np<channel>\x02.')
            rs.append(channelcodes)
        elif topic in [u'prevplayed', u'pp']:
            rs.append(u'Use \x02!prevplayed <channel> [<index>]\x02 to show '
                      u'what was previously playing on the radio.')
            rs.append(u'Short version is \x02!pp<channel> [<index>]\x02.')
            rs.append(u'Index should be one of (0, 1, 2), 0 is default, '
                      u'higher numbers are further in the past.')
            rs.append(channelcodes)
        elif topic == u'restart':
            if is_admin:
                rs.append(u'Use \x02!restart\x02 to restart the bot.')
            else:
                rs.append(notpermitted)
        elif topic == u'roll':
            rs.append(u'Use \x02!roll [#d^]\x02 to roll a ^-sided die # '
                      u'times.')
        elif topic == u'rps':
            rs.append(u'Use \x02!rock\x02, \x02!paper\x02, or '
                      u'\x02!scissors\x02 to play a game.')
            rs.append(u'Use \x02!rps record [<nick>]\x02 to see the record '
                      u'for <nick>, leave off <nick> to see your own record, '
                      u'use nick \'!global\' to see the global record.')
            rs.append(u'Use \x02!rps stats [<nick>]\x02 to see some '
                      u'statistics for <nick>, leave off <nick> to see your '
                      u'own statistics.')
            rs.append(u'Use \x02!rps reset\x02 to reset your record and '
                      u'delete your game history, there is no confirmation '
                      u'and this cannot be undone.')
            rs.append(u'Use \x02!rps who\x02 to see a list of known players')
            if is_admin:
                rs.append(u'Administrators can use \x02!rps rename <oldnick> '
                          u'<newnick>\x02 to reassign stats and game history '
                          u'from one nick to another.')
        elif topic == u'rq':
            rs.append(u'Use \x02!rq <song_id>\x02 to add a song to your '
                      u'request queue, find the <song_id> using '
                      u'\x02!lookup\x02 or \x02!unrated\x02.')
            rs.append(u'Use \x02!rq unrated\x02 to fill your request queue '
                      u'with unrated songs.')
            rs.append(u'Use \x02!rq fav\x02 to add favourite songs to your '
                      u'request queue.')
            rs.append(u'Use \x02!rq pause\x02 to pause your request queue).')
            rs.append(u'Use \x02!rq resume\x02 to resume your request queue).')
            rs.append(u'Use \x02!rq clear\x02 to remove all songs from your '
                      u'request queue.')
        elif topic == u'set':
            if is_admin:
                rs.append(u'Use \x02!set [<id>] [<value>]\x02 to display or '
                          u'change configuration settings.')
                rs.append(u'Leave off <value> to see the current setting.')
                rs.append(u'Leave off <id> and <value> to see a list of all '
                          u'available config ids.')
            else:
                rs.append(notpermitted)
        elif topic == u'stop':
            if is_admin:
                rs.append(u'Use \x02!stop\x02 to shut down the bot.')
            else:
                rs.append(notpermitted)
        elif topic == u'unset':
            if is_admin:
                rs.append(u'Use \x02!unset <id>\x02 to remove a configuration '
                          u'setting.')
            else:
                rs.append(notpermitted)
        else:
            rs.append(u'I cannot help you with \'{}\''.format(topic))
            rs.append(wiki)

        for r in rs:
            self.mb.add(nick, r)

    @command_handler(u'^!id(\s(?P<mode>\w+))?(\s(?P<id>\d+))?')
    def handle_id(self, nick, channel, mode=None, uid=None):
        '''Manage correlation between an IRC nick and Rainwave User ID

        Arguments:
            mode: string, one of 'add', 'drop', 'show'
            uid: numeric, the person's Rainwave User ID'''

        log.info(u'{} used !id'.format(nick))

        self.mb.clear(nick)

        if mode == u'add' and user_id:
            self.config.add_id_to_nick(uid, nick)
            r = u'I assigned the user id {} to nick \'{}\'.'.format(uid, nick)
            self.mb.add(nick, r)
        elif mode == u'drop':
            self.config.drop_id_for_nick(nick)
            r = u'I dropped the user id for nick \'{}\'.'.format(nick)
            self.mb.add(nick, r)
        elif mode == u'show':
            stored_id = self.config.get_id_for_nick(nick)
            if stored_id:
                r = u'The user id for \'{}\' is {}.'.format(nick, stored_id)
                self.mb.add(nick, r)
            else:
                r = u'I do not have a user id for nick \'{}\'.'.format(nick)
                self.mb.add(nick, r)
        else:
            self._help(nick, topic=u'id')

    @command_handler(u'^!key(\s(?P<mode>\w+))?(\s(?P<key>\w{10}))?')
    def handle_key(self, nick, channel, mode=None, key=None):
        '''Manage API keys

        Arguments:
            mode: string, one of 'add', 'drop', 'show'
            key: string, the API key to add'''

        log.info(u'{} used !key'.format(nick))

        self.mb.clear(nick)

        if mode == u'add' and key:
            self.config.add_key_to_nick(key, nick)
            r = u'I assigned the API key \'{}\' to \'{}\'.'.format(key, nick)
            self.mb.add(nick, r)
        elif mode == u'drop':
            self.config.drop_key_for_nick(nick)
            r = u'I dropped the API key for \'{}\'.'.format(nick)
            self.mb.add(nick, r)
        elif mode == u'show':
            stored_id = self.config.get_key_for_nick(nick)
            if stored_id:
                r = u'The API key for \'{}\' is'.format(nick)
                r = u'{} \'{}\'.'.format(r, stored_id)
                self.mb.add(nick, r)
            else:
                r = u'I do not have an API key for nick \'{}\'.'.format(nick)
                self.mb.add(nick, r)
        else:
            self._help(nick, topic=u'key')

    def handle_load(self, tokens):
        public = list()
        private = list()

        if len(tokens) < 2:
            private.append(u'Please specify a plugin to load.')
            return public, private

        plug_name = tokens[1]
        module_name = u'plugins.{}'.format(plug_name)
        if module_name in sys.modules:
            module = reload(sys.modules[module_name])
        else:
            try:
                module = importlib.import_module(module_name)
            except ImportError:
                err = u'Error while loading plugin: {}.'.format(plug_name)
                log.exception(err)
                private.append(err)
                return public, private

        plugins = set(self.config.get(u'plugins', list()))
        plugins.add(plug_name)
        self.config.set(u'plugins', list(plugins))
        for plug_handler in inspect.getmembers(module, inspect.isclass):
            cls = plug_handler[1]
            cmd_dict = _plug_commands
            if cls.admin:
                cmd_dict = _plug_commands_admin
            for cmd in cls.cmds:
                cmd_dict[cmd] = cls.handle
                private.append(u'Loaded a command: {}.'.format(cmd))

        return public, private

    def handle_unload(self, tokens):
        public = list()
        private = list()

        if len(tokens) < 2:
            private.append(u'Please specify a plugin to load.')
            return public, private

        plug_name = tokens[1]
        module_name = u'plugins.{}'.format(plug_name)

        plugins = set(self.config.get(u'plugins', list()))
        if plug_name in plugins:
            plugins.remove(plug_name)
            self.config.set(u'plugins', list(plugins))

        if module_name in sys.modules:
            module = sys.modules.get(module_name)
            for plug_handler in inspect.getmembers(module, inspect.isclass):
                cls = plug_handler[1]
                cmd_dict = _plug_commands
                if cls.admin:
                    cmd_dict = _plug_commands_admin
                for cmd in cls.cmds:
                    if cmd in cmd_dict:
                        del cmd_dict[cmd]
                        private.append(u'Unloaded a command: {}'.format(cmd))
                    else:
                        private.append(u'Command not found: {}'.format(cmd))
        else:
            private.append(u'Plugin not loaded: {}'.format(plug_name))

        return public, private

    @command_handler(u'!restart')
    def handle_restart(self, nick, channel):
        '''Restart the bot'''

        log.info(u'{} used !restart'.format(nick))

        if self._is_admin(nick):
            self.config.set(u'restart_on_stop', 1)
            self.handle_stop(nick, channel)
        else:
            log.warning(u'{} does not have privs to use !restart'.format(nick))

    @command_handler(u'!roll(\s(?P<dice>\d+)(d(?P<sides>\d+))?)?')
    def handle_roll(self, nick, channel, dice=None, sides=None):
        '''Roll some dice'''

        log.info(u'{} used !roll'.format(nick))

        self.mb.clear(nick)

        try:
            dice = min(int(dice), 100)
        except TypeError:
            dice = 1

        try:
            sides = max(min(int(sides), 100), 1)
        except TypeError:
            sides = 20

        rolls = []
        for i in range(dice):
            rolls.append(random.randint(1, sides))

        r = u'{}d{}: '.format(dice, sides)
        if dice > 1 and dice < 11:
            r += u'[' + u', '.join(map(str, rolls)) + u'] = '
        r += u'{}'.format(sum(rolls))

        if channel == PRIVMSG:
            self.mb.add(nick, r)
            return

        ltr = int(self.config.get(u'lasttime:roll', 0))
        wr = int(self.config.get(u'wait:roll', 0))
        if ltr < time.time() - wr:
            self.mb.add(channel, r)
            self.config.set(u'lasttime:roll', time.time())
        else:
            self.mb.add(nick, r)
            wait = ltr + wr - int(time.time())
            r = u'I am cooling down. You cannot use !roll in '
            r += u'{} for another {} seconds.'.format(channel, wait)
            self.mb.add(nick, r)

    @command_handler(u'!(?P<mode>rock|paper|scissors)')
    def handle_rps(self, nick, channel, mode=None):
        '''Rock, paper, scissors'''

        if mode is None:
            return
        else:
            mode = mode.lower()

        log.info(u'{} used !{}'.format(nick, mode))

        self.mb.clear(nick)

        rps = [u'rock', u'paper', u'scissors']
        challenge = rps.index(mode)
        response = random.randint(0, 2)

        self.config.log_rps(nick, challenge, response)

        r = u'You challenge with {}. I counter with'.format(mode)
        r = u'{} {}. '.format(r, rps[response])

        if challenge == (response + 1) % 3:
            r += u'You win!'
        elif challenge == response:
            r += u'We draw!'
        elif challenge == (response + 2) % 3:
            r += u'You lose!'

        w, d, l = self.config.get_rps_record(nick)
        pw = int(float(w) / float(w + d + l) * 100)
        pd = int(float(d) / float(w + d + l) * 100)
        pl = int(float(l) / float(w + d + l) * 100)
        r += u' Your current record is '
        r += u'{}-{}-{} or {}%-{}%-{}% (w-d-l).'.format(w, d, l, pw, pd, pl)

        if channel == PRIVMSG:
            self.mb.add(nick, r)
            return

        ltr = int(self.config.get(u'lasttime:rps', 0))
        wr = int(self.config.get(u'wait:rps', 0))
        if ltr < time.time() - wr:
            self.mb.add(channel, r)
            self.config.set(u'lasttime:rps', time.time())
        else:
            self.mb.add(nick, r)
            wait = ltr + wr - int(time.time())
            r = u'I am cooling down. You cannot use !{}'.format(mode)
            r = u'{} in {} for another {} seconds.'.format(r, channel, wait)
            self.mb.add(nick, r)

    @command_handler(u'^!rps record(\s(?P<target>\S+))?')
    def handle_rps_record(self, nick, channel, target=None):
        '''Report RPS record for a nick'''

        log.info(u'{} used !rps record'.format(nick))

        self.mb.clear(nick)

        if target is None:
            target = nick

        w, d, l = self.config.get_rps_record(target)
        total = sum((w, d, l))
        r = u'RPS record for {} ({} game'.format(target, total)
        if total != 1:
            r += u's'
        r += u') is {}-{}-{} (w-d-l).'.format(w, d, l)

        if channel == PRIVMSG:
            self.mb.add(nick, r)
            return

        ltr = int(self.config.get(u'lasttime:rps', 0))
        wr = int(self.config.get(u'wait:rps', 0))
        if ltr < time.time() - wr:
            self.mb.add(channel, r)
            self.config.set(u'lasttime:rps', time.time())
        else:
            self.mb.add(nick, r)
            wait = ltr + wr - int(time.time())
            m = u'I am cooling down. You cannot use !rps in '
            m += u'{} for another {} seconds.'.format(channel, wait)
            self.mb.add(nick, m)

    @command_handler(u'!rps rename(\s(?P<old>\S+))?(\s(?P<new>\S+))?')
    def handle_rps_rename(self, nick, channel, old=None, new=None):
        '''Rename an RPS nick, useful for merging game histories'''

        log.info(u'{} used !rps rename'.format(nick))

        if self._is_admin(nick) and old and new:
            self.mb.clear(nick)
            self.config.rename_rps_player(old, new)
            r = u'I assigned RPS game history for {} to {}.'.format(old, new)
            self.mb.add(nick, r)

    @command_handler(u'^!rps reset')
    def handle_rps_reset(self, nick, channel):
        '''Reset RPS stats and delete game history for a nick'''

        log.info(u'{} used !rps reset'.format(nick))

        self.mb.clear(nick)

        self.config.reset_rps_record(nick)
        r = u'I reset your RPS record and deleted your game history.'
        self.mb.add(nick, r)

    @command_handler(u'!rps stats(\s(?P<target>\S+))?')
    def handle_rps_stats(self, nick, channel, target=None):
        '''Get some RPS statistics for a player'''

        log.info(u'{} used !rps stats'.format(nick))

        self.mb.clear(nick)

        if target is None:
            target = nick

        totals = self.config.get_rps_challenge_totals(target)
        games = sum(totals)
        if games > 0:
            r_rate = totals[0] / float(games) * 100
            p_rate = totals[1] / float(games) * 100
            s_rate = totals[2] / float(games) * 100

            r = target
            r += u' challenges with rock/paper/scissors at these rates: '
            r += u'{:3.1f}/{:3.1f}/{:3.1f}%.'.format(r_rate, p_rate, s_rate)
        else:
            r = u'{} does not play. :('.format(target)

        if channel == PRIVMSG:
            self.mb.add(nick, r)
            return

        ltr = int(self.config.get(u'lasttime:rps', 0))
        wr = int(self.config.get(u'wait:rps', 0))
        if ltr < time.time() - wr:
            self.mb.add(channel, r)
            self.config.set(u'lasttime:rps', time.time())
        else:
            self.mb.add(nick, r)
            wait = ltr + wr - int(time.time())
            r = u'I am cooling down. You cannot use !rps in {}'.format(channel)
            r = u'{} for another {} seconds.'.format(r, wait)
            self.mb.add(nick, r)

    @command_handler(u'^!rps who')
    def handle_rps_who(self, nick, channel):
        '''List all players in the RPS game history'''

        log.info(u'{} used !rps who'.format(nick))

        self.mb.clear(nick)

        players = self.config.get_rps_players()

        mlnl = int(self.config.get(u'maxlength:nicklist', 10))
        while len(players) > mlnl:
            plist = players[:mlnl]
            players[:mlnl] = []
            r = u'RPS players: ' + u', '.join(plist)
            self.mb.add(nick, r)
        r = u'RPS players: ' + u', '.join(players)
        self.mb.add(nick, r)

    @command_handler(u'^!set(\s(?P<id>\S+))?(\s(?P<value>.+))?')
    def handle_set(self, nick, channel, id=None, value=None):
        '''View and set bot configuration'''

        log.info(u'{} used !set'.format(nick))

        self.mb.clear(nick)

        if self._is_admin(nick):
            self.mb.set(nick, self.config.handle(id, value))
        else:
            log.warning(u'{} does not have privs to use !set'.format(nick))

    @command_handler(u'!stop')
    def handle_stop(self, nick, channel):
        '''Shut down the bot'''

        log.info(u'{} used !stop'.format(nick))

        if self._is_admin(nick):
            if self.config.get(u'restart_on_stop'):
                self.config.unset(u'restart_on_stop')
                pid = subprocess.Popen(
                    [_abspath],
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE,
                    stdin=subprocess.PIPE)
            self.die(u'I was stopped by {}'.format(nick))
        else:
            log.warning(u'{} does not have privs to use !stop'.format(nick))

    @command_handler(u'^!unset(\s(?P<id>\S+))?')
    def handle_unset(self, nick, channel, id=None):
        '''Unset a configuration item'''

        log.info(u'{} used !unset'.format(nick))

        if self._is_admin(nick):
            if id:
                self.config.unset(id)
                self.mb.clear(nick)
                self.mb.add(nick, u'{} has been unset.'.format(id))
                return
        else:
            log.warning(u'{} does not have privs to use !unset'.format(nick))

    def on_join(self, c, e):
        '''This method is called when an IRC join event happens

        Arguments:
            c: the Connection object asociated with this event
            e: the Event object'''

        nick = e.source.nick
        irc_chan = e.target

        # Check for a join response
        jr = self.config.get(u'joinresponse:{}'.format(nick))
        if jr:
            self._to_irc(c, u'privmsg', irc_chan, jr)

        ja = self.config.get(u'joinaction:{}'.format(nick))
        if ja:
            self._to_irc(c, u'action', irc_chan, ja)

    def on_ping(self, c, e):
        '''This method is called when an IRC ping event happens'''

        # Start the periodic tasks.
        self._periodic(c)

    def on_privmsg(self, c, e):
        '''This method is called when a message is sent directly to the bot

        Arguments:
            c: the Connection object associated with this event
            e: the Event object'''

        nick = e.source.nick
        me = e.target
        msg = e.arguments[0].strip()
        chan = self.config.get(u'irc:channel')

        command_handled = False

        # Core commands
        tokens = msg.split()
        if len(tokens) == 0:
            return
        cmd = tokens[0].lower()
        if cmd == u'!load':
            command_handled = True
            if self._is_admin(nick):
                public, private = self.handle_load(tokens)
                self.mb.set(chan, public)
                self.mb.set(nick, private)
            else:
                self.mb.add(nick, u'You are not an admin.')

        if cmd == u'!unload':
            command_handled = True
            if self._is_admin(nick):
                public, private = self.handle_unload(tokens)
                self.mb.set(chan, public)
                self.mb.set(nick, private)
            else:
                self.mb.add(nick, u'You are not an admin.')

        # Try admin commands from plugins
        if not command_handled:
            if self._is_admin(nick) and cmd in _plug_commands_admin:
                command_handled = True
                handler = _plug_commands_admin.get(cmd)
                try:
                    public, private = handler(nick, me, tokens, self.config)
                    self.mb.set(chan, public)
                    self.mb.set(nick, private)
                except:
                    log.exception(u'Exception in {}'.format(cmd))
                    m = (u'I experienced a problem and recorded some '
                         u'exception information in the log.')
                    self.mb.set(nick, [m])

        # Try normal commands from plugins
        if not command_handled:
            if cmd in _plug_commands:
                command_handled = True
                handler = _plug_commands.get(cmd)
                try:
                    public, private = handler(nick, me, tokens, self.config)
                    self.mb.set(chan, public)
                    self.mb.set(nick, private)
                except:
                    log.exception(u'Exception in {}'.format(cmd))
                    m = (u'I experienced a problem and recorded some '
                         u'exception information in the log.')
                    self.mb.set(nick, [m])

        # Try all the decorated command handlers
        for command in _commands:
            if command(self, nick, msg, PRIVMSG):
                command_handled = True
                break

        if not command_handled:
            # No responses from the commands, punt to the brain
            self.mb.clear(nick)
            self.mb.add(nick, self._talk(msg))

        # Send responses
        while self.mb.items(chan):
            self._to_irc(c, u'privmsg', chan, self.mb.pop(chan, 0))

        rs = list()
        while len(rs) < 7 and self.mb.items(nick):
            rs.append(self.mb.pop(nick, 0))

        if len(self.mb.items(nick)) == 1:
            rs.append(self.mb.pop(nick, 0))

        if len(self.mb.items(nick)) > 1:
            num = len(self.mb.items(nick))
            r = u'Use \x02!\x02 to see more messages ({} left).'.format(num)
            rs.append(r)

        for r in rs:
            self._to_irc(c, u'privmsg', nick, r)

    def on_pubmsg(self, c, e):
        '''This method is called when a message is sent to the channel the bot
        is on

        Arguments:
            c: the Connection object associated with this event
            e: the Event object'''

        nick = e.source.nick
        msg = e.arguments[0].strip()
        chan = e.target

        command_handled = False

        # Core commands
        tokens = msg.split()
        if len(tokens) == 0:
            return
        cmd = tokens[0].lower()
        if cmd == u'!load':
            command_handled = True
            if self._is_admin(nick):
                public, private = self.handle_load(tokens)
                self.mb.set(chan, public)
                self.mb.set(nick, private)
            else:
                self.mb.add(nick, u'You are not an admin.')

        if cmd == u'!unload':
            command_handled = True
            if self._is_admin(nick):
                public, private = self.handle_unload(tokens)
                self.mb.set(chan, public)
                self.mb.set(nick, private)
            else:
                self.mb.add(nick, u'You are not an admin.')

        # Try admin commands from plugins
        if not command_handled:
            if self._is_admin(nick) and cmd in _plug_commands_admin:
                command_handled = True
                handler = _plug_commands_admin.get(cmd)
                try:
                    public, private = handler(nick, chan, tokens, self.config)
                    self.mb.set(chan, public)
                    self.mb.set(nick, private)
                except:
                    log.exception(u'Exception in {}'.format(cmd))
                    m = (u'I experienced a problem and recorded some '
                         u'exception information in the log.')
                    self.mb.set(nick, [m])

        # Try normal commands from plugins
        if not command_handled:
            if cmd in _plug_commands:
                command_handled = True
                handler = _plug_commands.get(cmd)
                try:
                    public, private = handler(nick, chan, tokens, self.config)
                    self.mb.set(chan, public)
                    self.mb.set(nick, private)
                except:
                    log.exception(u'Exception in {}'.format(cmd))
                    m = (u'I experienced a problem and recorded some '
                         u'exception information in the log.')
                    self.mb.set(nick, [m])

        # Try all the decorated command handlers
        if not command_handled:
            for command in _commands:
                if command(self, nick, msg, chan):
                    command_handled = True
                    break

        # If there are no responses from the commands, look for URLs
        title_found = False
        if not command_handled:
            urls = self._find_urls(msg)
            for url in urls:
                title = None
                try:
                    title = self.tf.get_title(url)
                except util.TitleFetcherError as err:
                    log.exception(err)
                if title:
                    log.info(u'Found a title: {}'.format(title))
                    title_found = True
                    self.mb.add(chan, u'[ {} ]'.format(title))

        # If there are no URLs, punt to the brain
        if not (command_handled or title_found):
            talkr = self._talk(msg)
            if talkr:
                self.config.set(u'msg:last', msg)
                self.config.set(u'lasttime:msg', time.time())
                ltr = int(self.config.get(u'lasttime:respond', 0))
                wr = int(self.config.get(u'wait:respond', 0))

                if self.config.get(u'irc:nick') in msg:
                    if time.time() > ltr + wr:
                        self.mb.add(chan, talkr)
                        self.config.set(u'msg:last', talkr)
                        self.config.set(u'lasttime:respond', time.time())
                    else:
                        self._to_irc(c, u'privmsg', nick, talkr)
                        wait = ltr + wr - int(time.time())
                        r = u'I am cooling down. I cannot respond in '
                        r += u'{} for another {} seconds.'.format(chan, wait)
                        self._to_irc(c, u'privmsg', nick, r)

        # Send responses
        while self.mb.items(chan):
            r = u'{}: {}'.format(nick, self.mb.pop(chan, 0))
            self._to_irc(c, u'privmsg', chan, r)

        if command_handled:
            rs = list()
            while len(rs) < 7 and self.mb.items(nick):
                rs.append(self.mb.pop(nick, 0))

            if len(self.mb.items(nick)) == 1:
                rs.append(self.mb.pop(nick, 0))

            if len(self.mb.items(nick)) > 1:
                n = len(self.mb.items(nick))
                r = u'Use \x02!\x02 to see more messages ({} left).'.format(n)
                rs.append(r)

            for r in rs:
                self._to_irc(c, u'privmsg', nick, r)

    def on_welcome(self, c, e):
        '''This method is called when the bot first connects to the server

        Arguments:
            c: the Connection object associated with this event
            e: the Event object'''

        passwd = self.config.get(u'irc:nickservpass')
        if passwd is not None:
            m = u'identify {}'.format(passwd)
            self._to_irc(c, u'privmsg', u'nickserv', m)
        c.join(self.config.get(u'irc:channel'))

    def _answers_8ball(self):
        return [
            u'As I see it, yes.',
            u'Ask again later.',
            u'Better not tell you now.',
            u'Cannot predict now.',
            u'Concentrate and ask again.',
            u'Don\'t count on it.',
            u'It is certain.',
            u'It is decidedly so.',
            u'Most likely.',
            u'My reply is no.',
            u'My sources say no.',
            u'Outlook good.',
            u'Outlook not so good.',
            u'Reply hazy, try again.',
            u'Signs point to yes.',
            u'Very doubtful.',
            u'Without a doubt.',
            u'Yes.',
            u'Yes - definitely.',
            u'You may rely on it.'
        ]

    def _events_not_logged(self):
        return [
            u'all_raw_messages',
            u'created',
            u'endofmotd',
            u'featurelist',
            u'luserchannels',
            u'luserclient',
            u'luserme',
            u'luserop',
            u'luserunknown',
            u'motd',
            u'motdstart',
            u'myinfo',
            u'n_global',
            u'n_local'
        ]

    def _find_urls(self, text):
        '''Look for URLs in arbitrary text. Return a list of the URLs found.'''

        log.info(u'Looking for URLs in: {}'.format(text))

        urls = []
        for token in text.split():
            try:
                o = urlparse(token)
            except ValueError:
                log.exception(u'Trouble looking for URLs.')
                return urls
            if u'http' in o.scheme and o.netloc:
                url = o.geturl()
                log.info(u'Found a URL: {}'.format(url))
                urls.append(url)
        return urls

    def _is_admin(self, nick):
        '''Check whether a nick has privileges to use admin commands'''

        channel = self.config.get(u'irc:channel').encode(u'ascii')
        if channel in self.channels:
            chan = self.channels[channel]
            if nick in chan.owners():
                return True
            elif nick in chan.opers():
                return True
            elif nick in chan.halfops():
                return True

        return False

    def _periodic(self, c):
        # If I have not checked for forum activity for 'timeout:forumcheck'
        # seconds, check now

        log.info(u'Performing periodic tasks')

        chan = self.config.get(u'irc:channel')

        ltm = int(self.config.get(u'lasttime:msg', 0))
        toc = int(self.config.get(u'timeout:chat', 3600))
        if int(time.time()) > ltm + toc:
            log.info(u'Chat timeout exceeded, keep the conversation moving')
            talkr = self._talk()
            if talkr:
                self.config.set(u'msg:last', talkr)
                self.config.set(u'lasttime:msg', time.time())
                self.config.set(u'lasttime:respond', time.time())
                self.mb.add(chan, talkr)

        while self.mb.items(chan):
            self._to_irc(c, u'privmsg', chan, self.mb.pop(chan, 0))

    quotes = [
        (u'Attack the evil that is within yourself, rather than attacking the '
         u'evil that is in others.'),
        u'Before you embark on a journey of revenge, dig two graves.',
        u'Better a diamond with a flaw than a pebble without.',
        u'Everything has beauty, but not everyone sees it.',
        u'He who knows all the answers has not been asked all the questions.',
        (u'He who learns but does not think, is lost! He who thinks but does '
         u'not learn is in great danger.'),
        u'I hear and I forget. I see and I remember. I do and I understand.',
        (u'If what one has to say is not better than silence, then one should '
         u'keep silent.'),
        (u'If you make a mistake and do not correct it, this is called a '
         u'mistake.'),
        (u'Ignorance is the night of the mind but a night without moon and '
         u'star.'),
        (u'Music produces a kind of pleasure which human nature cannot do '
         u'without.'),
        u'Only the wisest and stupidest of men never change.',
        (u'Our greatest glory is not in never falling, but in rising every '
         u'time we fall.'),
        u'Respect yourself and others will respect you.',
        u'Silence is a true friend who never betrays.',
        (u'The hardest thing of all is to find a black cat in a dark room, '
         u'especially if there is no cat.'),
        (u'The man who asks a question is a fool for a minute, the man who '
         u'does not ask is a fool for life.'),
        (u'The superior man is modest in his speech, but exceeds in his '
         u'actions.'),
        u'To be wronged is nothing, unless you continue to remember it.',
        (u'To see what is right and not to do it, is want of courage or of '
         u'principle.'),
        (u'What you know, you know, what you don\'t know, you don\'t know. '
         u'This is true wisdom.')
    ]

    def _talk(self, msg=None):
        '''Engage the brain, respond when appropriate

        Arguments:
            msg: the message to learn and possible reply to

        Returns: a string'''

        # If I am not replying to anything in particular, use the last message
        if msg is None:
            msg = self.config.get(u'msg:last')
        if msg is None:
            return random.choice(self.quotes)

        # Ignore messages with certain words
        if self.reignore:
            result = self.reignore.search(msg)
            if result is not None:
                return random.choice(self.quotes)

        # Clean up the message before sending to the brain
        tobrain = msg
        tobrain = tobrain.replace(self.config.get(u'irc:nick'), u'')
        tobrain = tobrain.replace(u':', u'')

        self.brain.learn(tobrain)

        return self.brain.reply(tobrain)

    def _to_irc(self, c, msgtype, target, msg):
        '''Send an IRC message'''

        log.debug(u'Sending {} to {} -- {}'.format(msgtype, target, msg))

        if hasattr(c, msgtype):
            f = getattr(c, msgtype)
            if type(msg) is not unicode:
                msg = unicode(msg, u'utf-8')
            try:
                f(target, msg)
            except:
                log.exception(u'Problem sending to IRC')
        else:
            log.error(u'Invalid message type \'{}\''.format(msgtype))
class MarkovChainChatter:
    chattiness = 300
    chain_length = 2
    commandQueueRef = None
    chatGeneratorThread = None
    initialWaitTime = 10

    markov = defaultdict(list)
    STOP_WORD = "\n"
    write_to_file = False
    fileLocation = ''
    max_words = 10000

    filteredCharacters = [
        '\\', '!', '.', '?', '/', ')', '(', '*', '-', '~', '\n', '\r', '\t',
        '>'
    ]
    emotes = [
        ':)', ':(', ':o', ':z', 'B)', ':\\', ';)', ';p', ':p', 'R)', 'o_O',
        ':D', '>(', '<3', '<3', 'R)', ':>', '<]', ':7', ':(', ':P', ';P', ':O',
        ':\\', ':|', ':s', ':D', '>(', '#/', 'KappaHD', 'MiniK', 'MiniK',
        'imGlitch', 'copyThis', 'pastaThat', '<3', '͡°', 'ʖ'
    ]
    faceEmotes = [
        'tppCrit', 'tppMiss', 'tppHax', 'tppRng', 'tppHelix', 'tppPokeyen',
        'tppRobored', 'tppRiot', 'tppPc', 'tppDome'
    ]
    wordsToFilter = ['raid', 'f**k', 'shit', 'bitch']

    brain = None
    brainCache = []
    sendChatMessageLock = threading.Lock()

    def __init__(self, commandQueueRef, trainingTextFileLocation):
        self.commandQueueRef = commandQueueRef
        self.fileLocation = trainingTextFileLocation

        self.chatGeneratorThread = threading.Thread(target=self.workerThread)
        self.chatGeneratorThread.start()

        emotesFileHandle = open('faceEmotes.txt', 'r')
        for line in emotesFileHandle.readlines():
            self.faceEmotes.append(line.replace(' ', '').replace('\n', ''))
        emotesFileHandle.close()
        '''
        trainingFileHandle = open(self.fileLocation)
        for line in trainingFileHandle.readlines():
            line = line.replace('\n', '').replace('\r', '')
            if len(line.split(' ')) > (self.chain_length + 1) and line.find('@') < 0:
                self.brain.learn(line)
        trainingFileHandle.close()
        '''

    def add_to_brain(self, msg):
        #self.sendChatMessageLock.acquire()
        currentMsg = self.cleanString(msg)
        if len(currentMsg.split(' ')) > 2 and currentMsg.find(
                '@') < 0:  #add new message if it meets certain criteria
            self.brainCache.append(currentMsg)
        #self.sendChatMessageLock.release()
        '''
        if self.write_to_file and len(msg.split(' ')) > (self.chain_length + 1):
            f = open(self.fileLocation, 'a')
            f.write(msg + '\n')
            f.close()
        buf = [self.STOP_WORD] * self.chain_length
        if len(msg.split(' ')) > (self.chain_length + 1): #must be enough words to store anything
            for word in msg.split():
                self.markov[tuple(buf)].append(word)
                del buf[0]
                buf.append(word)
            self.markov[tuple(buf)].append(self.STOP_WORD)
            '''

    def generate_sentence(self, msg):
        if self.brain is not None:
            return self.brain.reply(text=msg, max_len=30)
        '''
        buf = msg.split()[:self.chain_length]
        if len(msg.split()) > self.chain_length:
            message = buf[:]
        else:
            message = []
            for i in xrange(self.chain_length):
                message.append(random.choice(self.markov[random.choice(self.markov.keys())]))
        for i in xrange(self.max_words):
            try:
                next_word = random.choice(self.markov[tuple(buf)])
            except IndexError:
                continue
            if next_word == self.STOP_WORD:
                break
            message.append(next_word)
            del buf[0]
            buf.append(next_word)
        return ' '.join(message)
        '''

    def cleanString(self, msg):
        result = msg.lower()
        for character in self.filteredCharacters:
            result = result.replace(character, '')
        for emote in self.emotes:
            result = result.replace(emote.lower(), '')
        for faceEmote in self.faceEmotes:
            result = result.replace(faceEmote.lower(), '')
        for word in self.wordsToFilter:
            result = result.replace(word.lower(), '')
        return result

    def join(self):
        self.chatGeneratorThread.join()

    def workerThread(self):
        self.brain = Brain(self.fileLocation)
        #wait a few minutes to load enough information
        time.sleep(self.initialWaitTime)
        while True:
            time.sleep(self.chattiness)
            if len(self.brainCache) == 0:
                '''
                try:
                    self.sendChatMessageLock.release()
                except Exception, e:
                    z = e
                    print 'release exception: ' + str(z)
                    '''
                print 'there was nothing to reply to'
                pass
            else:
                print 'adding new info from cache: ' + str(self.brainCache)
                for msg in self.brainCache:  #add all current messages to the brain
                    self.brain.learn(msg)
                usedMessage = max(self.brainCache, key=lambda msg: len(msg))
                print 'replying to message: ' + usedMessage
                message = (usedMessage +
                           '.')[:-1]  #get a copy of the longest message
                del self.brainCache[:]  #clear cache after storing the messages in the brain
                self.brainCache = list()
                gc.collect()
                #release lock after making copy
                '''
                try:
                    self.sendChatMessageLock.release()
                except Exception, e:
                    z = e
                    print 'release exception: ' + str(z)
                 '''

                sentence = ''
                try:
                    sentence = self.generate_sentence(
                        message)  #make new message
                    print 'generated sentence: ' + sentence
                except IndexError, e:
                    a = 1
                if len(sentence.split(' ')) > 2 and sentence.find(
                        '@'
                ) < 0:  #send new message if it meets certain criteria
                    self.cleanString(sentence)
                    #print 'chatter says: ' + sentence
                    command = 'PRIVMSG #otherbrand ' + " :" + sentence + '\r\n'
                    self.commandQueueRef.sendCommandToQueue(
                        command, self.initialWaitTime)
Ejemplo n.º 31
0
    def testLearn(self):
        Brain.init(TEST_BRAIN_FILE, order=2)
        brain = Brain(TEST_BRAIN_FILE)

        brain.learn("this is a test")
        brain.learn("this is also a test")
Ejemplo n.º 32
0
#!/usr/bin/env python
import sys
from cobe.brain import Brain

if len(sys.argv) != 2:
    print "Usage: %s <brain>" % sys.argv[0]
    sys.exit(1)

brain = Brain(sys.argv[1])

while True:
    data = sys.stdin.readline().decode('utf-8')
    if len(data) == 0:
        break
    cmd, line = data.split(' ', 1)
    if cmd == 'learn':
        brain.learn(line)
    elif cmd == 'reply':
        reply = brain.reply(line)
        sys.stdout.write((reply + "\n").encode('utf-8'))
        sys.stdout.flush()
Ejemplo n.º 33
0
#!/usr/bin/env python
import sys
from cobe.brain import Brain

if len(sys.argv) != 2:
	print "Usage: %s <brain>" % sys.argv[0]
	sys.exit(1)

brain = Brain(sys.argv[1])

while True:
	data = sys.stdin.readline().decode('utf-8')
	if len(data) == 0:
		break
	cmd, line = data.split(' ', 1)
	if cmd == 'learn':
		brain.learn(line)
	elif cmd == 'reply':
		reply = brain.reply(line)
		sys.stdout.write((reply + "\n").encode('utf-8'))
		sys.stdout.flush()
Ejemplo n.º 34
0
        else:
            return content[:length].rsplit(' ', 1)[0]

for account in config['dump_accounts']:
    print "Grabbing tweets for %s" % account
    
    params = { 'screen_name': account, 'count': 200, 'exclude_replies': True, 'include_rts': False }
    
    if account in state['accounts']:
        last_tweet = long(state['accounts'][account])
        params['since_id'] = last_tweet
    else:
        last_tweet = 0

    timeline = api.statuses.user_timeline(**params)

    for tweet in timeline:
        b.learn(tweet['text'])
        #add it to the db
        db_manager.insert_tweet(tweet['text'].encode('utf-8', 'replace'), False)
        last_tweet = max(tweet['id'], last_tweet)
        tweets += 1

    print "%d found..." % tweets
    state['accounts'][account] = str(last_tweet)

print "Learning %d tweets" % tweets
b.stop_batch_learning()
#close the learned txt
open(os.path.join(os.path.dirname(__file__), '.state'), 'w').write(dumps(state))
Ejemplo n.º 35
0
class cobe(kibot.BaseModule.BaseModule):
    """intelligence"""

    _nolearn_uperm = UserPerm("nolearn")

    def __init__(self, bot):
        self._brain_file = os.path.join(bot.op.files.data_dir, "cobe.brain")
        self._trace_file = os.path.join(bot.op.files.data_dir, "cobe.trace")

        # rotate logs
        if os.path.exists(self._trace_file):
            now = datetime.datetime.now()
            stamp = now.strftime("%Y-%m-%d.%H%M%S")
            os.rename(self._trace_file, "%s.%s" % (self._trace_file, stamp))

        self._brain = Brain(self._brain_file, instatrace=self._trace_file)

        kibot.BaseModule.BaseModule.__init__(self, bot)

    def _on_pubmsg(self, conn, event):
        import string, re

        message = event.args[0]
        message = re.sub("<\S+>", "", message)

        match = re.match('"(.*)" --\S+, \d+-\S+\d+.', message)
        if match:
            message = match.group(1)

        match = re.match("\s*(\S+)\s*[,:]\s*(.*?)\s*$", message)

        if match:
            to = match.group(1)
            text = match.group(2)
        else:
            to = None
            text = message

        speaker = nm_to_n(event.source)

        # drop any extra whitespace in the string
        text = string.join(string.split(text), " ")

        user = self.bot.ircdb.get_user(nickmask=event.source)
        if user is not None:
            uperms = list(user.get_perms())
        else:
            uperms = list(self.bot.permdb.get_unknown_perms())
            uperms.append(self._nolearn_uperm)

        if "ignore" in uperms:
            return "NO MORE"

        # convert text to Unicode
        text = text.decode("utf-8")

        # if spoken to directly, generate a reply
        if str(to).lower() == self.bot.nick.lower():
            self._brain.learn(text)
            reply = self._brain.reply(text)

            # convert to utf-8 for output
            reply = reply.encode("utf-8")

            conn.privmsg(event.target, "%s: %s" % (speaker, reply))
        else:
            self._brain.learn(text)

        return "NO MORE"
Ejemplo n.º 36
0
from tqdm import tqdm
import praw
import sys

old_stdout = sys.stdout

sys.stdout = tqdm

brain = Brain("cobe.brain")

# Removed to prevent impersonation
USER_AGENT = ''
USERNAME = ''
PASSWORD = ''
PINGNAME = '+/u/' + USERNAME
interface = praw.Reddit(USER_AGENT)
interface.login(username=USERNAME, password=PASSWORD, disable_warning=True)


def getreply(comment):
    body = comment.body
    
    return brain.reply(body.replace('+/u/RedditSimulatorBot', ''))

if __name__ == '__main__':
    for comment in tqdm(praw.helpers.comment_stream(interface, 'all'), unit=' comments'):
        brain.learn(comment.body)
        if PINGNAME in comment.body:
            tqdm.write("%")
            comment.reply(getreply(comment))
Ejemplo n.º 37
0
		last_tweet = long(state['accounts'][account])
	else:
		last_tweet = 0

	try:
		timeline = api.GetUserTimeline(
			account, count=200, since_id=last_tweet,	
			include_rts=not config.skip_retweets,
			exclude_replies=config.skip_replies,
	
			trim_user=True,
			include_entities=False
		)
	except:
		continue

	for tweet in timeline:
		b.learn(tweet.text)
		#add it to the db
		db_manager.insert_tweet(tweet.text.encode('utf-8', 'replace'), False)
		last_tweet = max(tweet.id, last_tweet)
		tweets += 1

	print "%d found..." % tweets
	state['accounts'][account] = str(last_tweet)

print "Learning %d tweets" % tweets
b.stop_batch_learning()
#close the learned txt
open(os.path.join(os.path.dirname(__file__), '.state'), 'w').write(dumps(state))
Ejemplo n.º 38
0
import sys
sys.path.append("./cobe/")
from cobe.brain import Brain

print "Learning from all"

text = []

for line in sys.stdin:
    text.append(line)

print "Starting"

b = Brain("cobe.brain")
map(lambda x: b.learn(x), text)

print "Done"
Ejemplo n.º 39
0
class Cobe():
  def __init__(self, config=CONFIG):
    self.ready = False
    self.psapi = pushshift_api
    self.rapi = reddit_api
    self.config = CONFIG
    self.brain = Brain(self.config.get("cobe_main_db"))
    self.size = 0

  def get_reply(self, replyto: str=''):
    if self.ready:
      return self.brain.reply(replyto)
    else:
      log.info(f"cobe not initialized, run init")

  def init(self):
    log.info("using cobe to generate comments")
    main_db = self.config.get("cobe_main_db")
    
    # make sure db was initialized correctly
    if os.path.isfile(main_db):
      # set the initial size
      self.size = os.path.getsize(main_db)
    else:
      log.info(f"cobe db failed to initialize. exiting")
      sys.exit()

    log.debug('filling cobe database for commenting')
    # loop through learning comments until we reach the min db size
    while self.size <= tobytes(self.config.get("cobe_min_db_size")):

      log.info(f"cobe db size is: {str(bytesto(self.size, 'm'))}mb, need {self.config.get('cobe_min_db_size')} - learning...")
      
      # just learn from random subreddits for now
      subreddit = get_subreddit(getsubclass=True)
      
      log.info(f"learning from /r/{subreddit}")
      
      # get the comment generator function from pushshift
      comments = self.psapi.get_comments(subreddit)

      # go through 500 comments per subreddit
      for x in range(500):
        # get the comment from the generator function
        try:
          comment = next(comments)
        except StopIteration as e:
          log.info(f"end of comments")
        
        # bot responses are better when it learns from short comments
        if len(comment.body) < 240:
          log.debug(f"learning comment: {comment.body.encode('utf8')}")
          
          # only learn comments that don't contain an avoid word
          if not any(word in comment.body for word in AVOID_WORDS):
            self.brain.learn(comment.body.encode("utf8")) 

      # update the class size variable so the while loop
      # knows when to break
      self.size = os.path.getsize(main_db)

    log.info(f"database min size ({self.config.get('cobe_min_db_size')}) reached")
    self.ready = True
Ejemplo n.º 40
0
    def respond(self, irc, msg, args, channel, text):
        """[<channel>] <text>

        Replies to <text>. If the channel is not given, the current channel is used.
        """
        if not channel: # Did the user enter in a channel? If not, set the current channel
            channel = msg.args[0]

        if not irc.isChannel(msg.args[0]) and irc.isChannel(channel): 
            # Are we in a channel and is the channel supplied a channel?
            
            if os.path.exists(self._getBrainDirectoryForChannel(channel)):
                # Does this channel have a brain file?
                
                    text = self._cleanText(text)
                    if text and len(text) > 1 and not text.isspace():
                
                        cobeBrain = Brain(self.brainDirectories[channel])
                        response = cobeBrain.reply(text).encode('utf-8')
                        irc.reply(response)

                    else:
            
                        irc.error(_("No text to reply to!"), Raise=True)
                    
            else: 
                # Nope, create one!
            
                self.log.info("Non-existent brainfile in {0}!".format(channel))
                self.log.info("Creating a brainfile now in {0}".format(self._getBrainDirectoryForChannel(channel)))
                
                commands.getoutput('{0} {1}'.format(self._doCommand(channel), 'init'))
                
                text = self._cleanText(text)
                if text and len(text) > 1 and not text.isspace():
            
                    cobeBrain = Brain(self._getBrainDirectoryForChannel(channel))
                    response = cobeBrain.reply(text).encode('utf-8')
                    irc.reply(response)
                    
                else:
                    irc.error(_("No text to reply to!"), Raise=True)
                
        elif os.path.exists(self._getBrainDirectoryForChannel(channel)) and irc.isChannel(channel): 
            # We are in a channel! Does the brain file exist and is this a channel?
    
            text = self._cleanText(text)
            if text and len(text) > 1 and not text.isspace():

                cobeBrain = Brain(self._getBrainDirectoryForChannel(channel))
                response = cobeBrain.reply(text).encode('utf-8')
                irc.reply(response)

            else:
                irc.error(_("No text to reply to!"), Raise=True)

        elif not os.path.exists(self._getBrainDirectoryForChannel(channel)) and irc.isChannel(channel):
            # Nope, create one!
        
            self.log.info("Non-existent brainfile in {0}!".format(channel))
            self.log.info("Creating a brainfile now in {0}".format(self._getBrainDirectoryForChannel(channel)))
            
            commands.getoutput('{0} {1}'.format(self._doCommand(channel), 'init'))
            
            text = self._cleanText(text)
            if text and len(text) > 1 and not text.isspace():
        
                irc.reply("Learning text: {0}".format(text))
                cobeBrain = Brain(self._getBrainDirectoryForChannel(channel))
                cobeBrain.learn(text)
                
            else:
                irc.error(_("No text to reply to!"), Raise=True)
                
        else:
            irc.error(_("Improper channel given!"), Raise=True)
Ejemplo n.º 41
0
	
	if account in state['accounts']:
		last_tweet = long(state['accounts'][account])
	else:
		last_tweet = 0

	try:
		timeline = api.GetUserTimeline(
			account, count=200, since_id=last_tweet,	
			include_rts=not config.skip_retweets,
			exclude_replies=config.skip_replies,
	
			trim_user=True,
			include_entities=False
		)
	except:
		continue

	for tweet in timeline:
		b.learn(tweet.text)
		last_tweet = max(tweet.id, last_tweet)
		tweets += 1

	print "%d found..." % tweets
	state['accounts'][account] = str(last_tweet)

print "Learning %d tweets" % tweets
b.stop_batch_learning()

open(os.path.join(os.path.dirname(__file__), '.state'), 'w').write(dumps(state))