4
\$\begingroup\$

I wrote a simple chatbot in Python a while ago, and I'd like to know how it could be improved. Here's the code:

import random
import pickle

class Bot:
    current = ""
    botText = "BOT> "

    def __init__(self, data, saveFile):
        self.data = data
        self.saveFile = saveFile

    def say(self, text):
        print(self.botText + text)
        self.current = text

    def addResponse(self, userInput, response):
        if userInput in self.data:
            self.data[userInput].extend(response)

        else:
            self.data[userInput] = []
            self.data[userInput].extend(response)


    def evaluate(self, text):
        if text in self.data:
            self.say(random.choice(self.data[text]))

        elif text == "/SAVE":
            f = open(self.saveFile, 'wb')
            pickle.dump(self.data, f)
            f.close()

        elif text == "/LOAD":
            f = open(self.saveFile, 'rb')
            self.data = pickle.load(f)
            f.close()

        elif text == "/DATA":
            print(self.data)

        else:
            if not self.current in self.data:
                self.data[self.current] = []

            self.data[self.current].append(text)
            self.say(text)

Here's how the bot works. I'm sorry if you don't understand, I'm not the best at explaining things.

  1. User enters input.
  2. If the input is in the database, choose a random response associated with the input and output it.
  3. If it isn't, add the input to the database and echo the input.
  4. User enters input again.
  5. The input is associated with the bot's output.

Inputs and outputs can be added manually using the addResponse() function.

There are also a few commands, which are quite self-explanatory, but I'll list them here anyways.

  • /SAVE pickles the file and saves it in the saveFile.
  • /LOAD unpickles the saveFile and loads it.
  • /DATA displays the database.
\$\endgroup\$
5
\$\begingroup\$

Clean and straightforward, very nice.

Minor suggestions:

  • If you do

    from collections import defaultdict

    ...

    self.data = defaultdict(list)

    then you can make addResponse be just:

    self.data[userInput].extend(response)

    and likewise you can leave out the if block under the else clause in evaluate

  • The code:

    f = open(self.saveFile, 'rb')
    self.data = pickle.load(f)
    f.close()
    

    is slightly-better written as:

    with open(self.saveFile, 'rb') as f:
        self.data = pickle.load(f)
    

    so that if pickle.load() throws an exception, the file will still get closed. Similar for the /SAVE code.

\$\endgroup\$
  • 1
    \$\begingroup\$ The collections library is worth looking over, if only to lodge in your head that 'this kind of thing exists'. \$\endgroup\$ – pjz Aug 3 '16 at 15:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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