コード例 #1
0
ファイル: MarkovBot.py プロジェクト: J-Spade/slackov
    def __init__(self, client, slack, twitter):
        token = slack['token']
        user_id = slack['id']
        avatarsource = slack['avatarsource']

        slackbot.Slackbot.__init__(self, token, client, user_id, avatarsource)

        consumer_key = twitter['consumer_key']
        consumer_secret = twitter['consumer_secret']
        access_token = twitter['access_token']
        access_token_secret = twitter['access_token_secret']

        self.twitter = TwitterBot(consumer_key, consumer_secret, access_token,
                                  access_token_secret)

        self.dictLock = threading.Lock()

        print 'LOADING DICTIONARY...'
        try:
            self.load_dictionary()

            print 'COUNTING WORDS...'
            for wordpair in self.dictionary:

                temp = wordpair.split()
                uses = 0
                for temp in self.dictionary.get(wordpair)[0]:
                    uses = uses + temp[1]
                self.paircounts[wordpair] = uses

                tally = 0
                for prev in self.dictionary.get(wordpair)[0]:
                    tally += prev[1]

                first = wordpair.split()[0]
                if not (self.wordcounts.has_key(first)):
                    self.wordcounts[first] = 0
                self.wordcounts[first] = self.wordcounts.get(first) + tally

                if wordpair != self.STOPWORD:
                    second = wordpair.split()[1]
                    if not (self.wordcounts.has_key(second)):
                        self.wordcounts[second] = 0
                    self.wordcounts[second] = self.wordcounts.get(
                        second) + tally

            self.sentences_ever = self.wordcounts.get(self.STOPWORD)

            print 'STARTING AUTOSAVER...'
            self.autosaver = _autoSaveThread(self)
            self.autosaver.start()
        except IOError:
            print 'DICTIONARY COULD NOT BE LOADED'
コード例 #2
0
ファイル: MarkovBot.py プロジェクト: J-Spade/slackov
    def __init__(self, client, slack, twitter):
        token = slack['token']
        user_id = slack['id']
        avatarsource = slack['avatarsource']

        slackbot.Slackbot.__init__(self, token, client, user_id, avatarsource)

        consumer_key = twitter['consumer_key']
        consumer_secret = twitter['consumer_secret']
        access_token = twitter['access_token']
        access_token_secret = twitter['access_token_secret']

        self.twitter = TwitterBot(consumer_key, consumer_secret, access_token, access_token_secret)

	self.dictLock = threading.Lock()

	print 'LOADING DICTIONARY...'
        try:
            self.load_dictionary()

            print 'COUNTING WORDS...'            
            for wordpair in self.dictionary:

                temp = wordpair.split()
                uses = 0
                for temp in self.dictionary.get(wordpair)[0]:
                    uses = uses + temp[1]
                self.paircounts[wordpair] = uses

                tally = 0
                for prev in self.dictionary.get(wordpair)[0]:
                    tally += prev[1]

                first = wordpair.split()[0]
                if not (self.wordcounts.has_key(first)):
                    self.wordcounts[first] = 0
                self.wordcounts[first] = self.wordcounts.get(first) + tally

                if wordpair != self.STOPWORD:
                    second = wordpair.split()[1]
                    if not (self.wordcounts.has_key(second)):
                        self.wordcounts[second] = 0
                    self.wordcounts[second] = self.wordcounts.get(second) + tally

            self.sentences_ever = self.wordcounts.get(self.STOPWORD)

            print 'STARTING AUTOSAVER...'
	    self.autosaver = _autoSaveThread(self)
	    self.autosaver.start()
        except IOError:
            print 'DICTIONARY COULD NOT BE LOADED'
コード例 #3
0
ファイル: MarkovBot.py プロジェクト: aaronsky/slackov
    def __init__(self, client, slack, twitter):
        token = slack['token']
        nowplaying = slack['nowplaying']
        user_id = slack['id']
        avatarsource = slack['avatarsource']

        slackbot.Slackbot.__init__(self, token, nowplaying, client, user_id, avatarsource)

        twitter_creds = OAuth(twitter['consumer_key'],
                              twitter['consumer_secret'],
                              twitter['access_token'],
                              twitter['access_token_secret'])

        self.twitter = TwitterBot(twitter_creds)

        self.dictLock = threading.Lock()
        print 'LOADING DICTIONARY...'
        try:
            self.load_dictionary()
            print 'DICTIONARY LOADED SUCCESSFULLY'
        except IOError:
            print 'DICTIONARY COULD NOT BE LOADED'
