-
Notifications
You must be signed in to change notification settings - Fork 0
/
bot.py
164 lines (130 loc) · 5.14 KB
/
bot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
__author__ = 'V'
import threading
from knowledge import get_theatres
from classes import State
from tokeniser import tokeniser, get_tags
from collections import deque
from logic import narrow
class Bot:
requests = [] #Keeping track of all requests in requests
ntm, ntt, trash = get_theatres() # should not be changed after instantiation
'''
bot is tied to a unique user conversation
resource is unique conversation identifier. for a customer, it should be their number
we kill the bot when the conversation closes
'''
def __init__(self, resource='test'):
self.state = State(resource)
'''
handle potential crashing
'''
def sleek_get_response(self, message):
try:
response = self.get_response(message)
except:
response = "Chappie can't quite understand you!"
return response
'''
the bot thinks of what to say...
handles movie-related String input from the user
function takes in incoming lines from user then sends it to the relevant submodules.
current state of the Bot is kept track of in State object
returns new state of bot and the bot response
Submodules:
- function tokeniser returns spellchecked lists of tokens
- multiple tagging functions tag tokens for times, numbers, movie titles, addresses
- tagged tokens are sent to logic, to be checked for mutual compatibility and then inserted
into the MovieRequest object
- logic output is given to function narrow, to decide which questions to ask
Int question keeps track of which question we are on. -1 for no question, index of
MovieRequest.done for relevant question
'''
def get_response(self, message):
req, question, options = self.state.req, self.state.question, self.state.options
#closing
if message.lower() == "bye":
return "Goodbye!"
# send input to tokenizer
tokens = tokeniser(message)[1]
if len(tokens) < 1: return "..?"
# track of current conversation-create and update
# Conversation object
self.state.add_line(tokens[0])
# understand the prepositions to better find where the info is
# todo submodule, for now check everything, which works pretty well tbh
# at [theatre], watch|see [movie], at [time]
tags = get_tags(tokens, Bot.ntm, Bot.ntt, question)
# logic for what to do if there is more than one of the above,
# must narrow it down
# input items into the MovieRequest object based on the current
# state of the tags
# returns the new question that it needs to know to finish the request
# returns statement, the question itself
question, statement = narrow(self.state, tags, Bot.ntm, Bot.ntt)
# if we are still on the same question, add to the counter
# works because question is an immutable Int
if self.state.question == question:
self.state.timeout += 1
else: self.state.timeout = 0
self.state.question = question
self.state.starting = False
return statement
'''
run() function
used for debugging, can interact on console. user should always be able to keep typing,
and Bot will keep re-updating the submodules.
two threads:
1. for constantly updating raw input from the user and writing to a buffer
2. for popping items from the buffer and processing in order
thread 1 signals to thread 2 with a new_text Event every time a new text is sent
keeps track of and constantly updates State.
'''
def run(self):
chat_buffer = deque()
# accept input at all times
# open separate thread which writes it to a buffer
new_text = threading.Event()
end_buffer = threading.Event()
def add_to_buffer():
while True:
inp = raw_input()
chat_buffer.appendleft(inp)
new_text.set()
if inp.__eq__('bye'):
return
if end_buffer.is_set():
return
buffer_thread = threading.Thread(name='buffer_thread', target=add_to_buffer)
buffer_thread.start()
def close():
print(self.state.req.readout())
Bot.requests.append(self.state.req)
end_buffer.set()
return
# main thread
# while buffer_thread has items in it, pop off items and process
while True:
new_text.wait(timeout=20) # timeout wait doesn't seem to do anything todo
try:
inp = chat_buffer.pop()
new_text.clear()
except IndexError:
continue
if inp.lower() == ('bye'):
print("Goodbye!")
close()
return
response = self.get_response(inp)
if self.state.question == -1:
print("Got it, thanks. Bye!")
close()
return
else:
# ask a question to find out later information
print(response)
'''
for debugging
bot = Bot()
bot.run()
bye
'''