How To Create A Guide Chatbot With Python (2)

How To Create A Guide Chatbot With Python (2)

In this part, you will learn how to refactor your chatbot to bring it up to Conventional best practices

Refactor your Code

This tutorial explains how to refactor the codes used in creating a text-only chatbot using python. The tutorial is aimed at beginners in python programming who wish to learn the basics of python programming language. This tutorial assumes that you have gone through the first part of the series which explained How to Create A Guide Chatbot With Python (1). It is best to leave your code open in an editor as you refactor it while following this guide.

Remember, the first part of this tutorial covered the steps to create an interactive chatbot called Amanda, which guides users to choose a path in web development. When a user calls Amanda, she performs the following actions:

  • introduces herself to the user and explains web development and its various components to the user
  • finds out from the user, the aspect of web development they wish to focus
  • outlines the languages the user should learn in order to become successful in their chosen area
  • shortlists some of the platforms where the user can learn from (the platforms used in this write-up are platforms that the author personally learned from. They are used as references and not for any commercial purposes)
  • asks the user to select where they want to learn from
  • leads the user to the homepage of the platform of their choice

Remove Repetitions

One of the most repeated lines in the code is the time.sleep() function which you used to set a pause between the display of Amanda’s messages. To eliminate the repetition of time.sleep(), declare a function that could be called, while Amanda’s messages would be passed to the function as arguments. Let’s name this function message-pause. The parameter, message_to_print in the new function represents the messages you want Amanda to print. Below is the syntax:

def message_pause(message_to_print):
    print(message_to_print)
    time.sleep(2)

With this, you won’t need to keep repeating ‘time.sleep()’. You only call the function and pass the message you want as an argument. For instance, the code of the first line of Amanda’s introduction would look like this.

message_pause("Hello! I'm your friend, Amanda.\n")

Declare a function for your introduction

Next, declare a function for Amanda’s introduction so that you can call it anytime it is needed in the program. This function declaration removes the print and time.sleep() lines to ensure non-repetition. The example calls this function ‘intro’.

def intro():
    message_pause("Hello! I'm your friend, Amanda.\n")
    message_pause("I'm here to guide you throughout your journey to becoming a web developer\n")
    message_pause("First of all, I need to find out the aspect of Web development you wish to learn.\n")
    message_pause("Web-development is divided into front-end and back-end development\n")
    message_pause("As found on Wikipedia, Front-end web development refers to Front-end web\n "
                  "development is the development of the graphical user interface of a website,\n "
                  "through the use of HTML, CSS, and JavaScript, so that users can view and\n "
                  "interact with that website\n")
    message_pause("While back-end web development refers to the server-side of development\n "
                  "which focuses on the communications between the database and the browser.\n "
                  "including scripting and website architecture\n")
    message_pause("Meanwhile, a combination of these two components is what we know as full-stack web development\n")
    message_pause("If you wish to learn front-end web development, then you should learn HTML, CSS, JavaScript, Bootstrap, React, and/or other front end libraries and frameworks\n")
    message_pause("But if you wish to learn back-end development, you have to learn Python, Javascript, Ruby, PHP, C#, Java, and other back-end languages\n")
    message_pause("If you aspire to be a full-stack developer, you know what to do of course\n")
    message_pause("Take your time and master both components and their relevant languages.\n")

Notice that you have passed all the introductory messages into your message_pause function. With that, you have successfully eliminated the need to keep repeating print and time.sleep().

Another important thing to do while refactoring your codes is to check the length of your lines of code. The lines of code in the program are way too long. In fact, Python recommends less than or equal to 79 characters on one line. Therefore we have to adhere to this recommendation.

But what happens when your code is longer than 79 characters? How can we break them into different lines and still get python to recognize the different lines as one bit of code?

There are several ways to do this. You can use a triple quotation to enclose the words at both ends of the code. Or alternatively, you can enclose the lines of code within quotation marks inside a single bracket. And this is the one we used in this example. Remember you have to account for the spaces between words as python will not fix that for you.

