Skip to content

Commit 97e2ff5

Browse files
committed
First commit
0 parents  commit 97e2ff5

38 files changed

+1342
-0
lines changed

Diff for: bot_8.py

+306
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
#!/usr/bin/
2+
3+
#imports
4+
import sys
5+
import os
6+
import subprocess
7+
import time
8+
import random
9+
import pymongo
10+
import datetime
11+
import time
12+
import numpy
13+
from colors import *
14+
from pymongo import MongoClient
15+
from pprint import pprint
16+
from difflib import SequenceMatcher
17+
from fuzzywuzzy import fuzz
18+
19+
#main class where all the workings happen
20+
class talkLoop(object):
21+
22+
#initialise the class with all variables required
23+
def __init__(self, name, client, db, responses, allwords, inputWords, globalReply, botAccuracy, debugMode):
24+
self.name = name
25+
self.client = client
26+
self.db = db
27+
self.responses = responses
28+
self.allwords = allwords
29+
self.wordsIn = inputWords
30+
self.globalReply = globalReply
31+
self.botAccuracy = botAccuracy
32+
self.bResponse = globalReply
33+
self.debugMode = debugMode
34+
self.updateDB(inputWords)
35+
36+
#function for comparing string similarity
37+
def similar(self, a, b):
38+
return SequenceMatcher(None, a, b).ratio()
39+
40+
#function for grabbing a random document from the database
41+
def get_random_doc(self, collection):
42+
count = collection.count()
43+
return collection.find()[random.randrange(count)]
44+
45+
#this function generates a random sentence at any length between 1 and 10 words long
46+
def sentenceGen(self):
47+
#set a clear string and set a random integer 1-10
48+
result = ""
49+
length = random.randint(1, 10)
50+
51+
#for the range in the integer above find a random word from the db and append to the string
52+
for i in range(length):
53+
cursor = self.get_random_doc(self.allwords)
54+
for x, y in cursor.items():
55+
if x == "word":
56+
cWord = (y)
57+
result += cWord
58+
result += ' '
59+
#clear the cursor
60+
del cursor
61+
#return the constructed sentence
62+
return result
63+
64+
#this function searches the database for the input string and returns all replies for that string, returning a random one
65+
def dbSearch(self, searchIn):
66+
#search the database for inputs the bot has said prior
67+
cursor = self.responses.find_one({"whatbotsaid": searchIn})
68+
#return list of human replies to this response and choose one at random
69+
for x, y in cursor.items():
70+
if x == 'humanReply':
71+
chosenReply = (random.choice(y))
72+
#erase the cursor and return the chosen string
73+
del cursor
74+
return chosenReply
75+
76+
#this function returns a random sentence from the entire db
77+
def randomSentence(self):
78+
cursor = self.get_random_doc(self.responses)
79+
for x, y in cursor.items():
80+
if x == 'humanReply':
81+
chosenReply = (random.choice(y))
82+
return chosenReply
83+
84+
#the string comparison function
85+
def mongoFuzzyMatch(self, inputString, searchZone, termZone, setting):
86+
#create an empty dictionary
87+
compareList = {}
88+
#search the database passed in
89+
for cursor in searchZone.find():
90+
for x, y in cursor.items():
91+
#find the item in the cursor that matches the search term passed into the function, eg: 'whatbotsaid'
92+
if x == termZone:
93+
#compare the input string to the current string in the cursor, which returns a decimal point of accuracy (0.0 > 1.0)
94+
95+
#OLD METHOD
96+
#compareNo = self.similar(inputString, y)
97+
98+
#if accuracy is off then append the string and its accuracy to the dictionary no matter the accuracy
99+
if setting == ('off'):
100+
compareNo = fuzz.token_set_ratio(inputString.lower(), y.lower())
101+
if compareNo > self.botAccuracy-30:
102+
compareList[y] = compareNo
103+
#if accuracy is medium then append the string and its accuracy to the dictionary only if its over the medium setting
104+
elif setting == ('med'):
105+
compareNo = fuzz.partial_ratio(inputString.lower(), y.lower())
106+
if compareNo > self.botAccuracy-20:
107+
compareList[y] = compareNo
108+
#if accuracy is on/high then append the string and its accuracy to the dictionary only if its over the on/high setting
109+
elif setting == ('on'):
110+
compareNo = fuzz.ratio(inputString.lower(), y.lower())
111+
if compareNo > self.botAccuracy:
112+
compareList[y] = compareNo
113+
#if nothing found then return a non match
114+
if compareList == {}:
115+
compareChosen = 'none_match'
116+
#if there are matching strings identify the highest accuracy from the dictionary made above
117+
else:
118+
compareChosen = max(compareList.keys(), key=(lambda key: compareList[key]))
119+
#erase the cursor and return the chosen matching string
120+
del cursor
121+
if (self.debugMode == True):
122+
print(compareChosen)
123+
return compareChosen
124+
125+
126+
def replyTumbler(self):
127+
if self.name == ("--trainer--"):
128+
self.bResponse = self.wordsIn
129+
return ("")
130+
#find the search string using the high accuracy number - to find a decent match to what the bot has said prior
131+
#when this function is called it required four arguments: the human response, the database to search on, the response required from the database and the accuracy level
132+
searchSaid = self.mongoFuzzyMatch(self.wordsIn, self.responses, 'whatbotsaid', 'on')
133+
#if no matches then try with a lower accuracy to find a less similar sentence
134+
if searchSaid == ('none_match'):
135+
searchSaid = self.mongoFuzzyMatch(self.wordsIn, self.responses, 'whatbotsaid', 'med')
136+
if searchSaid == ('none_match'):
137+
searchSaid = self.mongoFuzzyMatch(self.wordsIn, self.responses, 'whatbotsaid', 'off')
138+
if searchSaid == ('none_match'):
139+
#if still no match then move onto generating a totally random reply or grab a random sentence from the db
140+
if searchSaid == ('none_match'):
141+
if random.randrange(100) <= 60:
142+
chosenReply = self.randomSentence()
143+
self.bResponse = chosenReply
144+
return (chosenReply)
145+
else:
146+
chosenReply = self.sentenceGen()
147+
self.bResponse = chosenReply
148+
return (chosenReply)
149+
else:
150+
#pass the response into the database to find prior human responses to the above sentence
151+
chosenReply = self.dbSearch(searchSaid)
152+
153+
#pass the response into the database to find prior human responses to the above sentence
154+
chosenReply = self.dbSearch(searchSaid)
155+
156+
#clear the search variable
157+
del searchSaid
158+
self.bResponse = chosenReply
159+
return (chosenReply)
160+
161+
#this function passes in the information from the loop, the input reply and the bots last reply and appends them to the database
162+
def updateDB(self, wordsIn):
163+
self.wordsIn = wordsIn
164+
#search the database for prior responses the bot has said
165+
cursor = self.responses.find_one({"whatbotsaid": self.bResponse})
166+
#if none then store a new bot response with the humans reply
167+
if cursor is None:
168+
postR = {"whatbotsaid": self.bResponse, "humanReply": [self.wordsIn]}
169+
self.responses.insert_one(postR).inserted_id
170+
del cursor
171+
#if already existing then update the database with a new reply
172+
else:
173+
self.responses.update_one({"whatbotsaid": self.bResponse}, {'$addToSet':{"humanReply": self.wordsIn}}, upsert=True)
174+
#clear the cursor
175+
del cursor
176+
177+
#split the input sentence into individual words and store each in the database
178+
wordsInDB = self.wordsIn.split(' ')
179+
for word in wordsInDB:
180+
#search the database for the word
181+
cursor = self.allwords.find_one({"word": word})
182+
#if its not already in the database then insert into the database
183+
if cursor is None:
184+
postW = {"word": word}
185+
self.allwords.insert_one(postW).inserted_id
186+
#if the word is already in the database pass and clear the cursor
187+
else:
188+
pass
189+
del cursor
190+
191+
192+
def dbWordsUpdate(objectIn):
193+
#split the input sentence into individual words and store each in the database
194+
wordsInDB = objectIn.split(' ')
195+
for word in wordsInDB:
196+
#search the database for the word
197+
cursor = allwords.find_one({"word": word})
198+
#if its not already in the database then insert into the database
199+
if cursor is None:
200+
postW = {"word": word}
201+
allwords.insert_one(postW).inserted_id
202+
#if the word is already in the database pass and clear the cursor
203+
else:
204+
pass
205+
del cursor
206+
207+
def conversation(inputWords, personName):
208+
#if person name is already initialised as a class with talk loop then check if its the same as the previous person from last response
209+
if personName in name_dict:
210+
if personName == prevPerson["prev_person"]:
211+
#if it is still the same person chatbot talking to put their response in and get a reply from the bot
212+
name_dict[personName].updateDB(inputWords)
213+
globalReply = (name_dict[personName].replyTumbler())
214+
else:
215+
#if it is a different person from before then get a reponse from the bot using the humans prior response - to continue the conversation
216+
globalReply = (name_dict[personName].replyTumbler())
217+
else:
218+
#if human new then initialise them with the talk loop class
219+
name_dict.update({personName: talkLoop(name=personName, client=client, db=db, responses=responses, allwords=allwords, inputWords="hello", globalReply="hello", botAccuracy=botAccuracy, debugMode=debugMode)})
220+
#get an intial reply
221+
globalReply = (name_dict[personName].replyTumbler())
222+
#combine the greeting with the humans name
223+
globalReply = str(globalReply + " " + personName)
224+
225+
#set previous person
226+
prevPerson["prev_person"] = personName
227+
228+
#return the reply
229+
return globalReply
230+
231+
#setting up variables for mongodb
232+
client = MongoClient('localhost', 27017)
233+
db = client.words_database
234+
responses = db.responses
235+
allwords = db.allwords
236+
237+
#accuracy variable (percentage)
238+
botAccuracy = 95
239+
debugMode = False
240+
241+
#blank variables
242+
name_dict = {}
243+
prevPerson = {"prev_person": ""}
244+
245+
#if called direct then run the function
246+
if __name__ == '__main__':
247+
if len(sys.argv) > 1:
248+
try:
249+
sys.argv[1] = int(sys.argv[1])
250+
except ValueError:
251+
print ('There are two optional switches: accuracy <0-100> and <-debug>')
252+
sys.exit()
253+
254+
botAccuracy = sys.argv[1]
255+
256+
if len(sys.argv) > 2:
257+
try:
258+
sys.argv[2] = str(sys.argv[2])
259+
except ValueError:
260+
print ('There are two optional switches: accuracy <0-100> and <-debug>')
261+
sys.exit()
262+
263+
if sys.argv[2] == ("-debug"):
264+
debugMode = True
265+
else:
266+
print ('There are two optional switches: accuracy <0-100> and <-debug>')
267+
sys.exit()
268+
269+
270+
#request name
271+
sys.stdout.write(BLUE)
272+
name = input('Your name: ')
273+
sys.stdout.write(RESET)
274+
275+
#get reply and print for logging/debugging
276+
reply = conversation(input, name)
277+
sys.stdout.write(RED)
278+
print("Bot: " + reply)
279+
sys.stdout.write(RESET)
280+
281+
while True:
282+
#get another response and print
283+
sys.stdout.write(BLUE)
284+
input = input('You: ')
285+
sys.stdout.write(RESET)#
286+
#if response is blank, rerun loop
287+
if input == (""):
288+
continue
289+
#with 'change_name' typed in it will request new name - for debugging and testing
290+
if input == ("change_name"):
291+
sys.stdout.write(BLUE)
292+
name = raw_input('Your name: ')
293+
sys.stdout.write(RESET)
294+
#get another reply
295+
reply = conversation(input, name)
296+
#print reply
297+
sys.stdout.write(RED)
298+
print("Bot: " + reply)
299+
sys.stdout.write(RESET)
300+
#rerun the loop with new name
301+
continue
302+
#for a normal response grab another reply and print
303+
reply = conversation(input, name)
304+
sys.stdout.write(RED)
305+
print("Bot: " + reply)
306+
sys.stdout.write(RESET)