コード例 #4
0
ファイル: MarkovBot.py プロジェクト: aaronsky/slackov
class MarkovBot(slackbot.Slackbot):
    """Handles chain generation and bot behavior"""

    talkBackFreq = 0.05
    isLearning = True
    censorWords = True #not implemented
    lastMessages = {}

    STOPWORD = 'BOGON'

    #       key        come-befores       come-afters
    DEFAULT_DICTIONARY = {STOPWORD: ([(STOPWORD, 1)], [(STOPWORD, 1)])}
    dictionary = copy.deepcopy(DEFAULT_DICTIONARY)

    def __init__(self, client, slack, twitter):
        token = slack['token']
        nowplaying = slack['nowplaying']
        user_id = slack['id']
        avatarsource = slack['avatarsource']

        slackbot.Slackbot.__init__(self, token, nowplaying, client, user_id, avatarsource)

        twitter_creds = OAuth(twitter['consumer_key'],
                              twitter['consumer_secret'],
                              twitter['access_token'],
                              twitter['access_token_secret'])

        self.twitter = TwitterBot(twitter_creds)

        self.dictLock = threading.Lock()
        print 'LOADING DICTIONARY...'
        try:
            self.load_dictionary()
            print 'DICTIONARY LOADED SUCCESSFULLY'
        except IOError:
            print 'DICTIONARY COULD NOT BE LOADED'

    def on_message_received(self, target, sender, message):
        callargs = {'token': self.TOKEN, 'user': sender}
        info = self.CLIENT.api_call('users.info', callargs)
        sentByAdmin = json.loads(info)['user']['is_admin']

        if self.do_commands(target, sender, message, sentByAdmin):
            return

        if sender != 'USLACKBOT':
            message = message.lower()
            if self.isLearning:
                lines = message.split(u'\n')
                for line in lines:
                    for sentence in line.split(u'. '):
                        if sentence.endswith(u'.'):  # get rid of last .
                            sentence = sentence[:-1]
                        self.interpret_message(sentence)
            if random.random() < self.talkBackFreq:
                response = self.generate_chain(message)
                if response != '':
                    self.send_message(target, response)

    def on_my_message_received(self, timestamp, message):
        if timestamp not in self.lastMessages:
            self.lastMessages[timestamp] = message

    def on_private_message_received(self, channel, sender, message):
        """
        PMs don't teach the bot anything,
        but will always get a response (if the bot can provide one)
        """
        callargs = {'token': self.TOKEN, 'user': sender}
        info = self.CLIENT.api_call('users.info', callargs)
        sentByAdmin = json.loads(info)['user']['is_admin']

        if self.do_commands(channel, sender, message, sentByAdmin):
            return

        message = message.lower()

        response = self.generate_chain(message)
        if response != '':
            self.send_message(channel, response)

    def on_name_ping_received(self, channel, sender):
    	self.send_message(channel, '<@%s>' % self.users[sender])

    def on_reaction_received(self, channel, timestamp, reaction):
        if timestamp in self.lastMessages:
            message = self.lastMessages[timestamp]
            if reaction == 'twitter':
                links = self.twitter.post(message)
                del self.lastMessages[timestamp]
                if links:
                    for link in links:
                        self.send_message(channel, link)

    def do_commands(self, target, sender, message, sentByAdmin):
        if sentByAdmin and ('!saveDict' in message):
            try:
                self.save_dictionary()
                self.send_message(target, 'DICTIONARY SAVED SUCCESSFULLY')
            except IOError:
                self.send_message(target, 'DICTIONARY COULD NOT BE SAVED')
            return True
        elif sentByAdmin and ('!loadDict' in message):
            try:
                self.load_dictionary()
                self.send_message(target, 'DICTIONARY LOADED SUCCESSFULLY')
            except IOError:
                self.send_message(target, 'DICTIONARY COULD NOT BE LOADED')
            return True
        elif sentByAdmin and ('!eraseDict' in message):
            self.dictionary = {
                self.STOPWORD : ([self.STOPWORD], [self.STOPWORD])
            }
            self.send_message(target, 'DICTIONARY ERASED (NOT SAVED YET)')
            return True
        elif sentByAdmin and ('!learn' in message):
            self.toggle_learn()
            print_message = 'I AM {} LEARNING'
            self.send_message(target,
                              print_message.format('NOW' if self.isLearning else 'NO LONGER'))
            return True
        elif sentByAdmin and ('!cleanURL' in message):
            self.clean_urls_in_dictionary()
            self.send_message(target, 'LINKS IN DICTIONARY HAVE BEEN CLEANED')
            return True
        elif '!search' in message:
            try:
                message = message.lower()
                searchterms = message.split()[1:]
		for i in range(0, len(searchterms)):
		    searchterms[i] = clean_url(searchterms[i])
                if len(searchterms) == 1:
                    phrases = []
                    for key in self.dictionary:
                        if searchterms[0] == key.split()[0] or \
                                             (len(key.split()) > 1 and \
                                             searchterms[0] == key.split()[1]):
                            phrases.append(key)
                    self.send_message(target, '"%s" in pairs: %s' % (searchterms[0], str(phrases)))
                else:
                    key = searchterms[0] + ' ' + searchterms[1]
                    if self.dictionary.has_key(key):
                        self.send_message(target, '"%s": %s' % (key, str(self.dictionary.get(key))))
                    else:
                        self.send_message(target, '"%s" not found in dictionary' % key)
            except IndexError:
                self.send_message(target, 'MALFORMED COMMAND')
            return True
        elif '!talkback' in message:
            try:
                self.talkBackFreq = float(message.split()[1])
                self.send_message(target, ('RESPONDING PROBABILITY SET TO %3f' % self.talkBackFreq))
            except (IndexError, TypeError):
                self.send_message(target, 'MALFORMED COMMAND')
            return True
        elif sentByAdmin and ('!quit' in message):
            self.quit()
            return True
        elif '!avatar' in message:
            self.send_message(target, 'SOURCE OF MY CURRENT AVATAR: %s' % self.AVATARSOURCE)
            return True

        elif ('!nowplaying' in message):
           songname, songartist = self.generate_song()
           self.send_message(target, 'Now Playing: "%s", by %s' % (string.capwords(songname), string.capwords(songartist)))
           return True

        return False # did not find a command

    def on_quit(self):
        # try:
        #   self.saveDictionary()
        #   print ('DICTIONARY SAVED SUCCESSFULLY')
        # except IOError:
        #   print ('DICTIONARY COULD NOT BE SAVED')
        pass

    def interpret_message(self, message):
        """Interprets a message"""
	    self.dictLock.acquire()
        words = message.split()
        words.append(self.STOPWORD)
        words.insert(0, self.STOPWORD)

        # find URLs, neaten them up
        for i in range(0, len(words)):
            words[i] = clean_url(words[i])
        index = 0
        word = words[index]
        # cannot be out of range; at least (stop, stop, word, stop, stop)
        wordpair = words[index] + ' ' + words[index + 1]

        while True:
            try:
                next = words[index + 2]
                nextpair = words[index + 1] + ' ' + words[index + 2]
            except IndexError:
                # this means we got to the end of the sentence
                break

            # add 'next' as a word that comes after 'wordpair'
            if self.dictionary.has_key(wordpair):
                temp = self.dictionary.get(wordpair)[1]
                wordindex = word_index_in_list(next, temp)
                if wordindex == -1:
                    temp.append((next, 1))
                else:
                    prevcount = temp[wordindex][1]
                    temp[wordindex] = (next, prevcount + 1)
            else:
                self.dictionary[wordpair] = ([], [(next, 1)])

            # add 'word' as a word that comes before 'nextpair'
            if self.dictionary.has_key(nextpair):
                othertemp = self.dictionary.get(nextpair)[0]
                wordindex = word_index_in_list(word, othertemp)
                if wordindex == -1:
                    othertemp.append((word, 1))
                else:
                    prevcount = othertemp[wordindex][1]
                    othertemp[wordindex] = (word, prevcount + 1)

            else:
                self.dictionary[nextpair] = ([(word, 1)], [])

            index = index + 1
            word = words[index]
            wordpair = word + ' ' + words[index + 1]

        #print self.dictionary
	self.dictLock.release()
