From 543944cb27cd37e5a84684b2dfa7844bb7f8eb87 Mon Sep 17 00:00:00 2001 From: faysal Date: Mon, 10 Mar 2025 16:42:17 +0000 Subject: [PATCH 1/2] Initialized Flask web app with basic structure: Set up app routes, templates, static files, and a homepage. --- src/app.py | 269 ++++++++++++++++++ .../15312c6817dee9ca56473a5245415fc0 | Bin 0 -> 23833 bytes .../2029240f6d1128be89ddc32729463129 | Bin 0 -> 9 bytes src/readme_app.md | 28 ++ src/static/css/style.css | 41 +++ src/templates/base.html | 73 +++++ src/templates/doe.html | 25 ++ src/templates/exploration.html | 138 +++++++++ src/templates/index.html | 14 + src/templates/index.html:Zone.Identifier | 0 src/templates/predict.html | 32 +++ src/templates/results.html | 17 ++ src/templates/results.html:Zone.Identifier | 0 src/templates/train.html | 103 +++++++ ...f2-5e1102565abb_smlp_toy_num_resp_mult.csv | 12 + ...412c-8c28-7813e4047477_smlp_toy_basic.spec | 23 ++ ...-4186-b5dd-d5756a90711e_smlp_toy_basic.csv | 11 + ...9399_smlp_toy_num_resp_mult_free_inps.spec | 1 + ...4823-8e43-0e2c1f8eea26_smlp_toy_basic.spec | 23 ++ ...04-2357f978bef8_smlp_toy_num_resp_mult.csv | 12 + ...2831_smlp_toy_num_resp_mult_free_inps.spec | 1 + ...-4e22-be47-f8df9eb88a5e_smlp_toy_basic.csv | 11 + ...47b5-aa3e-e2f0da50e0fe_smlp_toy_basic.spec | 23 ++ ...-46c0-a97e-3a40ad946fa6_smlp_toy_basic.csv | 11 + ...-4f50-806b-eb86c0c6ab16_smlp_toy_basic.csv | 11 + ...4d51-9f33-cf70042e69af_smlp_toy_basic.spec | 23 ++ 26 files changed, 902 insertions(+) create mode 100644 src/app.py create mode 100644 src/flask_session/15312c6817dee9ca56473a5245415fc0 create mode 100644 src/flask_session/2029240f6d1128be89ddc32729463129 create mode 100644 src/readme_app.md create mode 100644 src/static/css/style.css create mode 100644 src/templates/base.html create mode 100644 src/templates/doe.html create mode 100644 src/templates/exploration.html create mode 100644 src/templates/index.html create mode 100644 src/templates/index.html:Zone.Identifier create mode 100644 src/templates/predict.html create mode 100644 src/templates/results.html create mode 100644 src/templates/results.html:Zone.Identifier create mode 100644 src/templates/train.html create mode 100644 src/uploads/0b0ee21e-ee7c-4601-8ff2-5e1102565abb_smlp_toy_num_resp_mult.csv create mode 100644 src/uploads/141f263c-1c23-412c-8c28-7813e4047477_smlp_toy_basic.spec create mode 100644 src/uploads/501bbff2-ab6d-4186-b5dd-d5756a90711e_smlp_toy_basic.csv create mode 100644 src/uploads/6374879d-9342-4d70-8b8c-fdd73c0b9399_smlp_toy_num_resp_mult_free_inps.spec create mode 100644 src/uploads/7dedf43f-1b87-4823-8e43-0e2c1f8eea26_smlp_toy_basic.spec create mode 100644 src/uploads/80ca933c-3a5e-4354-a604-2357f978bef8_smlp_toy_num_resp_mult.csv create mode 100644 src/uploads/83347cf7-2773-45f0-ad6c-c2e1bf782831_smlp_toy_num_resp_mult_free_inps.spec create mode 100644 src/uploads/93f33a35-4eb3-4e22-be47-f8df9eb88a5e_smlp_toy_basic.csv create mode 100644 src/uploads/9b9674a3-31a0-47b5-aa3e-e2f0da50e0fe_smlp_toy_basic.spec create mode 100644 src/uploads/b6533bc5-d317-46c0-a97e-3a40ad946fa6_smlp_toy_basic.csv create mode 100644 src/uploads/c43061ee-8af0-4f50-806b-eb86c0c6ab16_smlp_toy_basic.csv create mode 100644 src/uploads/d4b63a65-b208-4d51-9f33-cf70042e69af_smlp_toy_basic.spec diff --git a/src/app.py b/src/app.py new file mode 100644 index 00000000..7ede9fac --- /dev/null +++ b/src/app.py @@ -0,0 +1,269 @@ + +import subprocess +from flask import Flask, render_template, request, redirect, url_for, session +import os +import sys +import uuid +from flask_session import Session + +# Flask App Setup +app = Flask(__name__) + +app.config['SECRET_KEY'] = os.environ.get('FLASK_SECRET_KEY', 'dev_secret_key') +app.config['SESSION_TYPE'] = 'filesystem' +Session(app) + + +UPLOAD_FOLDER = os.path.join(os.getcwd(), 'uploads') +os.makedirs(UPLOAD_FOLDER, exist_ok=True) +app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER + + + +def call_smlp_api( argument_list): + """ + mode: 'train', 'predict', 'verify', 'optimize', etc. + argument_list: e.g. ["-data", "my_dataset", "-resp", "y1,y2", ...] + """ + + cmd_string = " ".join(argument_list) + + + cwd_dir = os.path.abspath("../regr_smlp/code/") + try: + result = subprocess.run( + argument_list, + capture_output=True, + text=True, + cwd=cwd_dir + ) + full_output = f"STDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}" + print("DEBUG: Command output ->", full_output) + return result.stdout.strip() if result.returncode == 0 else full_output + + except Exception as e: + return f"Error calling SMLP: {str(e)}" + + +# HOME +@app.route('/') +def home(): + return render_template('index.html') + +# TRAIN +@app.route('/train', methods=['GET', 'POST']) +def train(): + if request.method == 'POST': + data_file = request.files.get('data_file') + dataset_path = None + + if data_file and data_file.filename: + dataset_path = os.path.join(app.config['UPLOAD_FOLDER'], f"{uuid.uuid4()}_{data_file.filename}") + data_file.save(dataset_path) + + def add_arg(flag, value): + if value is not None and value != "": + arguments.extend([flag, str(value)]) + + arguments = ['python3', os.path.abspath("../src/run_smlp.py")] + + if not dataset_path : + return "Error: Missing required dataset or spec file", 400 + + # Required arguments + + add_arg("-data", os.path.abspath(dataset_path)) + add_arg("-out_dir", request.form.get('out_dir_val', './')) + add_arg("-pref", request.form.get('pref_val', 'TestTrain')) + add_arg("-mode", "train") + add_arg("-model", request.form.get('model')) + add_arg("-dt_sklearn_max_depth", request.form.get('dt_sklearn_max_depth')) + add_arg("-mrmr_pred", request.form.get('mrmr_pred')) + add_arg("-resp", request.form.get('resp')) + add_arg("-feat", request.form.get('feat')) + add_arg("-save_model", request.form.get('save_model')) + add_arg("-model_name", request.form.get('model_name')) + add_arg("-scale_feat", request.form.get('scale_feat')) + add_arg("-scale_resp", request.form.get('scale_resp')) + add_arg("-dt_sklearn_max_depth", request.form.get('dt_sklearn_max_depth')) + add_arg("-train_split", request.form.get('train_split')) + add_arg("-seed", request.form.get('seed_val')) + add_arg("-plots", request.form.get('plots')) + + additional_command = request.form.get('additional_command') + if additional_command: + arguments.append(additional_command) + + # Debugging + print("DEBUG: Final SMLP Command ->", " ".join(arguments)) + + output = call_smlp_api(arguments) + session['output'] = output + return redirect(url_for('results')) + + return render_template('train.html') + + + +# PREDICT + + +# !!! To be done !!! + + +@app.route('/predict', methods=['GET', 'POST']) +def predict(): + if request.method == 'POST': + model_file = request.files.get('model_file') + new_data_file = request.files.get('new_data_file') + save_model = request.form.get('save_model', 'f') + model_name = request.form.get('model_name', 'my_model') + + model_path = None + if model_file and model_file.filename: + filename = f"{uuid.uuid4()}_{model_file.filename}" + model_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) + model_file.save(model_path) + + newdata_path = None + if new_data_file and new_data_file.filename: + filename = f"{uuid.uuid4()}_{new_data_file.filename}" + newdata_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) + new_data_file.save(newdata_path) + + arguments = [] + if model_path: + base_name, ext = os.path.splitext(model_path) + arguments += ["-use_model", "t", "-model_name", base_name] + + if newdata_path: + base_new_name, _ = os.path.splitext(newdata_path) + arguments += ["-new_data", base_new_name] + + if save_model == 't': + arguments += ["-save_model", "t", "-model_name", model_name] + + output = call_smlp_api("predict", arguments) + session['output'] = output + return redirect(url_for('results')) + + return render_template('predict.html') + + + + +# EXPLORATION +@app.route('/explore', methods=['GET', 'POST']) +def explore(): + modes_list = ['certify', 'query', 'verify', 'synthesize', 'optimize', 'optsyn'] + + if request.method == 'POST': + chosen_mode = request.form.get('explore_mode', '') + + if chosen_mode not in modes_list: + return "Error: Invalid mode selected", 400 + + data_file = request.files.get('data_file') + spec_file = request.files.get('spec_file') + + dataset_path = None + spec_path = None + + if data_file and data_file.filename: + dataset_path = os.path.join(app.config['UPLOAD_FOLDER'], f"{uuid.uuid4()}_{data_file.filename}") + data_file.save(dataset_path) + + if spec_file and spec_file.filename: + spec_path = os.path.join(app.config['UPLOAD_FOLDER'], f"{uuid.uuid4()}_{spec_file.filename}") + spec_file.save(spec_path) + + if not dataset_path or not spec_path: + return "Error: Missing required dataset or spec file", 400 + + arguments = ['python3', os.path.abspath("../src/run_smlp.py")] + + def add_arg(flag, value): + """Helper function to add arguments only if they are not empty.""" + if value is not None and value != "": + arguments.extend([flag, str(value)]) + + # Required arguments + add_arg("-data", os.path.abspath(dataset_path)) + add_arg("-out_dir", request.form.get('out_dir_val', './')) + add_arg("-pref", request.form.get('pref_val', 'Test113')) + add_arg("-mode", chosen_mode) + add_arg("-spec", os.path.abspath(spec_path)) + add_arg("-pareto", request.form.get('pareto')) + add_arg("-resp", request.form.get('resp_expr')) + add_arg("-feat", request.form.get('feat_expr')) + add_arg("-model", request.form.get('model_expr')) + add_arg("-dt_sklearn_max_depth", request.form.get('dt_sklearn_max_depth')) + add_arg("-mrmr_pred", request.form.get('mrmr_pred')) + add_arg("-epsilon", request.form.get('epsilon')) + add_arg("-delta_rel", request.form.get('delta_rel')) + add_arg("-save_model_config", request.form.get('save_model_config')) + add_arg("-plots", request.form.get('plots')) + add_arg("-log_time", request.form.get('log_time')) + add_arg("-seed", request.form.get('seed_val')) + add_arg("-objv_names", request.form.get('objv_names')) + add_arg("-objv_exprs", request.form.get('objv_exprs')) + + + additional_command = request.form.get('additional_command') + if additional_command: + arguments.append(additional_command) + + # Debugging + print("DEBUG: Final SMLP Command ->", " ".join(arguments)) + + output = call_smlp_api(arguments) + session['output'] = output + return redirect(url_for('results')) + + return render_template('exploration.html', modes=modes_list) + + +# DOE + +# !!! To be done !!! + +@app.route('/doe', methods=['GET', 'POST']) +def doe(): + """ + Let the user pick DOE options and pass them to SMLP in 'doe' mode. + """ + if request.method == 'POST': + doe_spec_file = request.files.get('doe_spec_file') + doe_algo = request.form.get('doe_algo') + doe_num_samples = request.form.get('doe_num_samples', '') + + arguments = [] + if doe_spec_file and doe_spec_file.filename: + specname = f"{uuid.uuid4()}_{doe_spec_file.filename}" + spec_path = os.path.join(app.config['UPLOAD_FOLDER'], specname) + doe_spec_file.save(spec_path) + base_spec, _ = os.path.splitext(spec_path) + arguments += ["-doe_spec", base_spec] + + if doe_algo: + arguments += ["-doe_algo", doe_algo] + if doe_num_samples: + arguments += ["-doe_num_samples", doe_num_samples] + + output = call_smlp_api("doe", arguments) + session['output'] = output + return redirect(url_for('results')) + + return render_template('doe.html') + +# RESULTS +@app.route('/results') +def results(): + output = session.get('output', 'No output available yet.') + print("\n--- RESULTS ---") + print(output) + return render_template('results.html', output=output) + +# MAIN +if __name__ == '__main__': + app.run(debug=False, use_reloader=False) diff --git a/src/flask_session/15312c6817dee9ca56473a5245415fc0 b/src/flask_session/15312c6817dee9ca56473a5245415fc0 new file mode 100644 index 0000000000000000000000000000000000000000..cfaca736884ef07d363f16637fc30f1f4e4dd84a GIT binary patch literal 23833 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 + + + + + SMLP Dashboard + + + + + + + +
+
+ {% block content %}{% endblock %} +
+
+ + + + + \ No newline at end of file diff --git a/src/templates/doe.html b/src/templates/doe.html new file mode 100644 index 00000000..6e0e8544 --- /dev/null +++ b/src/templates/doe.html @@ -0,0 +1,25 @@ +{% extends "base.html" %} +{% block content %} +