def intro():
    message_pause("Hello! I'm your friend, Amanda.\n")
    message_pause("I'm here to guide you throughout your journey\n "
                  "to becoming a web developer\n")
    message_pause("First of all, I need to find out the aspect\n "
                  "of Web development you wish to learn.\n")
    message_pause("Web-development is divided into front-end\n "
                  "and back-end development\n")
    message_pause("As found on Wikipedia, Front-end web development\n "
                  "refers to Front-end web development is\n "
                  "the development of the graphical user interface\n "
                  "of a website, through the use of HTML, CSS, and JavaScript,\n "
                  "so that users can view and interact with that website\n")
    message_pause("While back-end web development refers to the\n "
                  "server-side of development which focuses on the\n "
                  "communications between the database and the browser.\n "
                  "including scripting and website architecture\n")
    message_pause("Meanwhile, a combination of these two components is\n "
                  "what we know as full-stack web development\n")
    message_pause("If you wish to learn front-end web development, then you\n "
                  "should learn HTML, CSS, JavaScript, Bootstrap, React and/or\n "
                  "other front end libraries and frameworks\n")
    message_pause("But if you wish to learn back-end development, you have to\n "
                  "learn Python, Javascript, Ruby, PHP, C#, Java, and other "
                  "back-end languages\n")
    message_pause("If you aspire to be a full-stack developer,\n "
                  "you know what to do of course\n")
    message_pause("Take your time and master both components "
                  "and their relevant languages.\n")

We’re good to go. We will continue refactoring our code in line with this.

Declaring Functions for your Inputs

Remember that the bot is programmed to get input from the users to know what they want to learn in the first place. Refactor those input methods to callable functions. Hence, the code to find out the user’s choice of skill would look like this: We will name our function, what_to_learn

def what_to_learn():
    specialization = input("What do you want to learn?\n "
                           "Front-end\n " 
                           "Back-end\n " 
                           "Full-stack\n "
                           "Please select one\n").lower()

    if 'front-end' in specialization:
        learn_front_end()
    elif 'back-end' in specialization:
        learn_back_end()
    elif 'full-stack' in specialization:
        learn_full_stack()
    else:
        message_pause("please enter a valid response")
        what_to_learn()

Amanda the bot is programmed to perform certain actions whenever users choose the aspect of web development they want to learn. So put those actions in a function so that you can simply call them based on the user’s choice. We will name our functions, learn_front_end, learn_back_end, and learn_full_stack respectively. The functions would look like this:

def learn_front_end():
    message_pause("That\'s a great choice i must say\n")
    message_pause("So these are the languages you have to learn:\n"
                  "HTML, CSS, JavaScript\n")
    message_pause("You can learn these languages on the following platforms\n" 
                  "1. Freecodecamp\n" "2. W3schools\n")

def learn_back_end():
    message_pause("You've made a good choice\n")
    message_pause("So these are the languages you should learn: Java, Python,\n "
                  "JavaScript, PHP, and other back-end frameworks and libraries\n ")
    message_pause("You can learn these languages on the following platforms\n " 
                  "1. Freecodecamp\n " 
                  "2. W3schools\n")

def learn_full_stack():
    message_pause("That\'s great!")
    message_pause("So you will have to learn HTML, CSS,JavaScript, Java,\n"
                  "Python, PHP, and other web dev frameworks and libraries\n")
    message_pause("You can learn these languages on the following platforms\n "
                  "Freecodecamp, W3schools, Udacity, and Pluralsight\n")

The program needs to get input from the users to understand their platform preferences. Therefore convert the codes to a function that we assign to the name, where_to_learn. However, the function declaration for the full_stack option would be a bit different since we included other options which we didn’t include for front_end and back_end. We will name the other function, for_full_stack. The code is as follows:

def where_to_learn():
    learn = input("where do you want to learn from?\n"
                  "1. Freecodecamp\n"
                  "2. w3schools\n")
    if learn == '1':
        freecodecamp()
    elif learn == '2':
        w3schools()
    else:
        message_pause("please enter a valid response")
        where_to_learn()

def for_full_stack():
    learn = input("where do you want to learn from?\n "
                  "1. Freecodecamp\n "
                  "2. w3schools\n "
                  "3. Udacity\n "
                  "4. Pluralsight\n ")
    if learn == '1':
        freecodecamp()
    elif learn == '2':
        w3schools()
    elif learn == '3':
        udacity()
    elif learn == '4':
        pluralsight()
    else:
        message_pause("please enter a valid response")
        for_full_stack()

We also want Amanda to print some messages, and then redirect users to various learning platforms depending on where they wish to learn their skills. We will name our functions according to the platforms we provide for the users. This will be our function definitions:

def freecodecamp():
    message_pause("redirecting you to freecodecamp in a moment")
    webbrowser.open('https://www.freecodecamp.org/learn/')  

def w3schools():
    message_pause("redirecting you to W3schools")
    webbrowser.open('https://www.w3schools.com/')  

def udacity():
    message_pause("redirecting you to Udacity")
    webbrowser.open('https://www.udacity.com/')  

def pluralsight():
    message_pause("redirecting you to Pluralsight")
    webbrowser.open('https://www.pluralsight.com/')

Give Users another opportunity

Declare another function for our another_choice input, and assign the function to the name another_chance.