コード例 #5
0
ファイル: MarkovBot.py プロジェクト: J-Spade/slackov
class MarkovBot(slackbot.Slackbot):
    """Handles chain generation and bot behavior"""

    talkBackFreq = 0.05
    isLearning = True
    censorWords = True #not implemented
    lastMessages = {}

    STOPWORD = 'BOGON'

    #       key        come-befores       come-afters
    DEFAULT_DICTIONARY = {STOPWORD: ([(STOPWORD, 1)], [(STOPWORD, 1)])}
    dictionary = copy.deepcopy(DEFAULT_DICTIONARY)

    wordcounts = {STOPWORD: 0}
    paircounts = {STOPWORD: 0}
    sentences_ever = 0

    def __init__(self, client, slack, twitter):
        token = slack['token']
        user_id = slack['id']
        avatarsource = slack['avatarsource']

        slackbot.Slackbot.__init__(self, token, client, user_id, avatarsource)

        consumer_key = twitter['consumer_key']
        consumer_secret = twitter['consumer_secret']
        access_token = twitter['access_token']
        access_token_secret = twitter['access_token_secret']

        self.twitter = TwitterBot(consumer_key, consumer_secret, access_token, access_token_secret)

	self.dictLock = threading.Lock()

	print 'LOADING DICTIONARY...'
        try:
            self.load_dictionary()

            print 'COUNTING WORDS...'            
            for wordpair in self.dictionary:

                temp = wordpair.split()
                uses = 0
                for temp in self.dictionary.get(wordpair)[0]:
                    uses = uses + temp[1]
                self.paircounts[wordpair] = uses

                tally = 0
                for prev in self.dictionary.get(wordpair)[0]:
                    tally += prev[1]

                first = wordpair.split()[0]
                if not (self.wordcounts.has_key(first)):
                    self.wordcounts[first] = 0
                self.wordcounts[first] = self.wordcounts.get(first) + tally

                if wordpair != self.STOPWORD:
                    second = wordpair.split()[1]
                    if not (self.wordcounts.has_key(second)):
                        self.wordcounts[second] = 0
                    self.wordcounts[second] = self.wordcounts.get(second) + tally

            self.sentences_ever = self.wordcounts.get(self.STOPWORD)

            print 'STARTING AUTOSAVER...'
	    self.autosaver = _autoSaveThread(self)
	    self.autosaver.start()
        except IOError:
            print 'DICTIONARY COULD NOT BE LOADED'

    def on_message_received(self, target, sender, message):
        callargs = {'token': self.TOKEN, 'user': sender}
        info = self.CLIENT.api_call('users.info', token=self.TOKEN, user=sender)
        sentByAdmin = info['user']['is_admin']

        if self.do_commands(target, sender, message, sentByAdmin):
            return

        if sender != 'USLACKBOT':
            message = message.lower()
            if self.isLearning:
                lines = message.split(u'\n')
                for line in lines:
                    for sentence in line.split(u'. '):
                        if sentence.endswith(u'.'):  # get rid of last .
                            sentence = sentence[:-1]
                        self.interpret_message(sentence)
            if random.random() < self.talkBackFreq:
                response = self.generate_chain(message)
                if response != '':
                    self.send_message(target, response)

    def on_my_message_received(self, timestamp, message):
        if timestamp not in self.lastMessages:
            self.lastMessages[timestamp] = message

    def on_private_message_received(self, channel, sender, message):
        """
        PMs don't teach the bot anything,
        but will always get a response (if the bot can provide one)
        """
        callargs = {'token': self.TOKEN, 'user': sender}
        info = self.CLIENT.api_call('users.info', token=self.TOKEN, user=sender)
        sentByAdmin = info['user']['is_admin']

        if self.do_commands(channel, sender, message, sentByAdmin):
            return

        message = message.lower()

        response = self.generate_chain(message)
        if response != '':
            self.send_message(channel, response)

    def on_name_ping_received(self, channel, sender):
	self.send_message(channel, '<@%s>' % self.users[sender])

    def on_reaction_received(self, channel, timestamp):
        if timestamp in self.lastMessages:
            message = self.lastMessages[timestamp]
            links = self.twitter.post(message)
            del self.lastMessages[timestamp]
            if links:
                for link in links:
                    self.send_message(channel, link)

    def do_commands(self, target, sender, message, sentByAdmin):
        if sentByAdmin and ('!saveDict' in message):
            try:
                self.save_dictionary()
                self.send_message(target, 'DICTIONARY SAVED SUCCESSFULLY (%s bytes)' % str(os.path.getsize('Markov_Dict.pkl')))
            except IOError:
                self.send_message(target, 'DICTIONARY COULD NOT BE SAVED')
            return True
        elif sentByAdmin and ('!loadDict' in message):
            try:
                self.load_dictionary()
                self.send_message(target, 'DICTIONARY LOADED SUCCESSFULLY (%s bytes)' % str(os.path.getsize('Markov_Dict.pkl')))
            except IOError:
                self.send_message(target, 'DICTIONARY COULD NOT BE LOADED')
            return True
        elif sentByAdmin and ('!eraseDict' in message):
            self.dictionary = {
                self.STOPWORD : ([self.STOPWORD], [self.STOPWORD])
            }
            self.send_message(target, 'DICTIONARY ERASED (NOT SAVED YET)')
            return True
        elif sentByAdmin and ('!learn' in message):
            self.toggle_learn()
            print_message = 'I AM {} LEARNING'
            self.send_message(target,
                              print_message.format('NOW' if self.isLearning else 'NO LONGER'))
            return True
        elif sentByAdmin and ('!cleanURL' in message):
            self.clean_urls_in_dictionary()
            self.send_message(target, 'LINKS IN DICTIONARY HAVE BEEN CLEANED')
            return True
        elif '!search' in message:
            try:
                message = message.lower()
                searchterms = message.split()[1:]
		for i in range(0, len(searchterms)):
		    searchterms[i] = clean_url(searchterms[i])
                if len(searchterms) == 1:
                    phrases = []
                    for key in self.dictionary:
                        if searchterms[0] == key.split()[0] or \
                                             (len(key.split()) > 1 and \
                                             searchterms[0] == key.split()[1]):
                            phrases.append(key)
                    self.send_message(target, u'"%s" in pairs: %s' % (searchterms[0], str(phrases)))
                else:
                    key = searchterms[0] + u' ' + searchterms[1]
                    if self.dictionary.has_key(key):
                        self.send_message(target, u'"%s": %s' % (key, str(self.dictionary.get(key))))
                    else:
                        self.send_message(target, u'"%s" not found in dictionary' % key)
            except IndexError:
                self.send_message(target, u'MALFORMED COMMAND')
            return True
        elif '!talkback' in message:
            try:
                self.talkBackFreq = float(message.split()[1])
                self.send_message(target, ('RESPONDING PROBABILITY SET TO %3f' % self.talkBackFreq))
            except (IndexError, TypeError, ValueError):
                self.send_message(target, 'MALFORMED COMMAND')
            return True
        elif sentByAdmin and ('!quit' in message):
            self.quit()
            return True
        elif '!avatar' in message:
            self.send_message(target, 'SOURCE OF MY CURRENT AVATAR: %s' % self.AVATARSOURCE)
            return True

        elif ('!nowplaying' in message):
           songname, songartist = self.generate_song()
           self.send_message(target, u'Now Playing: "%s", by %s' % (string.capwords(songname), string.capwords(songartist)))
           return True

        return False # did not find a command

    def on_quit(self):
        # try:
        #   self.saveDictionary()
        #   print ('DICTIONARY SAVED SUCCESSFULLY')
        # except IOError:
        #   print ('DICTIONARY COULD NOT BE SAVED')
        pass

    def interpret_message(self, message):
        """Interprets a message"""
	
	self.dictLock.acquire()
        words = message.split()
        words.append(self.STOPWORD)
        words.insert(0, self.STOPWORD)

        self.sentences_ever = self.sentences_ever + 1

        # find URLs, neaten them up
        for i in range(0, len(words)):
            words[i] = clean_url(words[i])

	for word in words:
            if not (self.wordcounts.has_key(word)):
                self.wordcounts[word] = 0
            self.wordcounts[word] = self.wordcounts.get(word) + 1

        index = 0
        word = words[index]
        # cannot be out of range; at least (stop, stop, word, stop, stop)
        wordpair = words[index] + u' ' + words[index + 1]

        while True:
            try:
                next = words[index + 2]
                nextpair = words[index + 1] + u' ' + words[index + 2]
            except IndexError:
                # this means we got to the end of the sentence
                break

            if not (self.paircounts.has_key(wordpair)):
                self.paircounts[wordpair] = 0
            self.paircounts[wordpair] = self.paircounts.get(wordpair) + 1

            # add 'next' as a word that comes after 'wordpair'
            if self.dictionary.has_key(wordpair):
                temp = self.dictionary.get(wordpair)[1]
                wordindex = word_index_in_list(next, temp)
                if wordindex == -1:
                    temp.append((next, 1))
                else:
                    prevcount = temp[wordindex][1]
                    temp[wordindex] = (next, prevcount + 1)
            else:
                self.dictionary[wordpair] = ([], [(next, 1)])


            # add 'word' as a word that comes before 'nextpair'
            if self.dictionary.has_key(nextpair):
                othertemp = self.dictionary.get(nextpair)[0]
                wordindex = word_index_in_list(word, othertemp)
                if wordindex == -1:
                    othertemp.append((word, 1))
                else:
                    prevcount = othertemp[wordindex][1]
                    othertemp[wordindex] = (word, prevcount + 1)

            else:
                self.dictionary[nextpair] = ([(word, 1)], [])

            index = index + 1
            word = words[index]
            wordpair = word + u' ' + words[index + 1]

        #print self.dictionary
	self.dictLock.release()

    def generate_chain(self, message):
        """Generates a Markov chain from a message"""

        self.dictLock.acquire()

        words = message.split()
        words.append(self.STOPWORD)
        words.insert(0, self.STOPWORD)

        # find URLs, neaten them up
        for i in range(0, len(words)):
            words[i] = clean_url(words[i])
        if '<{}>'.format(self.users[self.BOT_ID]) in words[1]:
            del words[1]

        if len(words) < 2:
            return ''


        # try to guess which word is the most important
        subject = self.STOPWORD
        confidence = 0

        for word in words:
            if self.wordcounts.has_key(word):
                tfidf = tf_idf(word, words, self.wordcounts, self.sentences_ever)
                if tfidf > confidence:
                    confidence = tfidf
                    subject = word

        # pick a word pair we've seen used with that word before as a seed
        pairs = []
        for wordpair in self.paircounts:
            temp = wordpair.split()
            if (temp[0] == subject) or ((len(temp) > 1) and (temp[1] == subject)):
                pairs.append((wordpair, self.paircounts.get(wordpair)))

        seed = choose_word_from_list(pairs)

        chain = ''

        # forwards
        wordpair = seed
        if self.dictionary.has_key(wordpair):
            chain = wordpair
        #print wordpair
        while (wordpair.split()[1] != self.STOPWORD) and (self.dictionary.has_key(wordpair)):
            wordpair = wordpair.split()[1] + u' ' + \
                        choose_word_from_list(self.dictionary.get(wordpair)[1])
            #print wordpair
            chain = chain + u' ' + wordpair.split()[1]

        # backwards
        wordpair = seed
        if self.dictionary.has_key(wordpair) and wordpair.split()[0] != self.STOPWORD:
            wordpair = choose_word_from_list(
                self.dictionary.get(wordpair)[0]) + \
                u' ' + wordpair.split()[0]
        # so we don't have the seed twice


        while (wordpair.split()[0] != self.STOPWORD) and (self.dictionary.has_key(wordpair)):
            #print wordpair
            chain = wordpair.split()[0] + u' ' + chain
            wordpair = choose_word_from_list(
                self.dictionary.get(wordpair)[0]) + \
                u' ' + wordpair.split()[0]

        self.dictLock.release()

        return chain.replace(self.STOPWORD, u'')

    def generate_song(self):
	bandname = u''
	while True:
	    if bandname != u'':
		bandname = bandname + u' '
	    words = random.choice(self.dictionary.keys()).split()
	    index = random.randint(0, 1)
	    if words[index] == self.STOPWORD:
		bandname = bandname + words[1 - index]
	    else:
		bandname = bandname + words[index]
	    if random.random() > 0.6:
		break
	songtitle = u''
	seed = random.choice(self.dictionary.keys())
	firstword = seed.split()[0]
	secondword = seed.split()[1]
	if firstword != self.STOPWORD:
	    songtitle = firstword
	    currpair = seed
	    while True:
		end = False
		for prev in self.dictionary.get(currpair)[0]:
		    if prev[0] == self.STOPWORD:
			end = True
		if end:
		    break
		else:
		    prev = choose_word_from_list(self.dictionary.get(currpair)[0])
		    songtitle = prev + u' ' + songtitle
		    currpair = prev + u' ' + currpair.split()[0]
	if secondword != self.STOPWORD:
	    if songtitle == u'':
		songtitle = secondword
	    else:
		songtitle = songtitle + u' ' + secondword
	    currpair = seed
	    while True:
		end = False
		for next in self.dictionary.get(currpair)[1]:
		    if next[0] == self.STOPWORD:
			end = True
		if end:
		    break
		else:
		    next = choose_word_from_list(self.dictionary.get(currpair)[1])
		    songtitle = songtitle + u' ' + next
		    currpair = currpair.split()[1] + u' ' + next
	return songtitle, bandname

    def save_dictionary(self):
        """Save the dictionary to disk"""
	self.dictLock.acquire()
        output = open('Markov_Dict.pkl', 'w')
        pickle.dump(self.dictionary, output)
        output.close()
	self.dictLock.release()

    def load_dictionary(self):
        """Load the dictionary file"""
	self.dictLock.acquire()
        input = open('Markov_Dict.pkl', 'r')
        self.dictionary = pickle.load(input)
        input.close()
	self.dictLock.release()

    def toggle_learn(self):
        """Toggles the learning state"""
        self.isLearning = not self.isLearning

    def clean_urls_in_dictionary(self):
	self.dictLock.acquire()
        newdict = copy.deepcopy(self.DEFAULT_DICTIONARY)
        for key in self.dictionary:
            firsts = self.dictionary.get(key)[0]
            for i in range(0, len(firsts)):
                firsts[i] = (clean_url(firsts[i][0]), firsts[i][1])
            seconds = self.dictionary.get(key)[1]
            for i in range(0, len(seconds)):
                seconds[i] = (clean_url(seconds[i][0]), seconds[i][1])
	    newkey = clean_url(key.split()[0])
	    if len(key.split()) > 1:
		newkey = newkey + ' ' + clean_url(key.split()[1])
            newdict[newkey] = (firsts, seconds)
        self.dictionary = newdict
	self.dictLock.release()