Design of Experiments (DOE)

+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+{% endblock %} diff --git a/src/templates/exploration.html b/src/templates/exploration.html new file mode 100644 index 00000000..027c2213 --- /dev/null +++ b/src/templates/exploration.html @@ -0,0 +1,138 @@ +{% extends "base.html" %} +{% block content %} +

Explore SMLP

+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ + + + + +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+ + +
+ +
+ +
+ + + + + +
+
+ +
+ +
+ + + + + +
+ + + +
+ +
+ +{% endblock %} diff --git a/src/templates/index.html b/src/templates/index.html new file mode 100644 index 00000000..1958bcc0 --- /dev/null +++ b/src/templates/index.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} +{% block content %} +
+

Welcome to SMLP Dashboard

+

A powerful web interface for training, predicting, exploring, and DOE with SMLP.

+ +
+ Train + Predict + Explore + DOE +
+
+{% endblock %} \ No newline at end of file diff --git a/src/templates/index.html:Zone.Identifier b/src/templates/index.html:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/src/templates/predict.html b/src/templates/predict.html new file mode 100644 index 00000000..1cb7ad0e --- /dev/null +++ b/src/templates/predict.html @@ -0,0 +1,32 @@ +{% extends "base.html" %} +{% block content %} +

Predict with a Trained Model

+
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+{% endblock %} diff --git a/src/templates/results.html b/src/templates/results.html new file mode 100644 index 00000000..77a0c757 --- /dev/null +++ b/src/templates/results.html @@ -0,0 +1,17 @@ +{% extends "base.html" %} +{% block content %} +
+
+
+

Results

+
+
+
{{ output }}
+
+ +
+
+{% endblock %} \ No newline at end of file diff --git a/src/templates/results.html:Zone.Identifier b/src/templates/results.html:Zone.Identifier new file mode 100644 index 00000000..e69de29b diff --git a/src/templates/train.html b/src/templates/train.html new file mode 100644 index 00000000..78cc526c --- /dev/null +++ b/src/templates/train.html @@ -0,0 +1,103 @@ +{% extends "base.html" %} +{% block content %} +

Train a Model

