-
Notifications
You must be signed in to change notification settings - Fork 1
/
application.py
354 lines (313 loc) · 14.5 KB
/
application.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
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
from flask import Flask, render_template, jsonify, request, make_response
from numpy import result_type # BSD License
import pg8000
import torch
import overpy
from libraries.model import NeuralNet
import nltk
from libraries.nltk_utilities import bag_of_words, tokenize
# StdLibs
import random
import json
###################################################
#Programmato da Alex Prosdocimo e Matteo Mirandola#
###################################################
application = Flask(__name__)
@application.route("/") #Index
def index():
return make_response(render_template("index.html"))
@application.route("/tourist")
def tourist():
return make_response(render_template("tourist.html"))
@application.route("/cities", methods=["POST"])
def getCities():
with open("static/jsons/comuni.json", "r") as file:
response = json.load(file)
return jsonify(response)
# API: Richiede obbligatoriamente i campi city e tipo. Tutti gli altri campi sono opzionali. Se i campi opzionali non sono specificiati sono, si includono tutte le opzioni
# Generatore di query al database per ottenere gli alloggi
@application.route("/getAll", methods=["POST"])
def execAllQuery():
if "city" not in request.form or "tipo" not in request.form:
return "400 Bad Request"
try:
#Costruzione della query.
#Se il campo tipologia è == % allora non inserisce il constrain per tipologia di alloggio
#Aggiunge i constrain successivi solo se nella richiesta esiste una specificazione true/false per quel campo
query = f"SELECT * FROM alloggio WHERE comune='{request.form['''city''']}'"
if(request.form["tipo"] != "%"):
query += f" and tipologia='{request.form['''tipo''']}'"
if("piscina" in request.form):
query += f" and piscina={request.form['''piscina''']}"
if("ac" in request.form):
query += f" and ac={request.form['''ac''']}"
if("parcheggio" in request.form):
query += f" and parcheggio={request.form['''parcheggio''']}"
if("ristorante" in request.form):
query += f" and ristorante={request.form['''ristorante''']}"
if("animali" in request.form):
query += f" and animali={request.form['''animali''']}"
if("parcogiochi" in request.form):
query += f" and parcogiochi={request.form['''parcogiochi''']}"
if("sauna" in request.form):
query += f" and sauna={request.form['''sauna''']}"
if("palestra" in request.form):
query += f" and palestra={request.form['''palestra''']}"
query += ";"
#Connessione al database
#Cambiare dati del server adeguatamente, adattare nel caso non si stia usando postgresSQL
conn = pg8000.connect(host="pg1.cfhdttxorzlt.eu-south-1.rds.amazonaws.com", port=5432,
database="tourist_bot", user="tourist_bot_admin", password="daUqe%z*qqj&C7n.oR8iX,]4")
cur = conn.cursor()
cur.execute(query)
result = cur.fetchall()
response = []
#fecassoc del mysql per ottenere le righe e costruire il dizionario di risposte
provincia = ""
for row in result:
dicty = {}
dicty['id'] = row[0]
dicty['nome'] = row[1]
dicty['indirizzo'] = row[3]
dicty['stelle'] = row[5]
if row[6] != "":
dicty['sito'] = row[6]
if row[7] != "":
dicty['telefono'] = row[7]
if row[8] != "":
dicty['email'] = row[8]
dicty['lat'] = row[17]
dicty['lon'] = row[18]
provincia = row[19]
response.append(dicty)
#La risposta è un dizionario di dizionari
response = {"data": response, "provincia":provincia, "comune": request.form['''city''']}
#Chiusura connessione al database
cur.close()
conn.close()
return jsonify(response) #Ritorno json del dizionario
except:
return "500 Internal Server Error"
# API: Richiede i campi sentence e city in POST
@application.route("/chatbot", methods=["GET", "POST"])
def chatbot():
try:
if request.method == "GET":
return render_template("chat.html")
else:
if "sentence" in request.form and "city" in request.form:
risposta = {
"tag": "",
"message": "",
"data": []
}
#NON TOCCARE IL CODICE SOTTOSTANTE
#DELICATO E MOLTO TECNICO, SI RISCHIA DI ROMPERE TOTALMENTE LA FUNZIONALITA CHATBOT
#Il codice sottostante analizza una frase in lingua inglese, suddividendola in pezzi più piccoli
#detti token. In seguito, la frase trasformata in token viene fatta passare attraverso la rete neurale.
#Questa determina l'intento della frase (ne capisce il senso) e produce una risposta.
#Il programma analizza questa risposta ed esegue la corretta query ad overpass e ne ritorna i risultati al client
sentence = tokenize(request.form["sentence"])
x = bag_of_words(sentence, all_words)
x = x.reshape(1, x.shape[0])
x = torch.from_numpy(x)
output = model(x)
_, predicted = torch.max(output, dim=1)
tag = tags[predicted.item()]
probs = torch.softmax(output, dim=1)
prob = probs[0][predicted.item()]
with open('static/jsons/intents.json', 'r') as f:
intents = json.load(f)
if sentence[0] == 'help':
risposta['tag'] = 'help'
risposta['message'] = f"help"
return risposta
elif prob.item() > 0.75:
try:
amenitytag = ['hospital', 'nightclub' 'fast_food', 'restaurant', 'library', 'bicycle_parking', 'bicycle_rental', 'boat_rental', 'car_rental',
'charging_station', 'parking', 'atm', 'pharmacy', 'casino', 'cinema', 'theatre', 'drinking_water', 'toilets', 'internet_cafe', 'post_office',
'gym', 'fuel', 'bar']
tourismtag = ['museum', 'attraction', 'aquarium', 'caravan_site',
'gallery', 'picnic_site', 'theme_park', 'viewpoint', 'zoo']
leisuretag = ['park', 'beach_resort', 'swimming_pool']
buildingtag = ['cathedral', 'church']
naturaltag = ['water']
shoptag = ['mall']
for intent in intents['intents']:
if tag == intent['tag']:
risposta['tag'] = tag
risposta['message'] = f'{random.choice(intent["responses"])}'
if tag in amenitytag:
tmp = StructQuery(request.form['city'], tag, 'amenity')
if(tmp == []):
risposta['message'] = "There are no available results"
return risposta
else:
risposta['data'] = tmp
return risposta
elif tag in tourismtag:
tmp = StructQuery(request.form['city'], tag, 'tourism')
if(tmp == []):
risposta['message'] = "There are no available results"
return risposta
else:
risposta['data'] = tmp
return risposta
elif tag in leisuretag:
tmp = StructQuery(request.form['city'], tag, 'leisure')
if(tmp == []):
risposta['message'] = "There are no available results"
return risposta
else:
risposta['data'] = tmp
return risposta
elif tag in buildingtag:
tmp = StructQuery(request.form['city'], tag, 'building')
if(tmp == []):
risposta['message'] = "There are no available results"
return risposta
else:
risposta['data'] = tmp
return risposta
elif tag in naturaltag:
tmp = StructQuery(request.form['city'], tag, 'natural')
if(tmp == []):
risposta['message'] = "There are no available results"
return risposta
else:
risposta['data'] = tmp
return risposta
elif tag in shoptag:
tmp = StructQuery(request.form['city'], tag, 'shop')
if(tmp == []):
risposta['message'] = "There are no available results"
return risposta
else:
risposta['data'] = tmp
return risposta
else:
return risposta
except:
risposta["message"] = "Please slow down! You are doing to many requests!"
return
else:
risposta['tag'] = 'missunderstanding'
risposta['message'] = f"I can't understand you. Please repeat"
return risposta
else:
return "400 Bad Request"
except Exception as e:
return "500 Internal Server Error"
@application.route("/final") #Final page
def final():
return make_response(render_template("final.html"))
@application.route("/getCityCoords", methods=["POST"])
def getCoords():
api = overpy.Overpass(url="https://overpass.kumi.systems/api/interpreter")
query = ""
print(request.form['city'])
if(request.form['city'].lower() == "vicenza"):
query= f'''
[out:json];
(node["name"="{request.form['city']}"]["place"= "city"];);
out center meta;
'''
else:
query= f'''
[out:json];
(node["name"="{request.form['city']}"]["place"= "town"];);
out center meta;
'''
result = api.query(query)
list_of_node_tags = []
for node in result.nodes:
node.tags['latitude'] = node.lat
node.tags['longitude'] = node.lon
node.tags['id'] = node.id
list_of_node_tags.append(node.tags)
list_of_node_tags[0]['latitude'] = str(list_of_node_tags[0]['latitude'])
list_of_node_tags[0]['longitude'] = str(list_of_node_tags[0]['longitude'])
return list_of_node_tags[0]
#Query ad Overpass.
#Il parametr city per ora sarà sempre Vicenza poichè il programma gestisce solo il territorio vicentino.
#queryparam è la categoria generale di oggetto da trovare (solitamente Turismo, Passatempo, Negozio...)
#tag specifica il tipo di oggetto che si sta cercando (ad esempio Museo è una specificazione di Turismo)
#Le query possono durare un po', perchè il database di OpenStreetMap è molto grande.
def StructQuery(city, tag, queryparam):
api = overpy.Overpass(url="https://overpass.kumi.systems/api/interpreter")
addre = ''
query = f'''
[out:json];
area["name"="{city}"]->.searchArea;
node
["{queryparam}"="{tag}"]
(area.searchArea);
out;'''
result = api.query(query)
list_of_node_tags = []
for node in result.nodes:
node.tags['latitude'] = node.lat
node.tags['longitude'] = node.lon
node.tags['id'] = node.id
list_of_node_tags.append(node.tags)
tmp = 0
data = []
for struct in list_of_node_tags:
dictionout = {
'name': '',
'address': '',
'opening_hours': '',
'phone': '',
'lat': '',
'lon': '',
'cost': '',
'website': ''
}
if 'name' in struct:
dictionout['name'] = struct['name']
if 'addr:street' in struct:
addre = struct['addr:street']
if 'addr:housenumber' in struct:
addre += ', ' + struct['addr:housenumber']
if 'addr:postcode' in struct:
addre += ', ' + struct['addr:postcode']
dictionout['address'] = addre
if 'opening_hours' in struct:
dictionout['opening_hours'] = struct['opening_hours']
if 'phone' in struct:
dictionout['phone'] = struct['phone']
if 'latitude' in struct:
tmp = struct['latitude']
dictionout['lat'] = str(tmp)
if 'longitude' in struct:
tmp = struct['longitude']
dictionout['lon'] = str(tmp)
if 'cost' in struct:
dictionout['cost'] = struct['cost']
if 'website' in struct:
dictionout['website'] = struct['website']
data.append(dictionout)
return data
#########
#Startup#
#########
#Inizializazione rete neurale. Viene scaricato il tokenizer e viene impostata la cpu come dispositivo di elaborazione
def BotInitialize():
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
nltk.download('punkt')
FILE = 'data.pth'
data = torch.load(FILE)
input_size = data['input_size']
hidden_size = data['hidden_size']
output_size = data['output_size']
all_words = data['all_words']
model_state = data['model_state']
tags = data['tags']
model = NeuralNet(input_size, hidden_size, output_size).to(device)
model.load_state_dict(model_state)
model.eval()
return all_words, model, tags
all_words, model, tags = BotInitialize()
if __name__ == '__main__':
application.run(debug=True, port=80)
####Powered by Requiem####