コード例 #6
0
ファイル: MarkovBot.py プロジェクト: J-Spade/slackov
class MarkovBot(slackbot.Slackbot):
    """Handles chain generation and bot behavior"""

    talkBackFreq = 0.05
    isLearning = True
    censorWords = True  #not implemented
    lastMessages = {}

    STOPWORD = 'BOGON'

    #       key        come-befores       come-afters
    DEFAULT_DICTIONARY = {STOPWORD: ([(STOPWORD, 1)], [(STOPWORD, 1)])}
    dictionary = copy.deepcopy(DEFAULT_DICTIONARY)

    wordcounts = {STOPWORD: 0}
    paircounts = {STOPWORD: 0}
    sentences_ever = 0

    def __init__(self, client, slack, twitter):
        token = slack['token']
        user_id = slack['id']
        avatarsource = slack['avatarsource']

        slackbot.Slackbot.__init__(self, token, client, user_id, avatarsource)

        consumer_key = twitter['consumer_key']
        consumer_secret = twitter['consumer_secret']
        access_token = twitter['access_token']
        access_token_secret = twitter['access_token_secret']

        self.twitter = TwitterBot(consumer_key, consumer_secret, access_token,
                                  access_token_secret)

        self.dictLock = threading.Lock()

        print 'LOADING DICTIONARY...'
        try:
            self.load_dictionary()

            print 'COUNTING WORDS...'
            for wordpair in self.dictionary:

                temp = wordpair.split()
                uses = 0
                for temp in self.dictionary.get(wordpair)[0]:
                    uses = uses + temp[1]
                self.paircounts[wordpair] = uses

                tally = 0
                for prev in self.dictionary.get(wordpair)[0]:
                    tally += prev[1]

                first = wordpair.split()[0]
                if not (self.wordcounts.has_key(first)):
                    self.wordcounts[first] = 0
                self.wordcounts[first] = self.wordcounts.get(first) + tally

                if wordpair != self.STOPWORD:
                    second = wordpair.split()[1]
                    if not (self.wordcounts.has_key(second)):
                        self.wordcounts[second] = 0
                    self.wordcounts[second] = self.wordcounts.get(
                        second) + tally

            self.sentences_ever = self.wordcounts.get(self.STOPWORD)

            print 'STARTING AUTOSAVER...'
            self.autosaver = _autoSaveThread(self)
            self.autosaver.start()
        except IOError:
            print 'DICTIONARY COULD NOT BE LOADED'

    def on_message_received(self, target, sender, message):
        callargs = {'token': self.TOKEN, 'user': sender}
        info = self.CLIENT.api_call('users.info',
                                    token=self.TOKEN,
                                    user=sender)
        sentByAdmin = info['user']['is_admin']

        if self.do_commands(target, sender, message, sentByAdmin):
            return

        if sender != 'USLACKBOT':
            message = message.lower()
            if self.isLearning:
                lines = message.split(u'\n')
                for line in lines:
                    for sentence in line.split(u'. '):
                        if sentence.endswith(u'.'):  # get rid of last .
                            sentence = sentence[:-1]
                        self.interpret_message(sentence)
            if random.random() < self.talkBackFreq:
                response = self.generate_chain(message)
                if response != '':
                    self.send_message(target, response)

    def on_my_message_received(self, timestamp, message):
        if timestamp not in self.lastMessages:
            self.lastMessages[timestamp] = message

    def on_private_message_received(self, channel, sender, message):
        """
        PMs don't teach the bot anything,
        but will always get a response (if the bot can provide one)
        """
        callargs = {'token': self.TOKEN, 'user': sender}
        info = self.CLIENT.api_call('users.info',
                                    token=self.TOKEN,
                                    user=sender)
        sentByAdmin = info['user']['is_admin']

        if self.do_commands(channel, sender, message, sentByAdmin):
            return

        message = message.lower()

        response = self.generate_chain(message)
        if response != '':
            self.send_message(channel, response)

    def on_name_ping_received(self, channel, sender):
        self.send_message(channel, '<@%s>' % self.users[sender])

    def on_reaction_received(self, channel, timestamp):
        if timestamp in self.lastMessages:
            message = self.lastMessages[timestamp]
            links = self.twitter.post(message)
            del self.lastMessages[timestamp]
            if links:
                for link in links:
                    self.send_message(channel, link)

    def do_commands(self, target, sender, message, sentByAdmin):
        if sentByAdmin and ('!saveDict' in message):
            try:
                self.save_dictionary()
                self.send_message(
                    target, 'DICTIONARY SAVED SUCCESSFULLY (%s bytes)' %
                    str(os.path.getsize('Markov_Dict.pkl')))
            except IOError:
                self.send_message(target, 'DICTIONARY COULD NOT BE SAVED')
            return True
        elif sentByAdmin and ('!loadDict' in message):
            try:
                self.load_dictionary()
                self.send_message(
                    target, 'DICTIONARY LOADED SUCCESSFULLY (%s bytes)' %
                    str(os.path.getsize('Markov_Dict.pkl')))
            except IOError:
                self.send_message(target, 'DICTIONARY COULD NOT BE LOADED')
            return True
        elif sentByAdmin and ('!eraseDict' in message):
            self.dictionary = {
                self.STOPWORD: ([self.STOPWORD], [self.STOPWORD])
            }
            self.send_message(target, 'DICTIONARY ERASED (NOT SAVED YET)')
            return True
        elif sentByAdmin and ('!learn' in message):
            self.toggle_learn()
            print_message = 'I AM {} LEARNING'
            self.send_message(
                target,
                print_message.format(
                    'NOW' if self.isLearning else 'NO LONGER'))
            return True
        elif sentByAdmin and ('!cleanURL' in message):
            self.clean_urls_in_dictionary()
            self.send_message(target, 'LINKS IN DICTIONARY HAVE BEEN CLEANED')
            return True
        elif '!search' in message:
            try:
                message = message.lower()
                searchterms = message.split()[1:]
                for i in range(0, len(searchterms)):
                    searchterms[i] = clean_url(searchterms[i])
                if len(searchterms) == 1:
                    phrases = []
                    for key in self.dictionary:
                        if searchterms[0] == key.split()[0] or \
                                             (len(key.split()) > 1 and \
                                             searchterms[0] == key.split()[1]):
                            phrases.append(key)
                    self.send_message(
                        target,
                        u'"%s" in pairs: %s' % (searchterms[0], str(phrases)))
                else:
                    key = searchterms[0] + u' ' + searchterms[1]
                    if self.dictionary.has_key(key):
                        self.send_message(
                            target,
                            u'"%s": %s' % (key, str(self.dictionary.get(key))))
                    else:
                        self.send_message(
                            target, u'"%s" not found in dictionary' % key)
            except IndexError:
                self.send_message(target, u'MALFORMED COMMAND')
            return True
        elif '!talkback' in message:
            try:
                self.talkBackFreq = float(message.split()[1])
                self.send_message(
                    target,
                    ('RESPONDING PROBABILITY SET TO %3f' % self.talkBackFreq))
            except (IndexError, TypeError, ValueError):
                self.send_message(target, 'MALFORMED COMMAND')
            return True
        elif sentByAdmin and ('!quit' in message):
            self.quit()
            return True
        elif '!avatar' in message:
            self.send_message(
                target, 'SOURCE OF MY CURRENT AVATAR: %s' % self.AVATARSOURCE)
            return True

        elif ('!nowplaying' in message):
            songname, songartist = self.generate_song()
            self.send_message(
                target, u'Now Playing: "%s", by %s' %
                (string.capwords(songname), string.capwords(songartist)))
            return True

        return False  # did not find a command

    def on_quit(self):
        # try:
        #   self.saveDictionary()
        #   print ('DICTIONARY SAVED SUCCESSFULLY')
        # except IOError:
        #   print ('DICTIONARY COULD NOT BE SAVED')
        pass

    def interpret_message(self, message):
        """Interprets a message"""

        self.dictLock.acquire()
        words = message.split()
        words.append(self.STOPWORD)
        words.insert(0, self.STOPWORD)

        self.sentences_ever = self.sentences_ever + 1

        # find URLs, neaten them up
        for i in range(0, len(words)):
            words[i] = clean_url(words[i])

        for word in words:
            if not (self.wordcounts.has_key(word)):
                self.wordcounts[word] = 0
            self.wordcounts[word] = self.wordcounts.get(word) + 1

        index = 0
        word = words[index]
        # cannot be out of range; at least (stop, stop, word, stop, stop)
        wordpair = words[index] + u' ' + words[index + 1]

        while True:
            try:
                next = words[index + 2]
                nextpair = words[index + 1] + u' ' + words[index + 2]
            except IndexError:
                # this means we got to the end of the sentence
                break

            if not (self.paircounts.has_key(wordpair)):
                self.paircounts[wordpair] = 0
            self.paircounts[wordpair] = self.paircounts.get(wordpair) + 1

            # add 'next' as a word that comes after 'wordpair'
            if self.dictionary.has_key(wordpair):
                temp = self.dictionary.get(wordpair)[1]
                wordindex = word_index_in_list(next, temp)
                if wordindex == -1:
                    temp.append((next, 1))
                else:
                    prevcount = temp[wordindex][1]
                    temp[wordindex] = (next, prevcount + 1)
            else:
                self.dictionary[wordpair] = ([], [(next, 1)])

            # add 'word' as a word that comes before 'nextpair'
            if self.dictionary.has_key(nextpair):
                othertemp = self.dictionary.get(nextpair)[0]
                wordindex = word_index_in_list(word, othertemp)
                if wordindex == -1:
                    othertemp.append((word, 1))
                else:
                    prevcount = othertemp[wordindex][1]
                    othertemp[wordindex] = (word, prevcount + 1)

            else:
                self.dictionary[nextpair] = ([(word, 1)], [])

            index = index + 1
            word = words[index]
            wordpair = word + u' ' + words[index + 1]

        #print self.dictionary
        self.dictLock.release()

    def generate_chain(self, message):
        """Generates a Markov chain from a message"""

        self.dictLock.acquire()

        words = message.split()
        words.append(self.STOPWORD)
        words.insert(0, self.STOPWORD)

        # find URLs, neaten them up
        for i in range(0, len(words)):
            words[i] = clean_url(words[i])
        if '<{}>'.format(self.users[self.BOT_ID]) in words[1]:
            del words[1]

        if len(words) < 2:
            return ''

        # try to guess which word is the most important
        subject = self.STOPWORD
        confidence = 0

        for word in words:
            if self.wordcounts.has_key(word):
                tfidf = tf_idf(word, words, self.wordcounts,
                               self.sentences_ever)
                if tfidf > confidence:
                    confidence = tfidf
                    subject = word

        # pick a word pair we've seen used with that word before as a seed
        pairs = []
        for wordpair in self.paircounts:
            temp = wordpair.split()
            if (temp[0] == subject) or ((len(temp) > 1) and
                                        (temp[1] == subject)):
                pairs.append((wordpair, self.paircounts.get(wordpair)))

        seed = choose_word_from_list(pairs)

        chain = ''

        # forwards
        wordpair = seed
        if self.dictionary.has_key(wordpair):
            chain = wordpair
        #print wordpair
        while (wordpair.split()[1] !=
               self.STOPWORD) and (self.dictionary.has_key(wordpair)):
            wordpair = wordpair.split()[1] + u' ' + \
                        choose_word_from_list(self.dictionary.get(wordpair)[1])
            #print wordpair
            chain = chain + u' ' + wordpair.split()[1]

        # backwards
        wordpair = seed
        if self.dictionary.has_key(
                wordpair) and wordpair.split()[0] != self.STOPWORD:
            wordpair = choose_word_from_list(
                self.dictionary.get(wordpair)[0]) + \
                u' ' + wordpair.split()[0]
        # so we don't have the seed twice

        while (wordpair.split()[0] !=
               self.STOPWORD) and (self.dictionary.has_key(wordpair)):
            #print wordpair
            chain = wordpair.split()[0] + u' ' + chain
            wordpair = choose_word_from_list(
                self.dictionary.get(wordpair)[0]) + \
                u' ' + wordpair.split()[0]

        self.dictLock.release()

        return chain.replace(self.STOPWORD, u'')

    def generate_song(self):
        bandname = u''
        while True:
            if bandname != u'':
                bandname = bandname + u' '
            words = random.choice(self.dictionary.keys()).split()
            index = random.randint(0, 1)
            if words[index] == self.STOPWORD:
                bandname = bandname + words[1 - index]
            else:
                bandname = bandname + words[index]
            if random.random() > 0.6:
                break
        songtitle = u''
        seed = random.choice(self.dictionary.keys())
        firstword = seed.split()[0]
        secondword = seed.split()[1]
        if firstword != self.STOPWORD:
            songtitle = firstword
            currpair = seed
            while True:
                end = False
                for prev in self.dictionary.get(currpair)[0]:
                    if prev[0] == self.STOPWORD:
                        end = True
                if end:
                    break
                else:
                    prev = choose_word_from_list(
                        self.dictionary.get(currpair)[0])
                    songtitle = prev + u' ' + songtitle
                    currpair = prev + u' ' + currpair.split()[0]
        if secondword != self.STOPWORD:
            if songtitle == u'':
                songtitle = secondword
            else:
                songtitle = songtitle + u' ' + secondword
            currpair = seed
            while True:
                end = False
                for next in self.dictionary.get(currpair)[1]:
                    if next[0] == self.STOPWORD:
                        end = True
                if end:
                    break
                else:
                    next = choose_word_from_list(
                        self.dictionary.get(currpair)[1])
                    songtitle = songtitle + u' ' + next
                    currpair = currpair.split()[1] + u' ' + next
        return songtitle, bandname

    def save_dictionary(self):
        """Save the dictionary to disk"""
        self.dictLock.acquire()
        output = open('Markov_Dict.pkl', 'w')
        pickle.dump(self.dictionary, output)
        output.close()
        self.dictLock.release()

    def load_dictionary(self):
        """Load the dictionary file"""
        self.dictLock.acquire()
        input = open('Markov_Dict.pkl', 'r')
        self.dictionary = pickle.load(input)
        input.close()
        self.dictLock.release()

    def toggle_learn(self):
        """Toggles the learning state"""
        self.isLearning = not self.isLearning

    def clean_urls_in_dictionary(self):
        self.dictLock.acquire()
        newdict = copy.deepcopy(self.DEFAULT_DICTIONARY)
        for key in self.dictionary:
            firsts = self.dictionary.get(key)[0]
            for i in range(0, len(firsts)):
                firsts[i] = (clean_url(firsts[i][0]), firsts[i][1])
            seconds = self.dictionary.get(key)[1]
            for i in range(0, len(seconds)):
                seconds[i] = (clean_url(seconds[i][0]), seconds[i][1])
            newkey = clean_url(key.split()[0])
            if len(key.split()) > 1:
                newkey = newkey + ' ' + clean_url(key.split()[1])
            newdict[newkey] = (firsts, seconds)
        self.dictionary = newdict
        self.dictLock.release()