3

I'm a nub programmer, using python, and my current project is a chatbot for an irc channel I reside in. I wish to make it capable of keeping conversations organized, primarily between its self and one other person.

Right now, I'm creating a conversation object when the bot is initially addressed. The object has the attributed of peer (the other conversation member), topic (the basic topic of the conversation), log (a log of past messages to and from the peer), lastsent (super-simplified forms of the most recent 10 messages sent to the channel by the bot), and lastrecv (the last 10 messages received sent to the channel by the peer, also super-simplified). As messages are received, the bot checks the topic and runs through a list of expected replies. If one is matched, the bot chooses a response and send it to the channel. It then updates the topic if needed and the bot's conversation dictionary.

The bot has a conversation dictionary list, the key is the user's nickname, and the definition is the conversation object.

I feel this is unnecessarily excessive. I was wondering what some other approaches to keeping track of conversations were. Are there any simpler, easier approaches?

  • It is not much clear to me from your question what you are using to build the bot. It looks like you have already built it and now want to determine how to keep track of conversations. Well if that is the case then you have already done the hard part... What is keeping you from saving the peer name, timestamp and text? – Yasir Jul 9 '11 at 6:15
  • @ Yasir: I'm using python 2.6 and the Twisted irc module. I have built the bot and am trying to determine how to keep track of conversations, like you said. I do save the peer name and text. As for timestamp, I only save the time of the most recent message and that is overwritten each time a new message is received. – xBlink Jul 9 '11 at 6:23
  • Ok, so what is the purpose of saving conversations? This is possibly the biggest factor to determine what to save. – Yasir Jul 9 '11 at 6:37
  • More than saving the conversation, I want the program to keep track of them and respond to them. For example, without the conversation objects, the bot would respond to anything you tell it. You could jump from talking about dogs to telling it hello and it would not care, it would just respond. I want conversation objects to allow the program to keep track of who it's talking to, and what it's talking about. My question is really: what are some approaches to allow the program to maintain conversations and seem a little more human? – xBlink Jul 9 '11 at 6:45
  • Maybe you should change your approach. Try thinking about how do you reply if someone ask you something rather than how a piece of software should reply. You need a topic (if this is an IRC channel, maybe you dont need this) and a question in orden to make a decision on what to respond. – guiman Dec 6 '11 at 1:36
1

I'm curious what makes you think this is unnecessarily excessive. It seems perfectly reasonable to me, however, I'm sure there are ways to refactor it to a cleaner state.

I'm playing around with a very simple implementation of this right now to try and get a feel for it and some questions I'm finding myself asking are:

"Should the Conversation hold the topic or the Message hold the topic? Are there operations on a Conversation? (I think so, if only for the logic to keep a cache of recent messages.)"

"Is it important to cache a smaller list of messages last sent and recv? Can this be done with filtering/slicing the log?"

"Do messages deserve their own object? (Are there any operations on messages?) Can I get away with a tuple or a namedtuple?"

"Is the Conversation responsible for actually interacting with network IO and sending and receiving live messages or does it interact with some network object? If it does interact with some other object, how do they interface with each other?"

So far my playground for thinking about this problem looks like this:

from collections import deque                                                                                                                                                                                     

class Message():                                                                                                                                                                                                  
    def __init__(self, sender, contents):                                                                                                                                                                         
        self.sender = sender                                                                                                                                                                                      
        self.contents = contents                                                                                                                                                                                  


def find_appropriate_response(topic, message_contents):                                                                                                                                                           
    black_magic(topic, message_contents)                                                                                                                                                                          


available_topics = ['software_engineering', 'indie_film', 'naval_history']                                                                                                                                        


class Conversation:                                                                                                                                                                                               
    log = []                                                                                                                                                                                                      
    lastsent = deque()                                                                                                                                                                                            
    lastrecv = deque()                                                                                                                                                                                            

    def __init__(self, peer, message):                                                                                                                                                                            
        self.peer = peer                                                                                                                                                                                          
        (sender, contents) = message.split(":")                                                                                                                                                                   
        self.add_message(Message(sender, contents))                                                                                                                                                               

        self.topic = discern_message_topic(contents)                                                                                                                                                              
        if self.topic in available_topics:                                                                                                                                                                        
            response = find_appropriate_response(self.topic, contents)                                                                                                                                            
            reply_with(response)                                                                                                                                                                                  
        else:                                                                                                                                                                                                     
            reply_with("I'm sorry, I don't know this topic.")                                                                                                                                                     

    def recieved_message(self, message):                                                                                                                                                                          
        self.log.append(message)                                                                                                                                                                                  
        self.lastrecv.append(message)                                                                                                                                                                             
        if len(self.lastrecv) > 10:                                                                                                                                                                               
            self.lastrecv.popleft()                                                                                                                                                                               

    def sent_message(self, message)                                                                                                                                                                               
        self.log.append(message)                                                                                                                                                                                  
        self.lastsent.append(message)                                                                                                                                                                             
        if len(self.lastsent) > 10:                                                                                                                                                                               
            self.lastsent.popleft()                                                                                                                                                                               


    def discern_message_topic(self, message_contents):                                                                                                                                                            
        return black_magic(message_contents)

I'm hoping this is somewhat similar to your data model and way of thinking. In terms of what you actually asked about, which is... "Is there a more simple or easy way to keep track of the notion of a conversation?" That depends on your definition of simple, and a well-defined set of requirements, I'll give it a stab.

Message = namedtuple('Message', ['direction', 'contents'])
conversations = {}
conversations['someuser'] = []
conversations['someuser'].append(Message('recieved', 'Back in 1714 the people of ...'))
conversations['someuser'].append(Message('sent', "I don't know about history"))

That is pretty much just a storage mechanism with no logic, but that's all I think you need for the "idea of a conversation", it contains details about with whom the conversation is being held, who is responsible for creating the message contents, what the message contents are, and the order of messages. I think that's approaching more of what my idea of "simple" is.

The nature of a python list will keep them in the appropriate order, and if you want more order or more information about time you could add a field to the tuple and provide it a datetime value.

I must assume you have some method for determining the topic based on the contents of a message which you could call as you pass over them, and if that method is for some reason expensive, then you could also add it as a field to the tuple.

protected by gnat Feb 13 '15 at 19:37

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.