-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfullcode.py
320 lines (241 loc) · 11 KB
/
fullcode.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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
KB = '''
%%KB
%RULES
%rules for I HAVE SYMPTOMS
answer('You need to contact Geo Blue') :- intention('I am currently experiencing COVID symptoms, I want to know what to do'), \+reside(res), insured('GeoBlue').
answer('You need to contact your local provider') :- intention('I am currently experiencing COVID symptoms, I want to know what to do'), \+reside(res), \+insured('GeoBlue').
answer('You need to test at City Test SF') :- intention('I am currently experiencing COVID symptoms, I want to know what to do'), reside(res), res_hall(turk).
answer('You need to test at chinatown') :- intention('I am currently experiencing COVID symptoms, I want to know what to do'), reside(res), res_hall('851').
%rules for I HAVE TRAVELLED/ WILL BE TRAVELLING
answer('Visit the City Test SF test centera') :-
intention('I want to travel around'), result(urgent), res_hall(turk).
answer('Visit the glide test center') :-
intention('I want to travel around'), result(urgent), res_hall(turk).
answer('Visit the chinatown test center') :-
intention('I want to travel around'), result(urgent), res_hall('851').
answer('Test privately') :-
intention('I want to travel around'), \+result(urgent), testing(at_home).
answer('Visit the glide test center') :-
intention('I want to travel around'), \+result(urgent), testing(at_testing_center), reside(res), res_hall(turk).
answer('Visit the carbon health market test center') :-
intention('I want to travel around'), \+result(urgent), testing(at_testing_center), reside(res), res_hall(turk).
answer('Visit the carbon health market test center') :-
intention('I want to travel around'), \+result(urgent), testing(at_testing_center), reside(res), res_hall('851').
answer('Visit the carbon health market test center'):-
intention('I want to travel around'), \+result(urgent), testing(at_testing_center), reside(res), res_hall('851').
%rules for HAVE A CLOSE CONTACT WITH COVID
answer('You should start quarantine immediately'):-
intention('I had a close contact with a COVID patient. What next?'), exposure(known), \+quarantine_status(qurantine).
answer('You should continue your quarantine'):-
intention('I had a close contact with a COVID patient. What next?'), exposure(known), quarantine_status(quarantine).
answer('Visit City Test SF'):-
intention('I had a close contact with a COVID patient. What next?'), \+exposure(known), \+symptoms(felt).
answer('Visit the local provider'):-
intention('I had a close contact with a COVID patient. What next?'), \+exposure(known), symptoms(felt), \+reside(res), \+insured('GeoBlue').
answer('Visit Geo Blue'):-
intention('I had a close contact with a COVID patient. What next?'), \+exposure(known), symptoms(felt), \+reside(res),\+insured('GeoBlue').
answer('Visit City Test SF'):-
intention('I had a close contact with a COVID patient. What next?'), \+exposure(known), symptoms(felt), reside(res), res_hall(turk).
answer('Visit chinatown center'):-
intention('I had a close contact with a COVID patient. What next?'), \+exposure(known), symptoms(felt), reside(res), res_hall('851').
% rules for A CASUAL CHECK
%The 4 lines below I am not sure, as there are two options glide and carbon for given askables
answer('Visit the glide test center') :-
intention('I just wanted to know about some casual stuff'), testing(at_testing_center), res_hall(turk).
answer('Visit the carbon health market test center') :-
intention('I just wanted to know about some casual stuff'), testing(at_testing_center), res_hall(turk).
answer('Visit the Concentera Downtown Center') :-
intention('I just wanted to know about some casual stuff'), testing(at_testing_center), res_hall('851').
answer('Visit the carbon health fin test center') :-
intention('I just wanted to know about some casual stuff'), testing(at_testing_center), res_hall('851').
answer('Test privately') :-
intention('I just wanted to know about some casual stuff'), testing(at_home).
%FACTS
reside(X) :-
ask('Do you live in the', X).
res_hall(X) :-
menuask('Which res hall do you reside in?', X, [turk, '851']).
testing(X) :-
menuask('Where do you want to test?', X, [at_home, at_testing_center]).
exposure(X) :-
ask('Is your source of exposure', X).
result(X) :- ask('Is your need for testing', X).
insured(X) :- ask('Are you insured by', X).
intention(X) :-
menuask('What is your intention for taking the COVID test?', X, ['I am currently experiencing COVID symptoms, I want to know what to do', 'I want to travel around', 'I had a close contact with a COVID patient. What next?', 'I just wanted to know about some casual stuff']).
quarantine_status(X) :-
ask('Are you currently in', X).
symptoms(X) :-
ask('Are your symptoms', X).
% Asking clauses
multivalued(none). % We don't have any multivalued attributes
ask(A, V):-
known(yes, A, V), % succeed if true
!. % stop looking
ask(A, V):-
known(_, A, V), % fail if false
!, fail.
% If not multivalued, and already known, don't ask again for a different value.
ask(A, V):-
\+multivalued(A),
known(yes, A, V2),
V \== V2,
!.
ask(A, V):-
read_py(A,V,Y), % get the answer
asserta(known(Y, A, V)), % remember it
write_py(known(Y, A, V)),
Y == yes. % succeed or fail
menuask(A, V, _):-
known(yes, A, V), % succeed if true
!. % stop looking
menuask(A, V, _):-
known(yes, A, V2), % If already known, don't ask again for a different value.
V \== V2,
!,
fail.
menuask(A, V, MenuList) :-
read_py_menu(A, X, MenuList),
check_val(X, A, V, MenuList),
asserta( known(yes, A, X) ),
X == V.
check_val(X, _, _, MenuList) :-
member(X, MenuList),
!.
check_val(X, A, V, MenuList) :-
write_py(X), write_py(' is not a legal value, try again.'), nl,
menuask(A, V, MenuList).
'''
# The code here will ask the user for input based on the askables
# It will check if the answer is known first
import tempfile
import os
import pylcs
import numpy as np
import requests
from pyswip import Prolog, Functor, Variable, Atom, registerForeign, call
prolog = Prolog() # Global handle to interpreter
retractall = Functor("retractall")
known = Functor("known",3)
#Define foreign functions for getting user input and writing to the screen
def write_py(X):
"""Prints the input X to the console and returns True to Prolog"""
print(f'\t{X}')
return True
def read_py(A: Atom, V: Atom, Y: Variable) -> bool:
"""
Asks a question to the user and sends the response to Prolog.
It is used to get Yes, No questions.
Yes is normally evaluated by Prolog as True and any other input as False.
:param A: The question (askable) that the user should be prompted with.
:param V: The value that the user needs to agree (yes) or disagree
(any other input) with.
:param Y: The value that Prolog will match with as True. Normally it's 'Yes'.
:returns True if Y is a Prolog Variable and False otherwise.
"""
if isinstance(Y, Variable):
response = input(str(A) + " " + str(V) + "?\n--> ")
Y.unify(response)
return True
else:
return False
def read_py_menu(A: Atom, Y: Variable, MenuList: list) -> bool:
"""
Asks the user for input based on a menu. Choosing the index of the option
as well as the exact text of the option would work. When the response
has the best LCS match with an option above 10% it is the default response.
:param A: The prompt (askable) the user needs to answer.
:param V: The answer that the user would let Prolog know about.
:param MenuList: The options that the user has to choose from.
:returns True if Y is a Prolog variable and False otherwise.
"""
if isinstance(Y, Variable):
print(A)
list_for_lcs = []
for i, x in enumerate(MenuList):
print(i, ". " ,x)
list_for_lcs.append(str(x))
response = get_menu_input(MenuList, list_for_lcs)
print('\tYou chose', response)
Y.unify(response)
return True
else:
return False
def get_menu_input(MenuList: list, lst_lcs: list) -> str:
"""
Carries out the logic of identifying the choice of the user from the menu.
A user can either choose a number or write some text.
If they choose a number it has to be a valid number amount the count of
options given. If they provide a string it has to have the best match
(among the options) be more than 10%.
:param MenuList: The options that the user needs to choose from.
They are stored as Prolog Atoms.
:param lst_lcs: The options stored in a list of strings that Python
can interprate.
:returns a string of the option that the user chose.
"""
from_user = input('--> ')
response_int = float('inf')
try:
response_int = int(from_user)
response = str(MenuList[response_int])
except:
response = from_user.lower()
response = most_appropriate(response, lst_lcs)
return response
def most_appropriate(response: str, lst_lcs: list) -> str:
"""
Choose the most appropriate option given the response string.
It matches the choice by finding out the percentage LCS (Least Common Subsequence match).
If the best match is above 30%, it is taken as the choice of the user.
Otherwise the user will be reprompted for another option.
:parm response: The input from the user.
:param lst_lcs: The options stored in a list of strings that Python can interprate.
:returns a string of the option that the user chose.
"""
lcs = pylcs.lcs_of_list(response, lst_lcs)
lengths = []
for option in lst_lcs:
lengths.append(len(option))
# Calculate the percentage match of the LCS
similarities = np.array(lcs)/np.array(lengths)
# Identify the index of the highest match
option_idx = np.argmax(similarities)
# If the highest match is less than 10% return original response
# so that the user can be reprompted
# otherwise return the best option
if similarities[option_idx] < 0.1:
return response
return lst_lcs[option_idx]
write_py.arity = 1
read_py.arity = 3
read_py_menu.arity = 3
registerForeign(read_py)
registerForeign(write_py)
registerForeign(read_py_menu)
# Create a temporary file with the KB in it
(FD, name) = tempfile.mkstemp(suffix='.pl', text = "True")
with os.fdopen(FD, "w") as text_file:
text_file.write(KB)
prolog.consult(name) # open the KB for consulting
os.unlink(name) # Remove the temporary file
call(retractall(known))
# Using covidtracking API to give up to date information
response = requests.get(
"https://api.covidtracking.com/v1/states/ca/current.json"
)
print(
"Here is a quick update on COVID situation in San Francisco: \nThe death toll as of",
response.json()['checkTimeEt'],
"is",
response.json()['death']
)
print(
"Today, the number of cases increased by",
response.json()['positiveIncrease'],
",while death cases increased by",
response.json()['deathIncrease'],
"\n"
)
answer = [s for s in prolog.query("answer(X).", maxresult=1)]
print((answer[0]['X'] +"." if answer else "unknown."))