diff --git a/app.py b/app.py new file mode 100644 index 0000000000000000000000000000000000000000..bb94bca2e0167c4394bf9a3776dcca07528971bb --- /dev/null +++ b/app.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on: 16/01/2023 +@author: Andoni Aranguren Ubierna +@updates: Sergio Campos 02-03/2023 +""" + +import pickle +import pysmile +import sys +import json +print(sys.path) +from src import constants + +import mysql.connector +from flask import Flask, request, render_template + +from src import configuration, recommender, database, planner, modal_choice + +app = Flask(__name__) +cnx = None + + +@app.route("/") +def index(): + return render_template("index.html") + + + +# MODAL CHOICE: ------------------------------------------------------------------------------------------------------- +@app.get("/modal_choice/estimation") +def modal_choice_estimation(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return modal_choice.modal_choice_estimation(cnx, request) + +@app.get("/modal_choice/getProbabilites") +def modal_choice_getprobabilities(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return modal_choice.modal_choice_getprobabilities(cnx, request) + +@app.get("/modal_choice/setProbabilites") +def modal_choice_setprobabilities(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return modal_choice.modal_choice_setprobabilities(cnx, request) + + +@app.get("/modal_choice/getDependencies") +def modal_choice_getdependencies(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return modal_choice.modal_choice_getdependencies(cnx, request) + + +@app.get("/modal_choice/getValues") +def modal_choice_getvalues(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return modal_choice.modal_choice_getvalues(cnx, request) + + + + + +#Dexi configuration: ------------------------------------------------------------------------------------------------- +@app.get("/recommender/configuration/getMatrix") +def configuration_getmatrix(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return configuration.getmatrix(cnx, request) + + +@app.get("/recommender/configuration/setMatrix") +def configuration_setmatrix(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return configuration.setmatrix(cnx, request) + + +@app.get("/recommender/configuration/getSliders") +def configuration_getsliders(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return configuration.getsliders(cnx, request) + + +@app.get("/recommender/configuration/setSliders") +def configuration_setsliders(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return configuration.setsliders(cnx, request) + + + +@app.get("/recommender/configuration/getEvaluationFile") +def configuration_getevaluationfile(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return configuration.getevaluationfile(cnx, request) + + +@app.get("/recommender/configuration/getConfigurationFile") +def configuration_getconfigurationfile(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return configuration.getconfigurationfile(cnx, request) + + + +# RECOMMENDERS: ------------------------------------------------------------------------------------------------------- +@app.get("/recommender/popularity") +def recommender_popularity(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return recommender.recommender_popularity(cnx, request) + + +@app.get("/recommender/geographic/action_id") +def recommender_geographic_id(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return recommender.recommender_geographic_id(cnx, request) + + +@app.get("/recommender/geographic/lat_lon") +def recommender_geographic_lat_lon(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return recommender.recommender_geographic_lat_lon(cnx, request) + + +@app.get("/recommender/preferences") +def recommender_preferences(): + """ + We ask for kpis based on the affinity to the kpi provided. + :return: json + """ + return recommender.recommender_preferences(cnx, request) + + +@app.get("/recommender/kpis/kpi_id") +def recommender_kpis_kpi_id(): + """ + Provided a action it returns a set of kpis by their affinity regarding the provided action + :return: json + """ + return recommender.recommender_kpis_kpi_id(cnx, request) + + +@app.get("/recommender/kpis/action_id") +def recommender_kpis_action_id(): + """ + Provided a action it returns a set of kpis by their affinity regarding the provided action + :return: json + """ + return recommender.recommender_kpis_action_id(cnx, request) + + +@app.get("/recommender/bayesian") +def recommender_bayesian_action_id(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return recommender.recommender_bayesian_action_id(cnx, request) + + +# DATABASE SAVE: ------------------------------------------------------------------------------------------------------- +@app.post("/database/save/plan") +def database_save_plan(): + """ + It stores the plan_details that have been selected. + The json provided should have the same format that /planner/plan_detail outputs filled with each plan_detail + :return: json with the plan_detail + """ + if request.json: + return database.database_save_plan(cnx, request) + else: + return constants.ERROR_JSON_NEEDED + + +# plan_detail PLANNER: ------------------------------------------------------------------------------------------------------- +@app.get("/planner/plan_detail") +def planner_plan_detail(): + """ + It calculates the best plan_detail traversing streets and reordering the intermediate nodes provided. + :return: json with the plan_detail + """ + return planner.planner_plan_detail(cnx, request) + + +# MAIN: ---------------------------------------------------------------------------------------------------------------- +if __name__ == "__main__": + model = pickle.load(open('model.pkcls', 'rb')) + cnx = mysql.connector.connect(**constants.DDBB_CONFIG) + app.run(debug=True, host='0.0.0.0') diff --git a/ejemplo.txt b/ejemplo.txt new file mode 100644 index 0000000000000000000000000000000000000000..528bea8aef078ee1429772d78d8239ecc2973d1f --- /dev/null +++ b/ejemplo.txt @@ -0,0 +1,3 @@ +prueba1 +prueba2 +prueba3 diff --git a/kpis.json b/kpis.json new file mode 100644 index 0000000000000000000000000000000000000000..a74b417d52499042a605496de1f4d1e430b4449c --- /dev/null +++ b/kpis.json @@ -0,0 +1,34 @@ +{ + "simulation_id": 2, + "bilbao": { + "cityWide": { + "traffic": { + "pedestrianTravelTime": 2120.339269937224, + "dailyInternalBikeTravels": 1801 + }, + "pollution": { + "CO": 73208.2575225834, + "CO2_TOTAL": 3235293.3925066995, + "HC": 13157.842323619561, + "NOx": 5239.199220005189, + "PM": 77.20151943494339, + "CO2_rep": 2747710.252532586 + } + }, + "local": { + "traffic": { + "pedestrianTravelTime": 0, + "dailyInternalBikeTravels": 0 + }, + "pollution": { + "CO": 0.0, + "CO2_TOTAL": 0.0, + "HC": 0.0, + "NOx": 0.0, + "PM": 0.0, + "CO2_rep": 0.0 + } + }, + "entryCapacityToCenter": 0 + } +} \ No newline at end of file diff --git a/kpis_area.json b/kpis_area.json new file mode 100644 index 0000000000000000000000000000000000000000..0e43a744f7776d34cd6d78e5527a71b3de9235a8 --- /dev/null +++ b/kpis_area.json @@ -0,0 +1,35 @@ +{ + "simulation_id": 2, + "area": 1, + "bilbao": { + "cityWide": { + "traffic": { + "pedestrianTravelTime": 2120.339269937224, + "dailyInternalBikeTravels": 1801 + }, + "pollution": { + "CO": 73208.2575225834, + "CO2_TOTAL": 3235293.3925066995, + "HC": 13157.842323619561, + "NOx": 5239.199220005189, + "PM": 77.20151943494339, + "CO2_rep": 2747710.252532586 + } + }, + "local": { + "traffic": { + "pedestrianTravelTime": 0, + "dailyInternalBikeTravels": 0 + }, + "pollution": { + "CO": 0.0, + "CO2_TOTAL": 0.0, + "HC": 0.0, + "NOx": 0.0, + "PM": 0.0, + "CO2_rep": 0.0 + } + }, + "entryCapacityToCenter": 0 + } +} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..a048e9482b384977edee1535b1c0517a5ed1a95d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +mysql-connector-python~=8.0.31 +Flask~=2.2.2 +numpy~=1.23.5 +requests~=2.28.1 +pandas~=1.5.1 +utm~=0.7.0 \ No newline at end of file diff --git a/src/app - copia.py b/src/app - copia.py new file mode 100644 index 0000000000000000000000000000000000000000..e603f069b06ea5a8b769d9b10fdbfc4772636939 --- /dev/null +++ b/src/app - copia.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on: 16/01/2023 +@author: Andoni Aranguren Ubierna +""" +import sys +print(sys.path) +from src import constants + +import mysql.connector +from flask import Flask, request, render_template + +from src import recommender, database, planner + +app = Flask(__name__) +cnx = None + + +@app.plan_detail("/") +def index(): + return render_template("index.html") + + +# RECOMMENDERS: ------------------------------------------------------------------------------------------------------- +@app.get("/recommender/popularity") +def recommender_popularity(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return recommender.recommender_popularity(cnx, request) + + +@app.get("/recommender/geographic/action_id") +def recommender_geographic_id(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return recommender.recommender_geographic_id(cnx, request) + + +@app.get("/recommender/geographic/lat_lon") +def recommender_geographic_lat_lon(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return recommender.recommender_geographic_lat_lon(cnx, request) + + +@app.get("/recommender/preferences") +def recommender_preferences(): + """ + We ask for kpis based on the affinity to the kpi provided. + :return: json + """ + return recommender.recommender_preferences(cnx, request) + + +@app.get("/recommender/kpis/kpi_id") +def recommender_kpis_kpi_id(): + """ + Provided a action it returns a set of kpis by their affinity regarding the provided action + :return: json + """ + return recommender.recommender_kpis_kpi_id(cnx, request) + + +@app.get("/recommender/kpis/action_id") +def recommender_kpis_action_id(): + """ + Provided a action it returns a set of kpis by their affinity regarding the provided action + :return: json + """ + return recommender.recommender_kpis_action_id(cnx, request) + + +@app.get("/recommender/bayesian") +def recommender_bayesian_action_id(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return recommender.recommender_bayesian_action_id(cnx, request) + + +# DATABASE SAVE: ------------------------------------------------------------------------------------------------------- +@app.post("/database/save/plan") +def database_save_plan(): + """ + It stores the plan_details that have been selected. + The json provided should have the same format that /planner/plan_detail outputs filled with each plan_detail + :return: json with the plan_detail + """ + if request.json: + return database.database_save_plan(cnx, request) + else: + return constants.ERROR_JSON_NEEDED + + +# plan_detail PLANNER: ------------------------------------------------------------------------------------------------------- +@app.get("/planner/plan_detail") +def planner_plan_detail(): + """ + It calculates the best plan_detail traversing streets and reordering the intermediate nodes provided. + :return: json with the plan_detail + """ + return planner.planner_plan_detail(cnx, request) + + +# MAIN: ---------------------------------------------------------------------------------------------------------------- +if __name__ == "__main__": + cnx = mysql.connector.connect(**constants.DDBB_CONFIG) + app.run(debug=True, host='0.0.0.0') diff --git a/src/app.py b/src/app.py index d2cec3e0ace91d879e147629f57e59de655ed276..d3a68904124c656252b3230bafc0b2ab2afe29ba 100644 --- a/src/app.py +++ b/src/app.py @@ -3,7 +3,8 @@ """ Created on: 16/01/2023 @author: Andoni Aranguren Ubierna --- Adaptations: 02/2023 @author: Sergio Campos +@updates: Sergio Campos 02-03/2023 + """ import sys print(sys.path) @@ -12,7 +13,7 @@ from src import constants import mysql.connector from flask import Flask, request, render_template -from src import recommender, database, planner +from src import recommender, database, planner, modal_choice app = Flask(__name__) cnx = None diff --git a/src/configuration.py b/src/configuration.py new file mode 100644 index 0000000000000000000000000000000000000000..419e0f2c656c69869cf723a042c9e8bbc22d504f --- /dev/null +++ b/src/configuration.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on: 16/01/2023 +@author: Andoni Aranguren Ubierna +@updates: Sergio Campos 02-03/2023 +""" +import math + +import sys +print(sys.path) +from src import constants, utils + + +def getmatrix(cnx, request): + """ + We ask for actions based on popularity of the actions + :return: json + """ + try: + kpi = request.args.get("kpi", default=None, type=str) + ret_json = {"shape" : 3, "order" : 0, "data" : ["bien","bien","*", "bien","regular","muy guay", "bien","mal","*","regular","bien","*", "regular","regular","*", "regular","mal","*", + "mal","bien","*", "mal","regular","muy guay", "mal","mal","*"], "values":["muy chungo","chungo","guay","muy guay"]} + return ret_json + except: + return constants.ERROR_EXCEPTION + + +def setmatrix(cnx, request): + """ + We ask for actions based on popularity of the actions + :return: json + """ + try: + kpi = request.args.get("kpi", default=None, type=str) + matrix = request.args.get("matrix", default=None, type=str) + ret_json = {} + return matrix + except: + return constants.ERROR_EXCEPTION + + + +def getsliders(cnx, request): + """ + We ask for actions based on popularity of the actions + :return: json + """ + try: + kpi = request.args.get("kpi", default=None, type=str) + ret_json = {"sliders": [30, 43, 43,12, 43]} + return ret_json + except: + return constants.ERROR_EXCEPTION + + +def setsliders(cnx, request): + """ + We ask for actions based on popularity of the actions + :return: json + """ + try: + kpi = request.args.get("kpi", default=None, type=str) + sliders = request.args.get("sliders", default=None, type=str) + return sliders + except: + return constants.ERROR_EXCEPTION + + +def getevaluationfile(cnx, request): + """ + We ask for actions based on popularity of the actions + :return: json + """ + try: + type = request.args.get("type", default=None, type=str) + if (type=="zone"): + fichero = open('kpis_area.json') + zone = request.args.get("zone", default=None, type=str) + ret_json = fichero.read() + + if (type=="baseline"): + fichero = open('kpis.json') + ret_json = fichero.read() + + if (type=="simulation"): + fichero = open('kpis.json') + ret_json = fichero.read() + + return ret_json + except: + return constants.ERROR_EXCEPTION + + + +def getconfigurationfile(cnx, request): + """ + We ask for actions based on popularity of the actions + :return: json + """ + try: + city = request.args.get("city", default=None, type=str) + if (city=="BIO"): + fichero = open('kpis_bilbao.dex') + ret_json = fichero.read() + + if (city=="AMS"): + fichero = open('kpis_amsterdam.dex') + ret_json = fichero.read() + + if (city=="HEL"): + fichero = open('kpis_helsinki.dex') + ret_json = fichero.read() + + if (city=="MES"): + fichero = open('kpis_messina.dex') + ret_json = fichero.read() + + return ret_json + except: + return constants.ERROR_EXCEPTION + diff --git a/src/constants.py b/src/constants.py index fa2a847f71c08f607ead8ddac3387e92c0690f6c..2a705001903c7c08e4d979fc7b6b61ac16a60531 100644 --- a/src/constants.py +++ b/src/constants.py @@ -3,10 +3,10 @@ """ Created on: 16/01/2023 @author: Andoni Aranguren Ubierna --- Adaptations: 02/2023 @author: Sergio Campos +@updates: Sergio Campos 02-03/2023 """ -DDBB_CONFIG = {'user': 'root', 'password': 'admin', 'host': 'localhost', 'database': 'urbanite_recommender', 'autocommit': True} +DDBB_CONFIG = {'user': 'root', 'password': 'Tecnalia###2023', 'host': 'localhost', 'database': 'urbanite_recommender', 'autocommit': True} OTP_CONFIG = {'host': 'https://afrp.santander.urbanage.digital.tecnalia.dev/'} ERROR_EXCEPTION = [{"error": "Upss... Something went wrong"}, 415] diff --git a/src/database.py b/src/database.py index a189c5c3fbde8689a976e160db1c3718ff7648bc..c62049814bd78e97a6c51bcc300bb6980e89b63f 100644 --- a/src/database.py +++ b/src/database.py @@ -3,7 +3,7 @@ """ Created on: 16/01/2023 @author: Andoni Aranguren Ubierna --- Adaptations: 02/2023 @author: Sergio Campos +@updates: Sergio Campos 02-03/2023 """ from src import utils, constants diff --git a/src/load_data - copia.py b/src/load_data - copia.py new file mode 100644 index 0000000000000000000000000000000000000000..8ec5476b9ef49e031146cd7c18452f045c2b0f33 --- /dev/null +++ b/src/load_data - copia.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on: 16/01/2023 +@author: Andoni Aranguren Ubierna +""" +import os + +import sys +import numpy as np +import pandas as pd +import requests +from mysql import connector +from utm.conversion import to_latlon as utm_to_latlon + +import sys +print(sys.path) +from src import constants + + +def to_latlon(df, x_str, y_str): + x, y = [], [] + + for index, row in df.iterrows(): + coords_portal = utm_to_latlon(row[x_str], row[y_str], zone_number=30, zone_letter="T") + x += [coords_portal[0]] + y += [coords_portal[1]] + df["lon"] = np.round(x, 8) + df["lat"] = np.round(y, 8) + + return df + + +def generate_POIs(cnx): + cursor = cnx.cursor(buffered=True) + path = constants.PATH_POIS + + file = path + "/POIS_LugaresTuristicos_Bilbao.csv" + if os.path.isfile(file): + df = pd.read_csv(file, encoding="utf-8", sep=";", decimal=".", encoding_errors='replace') + df = to_latlon(df, "COORDENADA_UTM_X", "COORDENADA_UTM_Y") + df.drop_duplicates(subset=["lon", "lat", "NOMBRE_LUGAR_CAS"], inplace=True) + valores_preferencias = set([i for x in df["TAGS"].unique().tolist() for i in x.split(",")]) + + df_sql = df[["ID", "lon", "lat", "NOMBRE_LUGAR_CAS"]] + cursor.executemany(constants.sql_insert_poi, df_sql.values.tolist()) + cnx.commit() + for tag in valores_preferencias: + cursor.execute(constants.sql_insert_tag, [tag]) + cnx.commit() + + names_dict = {} + for tag in valores_preferencias: + names_dict[tag] = "" + + cursor.execute(constants.sql_get_tag_ids.format(names="','".join(names_dict.keys())), ) + cnx.commit() + ret = cursor.fetchall() + + for row in ret: + names_dict[row[0]] = row[1] + + for index, row in df.iterrows(): + for tag in row["TAGS"].split(","): + cursor.execute(constants.sql_insert_poi_tag.format(tag=names_dict[tag]), + row[["lon", "lat", "NOMBRE_LUGAR_CAS"]].values.tolist()) + cnx.commit() + + +def generate_routes(cnx): + cursor = cnx.cursor(buffered=True) + a, b = 'áéÃóúüÃÉÃÓÚÜ', '%%%%%%%%%%%%' + trans = str.maketrans(a, b) + path = constants.PATH_ROUTES + for filename in os.listdir(path): + f = os.path.join(path, filename) + if os.path.isfile(f): + df = pd.read_csv(f, sep="\t") + json_itinerary = None + for index, row in df.iterrows(): + names = row["poi_names"].replace(";", "','") + dict_id = {} + for name in row["poi_names"].split(";"): + cursor.execute(constants.sql_get_chosen_poi_ids,[name.translate(trans)]) + cnx.commit() + ret = cursor.fetchall() + try: + dict_id[ret[0][0]] = str(ret[0][1]) + except: + pass + + poi_id = ",".join(list(dict_id.values())) + + url_route = 'http://localhost:5000/planner/route?' + parameters = "&".join(["fromPlace=" + row["from_place"], + "toPlace=" + row["to_place"], + "timeSlot=" + str(int(row["time_slot"])), + "sports=" + str(row["sports"]), + "culture=" + str(row["culture"]), + "sightseeing=" + str(row["sightseeing"]), + "gastronomy=" + str(row["gastronomy"])]) + if poi_id != '': + parameters += "&intermediateNodesIds=" + poi_id + + if json_itinerary is None: + json_itinerary = requests.get(url_route+parameters).json() + else: + time_slot = str(int(row["time_slot"])) + json_itinerary["routes"][time_slot] = requests.get(url_route+parameters).json()["routes"][time_slot] + url_save_it = 'http://localhost:5000/database/save/itinerary' + requests.post(url_save_it, json=json_itinerary) + + +def main(ddbb_config: dict): + cnx = connector.connect(**ddbb_config) + generate_POIs(cnx) + generate_routes(cnx) + cnx.close() + + +if __name__ == '__main__': + ddbb_config = constants.DDBB_CONFIG + main(ddbb_config) diff --git a/src/load_data.py b/src/load_data.py index acaec831ef886eb5829c1dff06333ccacd24bb2b..fe49852da0f4960e2140f255e46f775a4a860ee7 100644 --- a/src/load_data.py +++ b/src/load_data.py @@ -3,8 +3,7 @@ """ Created on: 16/01/2023 @author: Andoni Aranguren Ubierna --- Adaptations: 02/2023 @author: Sergio Campos - +@updates: Sergio Campos 02-03/2023 """ import os diff --git a/src/modal_choice.py b/src/modal_choice.py new file mode 100644 index 0000000000000000000000000000000000000000..f0fc6e38fd7966d026168477559e28282c5f89dd --- /dev/null +++ b/src/modal_choice.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on: 16/01/2023 +@author: Andoni Aranguren Ubierna +@updates: Sergio Campos 02-03/2023 +""" +import math + +import sys +print(sys.path) +from src import constants, utils + + +def modal_choice_estimation(cnx, request): + """ + We ask for actions based on popularity of the actions + :return: json + """ + try: + kpi = request.args.get("kpi", default=None, type=int) + ret_json = {"modal_choice": [kpi]} + return ret_json + except: + return constants.ERROR_EXCEPTION + + +def modal_choice_getprobabilities(cnx, request): + """ + We ask for actions based on popularity of the actions + :return: json + """ + try: + node = request.args.get("node", default=None, type=str) + ret_json = {"node": [node], "probabilities": [32,43,54,23]} + return ret_json + except: + return constants.ERROR_EXCEPTION + + +def modal_choice_setprobabilities(cnx, request): + """ + We ask for actions based on popularity of the actions + :return: json + """ + try: + node = request.args.get("node", default=None, type=str) + probabilities = request.args.get("probabilities", default=None, type=str) + ret_json = {"node": [node], "probabilities": probabilities} + return ret_json + except: + return constants.ERROR_EXCEPTION + + + +def modal_choice_getdependencies(cnx, request): + """ + We ask for actions based on popularity of the actions + :return: json + """ + try: + node = request.args.get("node", default=None, type=str) + dependencies = ["node2","node3","node4"]; + ret_json = {"node": [node], "dependencies": dependencies} + return ret_json + except: + return constants.ERROR_EXCEPTION + + + +def modal_choice_getvalues(cnx, request): + """ + We ask for actions based on popularity of the actions + :return: json + """ + try: + node = request.args.get("node", default=None, type=str) + if (len(node) != 0): + ret_json = {"node": [node], "values": ["val1","val2","val3"]} + else: + ret_json = [{"node": "node1", "values": ["val1","val2","val3"]},{"node": "node2","values": ["val1", "val2", "val3"]},{"node": "node3","values": ["val1", "val2", "val3"]}] + + return ret_json + except: + return constants.ERROR_EXCEPTION + + diff --git a/src/planner.py b/src/planner.py index 565701ea7473c1cf4f11b0ac7ca0aa3d47ea5b77..92bb780d0dde84fd2ed177a20a95e5f86cd466fc 100644 --- a/src/planner.py +++ b/src/planner.py @@ -3,7 +3,7 @@ """ Created on: 16/01/2023 @author: Andoni Aranguren Ubierna --- Adaptations: 02/2023 @author: Sergio Campos +@updates: Sergio Campos 02-03/2023 """ import time diff --git a/src/recommender.py b/src/recommender.py index c99c05c7fb918ea46a8592c7e9eeb52c079beddb..d72d60a81a2ccbe3e4456e0722610ae85ff19e26 100644 --- a/src/recommender.py +++ b/src/recommender.py @@ -3,7 +3,7 @@ """ Created on: 16/01/2023 @author: Andoni Aranguren Ubierna --- Adaptations: 02/2023 @author: Sergio Campos +@updates: Sergio Campos 02-03/2023 """ import math diff --git a/src/templates/index.html b/src/templates/index.html new file mode 100644 index 0000000000000000000000000000000000000000..7c20f787199179f8343d3b8fa68c1a3a55d66cf8 --- /dev/null +++ b/src/templates/index.html @@ -0,0 +1,228 @@ +<!-- +Created on: 16/01/2023 +@author: Andoni Aranguren Ubierna +--> +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>URBANITE</title> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> +</head> +<body> +<div class="container"> + <h1>URBANITE RECOMMENDER API</h1> + <p class="lead">This is a Flask application developed by Tecnalia.</p> + + + <h3>Recommendation calls</h3> + <h4>/recommender/popularity</h4> + <p> + It recommends the most popular actions found in the DDBB.<br> + It can filter by kpi if a kpi is provided. + </p> + <p>Returns: <br> + Json with actions (action_id, action_name, Longitud, Latitud, kpi_id_list, kpi_name_list, Popularity)<p> + <p>Input</p> + <table class="table table-striped"> + <thead class="thead-dark"> + <tr> + <th scope="col">Parameter</th> + <th scope="col">Mandatory</th> + <th scope="col">Data</th> + <th scope="col">Example</th> + <th scope="col">Regexp</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">kpi</th> <td>No</td> <td>int</td> <td>7</td> <td>-</td> + </tr> + </tbody> + </table> + + <h4>/recommender/geographic/action_id</h4> + <p> + Provided action it returns a set of actions that are close by the location</b> + </p> + <p>Returns: <br> + Json with actions (action_id, action_name, Longitud, Latitud, kpi_id_list, kpi_name_list, Distance_in_meters)<p> + <p>Input</p> + <table class="table table-striped"> + <thead class="thead-dark"> + <tr> + <th scope="col">Parameter</th> + <th scope="col">Mandatory</th> + <th scope="col">Data</th> + <th scope="col">Example</th> + <th scope="col">Regexp</th> + </tr> + </thead> + <tbody> + <th scope="row">action</th> <td>Yes</td> <td>int</td> <td>7</td> <td>-</td> + </tr> + <tr> + <th scope="row">kpi</th> <td>No</td> <td>int</td> <td>12</td> <td>-</td> + </tr> + </tbody> + </table> + <h4>/recommender/geographic/lat_lon</h4> + <p> + Provided latitude and logitude coordinations it returns a set of actions that are close by the location</br> + </p> + <p>Returns: <br> + Json with actions (action_id, action_name, Longitud, Latitud, kpi_id_list, kpi_name_list, Popularity)<br> + </p> + <p>Input</p> + <table class="table table-striped"> + <thead class="thead-dark"> + <tr> + <th scope="col">Parameter</th> + <th scope="col">Mandatory</th> + <th scope="col">Data</th> + <th scope="col">Example</th> + <th scope="col">Regexp</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">lat</th> <td>Yes</td> <td>float</td> <td>43.1231</td> <td>-</td> + </tr> + <tr> + <th scope="row">lon</th> <td>Yes</td> <td>float</td> <td>-2.9345</td> <td>-</td> + </tr> + <tr> + <th scope="row">kpi</th> <td>No</td> <td>int</td> <td>12</td> <td>-</td> + </tr> + </tbody> + </table> + <h4>/recommender/preferences</h4> + <p> + Provided a set of preferences it recommends the best actions with a collaborative filtering.<br> + </p> + <p>Returns: <br> + Json with actions (action_id, action_name, Longitud, Latitud, kpi_id_list, kpi_name_list, Count)<br> + </p> + <p>Input</p> + <table class="table table-striped"> + <thead class="thead-dark"> + <tr> + <th scope="col">Parameter</th> + <th scope="col">Mandatory</th> + <th scope="col">Data</th> + <th scope="col">Example</th> + <th scope="col">Regexp</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">sports</th> <td>Preferences must add to 1</td> <td>float</td> <td>0.25</td> <td>-</td> + </tr> + <tr> + <th scope="row">culture</th> <td>Preferences must add to 1</td> <td>float</td> <td>0.25</td> <td>-</td> + </tr> + <tr> + <th scope="row">sightseeing</th> <td>Preferences must add to 1</td> <td>float</td> <td>0.4</td> <td>-</td> + </tr> + <tr> + <th scope="row">culture</th> <td>Preferences must add to 1</td> <td>float</td> <td>0.1</td> <td>-</td> + </tr> + <tr> + <th scope="row">kpi</th> <td>No</td> <td>int</td> <td>7</td> <td>-</td> + </tr> + </tbody> + </table> + + <h4>/recommender/kpis/kpi_id</h4> + <p> + Provided a action it returns a set of kpis by their affinity regarding the provided action</br> + </p> + <p>Returns: <br> + Json with kpis (kpi_id, kpi_name, Count, Popularity, Probability<br> + </p> + <p>Input</p> + <table class="table table-striped"> + <thead class="thead-dark"> + <tr> + <th scope="col">Parameter</th> + <th scope="col">Mandatory</th> + <th scope="col">Data</th> + <th scope="col">Example</th> + <th scope="col">Regexp</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">kpi</th> <td>Yes</td> <td>int</td> <td>12</td> <td>-</td> + </tr> + </tbody> + </table> + + <h4>/recommender/kpis/action_id</h4> + <p> + Provided a action it returns a set of kpis by their affinity regarding the provided action + </p> + <p>Returns: <br> + Json with kpis (kpi_id, kpi_name, Count, Popularity, Probability)<br> + </p> + <p>Input</p> + <table class="table table-striped"> + <thead class="thead-dark"> + <tr> + <th scope="col">Parameter</th> + <th scope="col">Mandatory</th> + <th scope="col">Data</th> + <th scope="col">Example</th> + <th scope="col">Regexp</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">action</th> <td>Yes</td> <td>int</td> <td>7</td> <td>-</td> + </tr> + </tbody> + </table> + + <h4>/recommender/bayesian</h4> + <p> + Provided a set of actions it recommends the best actions with a bayesian probability based collaborative filtering.<br> + </p> + <p>Returns: <br> + Json with actions (action_id, action_name, Longitud, Latitud, kpi_id_list, kpi_name_list, Popularity)<br> + </p> + <p>Input</p> + <table class="table table-striped"> + <thead class="thead-dark"> + <tr> + <th scope="col">Parameter</th> + <th scope="col">Mandatory</th> + <th scope="col">Data</th> + <th scope="col">Example</th> + <th scope="col">Regexp</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">actions</th> <td>Yes</td> <td>str</td> <td>10,7</td> <td>^[0-9]+(?:,[0-9]+)*$</td> + </tr> + <tr> + <th scope="row">kpi</th> <td>No</td> <td>int</td> <td>7</td> <td>-</td> + </tr> + </tbody> + </table> + + <h3>Database</h3> + Saving information into the database to improve the recommender + <h4>/database/save/plan</h4> + <p> + Takes a json file that matches the structure that /plan/plan_detail creates and it stores it into the database.<br> + </p> + <p>Returns: <br> + Nothing <br> + </p> + <p>Input: <br> + A json file that matches the structure of the response of /planner/plan_detail + </p> +</div> +</body> +</html> \ No newline at end of file diff --git a/src/utils.py b/src/utils.py index 2237afb1ba23a1c683fcf0792bb39b7d7e7a4931..c8223de62964f1b1207c0329ad7f9db08cac5028 100644 --- a/src/utils.py +++ b/src/utils.py @@ -3,8 +3,7 @@ """ Created on: 16/01/2023 @author: Andoni Aranguren Ubierna --- Adaptations: 02/2023 @author: Sergio Campos - +@updates: Sergio Campos 02-03/2023 """ import sys print(sys.path) diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000000000000000000000000000000000000..7c20f787199179f8343d3b8fa68c1a3a55d66cf8 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,228 @@ +<!-- +Created on: 16/01/2023 +@author: Andoni Aranguren Ubierna +--> +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>URBANITE</title> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> +</head> +<body> +<div class="container"> + <h1>URBANITE RECOMMENDER API</h1> + <p class="lead">This is a Flask application developed by Tecnalia.</p> + + + <h3>Recommendation calls</h3> + <h4>/recommender/popularity</h4> + <p> + It recommends the most popular actions found in the DDBB.<br> + It can filter by kpi if a kpi is provided. + </p> + <p>Returns: <br> + Json with actions (action_id, action_name, Longitud, Latitud, kpi_id_list, kpi_name_list, Popularity)<p> + <p>Input</p> + <table class="table table-striped"> + <thead class="thead-dark"> + <tr> + <th scope="col">Parameter</th> + <th scope="col">Mandatory</th> + <th scope="col">Data</th> + <th scope="col">Example</th> + <th scope="col">Regexp</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">kpi</th> <td>No</td> <td>int</td> <td>7</td> <td>-</td> + </tr> + </tbody> + </table> + + <h4>/recommender/geographic/action_id</h4> + <p> + Provided action it returns a set of actions that are close by the location</b> + </p> + <p>Returns: <br> + Json with actions (action_id, action_name, Longitud, Latitud, kpi_id_list, kpi_name_list, Distance_in_meters)<p> + <p>Input</p> + <table class="table table-striped"> + <thead class="thead-dark"> + <tr> + <th scope="col">Parameter</th> + <th scope="col">Mandatory</th> + <th scope="col">Data</th> + <th scope="col">Example</th> + <th scope="col">Regexp</th> + </tr> + </thead> + <tbody> + <th scope="row">action</th> <td>Yes</td> <td>int</td> <td>7</td> <td>-</td> + </tr> + <tr> + <th scope="row">kpi</th> <td>No</td> <td>int</td> <td>12</td> <td>-</td> + </tr> + </tbody> + </table> + <h4>/recommender/geographic/lat_lon</h4> + <p> + Provided latitude and logitude coordinations it returns a set of actions that are close by the location</br> + </p> + <p>Returns: <br> + Json with actions (action_id, action_name, Longitud, Latitud, kpi_id_list, kpi_name_list, Popularity)<br> + </p> + <p>Input</p> + <table class="table table-striped"> + <thead class="thead-dark"> + <tr> + <th scope="col">Parameter</th> + <th scope="col">Mandatory</th> + <th scope="col">Data</th> + <th scope="col">Example</th> + <th scope="col">Regexp</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">lat</th> <td>Yes</td> <td>float</td> <td>43.1231</td> <td>-</td> + </tr> + <tr> + <th scope="row">lon</th> <td>Yes</td> <td>float</td> <td>-2.9345</td> <td>-</td> + </tr> + <tr> + <th scope="row">kpi</th> <td>No</td> <td>int</td> <td>12</td> <td>-</td> + </tr> + </tbody> + </table> + <h4>/recommender/preferences</h4> + <p> + Provided a set of preferences it recommends the best actions with a collaborative filtering.<br> + </p> + <p>Returns: <br> + Json with actions (action_id, action_name, Longitud, Latitud, kpi_id_list, kpi_name_list, Count)<br> + </p> + <p>Input</p> + <table class="table table-striped"> + <thead class="thead-dark"> + <tr> + <th scope="col">Parameter</th> + <th scope="col">Mandatory</th> + <th scope="col">Data</th> + <th scope="col">Example</th> + <th scope="col">Regexp</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">sports</th> <td>Preferences must add to 1</td> <td>float</td> <td>0.25</td> <td>-</td> + </tr> + <tr> + <th scope="row">culture</th> <td>Preferences must add to 1</td> <td>float</td> <td>0.25</td> <td>-</td> + </tr> + <tr> + <th scope="row">sightseeing</th> <td>Preferences must add to 1</td> <td>float</td> <td>0.4</td> <td>-</td> + </tr> + <tr> + <th scope="row">culture</th> <td>Preferences must add to 1</td> <td>float</td> <td>0.1</td> <td>-</td> + </tr> + <tr> + <th scope="row">kpi</th> <td>No</td> <td>int</td> <td>7</td> <td>-</td> + </tr> + </tbody> + </table> + + <h4>/recommender/kpis/kpi_id</h4> + <p> + Provided a action it returns a set of kpis by their affinity regarding the provided action</br> + </p> + <p>Returns: <br> + Json with kpis (kpi_id, kpi_name, Count, Popularity, Probability<br> + </p> + <p>Input</p> + <table class="table table-striped"> + <thead class="thead-dark"> + <tr> + <th scope="col">Parameter</th> + <th scope="col">Mandatory</th> + <th scope="col">Data</th> + <th scope="col">Example</th> + <th scope="col">Regexp</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">kpi</th> <td>Yes</td> <td>int</td> <td>12</td> <td>-</td> + </tr> + </tbody> + </table> + + <h4>/recommender/kpis/action_id</h4> + <p> + Provided a action it returns a set of kpis by their affinity regarding the provided action + </p> + <p>Returns: <br> + Json with kpis (kpi_id, kpi_name, Count, Popularity, Probability)<br> + </p> + <p>Input</p> + <table class="table table-striped"> + <thead class="thead-dark"> + <tr> + <th scope="col">Parameter</th> + <th scope="col">Mandatory</th> + <th scope="col">Data</th> + <th scope="col">Example</th> + <th scope="col">Regexp</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">action</th> <td>Yes</td> <td>int</td> <td>7</td> <td>-</td> + </tr> + </tbody> + </table> + + <h4>/recommender/bayesian</h4> + <p> + Provided a set of actions it recommends the best actions with a bayesian probability based collaborative filtering.<br> + </p> + <p>Returns: <br> + Json with actions (action_id, action_name, Longitud, Latitud, kpi_id_list, kpi_name_list, Popularity)<br> + </p> + <p>Input</p> + <table class="table table-striped"> + <thead class="thead-dark"> + <tr> + <th scope="col">Parameter</th> + <th scope="col">Mandatory</th> + <th scope="col">Data</th> + <th scope="col">Example</th> + <th scope="col">Regexp</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">actions</th> <td>Yes</td> <td>str</td> <td>10,7</td> <td>^[0-9]+(?:,[0-9]+)*$</td> + </tr> + <tr> + <th scope="row">kpi</th> <td>No</td> <td>int</td> <td>7</td> <td>-</td> + </tr> + </tbody> + </table> + + <h3>Database</h3> + Saving information into the database to improve the recommender + <h4>/database/save/plan</h4> + <p> + Takes a json file that matches the structure that /plan/plan_detail creates and it stores it into the database.<br> + </p> + <p>Returns: <br> + Nothing <br> + </p> + <p>Input: <br> + A json file that matches the structure of the response of /planner/plan_detail + </p> +</div> +</body> +</html> \ No newline at end of file