+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ + + + + +
+
+ +
+ + +
+ + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ + + + + +
+
+ +
+ + +
+ +
+ +
+
+{% endblock %} diff --git a/src/uploads/0b0ee21e-ee7c-4601-8ff2-5e1102565abb_smlp_toy_num_resp_mult.csv b/src/uploads/0b0ee21e-ee7c-4601-8ff2-5e1102565abb_smlp_toy_num_resp_mult.csv new file mode 100644 index 00000000..6a401612 --- /dev/null +++ b/src/uploads/0b0ee21e-ee7c-4601-8ff2-5e1102565abb_smlp_toy_num_resp_mult.csv @@ -0,0 +1,12 @@ +categ,y1,y2,x,p1,p2 +c14,5,9,10.0,2.0,3 +c15,9,9,12.0,,4 +c1,5,9,,3.0,4 +c9,5,5,11.0,2.0,6 +c5,9,5,10.0,2.0,8 +c10,9,9,9.0,4.0,7 +c13,5,5,9.0,3.0,6 +c4,5,5,10.0,3.0,4 +c15,9,9,11.0,4.0,4 +c11,5,5,12.0,2.0,7 +c19,9,5,10.0,3.0,7 diff --git a/src/uploads/141f263c-1c23-412c-8c28-7813e4047477_smlp_toy_basic.spec b/src/uploads/141f263c-1c23-412c-8c28-7813e4047477_smlp_toy_basic.spec new file mode 100644 index 00000000..bdca0618 --- /dev/null +++ b/src/uploads/141f263c-1c23-412c-8c28-7813e4047477_smlp_toy_basic.spec @@ -0,0 +1,23 @@ +{ + "version": "1.2", + "variables": [ + {"label":"y1", "interface":"output", "type":"real"}, + {"label":"y2", "interface":"output", "type":"real"}, + {"label":"x1", "interface":"input", "type":"real", "range":[0,10]}, + {"label":"x2", "interface":"input", "type":"int", "range":[-1,1]}, + {"label":"p1", "interface":"knob", "type":"real", "range":[0,10], "rad-rel":0.1, "grid":[2,4,7]}, + {"label":"p2", "interface":"knob", "type":"int", "range":[3,7], "rad-abs":0.2} + ], + "alpha": "p2<5 and x1==10 and x2<12", + "beta": "y1>=4 and y2>=8", + "eta": "p1==4 or (p1==8 and p2 > 3)", + "assertions": { + "assert1": "(y2**3+p2)/2>6", + "assert2": "y1>=0", + "assert3": "y2>0" + }, + "objectives": { + "objective1": "(y1+y2)/2", + "objective2": "y1" + } +} diff --git a/src/uploads/501bbff2-ab6d-4186-b5dd-d5756a90711e_smlp_toy_basic.csv b/src/uploads/501bbff2-ab6d-4186-b5dd-d5756a90711e_smlp_toy_basic.csv new file mode 100644 index 00000000..7704d94d --- /dev/null +++ b/src/uploads/501bbff2-ab6d-4186-b5dd-d5756a90711e_smlp_toy_basic.csv @@ -0,0 +1,11 @@ +x1,x2,p1,p2,y1,y2 +2.98,-1,0.1,4,5.0233,8 +8.553,-1,3.9,3,0.6936,12.02 +0.558,1,2,4,0.6882,8.14 +3.867,0,1.1,3,0.24,8 +-0.8218,0,4,3,0.324,8 +5.252,0,4,5,6.03,8 +0.2998,1,7.1,6,0.91,10.125 +7.175,1,7,7,0.96,1.12 +9.546,0,7,6,10.7007,9.5661 +-0.454,1,10,7,8.7932,6.4015 diff --git a/src/uploads/6374879d-9342-4d70-8b8c-fdd73c0b9399_smlp_toy_num_resp_mult_free_inps.spec b/src/uploads/6374879d-9342-4d70-8b8c-fdd73c0b9399_smlp_toy_num_resp_mult_free_inps.spec new file mode 100644 index 00000000..0b0cc663 --- /dev/null +++ b/src/uploads/6374879d-9342-4d70-8b8c-fdd73c0b9399_smlp_toy_num_resp_mult_free_inps.spec @@ -0,0 +1 @@ +{"version": "1.1", "spec": [{"label": "y1", "type": "response", "range": "float"}, {"label": "y2", "type": "response", "range": "float"}, {"label": "x", "type": "input", "range": "float", "bounds":[-2, null]}, {"label": "p1", "type": "knob", "range": "float", "rad-rel": 0.1, "grid": [2,4,7], "bounds":[4,8]}, {"label": "p2", "type": "knob", "range": "float", "rad-abs": 0.2, "bounds": [3,7]}]} diff --git a/src/uploads/7dedf43f-1b87-4823-8e43-0e2c1f8eea26_smlp_toy_basic.spec b/src/uploads/7dedf43f-1b87-4823-8e43-0e2c1f8eea26_smlp_toy_basic.spec new file mode 100644 index 00000000..bdca0618 --- /dev/null +++ b/src/uploads/7dedf43f-1b87-4823-8e43-0e2c1f8eea26_smlp_toy_basic.spec @@ -0,0 +1,23 @@ +{ + "version": "1.2", + "variables": [ + {"label":"y1", "interface":"output", "type":"real"}, + {"label":"y2", "interface":"output", "type":"real"}, + {"label":"x1", "interface":"input", "type":"real", "range":[0,10]}, + {"label":"x2", "interface":"input", "type":"int", "range":[-1,1]}, + {"label":"p1", "interface":"knob", "type":"real", "range":[0,10], "rad-rel":0.1, "grid":[2,4,7]}, + {"label":"p2", "interface":"knob", "type":"int", "range":[3,7], "rad-abs":0.2} + ], + "alpha": "p2<5 and x1==10 and x2<12", + "beta": "y1>=4 and y2>=8", + "eta": "p1==4 or (p1==8 and p2 > 3)", + "assertions": { + "assert1": "(y2**3+p2)/2>6", + "assert2": "y1>=0", + "assert3": "y2>0" + }, + "objectives": { + "objective1": "(y1+y2)/2", + "objective2": "y1" + } +} diff --git a/src/uploads/80ca933c-3a5e-4354-a604-2357f978bef8_smlp_toy_num_resp_mult.csv b/src/uploads/80ca933c-3a5e-4354-a604-2357f978bef8_smlp_toy_num_resp_mult.csv new file mode 100644 index 00000000..6a401612 --- /dev/null +++ b/src/uploads/80ca933c-3a5e-4354-a604-2357f978bef8_smlp_toy_num_resp_mult.csv @@ -0,0 +1,12 @@ +categ,y1,y2,x,p1,p2 +c14,5,9,10.0,2.0,3 +c15,9,9,12.0,,4 +c1,5,9,,3.0,4 +c9,5,5,11.0,2.0,6 +c5,9,5,10.0,2.0,8 +c10,9,9,9.0,4.0,7 +c13,5,5,9.0,3.0,6 +c4,5,5,10.0,3.0,4 +c15,9,9,11.0,4.0,4 +c11,5,5,12.0,2.0,7 +c19,9,5,10.0,3.0,7 diff --git a/src/uploads/83347cf7-2773-45f0-ad6c-c2e1bf782831_smlp_toy_num_resp_mult_free_inps.spec b/src/uploads/83347cf7-2773-45f0-ad6c-c2e1bf782831_smlp_toy_num_resp_mult_free_inps.spec new file mode 100644 index 00000000..0b0cc663 --- /dev/null +++ b/src/uploads/83347cf7-2773-45f0-ad6c-c2e1bf782831_smlp_toy_num_resp_mult_free_inps.spec @@ -0,0 +1 @@ +{"version": "1.1", "spec": [{"label": "y1", "type": "response", "range": "float"}, {"label": "y2", "type": "response", "range": "float"}, {"label": "x", "type": "input", "range": "float", "bounds":[-2, null]}, {"label": "p1", "type": "knob", "range": "float", "rad-rel": 0.1, "grid": [2,4,7], "bounds":[4,8]}, {"label": "p2", "type": "knob", "range": "float", "rad-abs": 0.2, "bounds": [3,7]}]} diff --git a/src/uploads/93f33a35-4eb3-4e22-be47-f8df9eb88a5e_smlp_toy_basic.csv b/src/uploads/93f33a35-4eb3-4e22-be47-f8df9eb88a5e_smlp_toy_basic.csv new file mode 100644 index 00000000..7704d94d --- /dev/null +++ b/src/uploads/93f33a35-4eb3-4e22-be47-f8df9eb88a5e_smlp_toy_basic.csv @@ -0,0 +1,11 @@ +x1,x2,p1,p2,y1,y2 +2.98,-1,0.1,4,5.0233,8 +8.553,-1,3.9,3,0.6936,12.02 +0.558,1,2,4,0.6882,8.14 +3.867,0,1.1,3,0.24,8 +-0.8218,0,4,3,0.324,8 +5.252,0,4,5,6.03,8 +0.2998,1,7.1,6,0.91,10.125 +7.175,1,7,7,0.96,1.12 +9.546,0,7,6,10.7007,9.5661 +-0.454,1,10,7,8.7932,6.4015 diff --git a/src/uploads/9b9674a3-31a0-47b5-aa3e-e2f0da50e0fe_smlp_toy_basic.spec b/src/uploads/9b9674a3-31a0-47b5-aa3e-e2f0da50e0fe_smlp_toy_basic.spec new file mode 100644 index 00000000..bdca0618 --- /dev/null +++ b/src/uploads/9b9674a3-31a0-47b5-aa3e-e2f0da50e0fe_smlp_toy_basic.spec @@ -0,0 +1,23 @@ +{ + "version": "1.2", + "variables": [ + {"label":"y1", "interface":"output", "type":"real"}, + {"label":"y2", "interface":"output", "type":"real"}, + {"label":"x1", "interface":"input", "type":"real", "range":[0,10]}, + {"label":"x2", "interface":"input", "type":"int", "range":[-1,1]}, + {"label":"p1", "interface":"knob", "type":"real", "range":[0,10], "rad-rel":0.1, "grid":[2,4,7]}, + {"label":"p2", "interface":"knob", "type":"int", "range":[3,7], "rad-abs":0.2} + ], + "alpha": "p2<5 and x1==10 and x2<12", + "beta": "y1>=4 and y2>=8", + "eta": "p1==4 or (p1==8 and p2 > 3)", + "assertions": { + "assert1": "(y2**3+p2)/2>6", + "assert2": "y1>=0", + "assert3": "y2>0" + }, + "objectives": { + "objective1": "(y1+y2)/2", + "objective2": "y1" + } +} diff --git a/src/uploads/b6533bc5-d317-46c0-a97e-3a40ad946fa6_smlp_toy_basic.csv b/src/uploads/b6533bc5-d317-46c0-a97e-3a40ad946fa6_smlp_toy_basic.csv new file mode 100644 index 00000000..7704d94d --- /dev/null +++ b/src/uploads/b6533bc5-d317-46c0-a97e-3a40ad946fa6_smlp_toy_basic.csv @@ -0,0 +1,11 @@ +x1,x2,p1,p2,y1,y2 +2.98,-1,0.1,4,5.0233,8 +8.553,-1,3.9,3,0.6936,12.02 +0.558,1,2,4,0.6882,8.14 +3.867,0,1.1,3,0.24,8 +-0.8218,0,4,3,0.324,8 +5.252,0,4,5,6.03,8 +0.2998,1,7.1,6,0.91,10.125 +7.175,1,7,7,0.96,1.12 +9.546,0,7,6,10.7007,9.5661 +-0.454,1,10,7,8.7932,6.4015 diff --git a/src/uploads/c43061ee-8af0-4f50-806b-eb86c0c6ab16_smlp_toy_basic.csv b/src/uploads/c43061ee-8af0-4f50-806b-eb86c0c6ab16_smlp_toy_basic.csv new file mode 100644 index 00000000..7704d94d --- /dev/null +++ b/src/uploads/c43061ee-8af0-4f50-806b-eb86c0c6ab16_smlp_toy_basic.csv @@ -0,0 +1,11 @@ +x1,x2,p1,p2,y1,y2 +2.98,-1,0.1,4,5.0233,8 +8.553,-1,3.9,3,0.6936,12.02 +0.558,1,2,4,0.6882,8.14 +3.867,0,1.1,3,0.24,8 +-0.8218,0,4,3,0.324,8 +5.252,0,4,5,6.03,8 +0.2998,1,7.1,6,0.91,10.125 +7.175,1,7,7,0.96,1.12 +9.546,0,7,6,10.7007,9.5661 +-0.454,1,10,7,8.7932,6.4015 diff --git a/src/uploads/d4b63a65-b208-4d51-9f33-cf70042e69af_smlp_toy_basic.spec b/src/uploads/d4b63a65-b208-4d51-9f33-cf70042e69af_smlp_toy_basic.spec new file mode 100644 index 00000000..bdca0618 --- /dev/null +++ b/src/uploads/d4b63a65-b208-4d51-9f33-cf70042e69af_smlp_toy_basic.spec @@ -0,0 +1,23 @@ +{ + "version": "1.2", + "variables": [ + {"label":"y1", "interface":"output", "type":"real"}, + {"label":"y2", "interface":"output", "type":"real"}, + {"label":"x1", "interface":"input", "type":"real", "range":[0,10]}, + {"label":"x2", "interface":"input", "type":"int", "range":[-1,1]}, + {"label":"p1", "interface":"knob", "type":"real", "range":[0,10], "rad-rel":0.1, "grid":[2,4,7]}, + {"label":"p2", "interface":"knob", "type":"int", "range":[3,7], "rad-abs":0.2} + ], + "alpha": "p2<5 and x1==10 and x2<12", + "beta": "y1>=4 and y2>=8", + "eta": "p1==4 or (p1==8 and p2 > 3)", + "assertions": { + "assert1": "(y2**3+p2)/2>6", + "assert2": "y1>=0", + "assert3": "y2>0" + }, + "objectives": { + "objective1": "(y1+y2)/2", + "objective2": "y1" + } +} From f17450bab34304b0b792bcc82c56b302d82044e4 Mon Sep 17 00:00:00 2001 From: faysal Date: Fri, 21 Mar 2025 15:27:15 +0000 Subject: [PATCH 2/2] Implemented test files, added 3D visualizer, and handled file path routing for all website pages --- src/app.py | 165 +++++++++---- .../15312c6817dee9ca56473a5245415fc0 | Bin 23833 -> 0 bytes .../2029240f6d1128be89ddc32729463129 | Bin 9 -> 0 bytes src/smlp_py/smlp_plots.py | 35 ++- src/templates/base.html | 5 +- src/templates/doe.html | 38 ++- src/templates/exploration.html | 2 +- src/templates/predict.html | 51 +++- src/templates/results.html | 77 +++++- src/templates/train.html | 2 +- src/test_app.py | 226 ++++++++++++++++++ src/test_visual.py | 102 ++++++++ ...f2-5e1102565abb_smlp_toy_num_resp_mult.csv | 12 - ...412c-8c28-7813e4047477_smlp_toy_basic.spec | 23 -- ...-4186-b5dd-d5756a90711e_smlp_toy_basic.csv | 11 - ...9399_smlp_toy_num_resp_mult_free_inps.spec | 1 - ...4823-8e43-0e2c1f8eea26_smlp_toy_basic.spec | 23 -- ...04-2357f978bef8_smlp_toy_num_resp_mult.csv | 12 - ...2831_smlp_toy_num_resp_mult_free_inps.spec | 1 - ...-4e22-be47-f8df9eb88a5e_smlp_toy_basic.csv | 11 - ...47b5-aa3e-e2f0da50e0fe_smlp_toy_basic.spec | 23 -- ...-46c0-a97e-3a40ad946fa6_smlp_toy_basic.csv | 11 - ...-4f50-806b-eb86c0c6ab16_smlp_toy_basic.csv | 11 - ...4d51-9f33-cf70042e69af_smlp_toy_basic.spec | 23 -- src/visualize_h5.py | 110 +++++++++ 25 files changed, 729 insertions(+), 246 deletions(-) delete mode 100644 src/flask_session/15312c6817dee9ca56473a5245415fc0 delete mode 100644 src/flask_session/2029240f6d1128be89ddc32729463129 create mode 100644 src/test_app.py create mode 100644 src/test_visual.py delete mode 100644 src/uploads/0b0ee21e-ee7c-4601-8ff2-5e1102565abb_smlp_toy_num_resp_mult.csv delete mode 100644 src/uploads/141f263c-1c23-412c-8c28-7813e4047477_smlp_toy_basic.spec delete mode 100644 src/uploads/501bbff2-ab6d-4186-b5dd-d5756a90711e_smlp_toy_basic.csv delete mode 100644 src/uploads/6374879d-9342-4d70-8b8c-fdd73c0b9399_smlp_toy_num_resp_mult_free_inps.spec delete mode 100644 src/uploads/7dedf43f-1b87-4823-8e43-0e2c1f8eea26_smlp_toy_basic.spec delete mode 100644 src/uploads/80ca933c-3a5e-4354-a604-2357f978bef8_smlp_toy_num_resp_mult.csv delete mode 100644 src/uploads/83347cf7-2773-45f0-ad6c-c2e1bf782831_smlp_toy_num_resp_mult_free_inps.spec delete mode 100644 src/uploads/93f33a35-4eb3-4e22-be47-f8df9eb88a5e_smlp_toy_basic.csv delete mode 100644 src/uploads/9b9674a3-31a0-47b5-aa3e-e2f0da50e0fe_smlp_toy_basic.spec delete mode 100644 src/uploads/b6533bc5-d317-46c0-a97e-3a40ad946fa6_smlp_toy_basic.csv delete mode 100644 src/uploads/c43061ee-8af0-4f50-806b-eb86c0c6ab16_smlp_toy_basic.csv delete mode 100644 src/uploads/d4b63a65-b208-4d51-9f33-cf70042e69af_smlp_toy_basic.spec create mode 100644 src/visualize_h5.py diff --git a/src/app.py b/src/app.py index 7ede9fac..45bcd240 100644 --- a/src/app.py +++ b/src/app.py @@ -1,20 +1,35 @@ import subprocess -from flask import Flask, render_template, request, redirect, url_for, session +from flask import Flask, render_template, request, redirect, url_for, session, send_from_directory import os import sys import uuid from flask_session import Session +from visualize_h5 import h5_visualization_route +from visualize_h5 import get_h5_plot # Import the function +import shutil +import os + + # Flask App Setup app = Flask(__name__) + + + +SESSION_DIR = './flask_session' +if os.path.exists(SESSION_DIR): + shutil.rmtree(SESSION_DIR) + os.makedirs(SESSION_DIR) + app.config['SECRET_KEY'] = os.environ.get('FLASK_SECRET_KEY', 'dev_secret_key') app.config['SESSION_TYPE'] = 'filesystem' Session(app) +app.register_blueprint(h5_visualization_route) -UPLOAD_FOLDER = os.path.join(os.getcwd(), 'uploads') +UPLOAD_FOLDER = os.path.join('../regr_smlp/code/uploads') os.makedirs(UPLOAD_FOLDER, exist_ok=True) app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER @@ -58,7 +73,7 @@ def train(): dataset_path = None if data_file and data_file.filename: - dataset_path = os.path.join(app.config['UPLOAD_FOLDER'], f"{uuid.uuid4()}_{data_file.filename}") + dataset_path = os.path.join(UPLOAD_FOLDER, f"{uuid.uuid4()}_{data_file.filename}") data_file.save(dataset_path) def add_arg(flag, value): @@ -92,7 +107,7 @@ def add_arg(flag, value): additional_command = request.form.get('additional_command') if additional_command: - arguments.append(additional_command) + arguments.extend(additional_command.split()) # Debugging print("DEBUG: Final SMLP Command ->", " ".join(arguments)) @@ -107,43 +122,57 @@ def add_arg(flag, value): # PREDICT - -# !!! To be done !!! - - @app.route('/predict', methods=['GET', 'POST']) def predict(): if request.method == 'POST': model_file = request.files.get('model_file') new_data_file = request.files.get('new_data_file') - save_model = request.form.get('save_model', 'f') - model_name = request.form.get('model_name', 'my_model') model_path = None + newdata_path = None + if model_file and model_file.filename: - filename = f"{uuid.uuid4()}_{model_file.filename}" - model_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) + model_path = os.path.join(UPLOAD_FOLDER, f"{uuid.uuid4()}_{model_file.filename}") model_file.save(model_path) - newdata_path = None if new_data_file and new_data_file.filename: - filename = f"{uuid.uuid4()}_{new_data_file.filename}" - newdata_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) + newdata_path = os.path.join(UPLOAD_FOLDER, f"{uuid.uuid4()}_{new_data_file.filename}") new_data_file.save(newdata_path) - arguments = [] - if model_path: - base_name, ext = os.path.splitext(model_path) - arguments += ["-use_model", "t", "-model_name", base_name] + def add_arg(flag, value): + if value is not None and value != "": + arguments.extend([flag, str(value)]) + + arguments = ['python3', os.path.abspath("../src/run_smlp.py")] + + if not model_path or not newdata_path: + return "Error: Both model file and new data file are required", 400 - if newdata_path: - base_new_name, _ = os.path.splitext(newdata_path) - arguments += ["-new_data", base_new_name] + # Required + add_arg("-mode", "predict") + + # Process paths (remove file extension) + add_arg("-model_name", os.path.abspath(model_path)) + add_arg("-new_data", os.path.abspath(newdata_path)) + + # Optional user inputs + add_arg("-out_dir", request.form.get('out_dir_val', './')) + add_arg("-pref", request.form.get('pref_val', 'PredictRun')) + add_arg("-log_time", request.form.get('log_time', 'f')) + add_arg("-plots", request.form.get('plots')) + add_arg("-save_model", request.form.get('save_model')) + add_arg("-model_name", request.form.get('model_name')) + add_arg("-seed", request.form.get('seed_val')) + + + additional_command = request.form.get('additional_command') + if additional_command: + arguments.extend(additional_command.split()) - if save_model == 't': - arguments += ["-save_model", "t", "-model_name", model_name] + # Debug output + print("DEBUG: Final Predict SMLP Command ->", " ".join(arguments)) - output = call_smlp_api("predict", arguments) + output = call_smlp_api(arguments) session['output'] = output return redirect(url_for('results')) @@ -151,6 +180,14 @@ def predict(): +def clear_old_plots(): + """Remove all previous plots before running a new exploration.""" + if os.path.exists(PLOT_SAVE_DIR): + for filename in os.listdir(PLOT_SAVE_DIR): + file_path = os.path.join(PLOT_SAVE_DIR, filename) + if os.path.isfile(file_path): + os.remove(file_path) + # EXPLORATION @app.route('/explore', methods=['GET', 'POST']) @@ -158,6 +195,7 @@ def explore(): modes_list = ['certify', 'query', 'verify', 'synthesize', 'optimize', 'optsyn'] if request.method == 'POST': + clear_old_plots() chosen_mode = request.form.get('explore_mode', '') if chosen_mode not in modes_list: @@ -170,11 +208,11 @@ def explore(): spec_path = None if data_file and data_file.filename: - dataset_path = os.path.join(app.config['UPLOAD_FOLDER'], f"{uuid.uuid4()}_{data_file.filename}") + dataset_path = os.path.join(UPLOAD_FOLDER, f"{uuid.uuid4()}_{data_file.filename}") data_file.save(dataset_path) if spec_file and spec_file.filename: - spec_path = os.path.join(app.config['UPLOAD_FOLDER'], f"{uuid.uuid4()}_{spec_file.filename}") + spec_path = os.path.join(UPLOAD_FOLDER, f"{uuid.uuid4()}_{spec_file.filename}") spec_file.save(spec_path) if not dataset_path or not spec_path: @@ -211,8 +249,11 @@ def add_arg(flag, value): additional_command = request.form.get('additional_command') if additional_command: - arguments.append(additional_command) - + arguments.extend(additional_command.split()) + + # checks if there should be a 3d plot + session['use_h5'] = any('nn_keras' in arg for arg in arguments) + session.modified = True # Debugging print("DEBUG: Final SMLP Command ->", " ".join(arguments)) @@ -225,44 +266,72 @@ def add_arg(flag, value): # DOE -# !!! To be done !!! - @app.route('/doe', methods=['GET', 'POST']) def doe(): - """ - Let the user pick DOE options and pass them to SMLP in 'doe' mode. - """ if request.method == 'POST': doe_spec_file = request.files.get('doe_spec_file') - doe_algo = request.form.get('doe_algo') - doe_num_samples = request.form.get('doe_num_samples', '') + spec_path = None - arguments = [] if doe_spec_file and doe_spec_file.filename: - specname = f"{uuid.uuid4()}_{doe_spec_file.filename}" - spec_path = os.path.join(app.config['UPLOAD_FOLDER'], specname) + spec_path = os.path.join(UPLOAD_FOLDER, f"{uuid.uuid4()}_{doe_spec_file.filename}") doe_spec_file.save(spec_path) - base_spec, _ = os.path.splitext(spec_path) - arguments += ["-doe_spec", base_spec] - if doe_algo: - arguments += ["-doe_algo", doe_algo] - if doe_num_samples: - arguments += ["-doe_num_samples", doe_num_samples] + def add_arg(flag, value): + if value is not None and value != "": + arguments.extend([flag, str(value)]) - output = call_smlp_api("doe", arguments) + arguments = ['python3', os.path.abspath("../src/run_smlp.py")] + + if not spec_path: + return "Error: Missing DOE spec file", 400 + + # Required DOE mode + add_arg("-doe_spec", os.path.abspath(spec_path)) + add_arg("-out_dir", request.form.get('out_dir_val', './')) + add_arg("-pref", request.form.get('pref_val', 'TestDOE')) + add_arg("-mode", "doe") + add_arg("-doe_algo", request.form.get('doe_algo')) + add_arg("-log_time", request.form.get('log_time', 'f')) + + additional_command = request.form.get('additional_command') + if additional_command: + arguments.extend(additional_command.split()) + + # Debugging + print("DEBUG: Final DOE SMLP Command ->", " ".join(arguments)) + + output = call_smlp_api(arguments) session['output'] = output return redirect(url_for('results')) return render_template('doe.html') -# RESULTS + + +# results +PLOT_SAVE_DIR = os.path.abspath("../regr_smlp/code/images/results") +os.makedirs(PLOT_SAVE_DIR, exist_ok=True) # Ensure the directory is created + @app.route('/results') def results(): output = session.get('output', 'No output available yet.') print("\n--- RESULTS ---") print(output) - return render_template('results.html', output=output) + + # Get list of available plot files + plots = [] + if os.path.exists(PLOT_SAVE_DIR): + plots = [f for f in os.listdir(PLOT_SAVE_DIR) if f.endswith(".png")] + + use_h5 = session.get('use_h5', False) + h5_plot_html = get_h5_plot() if use_h5 else None + + return render_template('results.html', output=output, plots=plots, h5_plot_html=h5_plot_html, use_h5=use_h5) + +# Route to serve images from the custom directory +@app.route('/plots/') +def serve_plot(filename): + return send_from_directory(PLOT_SAVE_DIR, filename) # MAIN if __name__ == '__main__': diff --git a/src/flask_session/15312c6817dee9ca56473a5245415fc0 b/src/flask_session/15312c6817dee9ca56473a5245415fc0 deleted file mode 100644 index cfaca736884ef07d363f16637fc30f1f4e4dd84a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23833 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 -
+
{% block content %}{% endblock %}
@@ -42,7 +42,6 @@ +
+ {{ h5_plot_html | safe }} +
+
+
+
+ + {% endif %} + + + -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/src/templates/train.html b/src/templates/train.html index 78cc526c..c37fe72f 100644 --- a/src/templates/train.html +++ b/src/templates/train.html @@ -25,7 +25,7 @@

