diff --git a/README.md b/README.md index 88087a8722fc0eba17a7250faebd4c40e22abb12..a4d1a4db00d1369d842893548181b0a4a3f27ad0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Recommendation Engine - Alternative - +INSTALL +python -m pip install --index-url https://support.bayesfusion.com/pysmile-B/ pysmile ## Getting started diff --git a/app.py b/app.py index bb94bca2e0167c4394bf9a3776dcca07528971bb..111f00fd3805393629c67eec8463ad65727bf4dc 100644 --- a/app.py +++ b/app.py @@ -219,6 +219,17 @@ def planner_plan_detail(): """ return planner.planner_plan_detail(cnx, request) +@app.get("/database/store/kpi") +def database_store_kpi(): + """ + It stores the Kpis that have been selected. + The json provided should have the same format that json with the kpi + """ + #if request.json: + if request: + return database.database_store_kpi(cnx, request) + else: + return constants.ERROR_JSON_NEEDED # MAIN: ---------------------------------------------------------------------------------------------------------------- if __name__ == "__main__": diff --git a/ddbb scripts/.gitkeep b/ddbb scripts/.gitkeep deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/recommender_bayesian.sql b/ddbb scripts/recommender_bayesian.sql similarity index 100% rename from recommender_bayesian.sql rename to ddbb scripts/recommender_bayesian.sql diff --git a/recommender_geographic.sql b/ddbb scripts/recommender_geographic.sql similarity index 100% rename from recommender_geographic.sql rename to ddbb scripts/recommender_geographic.sql diff --git a/recommender_popularity.sql b/ddbb scripts/recommender_popularity.sql similarity index 100% rename from recommender_popularity.sql rename to ddbb scripts/recommender_popularity.sql diff --git a/recommender_preferences.sql b/ddbb scripts/recommender_preferences.sql similarity index 100% rename from recommender_preferences.sql rename to ddbb scripts/recommender_preferences.sql diff --git a/recommender_tags.sql b/ddbb scripts/recommender_tags.sql similarity index 100% rename from recommender_tags.sql rename to ddbb scripts/recommender_tags.sql diff --git a/ejemplo.txt b/ejemplo.txt deleted file mode 100644 index 528bea8aef078ee1429772d78d8239ecc2973d1f..0000000000000000000000000000000000000000 --- a/ejemplo.txt +++ /dev/null @@ -1,3 +0,0 @@ -prueba1 -prueba2 -prueba3 diff --git a/kpis.json b/extra_data/kpis.json similarity index 100% rename from kpis.json rename to extra_data/kpis.json diff --git a/kpis_area.json b/extra_data/kpis_area.json similarity index 100% rename from kpis_area.json rename to extra_data/kpis_area.json diff --git a/model.pkcls b/model.pkcls new file mode 100644 index 0000000000000000000000000000000000000000..e411d12e79697cd958f093cb976f947346f70662 Binary files /dev/null and b/model.pkcls differ diff --git a/requirements.txt b/requirements.txt index a048e9482b384977edee1535b1c0517a5ed1a95d..6bfca5ce52ee9b76af317fcbb0be77900a5be750 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,111 @@ -mysql-connector-python~=8.0.31 -Flask~=2.2.2 +anyio==3.6.2 +AnyQt==0.2.0 +asttokens==2.2.1 +backcall==0.2.0 +baycomp==1.0.2 +Bottleneck==1.3.7 +CacheControl==0.12.12 +certifi==2022.12.7 +cffi==1.15.1 +chardet==5.1.0 +charset-normalizer==3.0.1 +click==8.1.3 +comm==0.1.2 +commonmark==0.9.1 +contourpy==1.0.7 +cryptography==39.0.2 +cycler==0.11.0 +debugpy==1.6.6 +decorator==5.1.1 +dictdiffer==0.9.0 +docopt==0.6.2 +docutils==0.19 +et-xmlfile==1.1.0 +executing==1.2.0 +filelock==3.9.0 +Flask==2.2.3 +fonttools==4.39.0 +h11==0.14.0 +httpcore==0.16.3 +httpx==0.23.3 +idna==3.4 +importlib-metadata==6.0.0 +importlib-resources==5.12.0 +ipykernel==6.21.3 +ipython==8.11.0 +ipython-genutils==0.2.0 +itsdangerous==2.1.2 +jaraco.classes==3.2.3 +jedi==0.18.2 +jeepney==0.8.0 +Jinja2==3.1.2 +joblib==1.2.0 +jupyter_client==8.0.3 +jupyter_core==5.2.0 +keyring==23.13.1 +keyrings.alt==4.2.0 +kiwisolver==1.4.4 +MarkupSafe==2.1.2 +matplotlib==3.7.1 +matplotlib-inline==0.1.6 +more-itertools==9.1.0 +msgpack==1.0.5 +mysql-connector-python~=8.0.32 +nest-asyncio==1.5.6 +networkx==3.0 numpy~=1.23.5 -requests~=2.28.1 -pandas~=1.5.1 -utm~=0.7.0 \ No newline at end of file +openpyxl==3.1.2 +openTSNE==0.7.1 +orange-canvas-core==0.1.29 +orange-widget-base==4.19.0 +Orange3==3.34.1 +packaging==23.0 +pandas==1.5.3 +parso==0.8.3 +pexpect==4.8.0 +pickleshare==0.7.5 +Pillow==9.4.0 +pipreqs==0.4.11 +platformdirs==3.1.1 +prompt-toolkit==3.0.38 +protobuf==3.20.3 +psutil==5.9.4 +ptyprocess==0.7.0 +pure-eval==0.2.2 +pycparser==2.21 +Pygments==2.14.0 +pyparsing==3.0.9 +pyqtgraph==0.13.2 +pysmile==2.0.10 +python-dateutil==2.8.2 +python-louvain==0.16 +pytz==2022.7.1 +pywin32==305 +pywin32-ctypes==0.2.0 +PyYAML==6.0 +pyzmq==25.0.0 +qasync==0.23.0 +qtconsole==5.4.1 +QtPy==2.3.0 +requests=2.28.2 +rfc3986==1.5.0 +scikit-learn==1.1.3 +scipy==1.10.1 +SecretStorage==3.3.3 +serverfiles==0.3.1 +six==1.16.0 +sniffio==1.3.0 +stack-data==0.6.2 +threadpoolctl==3.1.0 +tornado==6.2 +traitlets==5.9.0 +typing_extensions==4.5.0 +urllib3==1.26.14 +utm==0.7.0 +wcwidth==0.2.6 +Werkzeug==2.2.3 +xlrd==2.0.1 +XlsxWriter==3.0.9 +xmltodict==0.13.0 +yarg==0.1.9 +zipp==3.14.0 diff --git a/src/app.py b/src/app.py index d3a68904124c656252b3230bafc0b2ab2afe29ba..ad17184eaf73d12f7ee81164fc8651eb8ca18ce2 100644 --- a/src/app.py +++ b/src/app.py @@ -4,16 +4,19 @@ 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 recommender, database, planner, modal_choice +from src import configuration, recommender, database, planner, modal_choice app = Flask(__name__) cnx = None @@ -24,6 +27,111 @@ 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(): @@ -101,6 +209,26 @@ def database_save_plan(): 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) + +@app.get("/database/store/kpi") +def database_store_kpi(): + """ + It stores the Kpis that have been selected. + The json provided should have the same format that json with the kpi + """ + #if request.json: + if request: + return database.database_store_kpi(cnx, request) + else: + return constants.ERROR_JSON_NEEDED # plan_detail PLANNER: ------------------------------------------------------------------------------------------------------- @app.get("/planner/plan_detail") @@ -114,5 +242,6 @@ def planner_plan_detail(): # 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/src/constants.py b/src/constants.py index 2a705001903c7c08e4d979fc7b6b61ac16a60531..0bb333dc9882eccfd793c39477856740aaf1fe9e 100644 --- a/src/constants.py +++ b/src/constants.py @@ -40,6 +40,7 @@ plan_JSON_TEMPLATE = dict(date=None, plan_details={0: {}, # Morning plan_detail # Load data PATH_plan_detailS = "data/Rutas" PATH_actionS = "data/actions" +PATH_extra = "../extra_data" # Load data - SQL queries sql_insert_action = """ @@ -51,12 +52,6 @@ sql_insert_kpi = """INSERT IGNORE INTO kpi(kpi_name) VALUES(%s)""" sql_get_kpi_ids = """SELECT kpi_name, kpi_id FROM kpi WHERE kpi_name IN ('{names}')""" -sql_insert_action_kpi = """ -INSERT IGNORE INTO kpi_action(action_id, kpi_id) -VALUES ( (SELECT action_id FROM action WHERE lat = %s AND lon = %s AND action_name = %s), - {kpi}) -""" - sql_insert_plan = """ INSERT IGNORE INTO plan(plan_date) VALUES(%s); @@ -78,3 +73,24 @@ INSERT IGNORE INTO CHOSEN_action(plan_id, time_slot, action_id) VALUES((SELECT plan_id FROM plan WHERE plan_date = '{date}'), %s, %s) """ + +sql_insert_kpi = """ +INSERT IGNORE INTO kpi (kpi_name, kpi_full_name, parent_id, kpi_level, popularity, use_case_id) +VALUES(%s, %s, %s, %s, %s, %s) +""" + +sql_get_kpis_data = """SELECT id, kpi_name, kpi_full_name, parent_id, kpi_level, popularity, use_case_id FROM kpi""" +sql_get_kpi_from_case_ids = """SELECT id, kpi_name, kpi_full_name, parent_id, kpi_level, popularity, use_case_id FROM kpi WHERE use_case_id IN (%s)""" + +sql_action_kpi = """SELECT id, action_id, kpi_id, kpi_name, use_case_id, absolute FROM kpi_action WHERE kpi_id = %s""" + +sql_insert_action_kpi = """ +INSERT IGNORE INTO kpi_action(action_id, kpi_id, kpi_name, use_case_id, absolute, relative, geographical, zoneId) +VALUES (%s, %s, %s, %s, %s, %s, %s, %s) +""" + +sql_update_action_kpi = """ +UPDATE kpi_action +SET action_id = %s, kpi_id = %s, kpi_name = %s, use_case_id = %s, absolute = %s, relative = %s, geographical = %s, zoneId = %s +WHERE kpi_id = %s +""" diff --git a/src/database.py b/src/database.py index c62049814bd78e97a6c51bcc300bb6980e89b63f..0d304f01915a580351f13a92abd9857edfa5cedb 100644 --- a/src/database.py +++ b/src/database.py @@ -7,6 +7,7 @@ Created on: 16/01/2023 """ from src import utils, constants +import json def __database_save_plan_detail__(cnx, otp_parameters, DDBB_params, intermediate_nodes): @@ -63,3 +64,128 @@ def database_save_plan(cnx, request): plan_detail["DDBBParameters"], intermediate_nodes) return constants.ALL_RIGHT + +def database_store_kpi(cnx, request): + """ + Stores kpi data from select json file in BD + :return: + """ + cursor = cnx.cursor(buffered=True) + dic = request.args.to_dict() + data = [key for key in dic.keys()] + file1 = open("../extra_data/%s" % data[0], "r") + file_contents= file1.read() + parsed_json = json.loads(file_contents) + keys_1_level = parsed_json.keys() + kpis_bd_bio_data = {} + pos = 0 + for key in keys_1_level: + if key == 'bilbao': + cursor.execute(constants.sql_get_kpi_from_case_ids, ['BIO']) + ret = cursor.fetchall() + for row in ret: + kpis_bd_bio_data[pos] = { + 'id': row[0], + 'kpi_name': row[1], + 'kpi_full_name': row[2], + 'parent_id': row[3], + 'kpi_level': row[4], + 'popularity': row[5], + 'use_case_id': row[6], + } + pos += 1 + load_json_kpi_data(cnx, parsed_json['bilbao'], 0, kpis_bd_bio_data, 'BIO') + +def kpi_by_name_level(cnx, kpi_name, kpi_level, case_id, parent_id=None): + cursor = cnx.cursor(buffered=True) + cursor.execute(constants.sql_get_kpi_from_case_ids, [case_id]) + ret = cursor.fetchall() + pos = 0 + kpis_dict = {} + for row in ret: + kpis_dict = { + 'id': row[0], + 'kpi_name': row[1], + 'kpi_full_name': row[2], + 'parent_id': row[3], + 'kpi_level': row[4], + 'popularity': row[5], + 'use_case_id': row[6], + } + if kpi_name in kpis_dict.values() and kpis_dict['kpi_level'] == kpi_level and kpis_dict['parent_id'] == parent_id: + return kpis_dict + kpi_full_name = kpi_name + if parent_id: + for row in ret: + if row[0] == parent_id: + kpi_full_name = '%s \ %s' % (row[2], kpi_name) + break + kpis_dict = { + 'kpi_name': kpi_name, + 'kpi_full_name': kpi_full_name, + 'parent_id': parent_id, + 'kpi_level': kpi_level, + 'popularity': 0, + 'use_case_id': 'BIO', + } + cursor.execute(constants.sql_insert_kpi, [kpi_name, kpi_full_name, parent_id, kpi_level, 0, case_id]) + cnx.commit() + last = cursor.lastrowid + kpis_dict['id'] = cursor.lastrowid + return kpis_dict + +def json_key_level(json, key, level=0): + # Devuelve el nivel del primero que encuentre + for json_key in json.keys(): + if key == json_key: + return level + else: + return json_level(json[json_key], key, level+1) + +def get_json_key_bd_data(key, level, kpis_bd_bio_data, parent_id): + ''' + :param key: Json key search + :param level: Key level + :param kpis_bd_bio_data: BD DATA + :return: Key data dict in BD or {} + ''' + bd_pos = 0 + for bd_pos in kpis_bd_bio_data: + if kpis_bd_bio_data[bd_pos]['kpi_name'] == key and kpis_bd_bio_data[bd_pos]['kpi_level'] == level and kpis_bd_bio_data[bd_pos]['parent_id'] == parent_id: + return kpis_bd_bio_data[bd_pos] + bd_pos +=1 + return {} + +def get_kpi_data_by_id(kpi_id, kpis_bd_bio_data): + ''' + :param kpi_id: kpi id in BD + :param kpis_bd_bio_data: BD DATA + :return: Key data dict in BD or {} + ''' + bd_pos = 0 + for bd_pos in kpis_bd_bio_data: + if kpis_bd_bio_data[bd_pos]['id'] == kpi_id: + return kpis_bd_bio_data[bd_pos] + return {} + +def update_kpi_action(cnx, value, kpi_name, case_id, parent_id): + cursor = cnx.cursor(buffered=True) + cursor.execute(constants.sql_action_kpi, [parent_id]) + ret = cursor.fetchall() + if ret: + cursor.execute(constants.sql_update_action_kpi, [4, parent_id, kpi_name, case_id, value, None, None, None, parent_id]) + else: + cursor.execute(constants.sql_insert_action_kpi, [4, parent_id, kpi_name, case_id, value, None, None, None]) + cnx.commit() + +def load_json_kpi_data(cnx, json, level, kpis_bd_bio_data, case_id, parent_id=None): + if isinstance(json, dict): + for json_key in json.keys(): + key_data = get_json_key_bd_data(json_key, level, kpis_bd_bio_data, parent_id) + if not key_data: + key_data = kpi_by_name_level(cnx, json_key, level, case_id, parent_id) + load_json_kpi_data(cnx, json[json_key], level+1, kpis_bd_bio_data, case_id, key_data['id']) + else: + parent_dict = get_kpi_data_by_id(parent_id, kpis_bd_bio_data) + if parent_dict: + update_kpi_action(cnx, json, parent_dict['kpi_name'], case_id, parent_dict['id'])