def another_chance():
    another_choice = input("Would you like to make another choice?\n "
                           "Please say 'yes' or 'no'\n").lower()
    if 'yes' in another_choice:
        message_pause("Very good. I am happy to give you another chance.\n")

    elif 'no' in another_choice:
        message_pause("okay, goodbye")
        exit()

    else:
        message_pause("please enter a valid response")

Call the Functions in Appropriate Segments

Call the functions in the places they are needed in the code as follows:

  • Call the ‘what_to_learn’ function immediately after the intro function so that Amanda would find out what users want to learn immediately after introducing herself.

  • Call the ‘what_to_learn’ function again under the first ‘if’ sentence of the ‘another_chance’ function so that it can run if the user chooses to go for another chance.

  • Call the ‘where_to_learn’ function below the ‘learn_front_end’ and ‘learn_back_end’ functions.

  • Call the ‘for_full_stack’ function next to the learn_full_stack function so that Amanda would know the platform preferences of her friends and redirect them accordingly.

  • Call all the functions that provide for another opportunity during invalid inputs immediately after their declaration. This gives the users another opportunity to choose again even if they select an invalid input.

With this description, we realize that the entire program hinges on three different functions to run which we must call sequentially in order to run the program. The functions include:

intro()
what_to_learn()
another_chance()

Running a program from a single function call

But you can also declare another function for this sequence of functions so that you can run the program from a single function call. We will call this super function ‘talk_to_amanda’:

def talk_to_amanda():
    intro()
    what_to_learn()
    another_chance()

Then call talk_to_amanda to run the entire program.

talk_to_amanda()

The Refactored Program

So, the entire refactored code would look like this:

import time
import webbrowser

def message_pause(message_to_print):
    print(message_to_print)
    time.sleep(2)

def intro():
    message_pause("Hello! I'm your friend, Amanda.\n")
    message_pause("I'm here to guide you throughout your journey\n "
                  "to becoming a web developer\n")
    message_pause("First of all, i need to find out the aspect\n "
                  "of Web development you wish to learn.\n")
    message_pause("Web-development is divided into front-end\n "
                  "and back-end development\n")
    message_pause("As found on Wikipedia, Front-end web development\n "
                  "refers to Front-end web development is\n "
                  "the development of the graphical user interface\n "
                  "of a website, through the use of HTML, CSS, and JavaScript,\n "
                  "so that users can view and interact with that website\n")
    message_pause("While back-end web development refers to the\n "
                  "server-side of development which focuses on the\n "
                  "communications between the database and the browser.\n "
                  "including scripting and website architecture\n")
    message_pause("Meanwhile, a combination of these two components is\n "
                  "what we know as full-stack web development\n")
    message_pause("If you wish to learn front-end web development, then you\n "
                  "should learn HTML, CSS, JavaScript, Bootstrap, React and/or\n "
                  "other front end libraries and frameworks\n")
    message_pause("But if you wish to learn back-end development, you have to\n "
                  "learn Python, Javascript, Ruby, PHP, C#, Java and other "
                  "back-end languages\n")
    message_pause("If you aspire to be a full-stack developer,\n "
                  "you know what to do of course\n")
    message_pause("Take your time and master both components "
                  "and their relevant languages.\n")
    what_to_learn()

def learn_front_end():
    message_pause("That\'s a great choice i must say\n")
    message_pause("So these are the languages you have to learn:\n"
                  "HTML, CSS, JavaScript\n")
    message_pause("You can learn these languages on the following platforms\n" 
                  "1. Freecodecamp\n" "2. W3schools\n")
    where_to_learn()

def learn_back_end():
    message_pause("You've made a good choice\n")
    message_pause("So these are the languages you should learn: Java, Python,\n "
                  "JavaScript, PHP, and other back-end frameworks and libraries\n ")
    message_pause("You can learn these languages on the following platforms\n " 
                  "1. Freecodecamp\n " 
                  "2. W3schools\n")
    where_to_learn()

def learn_full_stack():
    message_pause("That\'s great!")
    message_pause("So you will have to learn HTML, CSS,JavaScript, Java,\n"
                  "Python, PHP, and other web dev frameworks and libraries\n")
    message_pause("You can learn these languages on the following platforms\n "
                  "Freecodecamp, W3schools, Udacity, and Pluralsight\n")
    for_full_stack()

def freecodecamp():
    message_pause("redirecting you to freecodecamp in a moment")
    webbrowser.open('https://www.freecodecamp.org/learn/')  
    what_to_learn()

def w3schools():
    message_pause("redirecting you to W3schools")
    webbrowser.open('https://www.w3schools.com/')  
   what_to_learn()

def udacity():
    message_pause("redirecting you to Udacity")
    webbrowser.open('https://www.udacity.com/')  
    what_to_learn()