Diff for: bot_8_trainer.py

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import sys
2+
import re
3+
import time
4+
import pymongo
5+
from pymongo import MongoClient
6+
import bot_8 as b
7+
import deleteDB as d
8+
9+
name = ("--trainer--")
10+
inputWords = ("hello")
11+
12+
try:
13+
if sys.argv[1] == ("-fresh"):
14+
print("Clearing DB")
15+
d.delDB()
16+
except:
17+
print("Existing DB training")
18+
19+
b.conversation(inputWords, name)
20+
21+
f = open("learning.txt", "r")
22+
23+
for x in f:
24+
if not re.search('[a-zA-Z]', x[0]):
25+
continue
26+
27+
if (':') in x:
28+
try:
29+
x = str(x.split(": ")[1])
30+
except IndexError:
31+
continue
32+
33+
print(x)
34+
35+
b.conversation(x, name)
36+
37+
f.close()

Diff for: colors.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
RED = "\033[1;31m"
2+
BLUE = "\033[1;34m"
3+
CYAN = "\033[1;36m"
4+
GREEN = "\033[0;32m"
5+
RESET = "\033[0;0m"
6+
BOLD = "\033[;1m"
7+
REVERSE = "\033[;7m"

Diff for: deleteDB.py

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import sys
2+
import random
3+
import pymongo
4+
import sys
5+
from pymongo import MongoClient
6+
7+
def delDB():
8+
client = MongoClient('localhost', 27017)
9+
db = client.words_database
10+
11+
client.drop_database(db)
12+
13+
if __name__ == "__main__":
14+
delDB()

0 commit comments

Comments
 (0)