Permalink
Cannot retrieve contributors at this time
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?
6A-Chatbot/reminderTextProcessing.py
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
458 lines (407 sloc)
22.2 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import reminderStorage | |
import datetime | |
import calendar | |
import time | |
def isInt(variable): #determines if an inputted variable can be a string | |
try: | |
variable = int(variable) | |
return True | |
except ValueError: | |
return False | |
def monthsToYears(monthsAdd): | |
months = monthsAdd % 13 | |
years = int(monthsAdd / 13) | |
return months, years | |
def daysToMonth(daysAdd, time, nowTime): #this is if the number of days exceed the amount of days in the month | |
currentDaysInMonth = calendar.monthrange(time.year, time.month)[1] #https://stackoverflow.com/questions/9481136/how-to-find-number-of-days-in-the-current-month | |
months = time.month | |
days = daysAdd | |
years = 0 | |
while True: | |
if days > currentDaysInMonth: | |
months = months + 1 | |
difference = days - currentDaysInMonth | |
days = difference | |
else: | |
days = days % (currentDaysInMonth + 1) | |
tempMonth = months | |
months = monthsToYears(months)[0] | |
years = years + monthsToYears(tempMonth)[1] | |
if months == 0: | |
months = 1 | |
currentDaysInMonth = calendar.monthrange(time.year + years, months)[1] | |
if days <= currentDaysInMonth: | |
break | |
return days, months, years | |
def hoursToDays(hoursAdd): | |
hours = hoursAdd % 24 | |
days = int(hoursAdd / 24) | |
return hours, days | |
def minutesToHours(minutesAdd): | |
minutes = minutesAdd % 60 | |
hours = int(minutesAdd / 60) | |
return minutes, hours | |
def dictToDateTime(dict): | |
return datetime.datetime(dict["year"], dict["month"], dict["day"], dict["hour"], dict["minute"], 0) | |
def timeAddition(timeChange, now = datetime.datetime.now(), nowTime = True): | |
minutes, hours = minutesToHours(timeChange["minute"] + now.minute) #this section just makes the time more convienient to work with (example is 69 minutes will turn into 1 hour and 9 minutes) | |
timeChange["minute"] = minutes | |
timeChange["hour"] = timeChange["hour"] + hours | |
hours, days = hoursToDays(timeChange["hour"] + now.hour) | |
timeChange["hour"] = hours | |
timeChange["day"] = timeChange["day"] + days | |
days, months, years = daysToMonth(timeChange["day"] + now.day, now, nowTime) | |
timeChange["day"] = days | |
timeChange["month"] = timeChange["month"] + months | |
timeChange["year"] = timeChange["year"] + years + now.year | |
months, years = monthsToYears(timeChange["month"]) | |
timeChange["month"] = months | |
timeChange["year"] - timeChange["year"] + years | |
if timeChange["month"] == 0: | |
timeChange["month"] = 12 | |
if timeChange["day"] == 0: | |
timeChange["day"] = calendar.monthrange(timeChange["year"], timeChange["month"])[1] | |
return timeChange | |
def puncRemove(string): | |
string = string.replace(".","") | |
string = string.replace(",","") | |
string = string.replace("?","") | |
#string = string.replace(":","") | |
string = string.replace("/","") | |
return string | |
def addTimeDecipher(numberLoc, words, addTimeLoc): #this will try to get the datetime from the statement if it can from the view that it is saying something like in 3 hours | |
addTime = {"minute" : 0, "hour" : 0, "day" : 0, "month" : 0, "year" : 0} #these variables are there in case the user wants a reminder later in a set period of time (example is set reminder in 2 days) | |
noPunc = puncRemove(arrayToString(words)).lower() | |
if "tommorow" in noPunc or "tomorrow" in noPunc: #finding common ways of saying a period of time in the future without writing a number | |
addTime["day"] = addTime["day"] + 1 | |
if "in a day" in noPunc: | |
addTime["day"] = addTime["day"] + 1 | |
if "in an hour" in noPunc: | |
addTime["hour"] = addTime["hour"] + 1 | |
if "in a minute" in noPunc: | |
addTime["minute"] = addTime["minute"] + 1 | |
if "in a month" in noPunc: | |
addTime["month"] = addTime["month"] + 1 | |
if "in a year" in noPunc: | |
addTime["year"] = addTime["year"] + 1 | |
if "next year" in noPunc: | |
addTime["year"] = addTime["year"] + 1 | |
if addTimeLoc != None: | |
for i in range(0, len(numberLoc)): | |
numberInSentence = int(removeLetters(words[numberLoc[i]])) | |
if numberLoc[i] + 1 < len(words): | |
if ("minute" in words[numberLoc[i] + 1].lower()): #this determines if there needs to be an addition of times (example could be the number means 3 hours later) | |
addTime["minute"] = numberInSentence + addTime["minute"] | |
elif ("hour" in words[numberLoc[i] + 1].lower()): | |
addTime["hour"] = numberInSentence + addTime["hour"] | |
elif ("day" in words[numberLoc[i] + 1].lower()): | |
addTime["day"] = numberInSentence + addTime["day"] | |
elif ("month" in words[numberLoc[i] + 1].lower()): | |
addTime["month"] = numberInSentence + addTime["month"] | |
elif ("year" in words[numberLoc[i] + 1].lower()): | |
addTime["year"] = numberInSentence + addTime["year"] | |
return addTime | |
def isNearMonth(words, numberLoc, months, monthAsNumber): #will try to see if a month is nearby | |
if numberLoc + 2 < len(words): | |
twoBackAndFoward = words[numberLoc - 2] + words[numberLoc - 1] + words[numberLoc] + words[numberLoc + 1] + words[numberLoc + 2] | |
if inArray(months, twoBackAndFoward.lower()): #I know this is a bit inefficient but its a bit easier and faster to program and has insignificant performance impact | |
for i in range(0,len(months)): | |
if months[i].lower() in twoBackAndFoward.lower(): | |
return monthAsNumber[i] #returns the month as a number | |
else: | |
return None | |
else: | |
return None | |
def inArray(array, string): #will determine if a character in a string is the same as an element of an array | |
for i in range(0,len(array)): | |
if array[i].lower() in string.lower(): | |
return True | |
return False | |
def timeDetermineFromString(time, timeDetermine, next = None): #will try and determine the time if the input is the time (written as hour:minute maybe am or pm which will be shown as next for next sentence) | |
wordSplit = list(time) | |
for i in range(0,len(wordSplit)): | |
for j in range(0,len(timeDetermine)): | |
if timeDetermine[j] == wordSplit[i]: | |
if isInt(wordSplit[i - 1]): #determines the hours of the time | |
hour = wordSplit[i - 1] | |
if isInt(wordSplit[i - 2]) and i - 2 >= 0: #i - 2 >= 0 is there since if i - 2 is negative it would go to the end of an array which if its a number could get an additional 10 to 90 hours | |
hour = int(wordSplit[i - 2] + hour) | |
if not(int(hour) > 12): | |
if (next != None and next.lower() == "pm") or "pm" in time: | |
if int(hour) == 12: | |
hour = 12 | |
else: | |
hour = int(hour) + 12 | |
if hour > 23: | |
hour = 0 | |
elif (next != None and next.lower() == "am") or "am" in time: | |
if int(hour) == 12: | |
hour = 0 | |
if isInt(wordSplit[i + 1]) and isInt(wordSplit[i + 2]): #determines the minutes of the time | |
minute = int(wordSplit[i + 1] + wordSplit[i + 2]) | |
return minute, hour | |
return None, None | |
def dateDetermineFromString(date, dateDetermine): #will try and determine the date if the input is the date (will be written as days/month/year) | |
wordSplit = list(date) | |
day = None | |
month = None | |
year = None | |
for i in range(0,len(wordSplit)): | |
for j in range(0,len(dateDetermine)): | |
if dateDetermine[j] == wordSplit[i]: | |
if isInt(wordSplit[i - 1]): #determines the day of date | |
day = wordSplit[i - 1] | |
if isInt(wordSplit[i - 2]): | |
day = int(wordSplit[i - 2] + day) | |
if len(wordSplit) > i + 1: | |
if isInt(wordSplit[i + 1]) and isInt(wordSplit[i + 2]): #determines the minutes of the time | |
month = int(wordSplit[i + 1] + wordSplit[i + 2]) | |
if inArray(dateDetermine, wordSplit[i + 3]): | |
if isInt(wordSplit[i + 4]) and isInt(wordSplit[i + 5]): | |
year = wordSplit[i + 4] + wordSplit[i + 5] | |
if len(wordSplit) > i + 6: | |
if isInt(wordSplit[i + 6]) and isInt(wordSplit[i + 7]): | |
year = int(year + wordSplit[i + 6] + wordSplit[i + 7]) | |
else: | |
year = int(year) + 2000 | |
if day != None and month != None and year != None: | |
return day, month, year | |
return None, None, None | |
def puncYear(word): #this is to determine if there is punctuation in the middle of the number (2020. is very different to 20.20) | |
split = word.split() | |
punc = [".", ",","/","\\",":"] | |
for i in range(1,len(split) - 1): | |
if inArray(punc, split[i]): | |
return False | |
return True | |
def removeLetters(string): #removes letters from a string | |
string = puncRemove(string) | |
letters = "abcdefghijklomnpqrstuvwxyz" | |
for i in range(0,len(letters)): | |
if letters[i] in string.lower(): | |
string = string.replace(letters[i],"") | |
return string | |
def makeTimeInt(timeDict): #this is to make all the variables in the time dictionaries an integer since they occasiaonaly don't come out as such | |
try: | |
timeDict["minute"] = int(timeDict["minute"]) | |
except: | |
pass | |
try: | |
timeDict["hour"] = int(timeDict["hour"]) | |
except: | |
pass | |
timeDict["day"] = int(timeDict["day"]) | |
timeDict["month"] = int(timeDict["month"]) | |
timeDict["year"] = int(timeDict["year"]) | |
return timeDict | |
def specificTimeDecipher(numberLoc, words, specificTimeLoc, timeSection): #will try to determine a specific time that was inputted (example is 1st of jan 2021 will be determined as year = 2021, month = 1, day = 1) | |
time = {"minute" : None, "hour" : None, "day" : 0, "month" : 0, "year" : 0} | |
months = ["jan", "feb", "march", "april", "may", "june", "july", "aug", "sep", "oct", "nov", "dec"] | |
monthAsNumber = [] | |
timeDetermine = [":"] #this is the punctuation that will determine if the time was said (example is 3:30 meaning hour = 3, minute = 30) | |
dateAsNumDetermine = ["/", "\\", "."] #punctuation that will determine the date (example would be 3/11/2020 would mean day = 3, month = 1, year = 2020) note it will not be the american format | |
for i in range(0,len(months)): #this will act as a way to convert a month into a number (example jan = 1, feb = 2) | |
monthAsNumber.append(i + 1) | |
for i in range(timeSection["start"],timeSection["end"]): #sometimes a month isn't near a number so you have to look through every word in the section | |
if inArray(months, words[i].lower()): | |
for j in range(0,len(months)): | |
if months[j] in words[i].lower(): | |
time["month"] = monthAsNumber[j] | |
if specificTimeLoc != None: | |
month = None | |
for i in range(0, len(numberLoc)): | |
month = isNearMonth(words, numberLoc[i], months, monthAsNumber) #this will determine if the month was mentioned | |
if month != None: | |
time["month"] = month | |
if len(removeLetters(words[numberLoc[i]])) == 4: | |
time["year"] = int(removeLetters(words[numberLoc[i]])) | |
elif len(removeLetters(words[numberLoc[i]])) == 2 or len(removeLetters(words[numberLoc[i]])) == 1: | |
time["day"] = int(removeLetters(words[numberLoc[i]])) | |
break | |
dateLoc = [] | |
timeLoc = [] | |
for i in range(timeSection["start"],timeSection["end"]): #will determine if time is specified and date is specified in number form | |
if time["year"] == 0 and len(puncRemove(words[i])) == 4 and puncYear(words[i]) and isInt(puncRemove(words[i])): | |
time["year"] = int(puncRemove(words[i])) | |
if inArray(timeDetermine, words[i]): | |
timeLoc.append(i) | |
if inArray(dateAsNumDetermine, words[i]): | |
dateLoc.append(i) | |
if isInt(removeLetters(words[i])): #this checks to see if a specific hour has been inputted | |
if int(removeLetters(words[i])) <= 12: | |
if "am" in words[i].lower(): | |
if int(removeLetters(words[i])) == 12: | |
time["hour"] = 0 | |
else: | |
time["hour"] = int(removeLetters(words[i])) | |
elif "pm" in words[i].lower(): | |
if int(removeLetters(words[i])) == 12: | |
time["hour"] = 12 | |
else: | |
time["hour"] = int(removeLetters(words[i])) + 12 | |
if i + 1 < len(words): | |
if words[i + 1].lower() == "am": | |
if int(removeLetters(words[i]) == 12): | |
time["hour"] = 0 | |
else: | |
time["hour"] = int(removeLetters(words[i])) | |
elif words[i + 1].lower() == "pm": | |
if int(removeLetters(words[i]) == 12): | |
time["hour"] = 12 | |
else: | |
time["hour"] = int(removeLetters(words[i])) + 12 | |
if inArray(months, words[i]): | |
for j in range(0,len(months)): | |
if months[j] in words[i]: | |
time["month"] = monthAsNumber[j] | |
for i in range(0,len(timeLoc)): | |
if timeLoc[i] + 1 < len(words): | |
minute, hour = timeDetermineFromString(words[timeLoc[i]], timeDetermine, words[timeLoc[i] + 1]) | |
else: | |
minute, hour = timeDetermineFromString(words[timeLoc[i]], timeDetermine) | |
if minute != None and hour != None: | |
time["minute"] = minute | |
time["hour"] = hour | |
break | |
for i in range(0,len(dateLoc)): | |
day, month, year = dateDetermineFromString(words[dateLoc[i]], dateAsNumDetermine) | |
if day != None and month != None and year != None: | |
time["day"] = day | |
time["month"] = month | |
time["year"] = year | |
break | |
return makeTimeInt(time) #ensures all values in time is an integer | |
return makeTimeInt(time) | |
def arrayToString(array): #makes an array of characters into a string of characters | |
string = str(array[0]) | |
for i in range(1,len(array)): | |
string = string + " " + str(array[i]) | |
return string | |
def reminderStatement(words, reminderSection): #this will put the reminder together as a string | |
if reminderSection["start"] != None: | |
string = str(words[reminderSection["start"]]) | |
for i in range(reminderSection["start"] + 1, reminderSection["end"]): | |
string = string + " " + words[i] | |
return string | |
else: | |
return "" | |
def specificTimeClean(specTime, addTime): #this is to make the specific time make sense, for example if you want a reminder at 3 am and its currently at 5pm you want 3 am the next day not the same day | |
now = datetime.datetime.now() | |
if addTime["day"] == 0 and specTime["day"] == 0 and None != specTime["hour"]: | |
if specTime["minute"] != None: | |
if now.hour > specTime["hour"] or (now.hour == specTime["hour"] and now.minute > specTime["minute"]): | |
addTime["day"] = addTime["day"] + 1 | |
elif now.hour >= specTime["hour"]: | |
addTime["day"] = addTime["day"] + 1 | |
if specTime["month"] != 0 and addTime["year"] == 0 and specTime["year"] == 0 and now.month > specTime["month"]: | |
addTime["year"] = addTime["year"] + 1 | |
return addTime | |
def CheckUnspoken(time, startPos): #this is one of the checks for if parts of the date or time should be its minimum (example if someone only specifies only the month of febuary then you don't want to get 15:30 3rd of Febuary you want 00:00 1 Febuary) | |
timeMeasurements = ["minute", "hour", "day", "month", "year"] | |
startPosNum = 0 | |
for i in range(0,len(timeMeasurements)): | |
if timeMeasurements[i] == startPos: | |
startPosNum = i | |
for i in range(startPosNum + 1, len(timeMeasurements)): | |
if time[timeMeasurements[i]] != 0: | |
return True | |
return False | |
def setReminder(command, user, write = True): | |
words = command.split() | |
numberLoc = [] | |
time = {"minute" : 0, "hour" : 0, "day" : 0, "month" : 0, "year" : 0} | |
reminderStatementIndicator = ["that", "to"] #specific words that will indicate that the user will actually say their reminder (example: user may say remind me at ... to <insert reminder>) | |
TimeIndicator = ["at","in","for","on"] | |
startStateLoc = None #this is where the first word of the actual reminder starts | |
TimeLoc = None | |
for i in range(0,len(words)): | |
if words[i] in TimeIndicator and TimeLoc == None: #this will try to find where the time will be said | |
TimeLoc = i | |
elif words[i] in reminderStatementIndicator and startStateLoc == None: #this will try to find where the actual reminder starts | |
startStateLoc = i | |
timeSection = {"start" : 0, "end" : 0} #tjis will be the beggining and the end section of the time section of the sentence | |
reminderSection = {"start" : 0, "end" : 0} #this will be the beggining and the end of the reminder section of the sentence | |
if TimeLoc != None: | |
if startStateLoc > TimeLoc: | |
timeSection["start"] = 0 | |
timeSection["end"] = startStateLoc + 1 | |
reminderSection["start"] = startStateLoc | |
reminderSection["end"] = len(words) | |
else: | |
timeSection["start"] = TimeLoc | |
timeSection["end"] = len(words) | |
reminderSection["start"] = startStateLoc | |
reminderSection["end"] = TimeLoc + 1 | |
for i in range(timeSection["start"],timeSection["end"]): #this determines where the numbers are located in the sentence the user has inputted | |
if isInt(removeLetters(words[i])): | |
numberLoc.append(i) | |
else: | |
reminderSection["start"] = startStateLoc | |
reminderSection["end"] = len(words) | |
addTimeAddition = addTimeDecipher(numberLoc, words, TimeLoc) #this is if time addition is needed | |
futureTime = specificTimeDecipher(numberLoc, words, TimeLoc, timeSection) #this is if a specific time is specified | |
year = True | |
if futureTime["year"] == 0: | |
year = False | |
addTimeAddition = specificTimeClean(futureTime, addTimeAddition) | |
now = datetime.datetime.now() #need to do this since you can't have 0 year and 0 month | |
futurePlusCurrent = futureTime | |
if futurePlusCurrent["minute"] == None: #this will construct a specific time that makes sense (saying febuary will bring 00:00 1 feb) and also won't have something such as month 0 occuring | |
if CheckUnspoken(futurePlusCurrent, "minute") and addTimeAddition["minute"] == 0: | |
futurePlusCurrent["minute"] = 0 | |
else: | |
futurePlusCurrent["minute"] = now.minute | |
if futurePlusCurrent["hour"] == None: | |
if CheckUnspoken(futurePlusCurrent, "hour"): | |
futurePlusCurrent["hour"] = 0 | |
else: | |
futurePlusCurrent["hour"] = now.hour | |
if futurePlusCurrent["day"] == 0: | |
if CheckUnspoken(futurePlusCurrent, "day"): | |
futurePlusCurrent["day"] = 1 | |
else: | |
futurePlusCurrent["day"] = now.day | |
if futurePlusCurrent["month"] == 0: | |
if CheckUnspoken(futurePlusCurrent, "month"): | |
futurePlusCurrent["month"] = 1 | |
else: | |
futurePlusCurrent["month"] = now.month | |
if futurePlusCurrent["year"] == 0: | |
futurePlusCurrent["year"] = now.year | |
time = timeAddition(addTimeAddition, dictToDateTime(futurePlusCurrent), False) #adding them since people may have specified some parts of the desired time and not specified the other parts | |
#if False == year: #a little fix from a slight error timeAddition makes | |
#time["year"] = futureTime["year"] | |
reminder = reminderStatement(words, reminderSection) | |
timeSentence = reminderStatement(words, timeSection) #just to check where the program thinks the time is | |
dateTime = dictToDateTime(time) #converting the dictionary to a datetime struct because it would automatically send out an error if there is an illegal date or time (example month 0 cannot exist and minute 67 can't exits) | |
reminderSplit = reminder.split() #just to get rid of an unneccsary word that sometime comes up at the end | |
if len(reminderSplit) != 0: | |
if inArray(TimeIndicator, reminderSplit[len(reminderSplit) - 1]): | |
reminderSection["end"] = reminderSection["end"] - 1 | |
reminder = reminderStatement(words, reminderSection) | |
obj = reminderStorage.reminder(user, str(dateTime), reminder) | |
if write == True: | |
reminderStorage.appendReminder(obj) | |
return "reminder " + str(obj.reminder) + " for " + str(obj.dateTime) | |
# | |
def sayReminders(user): #will list all the reminders that the user has if the user asks for it | |
reminderObjList = reminderStorage.userReminderList(user) | |
if len(reminderObjList) > 0: | |
string = str(reminderObjList[0].dateTime) + " " + reminderObjList[0].reminder | |
for i in range(0,len(reminderObjList)): | |
string = "\n" + str(reminderObjList[i].dateTime) + " " + reminderObjList[i].reminder | |
return string | |
else: | |
return "you haven't got any reminders" | |
if __name__ == "__main__": #this is just the test of the code, won't be main running file | |
response = setReminder(input("Type in you reminder"), "Ben", False) | |
print(response) | |
#testing() | |
#print(demandReminders("Ben13")) | |
#timeChange = {"minute" : 61, "hour" : 0, "day" : 0, "month" : 13, "year" : 0} | |
#print(timeAddition(timeChange)) | |
#day, month, year = dateDetermineFromString("5/12/23", ["/", "\\", "."]) | |
#print(day) | |
#print(month) | |
#print(year) | |
#print(setReminder("remind me to create a reminder at 9:08 pm", "Ben", False)) |