diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..7f2de820687ee4621a7b8fd1549be0367c8d02cb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM tiangolo/uwsgi-nginx-flask:python3.10 + +RUN apt -qq -y update && apt -qq -y upgrade + +ENV STATIC_URL /static +ENV STATIC_PATH /var/www/app/static +COPY ./requirements_docker.txt /app/requirements.txt +RUN python -m pip install --no-cache-dir --index-url https://support.bayesfusion.com/pysmile-A/ pysmile +RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt +COPY . /app + +#EXPOSE 5000 +# Finally, we run uWSGI with the ini file we +# created earlier +#CMD [ "python", "./app/main.py" ] \ No newline at end of file diff --git a/README.md b/README.md index 94d0b432fe79ccc277ecef2cf152604c47e26b3d..45ad17cd1cc2f8708cbaf012d99b7ca5dd2529ba 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,11 @@ INSTALL python -m pip install --no-cache-dir --index-url https://support.bayesfusion.com/pysmile-A/ pysmile +Docker +https://hub.docker.com/r/tiangolo/uwsgi-nginx-flask + +docker compose -f docker-compose.yml up + ## Getting started To make it easy for you to get started with GitLab, here's a list of recommended next steps. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..5fc44b267da4d2bb5c44966f58771565f3889dc6 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,30 @@ +version: "3.9" +services: + urbanite: + build: +# build: . + context: . + dockerfile: ./Dockerfile + container_name: urbanite-api + depends_on: + - mysqldb + ports: + - "80:80" + links: + - mysqldb:mysql + mysqldb: + image: mysql + restart: always + ports: + - "3308:3306" + environment: + - MYSQL_ROOT_PASSWORD=admin + - MYSQL_DATABASE=urbanite_recommender + volumes: + #- db-data:/var/lib/mysql + - ./ddbb_scripts/Dump_urbanite_recommender.sql:/docker-entrypoint-initdb.d/urbanite_recommender.sql + +# Names our volume +volumes: + db-data: + driver: local diff --git a/extra_data/Dump20230302.zip b/extra_data/Dump20230302.zip new file mode 100644 index 0000000000000000000000000000000000000000..af81576ec78f828f9036ed2c10b8a909665b7873 Binary files /dev/null and b/extra_data/Dump20230302.zip differ diff --git a/main.py b/main.py new file mode 100644 index 0000000000000000000000000000000000000000..0ceb7bca5930b68d5b68694ca36832220a67669d --- /dev/null +++ b/main.py @@ -0,0 +1,303 @@ +#!/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, pysmile_license +from werkzeug.middleware.proxy_fix import ProxyFix + + +import mysql.connector +from flask import Flask, request, render_template + +from src import configuration, recommender, database, planner, modal_choice + +app = Flask(__name__) + +model = pickle.load(open('model.pkcls', 'rb')) +""" +net = pysmile.Network() +""" + +#CORS +from flask_cors import CORS +cors = CORS(app, resources={r"/*": {"origins": "*"}}) + +cnx = None + + +@app.route("/") +def index(): + return render_template("index.html") + + + +# MODAL CHOICE: ------------------------------------------------------------------------------------------------------- +@app.get("/modal_choice/getConfigurationFile") +def modal_choice_getconfigurationfile(): + """ + We ask for actions based on popularity of the actions + :return: json + """ + return modal_choice.modal_choice_getconfigurationfile(cnx, request) + + + + +@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) + +@app.get("/database/store/kpi") +def database_store_kpi(): + """ + 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 + +@app.get("/database/store/kpi_relative") +def database_store_kpi_relative(): + """ + 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, relative=True) + else: + return constants.ERROR_JSON_NEEDED + +@app.get("/database/store/kpi_area") +def database_store_kpi_area(): + """ + 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, area=True) + else: + return constants.ERROR_JSON_NEEDED + +@app.get("/database/store/kpi_relative_area") +def database_store_kpi_relative_area(): + """ + The json provided should have the same format that json with the kpi + """ + #if request.json: + if request: + return database.database_store_kpi_relative_area(cnx, request) + else: + return constants.ERROR_JSON_NEEDED + +# MAIN: ---------------------------------------------------------------------------------------------------------------- +if __name__ == "__main__": + """model = pickle.load(open('model.pkcls', 'rb')) + net = pysmile.Network() + net.read_file("URBANITE_ModalChoice.xdsl"); + """ + #cnx = mysql.connector.connect(**constants.DDBB_CONFIG) + user = 'root' + passwd = 'admin' + ip = 'mysql' + bd = 'urbanite_recommender' + cnx = "mysql+pymysql://%s:%s@%s/%s" % (user, passwd, ip, bd) + # app.run(debug=True, host='0.0.0.0') + # app.wsgi_app = ProxyFix( app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1) + diff --git a/requirements.txt b/requirements.txt index b57402671669020885201b9d048e6009fd8d7104..ab567178551e4a78e0b4697e770bf1b70d36d330 100644 --- a/requirements.txt +++ b/requirements.txt @@ -88,7 +88,7 @@ pyzmq==25.0.0 qasync==0.23.0 qtconsole==5.4.1 QtPy==2.3.0 -requests=2.28.2 +requests==2.28.2 rfc3986==1.5.0 scikit-learn==1.1.3 scipy==1.10.1 diff --git a/requirements_docker.txt b/requirements_docker.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f3169a0ba4e8c6202ae8c60d019c82a04b54853 --- /dev/null +++ b/requirements_docker.txt @@ -0,0 +1,7 @@ +Flask==2.2.3 +Flask-Cors==3.0.10 +mysql-connector-python~=8.0.32 +numpy==1.23.5 +Orange3==3.34.1 +requests==2.28.2 +xmltodict==0.13.0 diff --git a/uwsgi.ini b/uwsgi.ini new file mode 100644 index 0000000000000000000000000000000000000000..7a6dcccf47f0f720a3a203aaa3fa08da3c3a273d --- /dev/null +++ b/uwsgi.ini @@ -0,0 +1,4 @@ +[uwsgi] +module = main +callable = app +master = true