Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
from tkinter import *
from tkinter import ttk #this uses the nicer-looking ttk widgets. Placed after previous import so ttk overrides tkinter when applicable, but when not applicable, standard tkinter widgets are used. ttk was learnt about from here: https://docs.python.org/2/library/ttk.html
from tkinter import messagebox #for some reason, the messagebox worked without this line in idle, but it didn't work with the command prompt, even though the exact same machine and Python version were used. I added this code so it's compatible with both.
import webbrowser #import this so it is possible to open news articles in the web browser.
#importing group members' module code below
from Jokes import *
from News import *
from Weather import *
from YELP import *
from Entertainment import *
from Movies import *
from Sports import *
from ChatQuestions import *
from IrtizaFunctions import *
from FileSave import *
#end of group members' module coding importing
from random import randint #for creating random integers between two numbers
#All code below is written by Humza, except where noted. Most module functions called here were written by others (the author can be found by opening the respective files).
root = Tk()
#declaring global variables because variables inside function are all reset when function runs, but weather function needs to run multiple times due to asking user to type multiple things
#all ___Steps variables are declaed global for this same reason because they ask user to type multiple inputs
#also, another note about all ___Steps variables, they are all incremented (or set to 0 if function is complete) to make sure the next part of the if-statement is triggered.
global weatherSteps
weatherSteps = 0 #assign weatherSteps to 0 so it has an int value compatible with if-statement
global weatherCity
weatherCity = "" #intialise to empty string for use with if-statements; other global string variables are initialised to this for the same reason.
global weatherCountry
weatherCountry = ""
global feelingSteps
feelingSteps = 1 #initialise as 1 because this is the first question when the chatbot starts, so user should respond to this
global yelpSteps
yelpSteps = 0
global yelpLocation
yelpLocation = ""
global yelpIndex
yelpIndex = 0 #using global variable for index to keep track of index outside of function (because variable would reset each time if it was inside function).
global movieSteps
movieSteps = 0
global loginSteps
loginSteps = "" #using strings for these steps because different branches can be taken (such as registering new user or asking existing user for password))
global currentUser
currentUser = ""
global userTraits #use list so no need to create separate variable for each trait
userTraits = [] #initialise to empty list because cannot do userTraits.append() otherwise.
global userAccount #instance of Users class
global passAttempt #store what user put in for password
class Users:
"""Class for holding user data abd storing names of users"""
chatPeople = ["User: "] #append more to list as people log on.
def __init__(self, name):
self.name = name.capitalize() #using .capitalize() because gramatttically correct names should start with capital letters, and currentUser variable is all lower case
self.age = read(self.name+".txt", "age")
self.location = read(self.name+".txt", "location").title() #using title() to make sure location is gramatically correct if accessed.
self.course = read(self.name+".txt", "course").title() #ensuring that it is gramatically correct
self.password = read(self.name+".txt", "password")
if self.name not in self.chatPeople:
self.chatPeople.append(self.name + ": ") #added ": " because I also want the colon to be highlighted, and because the responses look better if there was a space between the colon and the response.
else:
#brings current user to end of list, without duplicating,
#which is important because that is how the program
#decides which name to print before user's messages
self.chatPeople.remove(self.name)
self.chatPeople.append(self.name)
def chatDelay():
"""Function to create small time delays between 0.5 and 1.5 seconds before the chatbot outputs a response, to make it seem like there is a person on the other side that thinks beore they responsd"""
chatHighlight() #call this here because chatHighlight() is usually called at end of sendClick(event) function, so the user and chatbot's names would not be highlighted at the time chat is being delayed without this here.
chatWindow.yview_moveto(1.0) #causes scrolling whenever function is called, because the chatbox is not usually scrolled when the delay occurs, which makes the program look weird otherwise
if commandEnter.get() != "": #no point running code and wasting computation time if commandEnter widget is already empty
commandEnter.delete(0, "end") #it would look weird for there to still be a string in the commandEnter widget while things are being printed, so clear contents of widget here.
root.update() #forces the GUI to update its appearance to reflect the chatHighlight(), the commandEnter.delete and other appearences. This is because the GUI pauses before these changes are shown to the user when root.after is used.
randNum = randint(500, 1500) #creates a random number so user doesn't wait same amount of time before every response
root.after(randNum) #learnt about x.after(num) from https://stackoverflow.com/questions/19887729/time-delay-tkinter
def sendClick(event):
"""Gets the user's input from the entry widget, and then inserts the user's request into the chatWindow. After that, it interprets what the user is asking for and then provides an appropriate response."""
chatWindow.config(state="normal") #set state to normal so it is possible for the program to eddit the contents of chatWindow
request = commandEnter.get()
if request != "": #runs code only if the user entered something, so no code is run if nothing is entered and if no subprocess modules are running
chatWindow.insert(END, Users.chatPeople[-1] + request + "\n")
requestInterpreter(request)
chatWindow.yview_moveto(1.0) #brings scrollbar to bottom of chatWindow, so user doesn't need to manually scroll down if text inside chatWindow gets too big
#yview_moveto(1.0) learnt and adapted from https://stackoverflow.com/questions/34680138/how-to-track-the-bottom-of-a-frame-when-used-on-a-canvas-with-a-scrollbar
chatHighlight()
commandEnter.delete(0, "end") #clear contents of commandEnter entry widget so user can type new request
chatWindow.config(state="disabled") #set state to disabled so, once the program is finished with writing to the chatWindow widget, the user cannot edit the contents of the chat window themselves.
commandEnter.focus() #sets the focus to the commandEnter widget, to save user the trouble of having to click before typing the request
def requestInterpreter(request):
"""Gets the text the user entered, then processes the request by looking for keywords and finally produces the correct output depending on what the request is"""
chatWindow.config(state="normal") #set state to normal so it is possible for the program to eddit the contents of chatWindow
#note: All global ____ functions are used to tell Python not to create a local variable with this name, but to access the global variable of the same name.
#note: Most modules check for the presence of certain words by using ("string" in request) because this allows user to trigger modules with more natural language.
#note: For example, using ("joke" in request) lets the user type in a way natural to them (such as: "tell me a joke", "what's a good joke?", "do you have a favourite joke?") while all trigger joke module.
#note: unfortunately, some modules use dictionaries that require an exact string (or return a keyError otherwise), which is less versatile.
#note: I have used (request == "string") for these cases.
global loginSteps #initialise loginSteps here because it is used in if-statement at the start, instead of being initialised with other global login-related variables
if loginSteps != "verifyPassword" and loginSteps != "newPassword": #don't want request to become lowercase in this scenario because doing so would make security weaker, due to a lack of case sensitivity
request = request.lower() #convert user's input to lower case so checking for strings works regardless of capitalisatoin (as Python recognise lower and upper case characters as different)
recognised = False #variable to store whether a command was recognised, so if it isn't recognised, then the chatbot can ask for clarificatoin.
#all interpretation-based if-statements (deciding what to do on user's command) will have "and False:" at the end to ensure that this if-statement doesn't run if a previous if-statement was run
chatDelay() #introduces delay after user's input is shown, but before the chatbot outputs anything
#integrating Irtiza's feeling function here
global feelingSteps
if feelingSteps == 1:
recognised = True #so other interpretation-based if-statements after this one don't run
response = feeling(request)
chatWindow.insert(END, "Chatbot: " + str(response) + "\n")
feelingSteps = 0
chatDelay()
chatWindow.insert(END, 'Chatbot: If you want help on how to use this chatbot, type "help".\n') #tell user how to find out commands without reading the readme file in case they never used the chatbot before. Don't give command list at start because the list is big and it might look untidy if it was given every time the prgram starts.
#end of feeling integration
#integrating Khadija's blacklist code into GUI here
profanityCheck = blackList(request)
if profanityCheck != None and recognised == False:
recognised = True
chatWindow.insert(END, "Chatbot: " + str(profanityCheck) + "\n")
recognised = True #don't want any subsequent commands to be interpreted if there is any profanity found
#end of blacklist integration
#integrating Irtiza's other functions here
if request == "suggest some good places to eat at" and recognised == False:
recognised = True
response = food(request)
counter = 0
while counter != 5:
chatWindow.insert(END, "Chatbot: " + str(response[counter]) + "\n")
counter +=1
chatDelay()
if request == "i'm bored tell me a joke" or request == "Can you tell me a joke pls?" and recognised == False:
recognised = True
chatWindow.insert(END, "Chatbot: " + str(joke(request)) + "\n")
if request == "anything good in the news today?" or request == "what's the latest news?" or "news" in request and (("bbc" or "espn" or "times" or "india" or "york" or "bible" or "mtv") not in request) and recognised == False: #makes sure user didn't ask for a specific news source, and makes sure dictionary keys are sent through
recognised = True
if request == "anything good in the news today?" or request == "what's the latest news?":
requestInterpreter(news(request)) #recursive function that gets one of the news sources returned by the news() function and then gets news from that source by triggering the interpreter for Vinayak and Rahul's news APIs
elif "news" in request:
requestInterpreter(news("anything good in the news today?")) #same as above branch, but gives false dictionary key value (to satisfy if-statement in Irtiza's news() function). False dictinoary key value does not matter because both keys have same output regardless.
#end of integration of Irtiza's functions
#integrating Khadija's questions/answers here
if request == "how are you feeling" or request == "how old are you" or request == "what is your favourite colour" or request == "where do you live" or request == "who created you" or request == "what is your hobby" or request == "when were you born" or request == "who is your master" or request == "are you my friend" or request == "do you eat and drink" or request == "what features do you have" or request == "how can you help me today" or request == "whats your favourite country" or request == "are you my father" or request == "who are you" or request == "where's my address" or request == "i'm feeling bored" or request == "are you an expert at hacking" or request == "what languages do you speak" or request == "what is your religion" or request == "where were you created" or request == "how many people were involved in creating you" or request == "what gender are you" or request == "can you sing" or request == "what are your talents" and recognised == False:
recognised = True
answer = questionAnswer(request.capitalize()) #capitalise first latter because dictionary keys all have capital first letter, but the requestInterpreter function has request.lower() at the start
chatWindow.insert(END, "Chatbot: " + str(answer) + "\n")
#end of question/answer integration
#integrating Benjamin's FileSave code
global currentUser
global userTraits
global userAccount
global passAttempt
if "log" in request and "in" in request and loginSteps == "" and recognised == False:
recognised = True
chatWindow.insert(END, "Chatbot: What is your name?\n")
loginSteps = "checkExist"
elif loginSteps == "checkExist" and recognised == False:
recognised = True
currentUser = request
if readFile(currentUser) == "newUser":
chatWindow.insert(END, "Chatbot: How old are you?\n")
loginSteps = "userLocation"
else:
chatWindow.insert(END, "Chatbot: Please enter your password.\n")
loginSteps = "verifyPassword"
elif loginSteps == "userLocation" and recognised == False:
recognised = True
userTraits.append(request.capitalize()) #using .capitalize() because area names gematically need to start with a capital letter
chatWindow.insert(END, "Chatbot: Where are you from?\n")
loginSteps = "studyCourse"
elif loginSteps == "studyCourse" and recognised == False:
recognised = True
userTraits.append(request.title()) #using .title() because course names gematically usually have a capital letter at the start of each word
chatWindow.insert(END, "Chatbot: What course are you studying?\n")
loginSteps = "newPassword"
elif loginSteps == "newPassword" and recognised == False:
recognised = True
userTraits.append(request)
chatWindow.insert(END, "Chatbot: What do you want your password to be?\n")
loginSteps = "saveData"
elif loginSteps == "saveData" and recognised == False:
recognised = True
userTraits.append(request)
NewUser(currentUser, userTraits)
chatDelay()
chatWindow.insert(END, "Chatbot: Thank you. We have saved your information.\n")
chatDelay()
chatWindow.insert(END, "Chatbot: You have also been logged in.\n")
loginSteps = ""
userAccount = Users(currentUser)
elif loginSteps == "verifyPassword" and recognised == False:
recognised = True
passAttempt = request
actualPassword = read(currentUser+".txt", "password")
if passAttempt == actualPassword:
userAccount = Users(currentUser)
chatWindow.insert(END, "Chatbot: Welcome back, " + userAccount.name + ".\n")
chatDelay()
chatWindow.insert(END, "Chatbot: It's nice to see you again.\n")
loginSteps = ""
else:
chatWindow.insert(END, "Chatbot: Sorry, but your password is incorrect. We can't log you in.\n")
loginSteps = ""
#end of FileSave integration
#integrating Vinayak's joke function here
if "joke" in request and recognised == False:
recognised = True
chatWindow.insert(END, "Chatbot: " + str(Joke_return()) + "\n")
#end of joke integration
#integrating Rahul's IMDB API here
global movieSteps
if ("imdb" in request or "movie" in request) and movieSteps == 0 and recognised == False:
recognised = True
chatWindow.insert(END, "Chatbot: Which movie or TV show do you want to search for?\n")
movieSteps = 1
elif movieSteps == 1 and recognised == False:
recognised = True
title, years, actors, story, genre, ratings = movie_tvSE(request)
chatWindow.insert(END, "Chatbot: " + title + ".\n")
chatWindow.insert(END, "Chatbot: " + years + ".\n")
chatWindow.insert(END, "Chatbot: " + actors + ".\n")
chatWindow.insert(END, "Chatbot: " + story + "\n")
chatWindow.insert(END, "Chatbot: " + genre + ".\n")
chatWindow.insert(END, "Chatbot: " + ratings + ".\n")
movieSteps = 0
#end of IMDB integration
#integrating Vinayak's news APIs and Rahul's news APIs here
if ("bbc" in request) or ("times" in request and "india" in request) or ("new" in request and "york" in request and "times" in request) or ("mtv" in request) or ("lad" in request and "bible" in request) or ("buzz" in request and "feed" in request) or ("espn" in request) or ("sports" in request and "bible" in request) and recognised == False:
recognised = True
#first three parts of if-statement for Vinayak Saneer's news APIs and subsequent parts of if-statement for Rahul Verma's news APIs
descriptionList = [] #Rahul's APIs use a description, but Vinayak's don't, so initialise empty list to prevent exceptions in Vinayak's APIs
if "bbc" in request and "sports" not in request: #"sports" not in request so this branch doesn't run if the user types "bbc sports"
newsSource = "bbc"
articleList, urlList = newsFunc(newsSource)
elif "times" in request and "india" in request:
newsSource = "times of india"
articleList, urlList = newsFunc(newsSource)
elif "new" in request and "york" in request and "times" in request: #check for each word in string separately because user might make a mistake or hae a different spelling style (like "new york" or "newyork"
newsSource = "new york times"
articleList, urlList = newsFunc(newsSource)
elif "mtv" in request:
articleList, descriptionList, urlList = mtvAPI()
elif "lad" in request and "bible" in request:
articleList, descriptionList, urlList = lad_bibleAPI()
elif "buzz" in request and "feed" in request:
articleList, descriptionList, urlList = buzzfeedAPI()
elif "bbc" in request and "sports" in request: #runs only if both "bbc" and "sports" are in request, for same reason as first if-statement branch in this section
articleList, descriptionList, urlList = bbc_sportsAPI()
elif "espn" in request:
articleList, descriptionList, urlList = espnAPI()
elif "sports" in request and "bible" in request:
articleList, descriptionList, urlList = sports_BibleAPI()
for i in range(len(articleList)): #loop goes through every article in list, printing article name and asking user if they want to open article each time.
chatWindow.insert(END, "Chatbot: " + articleList[i]+ "\n")
if len(descriptionList) > 0: #checks if descriptionList is empty, because no point printing empty list
chatDelay()
chatWindow.insert(END, "Chatbot: " + descriptionList[i]+ "\n")
chatDelay() #chat is not initially highlighted when the linkAsk function is called because, without this being placed here, the code would be highlighted after the sendClick function finishes. Also, used chatDelay() instead of chatHighlight (former calls latter) so user has more time to read before message box appears.
openArticle = linkAsk(articleList[i], urlList[i])
if openArticle == None:
chatDelay()
break; #stops further news from appearing
if i == len(articleList) - 1:
chatDelay()
chatWindow.insert(END, "Chatbot: Finished showing news.\n") #tell user news is finished so they aren't confused about why no more news is appearing
chatDelay()
#end of Vinayak and Rahul's news integration
#integrating Vinayak's weather API
global weatherSteps
global weatherCity
global weatherCountry
#note: using if-elif, so weatherSteps = 1 doesn't trigger weatherSteps == 1 if-statement
if "weather" in request and weatherSteps == 0 and recognised == False:
recognised = True
weatherSteps = 1
chatWindow.insert(END, "Chatbot: Which city do you want to check?\n")
elif weatherSteps == 1 and recognised == False:
recognised = True
weatherCity = request
chatWindow.insert(END, "Chatbot: Which country do you want to check?\n")
weatherSteps = 2
elif weatherSteps == 2 and recognised == False:
recognised = True
try: #using try because the API might not find the area the user inputted; if found, then proceed as normal, otherwise, show user error message
weatherCountry = request
minTemp, maxTemp, description = Data_Sorting(weatherCity, weatherCountry)
minTemp = str(minTemp)
maxTemp = str(maxTemp)
chatWindow.insert(END, "Chatbot: The minimum temperature will be: " + str(minTemp) + ".\n")
chatDelay()
chatWindow.insert(END, "Chatbot: The maximum temperature will be: " + str(maxTemp) + ".\n")
chatDelay()
chatWindow.insert(END, "Chatbot: The average weather condition will have " + str(description) + ".\n")
except KeyError: #if API does not find a place with the specified city and country
chatWindow.insert(END, "Chatbot: We are sorry, but the specified location is not inside our databases.\n")
finally:
#resetting global variables to prevent them from interfering with future runs of weather function
weatherSteps = 0
weatherCountry = ""
weatherCity = ""
#end of weather input integration
#help message made by Humza in case user doesn't know what to do and hasn't read readme file
if request == "help" and recognised == False:
recognised = True
chatWindow.insert(END, "Chatbot: Hi there. I'm a personal assistant.\n")
chatDelay()
chatWindow.insert(END, "Chatbot: Some of the things I can help you with are:\n")
chatDelay()
chatWindow.insert(END, "Chatbot: Finding latest news about current affairs, sports and entertainment.\n")
chatWindow.insert(END, "Chatbot: To do this, type the name of your news source.\n")
chatWindow.insert(END, "Chatbot: Supported news sources are:\nChatbot: -BBC\nChatbot: -Times of India\nChatbot: -New York Times\nChatbot: -BBC Sports\nChatbot: -ESPN\nChatbot: -Sports Bible\nChatbot: -MTV\nChatbot: -Lad Bible\nChatbot: -Buzz Feed.\n")
chatDelay()
chatWindow.insert(END, "Chatbot: Telling funny jokes.\n")
chatWindow.insert(END, 'Chatbot: To do this, type "joke" or "Tell me a joke".\n')
chatDelay()
chatWindow.insert(END, "Chatbot: Giving the weather for any city.\n")
chatWindow.insert(END, 'Chatbot: To do this, type "weather".\n')
chatDelay()
chatWindow.insert(END, "Chatbot: Finding local stores.\n")
chatWindow.insert(END, 'Chatbot: To do this, type "yelp" or "where is".\n')
chatDelay()
chatWindow.insert(END, "Chatbot: Finding information about movies.\n")
chatWindow.insert(END, 'Chatbot: To do this, type "IMDB" or "movie".\n')
chatDelay()
chatWindow.insert(END, "Chatbot: Logging in or making an account to personalist this chatbot.\n")
chatWindow.insert(END, 'Chatbot: To do this, type "login" or "log in".\n')
chatDelay()
chatWindow.insert(END, "Chatbot: For more information, read our readme.md file.\n")
chatWindow.insert(END, "Chatbot: We have fun Q&A commands that are too long to list here.\n")
chatDelay()
chatWindow.insert(END, 'Chatbot: To disconnect from the chatbot, you may type "end".\n')
#end of Humza's help message
#integrating Vinayak's Yelp API
global yelpSteps
global yelpLocation
global yelpIndex
if ("yelp" in request or "find" in request or "location" in request or "locate" in request or "where is" in request) and yelpSteps == 0 and recognised == False:
recognised = True
chatDelay()
chatWindow.insert(END, "Chatbot: What would you like to find?\n")
yelpSteps = 1
elif yelpSteps == 1 and recognised == False:
recognised = True
if request != "": #checks if function is called recusively; if it isn't, then the area the user typed is set to yelpLocation
yelpLocation = request
store, rating = yelpSearch(yelpLocation, yelpIndex)
if rating != "": #checks if the yelpSearch() function gave an index error
chatWindow.insert(END, "Chatbot: The store we found is " + str(store) + ", which has a rating of " + str(rating) + ".\n")
chatDelay()
chatWindow.insert(END, "Chatbot: Would you like to find another store?\n")
yelpSteps = 2
else:
chatWindow.insert(END, store) #store is set to a message telling user a place could not be found, so printing that if index is out of range.
elif yelpSteps == 2 and recognised == False:
recognised = True
if "yeah" in request or "yes" in request:
yelpIndex += 1
yelpSteps = 1 #go back to previous if-statement, which prints the store name and rating, and then asks user if they want to search for another store again.
requestInterpreter("") #calls current function recursively, so user doesn't need to press enter to go through the request interpreter again.
elif "no" in request:
chatWindow.insert(END, "Chatbot: Stopped searching for areas.\n")
#reset global variables so they don't interfere with future yelp searches. In else statement below, variables reset for same reason.
yelpSteps = 0
yelpLocation = ""
yelpIndex = 0
else:
chatWindow.insert(END, "Chatbot: Sorry, but we didn't understand that. Yelp search cancelled.\n")
yelpSteps = 0
yelpLocation = ""
yelpIndex = 0
#end of Yelpintegration
#code by Humza to close the chatbot if user wants to stop using it
#using (request == "end") because this removes all doubt that the user wants to end the program.
#for example, if I used ("end" in request), then the user would trigger the program's disconnection inadvertently
#if the user was to type "friend", which is dangerous when there is a strong impact like the program closing.
if request == "end" and recognised == False:
recognised = True
chatWindow.insert(END, "Chatbot: Disconnecting now... goodbye.")
#calling chatDelay() to highlight speaker names, to cause a delay before the program closes so the user can read that the program is closing
chatDelay()
root.after(2500) #extra delay because chatDelay() might not wait long enough for reader to see message.
root.destroy()
#end of code to close chatbot
if recognised == False: #runs if the command wasn't recognised.
chatWindow.insert(END, "Chatbot: Sorry, but I didn't understand your request. There might be a typo.\n")
chatDelay()
chatWindow.insert(END, "Chatbot: Can you try rephrasing it another way please?\n")
if Users.chatPeople[-1] != "User: " and weatherSteps == 0 and loginSteps == "" and yelpSteps == 0 and movieSteps == 0:
#checks if user has logged in
#also checks if any multi-step APIs are being used, so they are not interrupted.
randNum = randint(1, 10)
if randNum >= 9: #has 20% of producing a comment, because if a comment was produced every time, the user might get annoyed with spam. 20% chance because 2/10 values trigger if-statement (9 and 10).
chatDelay()
chatComments()
def chatComments():
"""Function to comment on userAccount's attributes if user is logged in. No input and no output returned."""
attributeChoose = randint(1, 4) #attribute chosen to comment on is made randomly.
attributeList = ["name", "age", "location", "course"] #intentionally omit password because do not want other people to see it.
#list above is actually useless because it's not in the code, but it reminds of the category of comment to write
commentNum = randint(1, 3) #some comments also chosen randomly (3 comments per attribute)
chatDelay()
if attributeChoose == 1:
if commentNum == 1:
chatWindow.insert(END, "Chatbot: " + userAccount.name + " is a nice name.\n")
elif commentNum == 2:
chatWindow.insert(END, "Chatbot: " + userAccount.name + " isn't a common name here.\n")
chatWindow.insert(END, "Chatbot: Did your family originate from another country?\n")
elif commentNum == 3:
chatWindow.insert(END, "Chatbot: " + userAccount.name + " isn't really a nice name, in my opinion...\n")
if attributeChoose == 2:
try:
age = int(userAccount.age) #when read from file, age is interpreted as string, so need to convert to int
if commentNum == 1:
chatWindow.insert(END, "Chatbot: You'll be " + str(age + 1) + "on your next birthday!.\n")
chatWindow.insert(END, "Chatbot: Maybe you should stop keeping track of your age so you don't feel like you'getting old.\n")
if commentNum == 2:
if age < 20:
chatWindow.insert(END, "Chatbot: You're young.\n")
chatWindow.insert(END, "Chatbot: Don't lose motivation if you find work hard!.\n")
elif age > 40:
chatWindow.insert(END, "Chatbot: You're kind of old\n")
chatWindow.insert(END, "Chatbot: You probably have a lot of experience in your chosen field.\n")
elif age > 20:
chatWindow.insert(END, "Chatbot: You're " + str(userAccount.age) + " years old, so you probably have a job, right?\n")
chatWindow.insert(END, "Chatbot: Don't forget to donate to charity once in a while.\n")
if commentNum == 3:
tenYearsAgo = age - 10
if tenYearsAgo > 0:
chatWindow.insert(END, "Chatbot: You were " + str(tenYearsAgo) + " years old ten years ago.\n")
chatWindow.insert(END, "Chatbot: Do you feel old now?\n")
else:
chatWindow.insert(END, "Chatbot: You weren't even born ten years ago.\n")
chatWindow.insert(END, "Chatbot: Aren't you too young to use this chatbot?\n")
chatWindow.insert(END, "Chatbot: Or maybe you lied about your age?\n")
except ValueError: #occurs if user didn't enter an actual integer (like having a decimal place or a letter) when registering.
if commentNum == 1:
chatWindow.insert(END, "Chatbot: Hey, I know you didn't put in a valid age.\n")
chatWindow.insert(END, "Chatbot: Did you think I wouldn't notice?\n")
elif commentNum == 2:
chatWindow.insert(END, "Chatbot: Why did you bother putting in an invalid age?\n")
chatWindow.insert(END, "Chatbot: Don't you have anything better to do than lie?\n")
elif commentNum == 3:
chatWindow.insert(END, "Chatbot: I bet you think you're smart for putting in an invalid age.\n")
elif attributeChoose == 3:
if commentNum == 1:
chatWindow.insert(END, "Chatbot: I've never been to " + userAccount.location + " before.\n")
chatWindow.insert(END, "Chatbot: Is it nice?\n")
elif commentNum == 2:
chatWindow.insert(END, "Chatbot: Chatbots like me can't travel to real places like " + userAccount.location + ".\n")
chatWindow.insert(END, "Chatbot: I don't know what it's like.\n")
elif commentNum == 3:
chatWindow.insert(END, "Chatbot: You're probably sick of " + userAccount.location + " by now.\n")
chatWindow.insert(END, "Chatbot: Where would you like to travel to?\n")
elif attributeChoose == 4:
if commentNum == 1:
chatWindow.insert(END, "Chatbot: I wonder what kind of job you can get with a " + userAccount.course + " degree.\n")
elif commentNum == 2:
chatWindow.insert(END, "Chatbot: Did you want to study " + userAccount.course + " when you were a kid?\n")
elif commentNum == 3:
chatWindow.insert(END, "Chatbot: I hope you're not studying for a " + userAccount.course + " exam past midnight.\n")
def linkAsk(article, url):
"""Interrupts news output with a message box asking if the user wants to open the link and gives the option to cancel the news output"""
userClicked = messagebox.askyesnocancel("Open article", "Do you want to open " + '"' + article + '"?' + "\nWarning: clicking cancel will stop further news from appearing.")
if userClicked == True:
webbrowser.open_new_tab(url)
elif userClicked == None:
chatWindow.insert(END, "Chatbot: Request to see news has been cancelled.\n")
return None
return True #stops loop from breaking if user clicks yes or no by giving value for if-statement to test (True or None).
def chatHighlight():
"""Changes colour of words in chatWindow at the start of each line indicating who is talking."""
#Code below adapted from Stack Overflow via: https://stackoverflow.com/questions/29315898/searching-for-a-list-of-words-within-a-tkinter-text-widgit-in-python-2-7
#Code changed by Humza slightly to fit chatbot situation batter
#remove tag at start because two tags with same name cannot exist.
chatWindow.tag_remove("user", "1.0", END)
for word in Users.chatPeople: #for loop that runs for each entry in the list so every applicable user/chat-person can have their name highlighted
idx = '1.0'
while idx: #while loop that runs while the idx variable is not equal to the last indext
idx = chatWindow.search(word, idx, nocase=1, stopindex=END) #increments idx variable so the loop searches for the next occurrence of User: or Chatbot:
if idx:
lastidx = '%s+%dc' % (idx, len(word))
chatWindow.tag_add('user', idx, lastidx)
idx = lastidx
#removed list because only one string is being searched for this time
idx = '1.0' #reset idx to 1.0 because it searches from the beginning of the chatWindow for another word this time
while idx: #while loop that runs while the idx variable is not equal to the last indext
idx = chatWindow.search("Chatbot:", idx, nocase=1, stopindex=END) #increments idx variable so the loop searches for the next occurrence of User: or Chatbot:
if idx:
lastidx = '%s+%dc' % (idx, len("Chatbot:"))
chatWindow.tag_add('bot', idx, lastidx)
idx = lastidx
chatWindow.tag_config("user", foreground="blue")
chatWindow.tag_config("bot", foreground="red")
#end of code adapted from aforementioned Stack Overflow link
chatView = Frame(pady = 10) #frame to group top part of GUI (chat window and scroll bar) together.
chatView.pack()
chatWindow = Text(chatView)
chatWindow.insert(END, "Chatbot: Hi there! How are you feeling today?\n") #There's a function by a group member asking the user how they feel, but the user is meant to ask the chatbot questions (not other way around). Asked user at start so the function isn't wasted and to make chatbot seem more conversational.
chatWindow.config(state="disabled") #explained why this is disabled in sendClick() functoin. Look there if confused.
chatWindow.pack(side=LEFT, fill=Y)
chatHighlight() #called chatHighlight() here to highlight question about feeling
chatScroll = ttk.Scrollbar(chatView, command = chatWindow.yview)
chatScroll.pack(side=RIGHT, fill=Y)
chatWindow['yscrollcommand'] = chatScroll.set #links the scrollbar to the chat window so moving the scrollbar up/down causes the text on the chat window to move up/down as well
chatTalk = Frame(pady = 10, padx = 10) #frame to group bottom part of GUI (entry box and send button) together.
chatTalk.pack()
commandEnter = ttk.Entry(chatTalk, width=100)
commandEnter.pack(side=LEFT, padx = 10)
sendButton = ttk.Button(chatTalk, text = "Send")
sendButton.pack(side=RIGHT)
root.bind('<Return>', sendClick)
sendButton.bind("<Button-1>", sendClick)
commandEnter.focus() #sets the focus to the commandEnter widget when user starts program, to save user the trouble of having to click before typing the request
root.mainloop()