From 40a711cd7dc0f15dcaa70fbe2af0c749ffd28487 Mon Sep 17 00:00:00 2001 From: Campos Airas <d.campos@ibermatica.com> Date: Thu, 16 Mar 2023 10:18:03 +0100 Subject: [PATCH] [IMP] First version --- app.py | 227 ++++++++++++++++++++++++++++++++++++++ ejemplo.txt | 3 + kpis.json | 34 ++++++ kpis_area.json | 35 ++++++ requirements.txt | 6 ++ src/app - copia.py | 116 ++++++++++++++++++++ src/app.py | 5 +- src/configuration.py | 122 +++++++++++++++++++++ src/constants.py | 4 +- src/database.py | 2 +- src/load_data - copia.py | 123 +++++++++++++++++++++ src/load_data.py | 3 +- src/modal_choice.py | 87 +++++++++++++++ src/planner.py | 2 +- src/recommender.py | 2 +- src/templates/index.html | 228 +++++++++++++++++++++++++++++++++++++++ src/utils.py | 3 +- templates/index.html | 228 +++++++++++++++++++++++++++++++++++++++ 18 files changed, 1219 insertions(+), 11 deletions(-) create mode 100644 app.py create mode 100644 ejemplo.txt create mode 100644 kpis.json create mode 100644 kpis_area.json create mode 100644 requirements.txt create mode 100644 src/app - copia.py create mode 100644 src/configuration.py create mode 100644 src/load_data - copia.py create mode 100644 src/modal_choice.py create mode 100644 src/templates/index.html create mode 100644 templates/index.html diff --git a/app.py b/app.py new file mode 100644 index 0000000..bb94bca --- /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 0000000..528bea8 --- /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 0000000..a74b417 --- /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 0000000..0e43a74 --- /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 0000000..a048e94 --- /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 0000000..e603f06 --- /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 d2cec3e..d3a6890 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 0000000..419e0f2 --- /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 fa2a847..2a70500 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 a189c5c..c620498 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 0000000..8ec5476 --- /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 acaec83..fe49852 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 0000000..f0fc6e3 --- /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 565701e..92bb780 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 c99c05c..d72d60a 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 0000000..7c20f78 --- /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 2237afb..c8223de 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 0000000..7c20f78 --- /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 -- GitLab