Train a Model

- +
diff --git a/src/test_app.py b/src/test_app.py new file mode 100644 index 00000000..b449ec78 --- /dev/null +++ b/src/test_app.py @@ -0,0 +1,226 @@ +import os +import unittest +import tempfile +import subprocess +from unittest.mock import patch +from app import app, call_smlp_api + +class AppTestCase(unittest.TestCase): + def setUp(self): + app.config['TESTING'] = True + self.client = app.test_client() + self.upload_folder = tempfile.mkdtemp() + app.config['UPLOAD_FOLDER'] = self.upload_folder + + def tearDown(self): + for file in os.listdir(self.upload_folder): + os.remove(os.path.join(self.upload_folder, file)) + os.rmdir(self.upload_folder) + + def test_home(self): + response = self.client.get('/') + self.assertEqual(response.status_code, 200) + + def test_explore_get(self): + response = self.client.get('/explore') + self.assertEqual(response.status_code, 200) + + def test_explore_invalid_mode(self): + response = self.client.post('/explore', data={'explore_mode': 'invalid_mode'}) + self.assertEqual(response.status_code, 400) + self.assertIn(b"Error: Invalid mode selected", response.data) + + def test_explore_missing_files(self): + response = self.client.post('/explore', data={'explore_mode': 'certify'}) + self.assertEqual(response.status_code, 400) + self.assertIn(b"Error: Missing required dataset or spec file", response.data) + + def test_explore_full_form_submission(self): + data_file_path = os.path.join(self.upload_folder, "data.csv") + spec_file_path = os.path.join(self.upload_folder, "spec.txt") + + with open(data_file_path, 'w') as f: + f.write("sample,data,content") + with open(spec_file_path, 'w') as f: + f.write('''{ + "version": "1.2", + "spec": { + "targets": ["y1"], + "constraints": [] + } + }''') + with self.client.session_transaction() as session: + output = session.get('output', '') + self.assertNotIn('Exception', output) + self.assertNotIn('Traceback', output) + + with open(data_file_path, 'rb') as data_file, open(spec_file_path, 'rb') as spec_file: + response = self.client.post('/explore', data={ + 'explore_mode': 'optimize', + 'data_file': (data_file, 'data.csv'), + 'spec_file': (spec_file, 'spec.txt'), + 'out_dir_val': './results', + 'pref_val': 'Test113', + 'pareto': 't', + 'resp': 'y', + 'feat': 'x1,x2', + 'model_expr': 'dt', + 'dt_sklearn_max_depth': '5', + 'mrmr_pred': '5', + 'epsilon': '0.01', + 'delta_rel': '0.05', + 'save_model_config': 'yes', + 'plots': 'yes', + 'log_time': 'yes', + 'seed_val': '42', + 'objv_names': 'objv1,objv2', + 'objv_exprs': 'y1>7 and y2<3', + 'additional_command': '-seed 10' + }, content_type='multipart/form-data') + + self.assertEqual(response.status_code, 302) + self.assertTrue(response.headers['Location'].endswith('/results')) + + def test_train_missing_file(self): + response = self.client.post('/train', data={}) + self.assertEqual(response.status_code, 400) + self.assertIn(b"Error: Missing required dataset or spec file", response.data) + + def test_train_valid_submission(self): + data_file_path = os.path.join(self.upload_folder, "data.csv") + with open(data_file_path, 'w') as f: + f.write("sample,data,content") + + with open(data_file_path, 'rb') as data_file: + response = self.client.post('/train', data={ + 'data_file': (data_file, 'data.csv'), + 'out_dir_val': './results' + }, content_type='multipart/form-data') + + self.assertEqual(response.status_code, 302) + self.assertTrue(response.headers['Location'].endswith('/results')) + + def test_call_smlp_api(self): + result = call_smlp_api(['echo', 'hello']) + self.assertEqual(result.strip(), 'hello') + + def test_results_route(self): + plot_dir = os.path.abspath("../regr_smlp/code/images/results") + os.makedirs(plot_dir, exist_ok=True) + plot_path = os.path.join(plot_dir, "dummy_plot.png") + with open(plot_path, 'wb') as f: + f.write(b'\x89PNG\r\n\x1a\n') + + with self.client.session_transaction() as sess: + sess['output'] = 'Test output message' + sess['use_h5'] = False + + response = self.client.get('/results') + self.assertEqual(response.status_code, 200) + self.assertIn(b'Test output message', response.data) + self.assertIn(b'dummy_plot.png', response.data) + + os.remove(plot_path) + + def test_serve_plot_route(self): + plot_dir = os.path.abspath("../regr_smlp/code/images/results") + os.makedirs(plot_dir, exist_ok=True) + filename = "test_image.png" + filepath = os.path.join(plot_dir, filename) + + with open(filepath, 'wb') as f: + f.write(b'\x89PNG\r\n\x1a\n') + + with open(filepath, 'rb') as f: + response = self.client.get(f'/plots/{filename}') + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content_type, 'image/png') + + os.remove(filepath) + + @patch('app.get_h5_plot') + def test_results_route_with_h5(self, mock_get_h5_plot): + mock_get_h5_plot.return_value = "
Mock H5 Plot
" + + with self.client.session_transaction() as sess: + sess['output'] = 'Output with H5' + sess['use_h5'] = True + + response = self.client.get('/results') + self.assertEqual(response.status_code, 200) + self.assertIn(b'Output with H5', response.data) + self.assertIn(b'Mock H5 Plot', response.data) + + def test_clear_old_plots(self): + from app import clear_old_plots, PLOT_SAVE_DIR + os.makedirs(PLOT_SAVE_DIR, exist_ok=True) + dummy_plot = os.path.join(PLOT_SAVE_DIR, 'dummy.png') + with open(dummy_plot, 'wb') as f: + f.write(b'\x89PNG\r\n\x1a\n') + + self.assertTrue(os.path.exists(dummy_plot)) + clear_old_plots() + self.assertFalse(os.path.exists(dummy_plot)) + + def test_doe_missing_file(self): + response = self.client.post('/doe', data={}) + self.assertEqual(response.status_code, 400) + self.assertIn(b"Error: Missing DOE spec file", response.data) + + def test_doe_valid_submission(self): + doe_file_path = os.path.join(self.upload_folder, "doe_spec.json") + with open(doe_file_path, 'w') as f: + f.write('''{ + "version": "1.2", + "spec": { + "design": "lhs", + "samples": 10 + } + }''') + + with open(doe_file_path, 'rb') as doe_file: + response = self.client.post('/doe', data={ + 'doe_spec_file': (doe_file, 'doe_spec.json'), + 'out_dir_val': './results', + 'pref_val': 'TestDOE', + 'doe_algo': 'lhs', + 'log_time': 'yes', + 'additional_command': '-seed 999' + }, content_type='multipart/form-data') + + self.assertEqual(response.status_code, 302) + self.assertTrue(response.headers['Location'].endswith('/results')) + + def test_predict_missing_files(self): + response = self.client.post('/predict', data={}) + self.assertEqual(response.status_code, 400) + self.assertIn(b"Error: Both model file and new data file are required", response.data) + + def test_predict_valid_submission(self): + model_file_path = os.path.join(self.upload_folder, "model.h5") + new_data_file_path = os.path.join(self.upload_folder, "new_data.csv") + + with open(model_file_path, 'w') as f: + f.write("mock model content") + with open(new_data_file_path, 'w') as f: + f.write("mock,new,data") + + with open(model_file_path, 'rb') as model_file, open(new_data_file_path, 'rb') as new_data_file: + response = self.client.post('/predict', data={ + 'model_file': (model_file, 'model.h5'), + 'new_data_file': (new_data_file, 'new_data.csv'), + 'out_dir_val': './results', + 'pref_val': 'PredictRun', + 'log_time': 'yes', + 'plots': 'yes', + 'save_model': 't', + 'model_name': 'my_model', + 'seed_val': '123', + 'additional_command': '-seed 999' + }, content_type='multipart/form-data') + + self.assertEqual(response.status_code, 302) + self.assertTrue(response.headers['Location'].endswith('/results')) + +if __name__ == '__main__': + unittest.main() diff --git a/src/test_visual.py b/src/test_visual.py new file mode 100644 index 00000000..d1327085 --- /dev/null +++ b/src/test_visual.py @@ -0,0 +1,102 @@ +import os +import unittest +import tempfile +import numpy as np +import pandas as pd +from unittest.mock import patch, MagicMock + +from visualize_h5 import ( + get_latest_file, + get_latest_h5_file, + get_latest_training_csv, + get_feature_estimates, + load_model_and_generate_predictions, + get_h5_plot, + H5_DIRECTORY, + CSV_DIRECTORY +) + +class TestVisualizeH5(unittest.TestCase): + def setUp(self): + self.test_dir = tempfile.mkdtemp() + + def tearDown(self): + for f in os.listdir(self.test_dir): + os.remove(os.path.join(self.test_dir, f)) + os.rmdir(self.test_dir) + + def test_get_latest_file_returns_none_if_no_files(self): + result = get_latest_file(self.test_dir, '*.csv') + self.assertIsNone(result) + + def test_get_latest_file_returns_latest(self): + file1 = os.path.join(self.test_dir, 'file1.csv') + file2 = os.path.join(self.test_dir, 'file2.csv') + with open(file1, 'w') as f: + f.write('test1') + with open(file2, 'w') as f: + f.write('test2') + os.utime(file1, (1, 1)) + os.utime(file2, (2, 2)) + + result = get_latest_file(self.test_dir, '*.csv') + self.assertEqual(result, file2) + + @patch('visualize_h5.get_latest_file') + def test_get_latest_h5_file(self, mock_get): + mock_get.return_value = '/path/to/latest.h5' + self.assertEqual(get_latest_h5_file(), '/path/to/latest.h5') + + @patch('visualize_h5.get_latest_file') + def test_get_latest_training_csv(self, mock_get): + mock_get.return_value = '/path/to/latest.csv' + self.assertEqual(get_latest_training_csv(), '/path/to/latest.csv') + + @patch('visualize_h5.get_latest_training_csv') + def test_get_feature_estimates_returns_means(self, mock_csv): + df = pd.DataFrame({"y1": [1, 2, 3], "y2": [4, 5, 6]}) + temp_csv = os.path.join(self.test_dir, 'test.csv') + df.to_csv(temp_csv, index=False) + mock_csv.return_value = temp_csv + + y1, y2 = get_feature_estimates() + self.assertEqual(y1, 2.0) + self.assertEqual(y2, 5.0) + + @patch('visualize_h5.tf.keras.models.load_model') + @patch('visualize_h5.get_latest_h5_file') + @patch('visualize_h5.get_feature_estimates') + def test_load_model_and_generate_predictions(self, mock_est, mock_h5, mock_load): + mock_h5.return_value = '/mock/model.h5' + mock_est.return_value = (5.0, 5.0) + + dummy_model = MagicMock() + dummy_model.predict.return_value = np.random.rand(900, 1) + mock_load.return_value = dummy_model + + y1, y2, z = load_model_and_generate_predictions() + self.assertIsNotNone(y1) + self.assertIsNotNone(y2) + self.assertIsNotNone(z) + self.assertEqual(y1.shape, y2.shape) + self.assertEqual(y1.shape, z.shape) + + @patch('visualize_h5.load_model_and_generate_predictions') + def test_get_h5_plot_returns_html(self, mock_load): + y1 = y2 = np.linspace(0, 1, 10) + Y1, Y2 = np.meshgrid(y1, y2) + Z = np.random.rand(10, 10) + mock_load.return_value = (Y1, Y2, Z) + + html = get_h5_plot() + self.assertIn('=4 and y2>=8", - "eta": "p1==4 or (p1==8 and p2 > 3)", - "assertions": { - "assert1": "(y2**3+p2)/2>6", - "assert2": "y1>=0", - "assert3": "y2>0" - }, - "objectives": { - "objective1": "(y1+y2)/2", - "objective2": "y1" - } -} diff --git a/src/uploads/501bbff2-ab6d-4186-b5dd-d5756a90711e_smlp_toy_basic.csv b/src/uploads/501bbff2-ab6d-4186-b5dd-d5756a90711e_smlp_toy_basic.csv deleted file mode 100644 index 7704d94d..00000000 --- a/src/uploads/501bbff2-ab6d-4186-b5dd-d5756a90711e_smlp_toy_basic.csv +++ /dev/null @@ -1,11 +0,0 @@ -x1,x2,p1,p2,y1,y2 -2.98,-1,0.1,4,5.0233,8 -8.553,-1,3.9,3,0.6936,12.02 -0.558,1,2,4,0.6882,8.14 -3.867,0,1.1,3,0.24,8 --0.8218,0,4,3,0.324,8 -5.252,0,4,5,6.03,8 -0.2998,1,7.1,6,0.91,10.125 -7.175,1,7,7,0.96,1.12 -9.546,0,7,6,10.7007,9.5661 --0.454,1,10,7,8.7932,6.4015 diff --git a/src/uploads/6374879d-9342-4d70-8b8c-fdd73c0b9399_smlp_toy_num_resp_mult_free_inps.spec b/src/uploads/6374879d-9342-4d70-8b8c-fdd73c0b9399_smlp_toy_num_resp_mult_free_inps.spec deleted file mode 100644 index 0b0cc663..00000000 --- a/src/uploads/6374879d-9342-4d70-8b8c-fdd73c0b9399_smlp_toy_num_resp_mult_free_inps.spec +++ /dev/null @@ -1 +0,0 @@ -{"version": "1.1", "spec": [{"label": "y1", "type": "response", "range": "float"}, {"label": "y2", "type": "response", "range": "float"}, {"label": "x", "type": "input", "range": "float", "bounds":[-2, null]}, {"label": "p1", "type": "knob", "range": "float", "rad-rel": 0.1, "grid": [2,4,7], "bounds":[4,8]}, {"label": "p2", "type": "knob", "range": "float", "rad-abs": 0.2, "bounds": [3,7]}]} diff --git a/src/uploads/7dedf43f-1b87-4823-8e43-0e2c1f8eea26_smlp_toy_basic.spec b/src/uploads/7dedf43f-1b87-4823-8e43-0e2c1f8eea26_smlp_toy_basic.spec deleted file mode 100644 index bdca0618..00000000 --- a/src/uploads/7dedf43f-1b87-4823-8e43-0e2c1f8eea26_smlp_toy_basic.spec +++ /dev/null @@ -1,23 +0,0 @@ -{ - "version": "1.2", - "variables": [ - {"label":"y1", "interface":"output", "type":"real"}, - {"label":"y2", "interface":"output", "type":"real"}, - {"label":"x1", "interface":"input", "type":"real", "range":[0,10]}, - {"label":"x2", "interface":"input", "type":"int", "range":[-1,1]}, - {"label":"p1", "interface":"knob", "type":"real", "range":[0,10], "rad-rel":0.1, "grid":[2,4,7]}, - {"label":"p2", "interface":"knob", "type":"int", "range":[3,7], "rad-abs":0.2} - ], - "alpha": "p2<5 and x1==10 and x2<12", - "beta": "y1>=4 and y2>=8", - "eta": "p1==4 or (p1==8 and p2 > 3)", - "assertions": { - "assert1": "(y2**3+p2)/2>6", - "assert2": "y1>=0", - "assert3": "y2>0" - }, - "objectives": { - "objective1": "(y1+y2)/2", - "objective2": "y1" - } -} diff --git a/src/uploads/80ca933c-3a5e-4354-a604-2357f978bef8_smlp_toy_num_resp_mult.csv b/src/uploads/80ca933c-3a5e-4354-a604-2357f978bef8_smlp_toy_num_resp_mult.csv deleted file mode 100644 index 6a401612..00000000 --- a/src/uploads/80ca933c-3a5e-4354-a604-2357f978bef8_smlp_toy_num_resp_mult.csv +++ /dev/null @@ -1,12 +0,0 @@ -categ,y1,y2,x,p1,p2 -c14,5,9,10.0,2.0,3 -c15,9,9,12.0,,4 -c1,5,9,,3.0,4 -c9,5,5,11.0,2.0,6 -c5,9,5,10.0,2.0,8 -c10,9,9,9.0,4.0,7 -c13,5,5,9.0,3.0,6 -c4,5,5,10.0,3.0,4 -c15,9,9,11.0,4.0,4 -c11,5,5,12.0,2.0,7 -c19,9,5,10.0,3.0,7 diff --git a/src/uploads/83347cf7-2773-45f0-ad6c-c2e1bf782831_smlp_toy_num_resp_mult_free_inps.spec b/src/uploads/83347cf7-2773-45f0-ad6c-c2e1bf782831_smlp_toy_num_resp_mult_free_inps.spec deleted file mode 100644 index 0b0cc663..00000000 --- a/src/uploads/83347cf7-2773-45f0-ad6c-c2e1bf782831_smlp_toy_num_resp_mult_free_inps.spec +++ /dev/null @@ -1 +0,0 @@ -{"version": "1.1", "spec": [{"label": "y1", "type": "response", "range": "float"}, {"label": "y2", "type": "response", "range": "float"}, {"label": "x", "type": "input", "range": "float", "bounds":[-2, null]}, {"label": "p1", "type": "knob", "range": "float", "rad-rel": 0.1, "grid": [2,4,7], "bounds":[4,8]}, {"label": "p2", "type": "knob", "range": "float", "rad-abs": 0.2, "bounds": [3,7]}]} diff --git a/src/uploads/93f33a35-4eb3-4e22-be47-f8df9eb88a5e_smlp_toy_basic.csv b/src/uploads/93f33a35-4eb3-4e22-be47-f8df9eb88a5e_smlp_toy_basic.csv deleted file mode 100644 index 7704d94d..00000000 --- a/src/uploads/93f33a35-4eb3-4e22-be47-f8df9eb88a5e_smlp_toy_basic.csv +++ /dev/null @@ -1,11 +0,0 @@ -x1,x2,p1,p2,y1,y2 -2.98,-1,0.1,4,5.0233,8 -8.553,-1,3.9,3,0.6936,12.02 -0.558,1,2,4,0.6882,8.14 -3.867,0,1.1,3,0.24,8 --0.8218,0,4,3,0.324,8 -5.252,0,4,5,6.03,8 -0.2998,1,7.1,6,0.91,10.125 -7.175,1,7,7,0.96,1.12 -9.546,0,7,6,10.7007,9.5661 --0.454,1,10,7,8.7932,6.4015 diff --git a/src/uploads/9b9674a3-31a0-47b5-aa3e-e2f0da50e0fe_smlp_toy_basic.spec b/src/uploads/9b9674a3-31a0-47b5-aa3e-e2f0da50e0fe_smlp_toy_basic.spec deleted file mode 100644 index bdca0618..00000000 --- a/src/uploads/9b9674a3-31a0-47b5-aa3e-e2f0da50e0fe_smlp_toy_basic.spec +++ /dev/null @@ -1,23 +0,0 @@ -{ - "version": "1.2", - "variables": [ - {"label":"y1", "interface":"output", "type":"real"}, - {"label":"y2", "interface":"output", "type":"real"}, - {"label":"x1", "interface":"input", "type":"real", "range":[0,10]}, - {"label":"x2", "interface":"input", "type":"int", "range":[-1,1]}, - {"label":"p1", "interface":"knob", "type":"real", "range":[0,10], "rad-rel":0.1, "grid":[2,4,7]}, - {"label":"p2", "interface":"knob", "type":"int", "range":[3,7], "rad-abs":0.2} - ], - "alpha": "p2<5 and x1==10 and x2<12", - "beta": "y1>=4 and y2>=8", - "eta": "p1==4 or (p1==8 and p2 > 3)", - "assertions": { - "assert1": "(y2**3+p2)/2>6", - "assert2": "y1>=0", - "assert3": "y2>0" - }, - "objectives": { - "objective1": "(y1+y2)/2", - "objective2": "y1" - } -} diff --git a/src/uploads/b6533bc5-d317-46c0-a97e-3a40ad946fa6_smlp_toy_basic.csv b/src/uploads/b6533bc5-d317-46c0-a97e-3a40ad946fa6_smlp_toy_basic.csv deleted file mode 100644 index 7704d94d..00000000 --- a/src/uploads/b6533bc5-d317-46c0-a97e-3a40ad946fa6_smlp_toy_basic.csv +++ /dev/null @@ -1,11 +0,0 @@ -x1,x2,p1,p2,y1,y2 -2.98,-1,0.1,4,5.0233,8 -8.553,-1,3.9,3,0.6936,12.02 -0.558,1,2,4,0.6882,8.14 -3.867,0,1.1,3,0.24,8 --0.8218,0,4,3,0.324,8 -5.252,0,4,5,6.03,8 -0.2998,1,7.1,6,0.91,10.125 -7.175,1,7,7,0.96,1.12 -9.546,0,7,6,10.7007,9.5661 --0.454,1,10,7,8.7932,6.4015 diff --git a/src/uploads/c43061ee-8af0-4f50-806b-eb86c0c6ab16_smlp_toy_basic.csv b/src/uploads/c43061ee-8af0-4f50-806b-eb86c0c6ab16_smlp_toy_basic.csv deleted file mode 100644 index 7704d94d..00000000 --- a/src/uploads/c43061ee-8af0-4f50-806b-eb86c0c6ab16_smlp_toy_basic.csv +++ /dev/null @@ -1,11 +0,0 @@ -x1,x2,p1,p2,y1,y2 -2.98,-1,0.1,4,5.0233,8 -8.553,-1,3.9,3,0.6936,12.02 -0.558,1,2,4,0.6882,8.14 -3.867,0,1.1,3,0.24,8 --0.8218,0,4,3,0.324,8 -5.252,0,4,5,6.03,8 -0.2998,1,7.1,6,0.91,10.125 -7.175,1,7,7,0.96,1.12 -9.546,0,7,6,10.7007,9.5661 --0.454,1,10,7,8.7932,6.4015 diff --git a/src/uploads/d4b63a65-b208-4d51-9f33-cf70042e69af_smlp_toy_basic.spec b/src/uploads/d4b63a65-b208-4d51-9f33-cf70042e69af_smlp_toy_basic.spec deleted file mode 100644 index bdca0618..00000000 --- a/src/uploads/d4b63a65-b208-4d51-9f33-cf70042e69af_smlp_toy_basic.spec +++ /dev/null @@ -1,23 +0,0 @@ -{ - "version": "1.2", - "variables": [ - {"label":"y1", "interface":"output", "type":"real"}, - {"label":"y2", "interface":"output", "type":"real"}, - {"label":"x1", "interface":"input", "type":"real", "range":[0,10]}, - {"label":"x2", "interface":"input", "type":"int", "range":[-1,1]}, - {"label":"p1", "interface":"knob", "type":"real", "range":[0,10], "rad-rel":0.1, "grid":[2,4,7]}, - {"label":"p2", "interface":"knob", "type":"int", "range":[3,7], "rad-abs":0.2} - ], - "alpha": "p2<5 and x1==10 and x2<12", - "beta": "y1>=4 and y2>=8", - "eta": "p1==4 or (p1==8 and p2 > 3)", - "assertions": { - "assert1": "(y2**3+p2)/2>6", - "assert2": "y1>=0", - "assert3": "y2>0" - }, - "objectives": { - "objective1": "(y1+y2)/2", - "objective2": "y1" - } -} diff --git a/src/visualize_h5.py b/src/visualize_h5.py new file mode 100644 index 00000000..12805cc7 --- /dev/null +++ b/src/visualize_h5.py @@ -0,0 +1,110 @@ +import os +import glob +import numpy as np +import pandas as pd +import plotly.graph_objs as go +import plotly.io as pio +import tensorflow as tf +from flask import Blueprint + +h5_visualization_route = Blueprint('h5_visualization', __name__) + +H5_DIRECTORY = os.path.abspath("../regr_smlp/code/results/") +CSV_DIRECTORY = os.path.abspath("../regr_smlp/code/results/") + +def get_latest_file(directory, file_pattern): + """Find the most recently created file in a directory that matches a pattern.""" + files = glob.glob(os.path.join(directory, file_pattern)) + + if not files: + print(f"⚠ No {file_pattern} files found in:", directory) + return None + + latest_file = max(files, key=os.path.getctime) + print(f"✅ Latest {file_pattern} file:", latest_file) + return latest_file + +def get_latest_h5_file(): + """Get the latest H5 model file.""" + return get_latest_file(H5_DIRECTORY, "*e.h5") + +def get_latest_training_csv(): + """Get the latest training CSV file.""" + return get_latest_file(CSV_DIRECTORY, "*_training_predictions_summary.csv") + +def get_feature_estimates(): + """Compute mean values for y1 and y2 from the latest training CSV.""" + csv_file = get_latest_training_csv() + if not csv_file: + return 0, 0 + + try: + df = pd.read_csv(csv_file) + y1_mean = df['y1'].mean() + y2_mean = df['y2'].mean() + print(f"📌 Estimated Feature 1 (y1) = {y1_mean}") + print(f"📌 Estimated Feature 2 (y2) = {y2_mean}") + return y1_mean, y2_mean + except Exception as e: + print(f"⚠ Error reading CSV file: {str(e)}") + return 0, 0 + + +def load_model_and_generate_predictions(): + """Load the Keras model and generate predictions using y1, y2 as inputs.""" + h5_file = get_latest_h5_file() + + if not h5_file: + return None, None, None + + try: + model = tf.keras.models.load_model(h5_file) + print("✅ Model loaded successfully.") + print(model.summary()) + + y1_range = np.linspace(0, 12, 30) + y2_range = np.linspace(0, 10, 30) + Y1, Y2 = np.meshgrid(y1_range, y2_range) + + f3, f4 = get_feature_estimates() + + feature3 = np.full_like(Y1.ravel(), f3) + feature4 = np.full_like(Y2.ravel(), f4) + inputs = np.c_[Y1.ravel(), Y2.ravel(), feature3, feature4] + + predictions = model.predict(inputs) + + print(f"📌 Model Prediction Shape: {predictions.shape}") + + if predictions.shape[1] > 1: + predictions = predictions[:, 0] + + + Z = predictions.reshape(Y1.shape) + return Y1, Y2, Z + except Exception as e: + print(f"❌ Error loading model or generating predictions: {str(e)}") + return None, None, None + +def get_h5_plot(): + """Generate an interactive 3D surface plot from the model predictions.""" + y1, y2, z = load_model_and_generate_predictions() + + if y1 is None or y2 is None or z is None: + return "

⚠ Error: No valid model output found.

" + + pio.renderers.default = 'browser' + + fig = go.Figure() + + fig.add_trace(go.Surface( + x=y1, y=y2, z=z + )) + + fig.update_layout( + title="Interactive 3D Model Output", + scene=dict(xaxis_title="y1", yaxis_title="y2", zaxis_title="Model Prediction (Z)"), + margin=dict(l=0, r=0, b=0, t=40) + ) + + return pio.to_html(fig, full_html=False)