def pluralsight():
    message_pause("redirecting you to Pluralsight")
    webbrowser.open('https://www.pluralsight.com/')  
    what_to_learn()

def what_to_learn():
    specialization = input("What do you want to learn?\n "
                           "Front-end\n " 
                           "Back-end\n " 
                           "Full-stack\n "
                           "Please select one\n").lower()

    if 'front-end' in specialization:
        learn_front_end()
    elif 'back-end' in specialization:
        learn_back_end()
    elif 'full-stack' in specialization:
        learn_full_stack()
    else:
        message_pause("please enter a valid response")
        what_to_learn()

def where_to_learn():
    learn = input("where do you want to learn from?\n"
                  "1. Freecodecamp\n"
                  "2. w3schools\n")
    if learn == '1':
        freecodecamp()
    elif learn == '2':
        w3schools()
    else:
        message_pause("please enter a valid response")
        where_to_learn()

def for_full_stack():
    learn = input("where do you want to learn from?\n "
                  "1. Freecodecamp\n "
                  "2. w3schools\n "
                  "3. Udacity\n "
                  "4. Pluralsight\n ")
    if learn == '1':
        freecodecamp()
    elif learn == '2':
        w3schools()
    elif learn == '3':
        udacity()
    elif learn == '4':
        pluralsight()
    else:
        message_pause("please enter a valid response")
        for_full_stack()


def another_chance():
    another_choice = input("Would you like to make another choice?\n "
                           "Please say 'yes' or 'no'\n").lower()
    if 'yes' in another_choice:
        message_pause("Very good. I am happy to give you another chance.\n")
        what_to_learn()

    elif 'no' in another_choice:
        message_pause("okay, goodbye")
        exit()

    else:
        message_pause("please enter a valid response")
        another_chance()

def talk_to_amanda():
    intro()
    what_to_learn()
    another_chance()

talk_to_amanda()

Great you have gotten to this point. You’re a real warrior. But we still have one more step to go.

Checking Python style conventions using Pycodestyle

Finally, before we go, you have to check your code with the pycodestyle to know if it is in line with python's best practices. But before we do that, you have to install pycodestyle in your system (in case you do not have it already). You do that with:

$ pip install pycodestyle

Once it is installed, you can run your code with pycodestyle in your GIT Bash or terminal using the command:

$ pycodestyle amanda_the_bot.py

amanda_the_bot is my own program name. You can name yours anything meaningful. Remember, you must navigate to the directory where your program is saved before running the program with pycodestyle. Below are the problems my program had:

$ pycodestyle amanda_the_bot.py
web_guide.py:4:1: E302 expected 2 blank lines, found 1
web_guide.py:8:1: E302 expected 2 blank lines, found 1
web_guide.py:19:80: E501 line too long (82 > 79 characters)
web_guide.py:28:80: E501 line too long (82 > 79 characters)
web_guide.py:30:80: E501 line too long (81 > 79 characters)
web_guide.py:44:79: W291 trailing whitespace
web_guide.py:51:80: E501 line too long (81 > 79 characters)
web_guide.py:52:80: E501 line too long (84 > 79 characters)
web_guide.py:53:80: W291 trailing whitespace
web_guide.py:54:39: W291 trailing whitespace
web_guide.py:70:59: W291 trailing whitespace
web_guide.py:72:1: E302 expected 2 blank lines, found 1
web_guide.py:74:50: W291 trailing whitespace
web_guide.py:79:48: W291 trailing whitespace
web_guide.py:84:52: W291 trailing whitespace
web_guide.py:89:42: W291 trailing whitespace
web_guide.py:90:41: W291 trailing whitespace
web_guide.py:93:1: W293 blank line contains whitespace
web_guide.py:136:1: W293 blank line contains whitespace
web_guide.py:143:1: W293 blank line contains whitespace
web_guide.py:147:1: W293 blank line contains whitespace
web_guide.py:158:1: E305 expected 2 blank lines after class or function definition, found 1

Fixing Errors Detected by Pycodestyle

What do these messages mean?

The first message is telling me that, on line 4, column 1; python expected to see two blank lines. But it only found one. (Pycodestyle recommends two blank lines after every function declaration).

The messages bearing ‘line too long’ are saying that on those lines and columns, the code have exceeded the recommended 79 characters per line of code. So I have to correct that.

The messages bearing ‘trailing whitespaces’ indicate that there are whitespaces at the end of those lines which you need to remove.

Finally, the messages bearing ‘blank line contains whitespaces’ are advising me to remove the whitespaces found in blank lines inside my code.

Once all these problems are corrected, run your program again with pycodestyle. This time, it will bring out no message. This means that the code is free of style bugs.

Thank you very much for hanging on. I hope you got value.

Be assured that your feedback is important to me.