ivoryos 0.1.21__py3-none-any.whl → 0.1.22__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ivoryos might be problematic. Click here for more details.
- ivoryos/__init__.py +13 -5
- ivoryos/routes/control/control.py +2 -2
- ivoryos/routes/control/templates/control/controllers_home.html +6 -1
- ivoryos/routes/database/database.py +43 -2
- ivoryos/routes/database/templates/database/experiment_database.html +3 -3
- ivoryos/routes/database/templates/database/workflow_run_database.html +81 -0
- ivoryos/routes/design/design.py +16 -2
- ivoryos/routes/design/templates/design/experiment_run.html +159 -81
- ivoryos/routes/main/templates/main/home.html +80 -47
- ivoryos/templates/base.html +6 -3
- ivoryos/utils/client_proxy.py +57 -0
- ivoryos/utils/db_models.py +43 -1
- ivoryos/utils/llm_agent.py +1 -1
- ivoryos/utils/script_runner.py +91 -42
- ivoryos/utils/utils.py +23 -0
- ivoryos/version.py +1 -1
- {ivoryos-0.1.21.dist-info → ivoryos-0.1.22.dist-info}/METADATA +7 -3
- {ivoryos-0.1.21.dist-info → ivoryos-0.1.22.dist-info}/RECORD +21 -19
- {ivoryos-0.1.21.dist-info → ivoryos-0.1.22.dist-info}/LICENSE +0 -0
- {ivoryos-0.1.21.dist-info → ivoryos-0.1.22.dist-info}/WHEEL +0 -0
- {ivoryos-0.1.21.dist-info → ivoryos-0.1.22.dist-info}/top_level.txt +0 -0
ivoryos/__init__.py
CHANGED
|
@@ -18,6 +18,16 @@ from ivoryos.utils.script_runner import ScriptRunner
|
|
|
18
18
|
from ivoryos.version import __version__ as ivoryos_version
|
|
19
19
|
from importlib.metadata import entry_points
|
|
20
20
|
global_config = GlobalConfig()
|
|
21
|
+
from sqlalchemy import event
|
|
22
|
+
from sqlalchemy.engine import Engine
|
|
23
|
+
import sqlite3
|
|
24
|
+
|
|
25
|
+
@event.listens_for(Engine, "connect")
|
|
26
|
+
def enforce_sqlite_foreign_keys(dbapi_connection, connection_record):
|
|
27
|
+
if isinstance(dbapi_connection, sqlite3.Connection):
|
|
28
|
+
cursor = dbapi_connection.cursor()
|
|
29
|
+
cursor.execute("PRAGMA foreign_keys=ON")
|
|
30
|
+
cursor.close()
|
|
21
31
|
|
|
22
32
|
url_prefix = os.getenv('URL_PREFIX', "/ivoryos")
|
|
23
33
|
app = Flask(__name__, static_url_path=f'{url_prefix}/static', static_folder='static')
|
|
@@ -29,8 +39,9 @@ app.register_blueprint(database, url_prefix=url_prefix)
|
|
|
29
39
|
|
|
30
40
|
|
|
31
41
|
def create_app(config_class=None):
|
|
32
|
-
|
|
33
|
-
|
|
42
|
+
"""
|
|
43
|
+
create app, init database
|
|
44
|
+
"""
|
|
34
45
|
app.config.from_object(config_class or 'config.get_config()')
|
|
35
46
|
|
|
36
47
|
# Initialize extensions
|
|
@@ -85,7 +96,6 @@ def run(module=None, host="0.0.0.0", port=None, debug=None, llm_server=None, mod
|
|
|
85
96
|
:param logger: logger name of list of logger names, defaults to None
|
|
86
97
|
:param logger_output_name: log file save name of logger, defaults to None, and will use "default.log"
|
|
87
98
|
:param enable_design: enable design canvas, database and workflow execution
|
|
88
|
-
:param stream_address:
|
|
89
99
|
"""
|
|
90
100
|
app = create_app(config_class=config or get_config()) # Create app instance using factory function
|
|
91
101
|
|
|
@@ -110,10 +120,8 @@ def run(module=None, host="0.0.0.0", port=None, debug=None, llm_server=None, mod
|
|
|
110
120
|
app.config["MODULE"] = module
|
|
111
121
|
app.config["OFF_LINE"] = False
|
|
112
122
|
global_config.deck = sys.modules[module]
|
|
113
|
-
# global_config.heinsight = HeinsightAPI("http://127.0.0.1:8080")
|
|
114
123
|
global_config.deck_snapshot = utils.create_deck_snapshot(global_config.deck,
|
|
115
124
|
output_path=app.config["DUMMY_DECK"], save=True)
|
|
116
|
-
# global_config.runner = ScriptRunner(globals())
|
|
117
125
|
else:
|
|
118
126
|
app.config["OFF_LINE"] = True
|
|
119
127
|
if model:
|
|
@@ -151,7 +151,7 @@ def controllers(instrument: str):
|
|
|
151
151
|
return render_template('controllers.html', instrument=instrument, forms=forms, format_name=format_name)
|
|
152
152
|
|
|
153
153
|
|
|
154
|
-
@control.route("/backend_control/<instrument>", methods=['
|
|
154
|
+
@control.route("/backend_control/<instrument>", methods=['POST'])
|
|
155
155
|
def backend_control(instrument: str=None):
|
|
156
156
|
"""
|
|
157
157
|
.. :quickref: Backend Control; backend control
|
|
@@ -187,7 +187,7 @@ def backend_control(instrument: str=None):
|
|
|
187
187
|
return json_output, 400
|
|
188
188
|
else:
|
|
189
189
|
return "instrument not exist", 400
|
|
190
|
-
|
|
190
|
+
return json_output, 200
|
|
191
191
|
|
|
192
192
|
|
|
193
193
|
@control.route("/backend_control", methods=['GET'])
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
{# {% if not deck %}#}
|
|
10
10
|
{# <a href="{{ url_for('control.disconnect', instrument=instrument) }}" class="stretched-link controller-card" style="float: right;color: red; position: relative;">Disconnect <i class="bi bi-x-square"></i></a>#}
|
|
11
11
|
<div class="p-4 controller-card">
|
|
12
|
-
<h5 class=""><a href="{{ url_for('control.controllers', instrument=instrument) }}" class="text-dark stretched-link">{{instrument}}</a></h5>
|
|
12
|
+
<h5 class=""><a href="{{ url_for('control.controllers', instrument=instrument) }}" class="text-dark stretched-link">{{instrument.split(".")[1]}}</a></h5>
|
|
13
13
|
</div>
|
|
14
14
|
{# {% else %}#}
|
|
15
15
|
{# <div class="p-4 controller-card">#}
|
|
@@ -19,6 +19,11 @@
|
|
|
19
19
|
</div>
|
|
20
20
|
</div>
|
|
21
21
|
{% endfor %}
|
|
22
|
+
<div class="d-flex mb-3">
|
|
23
|
+
<a href="{{ url_for('design.download', filetype='proxy') }}" class="btn btn-outline-primary">
|
|
24
|
+
<i class="bi bi-download"></i> Download remote control script
|
|
25
|
+
</a>
|
|
26
|
+
</div>
|
|
22
27
|
{% if not deck %}
|
|
23
28
|
<div class="col-xl-3 col-lg-4 col-md-6 mb-4 ">
|
|
24
29
|
<div class="bg-white rounded shadow-sm position-relative">
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from flask import Blueprint, redirect, url_for, flash, request, render_template, session, current_app
|
|
1
|
+
from flask import Blueprint, redirect, url_for, flash, request, render_template, session, current_app, jsonify
|
|
2
2
|
from flask_login import login_required
|
|
3
3
|
|
|
4
|
-
from ivoryos.utils.db_models import Script, db
|
|
4
|
+
from ivoryos.utils.db_models import Script, db, WorkflowRun, WorkflowStep
|
|
5
5
|
from ivoryos.utils.utils import get_script_file, post_script_file
|
|
6
6
|
|
|
7
7
|
database = Blueprint('database', __name__, template_folder='templates/database')
|
|
@@ -188,3 +188,44 @@ def save_as():
|
|
|
188
188
|
else:
|
|
189
189
|
flash("Script name is already exist in database")
|
|
190
190
|
return redirect(url_for("design.experiment_builder"))
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
@database.route('/workflow_runs')
|
|
194
|
+
def list_workflows():
|
|
195
|
+
query = WorkflowRun.query
|
|
196
|
+
search_term = request.args.get("keyword", None)
|
|
197
|
+
if search_term:
|
|
198
|
+
query = query.filter(WorkflowRun.name.like(f'%{search_term}%'))
|
|
199
|
+
page = request.args.get('page', default=1, type=int)
|
|
200
|
+
per_page = 10
|
|
201
|
+
|
|
202
|
+
workflows = query.paginate(page=page, per_page=per_page, error_out=False)
|
|
203
|
+
return render_template('workflow_run_database.html', workflows=workflows)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
@database.route('/workflow_steps/<int:workflow_id>')
|
|
207
|
+
def get_workflow_steps(workflow_id):
|
|
208
|
+
steps = WorkflowStep.query.filter_by(workflow_id=workflow_id).all()
|
|
209
|
+
steps_data = [step.as_dict() for step in steps]
|
|
210
|
+
return jsonify({'steps': steps_data})
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@database.route("/delete_workflow_data/<workflow_id>")
|
|
214
|
+
@login_required
|
|
215
|
+
def delete_workflow_data(workflow_id: str):
|
|
216
|
+
"""
|
|
217
|
+
.. :quickref: Database; delete experiment data from database
|
|
218
|
+
|
|
219
|
+
delete workflow data from database
|
|
220
|
+
|
|
221
|
+
.. http:get:: /delete_workflow_data/<workflow_id>
|
|
222
|
+
|
|
223
|
+
:param workflow_id: workflow id
|
|
224
|
+
:type workflow_id: str
|
|
225
|
+
:status 302: redirect to :http:get:`/ivoryos/workflow_runs/`
|
|
226
|
+
|
|
227
|
+
"""
|
|
228
|
+
run = WorkflowRun.query.get(workflow_id)
|
|
229
|
+
db.session.delete(run)
|
|
230
|
+
db.session.commit()
|
|
231
|
+
return redirect(url_for('database.list_workflows'))
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
<th scope="col">Time created</th>
|
|
31
31
|
<th scope="col">Last modified</th>
|
|
32
32
|
<th scope="col">Author</th>
|
|
33
|
-
<th scope="col">Registered</th
|
|
33
|
+
{# <th scope="col">Registered</th>#}
|
|
34
34
|
<th scope="col"></th>
|
|
35
35
|
</tr>
|
|
36
36
|
</thead>
|
|
@@ -43,13 +43,13 @@
|
|
|
43
43
|
<td>{{ workflow.time_created }}</td>
|
|
44
44
|
<td>{{ workflow.last_modified }}</td>
|
|
45
45
|
<td>{{ workflow.author }}</td>
|
|
46
|
-
<td>{{ workflow.registered }}</td
|
|
46
|
+
{# <td>{{ workflow.registered }}</td>#}
|
|
47
47
|
<td>
|
|
48
48
|
{#not workflow.status == "finalized" or#}
|
|
49
49
|
{% if session['user'] == 'admin' or session['user'] == workflow.author %}
|
|
50
50
|
<a href="{{ url_for('database.delete_workflow', workflow_name=workflow.name) }}">delete</a>
|
|
51
51
|
{% else %}
|
|
52
|
-
<a class="disabled-link"
|
|
52
|
+
<a class="disabled-link">delete</a>
|
|
53
53
|
{% endif %}
|
|
54
54
|
<td>
|
|
55
55
|
</tr>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{% extends 'base.html' %}
|
|
2
|
+
|
|
3
|
+
{% block title %}IvoryOS | Design Database{% endblock %}
|
|
4
|
+
{% block body %}
|
|
5
|
+
|
|
6
|
+
<table class="table table-hover" id="workflowResultLibrary">
|
|
7
|
+
<thead>
|
|
8
|
+
<tr>
|
|
9
|
+
<th scope="col">Workflow name</th>
|
|
10
|
+
<th scope="col">Start time</th>
|
|
11
|
+
<th scope="col">End time</th>
|
|
12
|
+
<th scope="col">Data</th>
|
|
13
|
+
</tr>
|
|
14
|
+
</thead>
|
|
15
|
+
<tbody>
|
|
16
|
+
{% for workflow in workflows %}
|
|
17
|
+
<tr>
|
|
18
|
+
<td><a href="{{ url_for('database.get_workflow_steps', workflow_id=workflow.id) }}">{{ workflow.name }}</a></td>
|
|
19
|
+
<td>{{ workflow.start_time.strftime("%Y-%m-%d %H:%M:%S") if workflow.start_time else '' }}</td>
|
|
20
|
+
<td>{{ workflow.end_time.strftime("%Y-%m-%d %H:%M:%S") if workflow.end_time else '' }}</td>
|
|
21
|
+
|
|
22
|
+
<td>
|
|
23
|
+
{% if workflow.data_path %}
|
|
24
|
+
<a href="{{ url_for('design.download_results', filename=workflow.data_path) }}">{{ workflow.data_path }}</a>
|
|
25
|
+
{% endif %}
|
|
26
|
+
</td>
|
|
27
|
+
<td>
|
|
28
|
+
{% if session['user'] == 'admin' or session['user'] == workflow.author %}
|
|
29
|
+
<a href="{{ url_for('database.delete_workflow_data', workflow_id=workflow.id) }}">delete</a>
|
|
30
|
+
{% else %}
|
|
31
|
+
<a class="disabled-link">delete</a>
|
|
32
|
+
{% endif %}
|
|
33
|
+
</td>
|
|
34
|
+
</tr>
|
|
35
|
+
{% endfor %}
|
|
36
|
+
</tbody>
|
|
37
|
+
</table>
|
|
38
|
+
|
|
39
|
+
{# paging#}
|
|
40
|
+
<div class="pagination justify-content-center">
|
|
41
|
+
<div class="page-item {{ 'disabled' if not workflows.has_prev else '' }}">
|
|
42
|
+
<a class="page-link" href="{{ url_for('database.list_workflows', page=workflows.prev_num) }}">Previous</a>
|
|
43
|
+
</div>
|
|
44
|
+
{% for num in workflows.iter_pages() %}
|
|
45
|
+
<div class="page-item">
|
|
46
|
+
<a class="page-link {{ 'active' if num == workflows.page else '' }}" href="{{ url_for('database.list_workflows', page=num) }}">{{ num }}</a>
|
|
47
|
+
</div>
|
|
48
|
+
{% endfor %}
|
|
49
|
+
<div class="page-item {{ 'disabled' if not workflows.has_next else '' }}">
|
|
50
|
+
<a class="page-link" href="{{ url_for('database.list_workflows', page=workflows.next_num) }}">Next</a>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<div id="steps-container"></div>
|
|
55
|
+
|
|
56
|
+
<script>
|
|
57
|
+
function showSteps(workflowId) {
|
|
58
|
+
fetch(`/workflow_steps/${workflowId}`)
|
|
59
|
+
.then(response => response.json())
|
|
60
|
+
.then(data => {
|
|
61
|
+
const container = document.getElementById('steps-container');
|
|
62
|
+
container.innerHTML = ''; // Clear previous content
|
|
63
|
+
const stepsList = document.createElement('ul');
|
|
64
|
+
|
|
65
|
+
data.steps.forEach(step => {
|
|
66
|
+
const li = document.createElement('li');
|
|
67
|
+
li.innerHTML = `
|
|
68
|
+
<strong>Step: </strong> ${step.method_name} <br>
|
|
69
|
+
<strong>Start Time:</strong> ${step.start_time} <br>
|
|
70
|
+
<strong>End Time:</strong> ${step.end_time} <br>
|
|
71
|
+
<strong>Human Intervention:</strong> ${step.run_error ? 'Yes' : 'No'}
|
|
72
|
+
`;
|
|
73
|
+
stepsList.appendChild(li);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
container.appendChild(stepsList);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
</script>
|
|
80
|
+
|
|
81
|
+
{% endblock %}
|
ivoryos/routes/design/design.py
CHANGED
|
@@ -11,6 +11,7 @@ from flask_socketio import SocketIO
|
|
|
11
11
|
from werkzeug.utils import secure_filename
|
|
12
12
|
|
|
13
13
|
from ivoryos.utils import utils
|
|
14
|
+
from ivoryos.utils.client_proxy import create_function, export_to_python
|
|
14
15
|
from ivoryos.utils.global_config import GlobalConfig
|
|
15
16
|
from ivoryos.utils.form import create_builtin_form, create_action_button, format_name, create_form_from_pseudo, \
|
|
16
17
|
create_form_from_action, create_all_builtin_forms
|
|
@@ -360,7 +361,7 @@ def experiment_run():
|
|
|
360
361
|
run_name = script.validate_function_name(run_name)
|
|
361
362
|
runner.run_script(script=script, run_name=run_name, config=config, bo_args=bo_args,
|
|
362
363
|
logger=g.logger, socketio=g.socketio, repeat_count=repeat,
|
|
363
|
-
output_path=datapath
|
|
364
|
+
output_path=datapath, current_app=current_app._get_current_object()
|
|
364
365
|
)
|
|
365
366
|
if utils.check_config_duplicate(config):
|
|
366
367
|
flash(f"WARNING: Duplicate in config entries.")
|
|
@@ -525,7 +526,20 @@ def download(filetype):
|
|
|
525
526
|
outfile.write(json_object)
|
|
526
527
|
elif filetype == "python":
|
|
527
528
|
filepath = os.path.join(current_app.config["SCRIPT_FOLDER"], f"{run_name}.py")
|
|
528
|
-
|
|
529
|
+
elif filetype == "proxy":
|
|
530
|
+
snapshot = global_config.deck_snapshot.copy()
|
|
531
|
+
class_definitions = {}
|
|
532
|
+
# Iterate through each instrument in the snapshot
|
|
533
|
+
for instrument_key, instrument_data in snapshot.items():
|
|
534
|
+
# Iterate through each function associated with the current instrument
|
|
535
|
+
for function_key, function_data in instrument_data.items():
|
|
536
|
+
# Convert the function signature to a string representation
|
|
537
|
+
function_data['signature'] = str(function_data['signature'])
|
|
538
|
+
class_name = instrument_key.split('.')[-1] # Extracting the class name from the path
|
|
539
|
+
class_definitions[class_name.capitalize()] = create_function(request.url_root, class_name, instrument_data)
|
|
540
|
+
# Export the generated class definitions to a .py script
|
|
541
|
+
export_to_python(class_definitions, current_app.config["OUTPUT_FOLDER"])
|
|
542
|
+
filepath = os.path.join(current_app.config["OUTPUT_FOLDER"], "generated_proxy.py")
|
|
529
543
|
return send_file(os.path.abspath(filepath), as_attachment=True)
|
|
530
544
|
|
|
531
545
|
|
|
@@ -128,75 +128,132 @@
|
|
|
128
128
|
{% endif %}
|
|
129
129
|
</div>
|
|
130
130
|
|
|
131
|
-
<div class="tab-pane fade " id="tab3" role="tabpanel" aria-labelledby="tab3-tab"
|
|
132
|
-
<form role="form" method='POST' name="bo" action="{{ url_for('design.experiment_run')}}"
|
|
133
|
-
<div class="form-group"
|
|
134
|
-
<p><h5>Parameters:</h5><p
|
|
135
|
-
{% for config in config_list %}
|
|
136
|
-
<div class="row g-3 align-items-center"
|
|
137
|
-
<div class="col-lg-3 col-sm-6 "
|
|
138
|
-
{{config}}
|
|
139
|
-
</div
|
|
131
|
+
{# <div class="tab-pane fade " id="tab3" role="tabpanel" aria-labelledby="tab3-tab">#}
|
|
132
|
+
{# <form role="form" method='POST' name="bo" action="{{ url_for('design.experiment_run')}}">#}
|
|
133
|
+
{# <div class="form-group">#}
|
|
134
|
+
{# <p><h5>Parameters:</h5><p>#}
|
|
135
|
+
{# {% for config in config_list %}#}
|
|
136
|
+
{# <div class="row g-3 align-items-center">#}
|
|
137
|
+
{# <div class="col-lg-3 col-sm-6 ">#}
|
|
138
|
+
{# {{config}}:#}
|
|
139
|
+
{# </div>#}
|
|
140
140
|
{# <div class="col-auto">#}
|
|
141
141
|
{# <label class="col-form-label" for="{{config}}_type">Type</label>#}
|
|
142
142
|
{# </div>#}
|
|
143
|
-
<div class="col-auto"
|
|
144
|
-
<select class="form-select" id="{{config}}_type" name="{{config}}_type"
|
|
145
|
-
<option selected value="range">range</option
|
|
146
|
-
<option value="choice">choice</option
|
|
147
|
-
<option value="fixed">fixed</option
|
|
148
|
-
</select
|
|
149
|
-
</div
|
|
150
|
-
<div class="col-auto"
|
|
151
|
-
<label class="" for="{{config}}_value">Values</label
|
|
152
|
-
</div
|
|
153
|
-
<div class="col-auto"
|
|
154
|
-
<input type="text" class="form-control" id="{{config}}_value" name="{{config}}_value" placeholder="1, 2, 3"
|
|
155
|
-
</div
|
|
143
|
+
{# <div class="col-auto">#}
|
|
144
|
+
{# <select class="form-select" id="{{config}}_type" name="{{config}}_type">#}
|
|
145
|
+
{# <option selected value="range">range</option>#}
|
|
146
|
+
{# <option value="choice">choice</option>#}
|
|
147
|
+
{# <option value="fixed">fixed</option>#}
|
|
148
|
+
{# </select>#}
|
|
149
|
+
{# </div>#}
|
|
150
|
+
{# <div class="col-auto">#}
|
|
151
|
+
{# <label class="" for="{{config}}_value">Values</label>#}
|
|
152
|
+
{# </div>#}
|
|
153
|
+
{# <div class="col-auto">#}
|
|
154
|
+
{# <input type="text" class="form-control" id="{{config}}_value" name="{{config}}_value" placeholder="1, 2, 3">#}
|
|
155
|
+
{# </div>#}
|
|
156
156
|
{# <div class="col-auto">#}
|
|
157
157
|
{# <input type="text" class="form-control" id="{{config}}_value_max" style="display: none;" placeholder="1, 2, 3">#}
|
|
158
158
|
{# </div>#}
|
|
159
|
-
</div
|
|
160
|
-
{% endfor %}
|
|
161
|
-
<p><h5>Objective:</h5><p
|
|
162
|
-
{% for objective in return_list %}
|
|
163
|
-
<div class="row gy-2 gx-3 align-items-center input-group"
|
|
164
|
-
<div class="col-3"
|
|
165
|
-
{{objective}}
|
|
166
|
-
</div
|
|
159
|
+
{# </div>#}
|
|
160
|
+
{# {% endfor %}#}
|
|
161
|
+
{# <p><h5>Objective:</h5><p>#}
|
|
162
|
+
{# {% for objective in return_list %}#}
|
|
163
|
+
{# <div class="row gy-2 gx-3 align-items-center input-group">#}
|
|
164
|
+
{# <div class="col-3">#}
|
|
165
|
+
{# {{objective}}:#}
|
|
166
|
+
{# </div>#}
|
|
167
167
|
{# <div class="col-auto">#}
|
|
168
168
|
{# <label class="" for="{{objective}}_min">Minimize</label>#}
|
|
169
169
|
{# </div>#}
|
|
170
|
-
<div class="col-auto"
|
|
171
|
-
<select class="form-select" id="{{objective}}_min" name="{{objective}}_min"
|
|
172
|
-
<option selected>minimize</option
|
|
173
|
-
<option>maximize</option
|
|
174
|
-
<option>none</option
|
|
175
|
-
</select
|
|
176
|
-
</div
|
|
170
|
+
{# <div class="col-auto">#}
|
|
171
|
+
{# <select class="form-select" id="{{objective}}_min" name="{{objective}}_min">#}
|
|
172
|
+
{# <option selected>minimize</option>#}
|
|
173
|
+
{# <option>maximize</option>#}
|
|
174
|
+
{# <option>none</option>#}
|
|
175
|
+
{# </select>#}
|
|
176
|
+
{# </div>#}
|
|
177
177
|
{# <div class="col-auto">#}
|
|
178
178
|
{# <label class="" for="{{objective}}_threshold">Threshold</label>#}
|
|
179
179
|
{# </div>#}
|
|
180
180
|
{# <div class="col-auto">#}
|
|
181
181
|
{# <input type="text" class="form-control" id="{{objective}}_threshold" name="{{objective}}_threshold" placeholder="None">#}
|
|
182
182
|
{# </div>#}
|
|
183
|
-
</div
|
|
184
|
-
{% endfor %}
|
|
185
|
-
<p><h5>Budget:</h5></p
|
|
186
|
-
<div class="input-group mb-3"
|
|
187
|
-
<label class="input-group-text" for="repeat">Max iteration </label
|
|
188
|
-
<input class="form-control" type="number" id="repeat" name="repeat" min="1" max="1000" value="25"
|
|
189
|
-
</div
|
|
190
|
-
{% if not no_deck_warning%}
|
|
191
|
-
<div class="input-group mb-3"
|
|
192
|
-
<button class="form-control" type="submit" name="bo">Run</button
|
|
193
|
-
</div
|
|
194
|
-
{% endif %}
|
|
195
|
-
</div
|
|
196
|
-
</form
|
|
197
|
-
</div
|
|
183
|
+
{# </div>#}
|
|
184
|
+
{# {% endfor %}#}
|
|
185
|
+
{# <p><h5>Budget:</h5></p>#}
|
|
186
|
+
{# <div class="input-group mb-3">#}
|
|
187
|
+
{# <label class="input-group-text" for="repeat">Max iteration </label>#}
|
|
188
|
+
{# <input class="form-control" type="number" id="repeat" name="repeat" min="1" max="1000" value="25">#}
|
|
189
|
+
{# </div>#}
|
|
190
|
+
{# {% if not no_deck_warning%}#}
|
|
191
|
+
{# <div class="input-group mb-3">#}
|
|
192
|
+
{# <button class="form-control" type="submit" name="bo">Run</button>#}
|
|
193
|
+
{# </div>#}
|
|
194
|
+
{# {% endif %}#}
|
|
195
|
+
{# </div>#}
|
|
196
|
+
{# </form>#}
|
|
197
|
+
{# </div>#}
|
|
198
|
+
<div class="tab-pane fade" id="tab3" role="tabpanel" aria-labelledby="tab3-tab">
|
|
199
|
+
<form method="POST" name="bo" action="{{ url_for('design.experiment_run') }}">
|
|
200
|
+
<div class="container py-2">
|
|
201
|
+
|
|
202
|
+
<!-- Parameters -->
|
|
203
|
+
<h6 class="fw-bold mt-2 mb-1">Parameters</h6>
|
|
204
|
+
{% for config in config_list %}
|
|
205
|
+
<div class="row align-items-center mb-2">
|
|
206
|
+
<div class="col-3 col-form-label-sm">
|
|
207
|
+
{{ config }}:
|
|
208
|
+
</div>
|
|
209
|
+
<div class="col-6">
|
|
210
|
+
<select class="form-select form-select-sm" id="{{config}}_type" name="{{config}}_type">
|
|
211
|
+
<option selected value="range">range</option>
|
|
212
|
+
<option value="choice">choice</option>
|
|
213
|
+
<option value="fixed">fixed</option>
|
|
214
|
+
</select>
|
|
215
|
+
</div>
|
|
216
|
+
<div class="col-3">
|
|
217
|
+
<input type="text" class="form-control form-control-sm" id="{{config}}_value" name="{{config}}_value" placeholder="1, 2, 3">
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
{% endfor %}
|
|
221
|
+
|
|
222
|
+
<!-- Objective -->
|
|
223
|
+
<h6 class="fw-bold mt-3 mb-1">Objectives</h6>
|
|
224
|
+
{% for objective in return_list %}
|
|
225
|
+
<div class="row align-items-center mb-2">
|
|
226
|
+
<div class="col-3 col-form-label-sm">
|
|
227
|
+
{{ objective }}:
|
|
228
|
+
</div>
|
|
229
|
+
<div class="col-6">
|
|
230
|
+
<select class="form-select form-select-sm" id="{{objective}}_min" name="{{objective}}_min">
|
|
231
|
+
<option selected>minimize</option>
|
|
232
|
+
<option>maximize</option>
|
|
233
|
+
<option>none</option>
|
|
234
|
+
</select>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
{% endfor %}
|
|
238
|
+
|
|
239
|
+
<h6 class="fw-bold mt-3 mb-1">Budget</h6>
|
|
240
|
+
|
|
241
|
+
<div class="input-group mb-3">
|
|
242
|
+
<label class="input-group-text" for="repeat">Max iteration </label>
|
|
243
|
+
<input class="form-control" type="number" id="repeat" name="repeat" min="1" max="1000" value="25">
|
|
244
|
+
</div>
|
|
245
|
+
{% if not no_deck_warning%}
|
|
246
|
+
<div class="input-group mb-3">
|
|
247
|
+
<button class="form-control" type="submit" name="bo">Run</button>
|
|
248
|
+
</div>
|
|
249
|
+
{% endif %}
|
|
250
|
+
</div>
|
|
251
|
+
</form>
|
|
252
|
+
</div>
|
|
253
|
+
|
|
254
|
+
|
|
198
255
|
<div class="tab-pane fade {{ 'show active' if config_list and config_list|count<=5 else '' }}" id="tab4" role="tabpanel" aria-labelledby="tab4-tab">
|
|
199
|
-
<p><h5>Control panel:</h5></p
|
|
256
|
+
{# <p><h5>Control panel:</h5></p>#}
|
|
200
257
|
<div>
|
|
201
258
|
<form method="POST" name="online-config" id="online-config" action="{{url_for('design.experiment_run')}}">
|
|
202
259
|
<table id="dataInputTable" class="table table-striped">
|
|
@@ -210,8 +267,12 @@
|
|
|
210
267
|
<tbody>
|
|
211
268
|
</tbody>
|
|
212
269
|
</table>
|
|
213
|
-
<div class="
|
|
214
|
-
|
|
270
|
+
<div class="d-flex align-items-center gap-2">
|
|
271
|
+
<div class="btn btn-light" onclick="addRow()">
|
|
272
|
+
<i class="bi bi-plus-circle"></i>
|
|
273
|
+
</div>
|
|
274
|
+
<button type="submit" name="online-config" class="form-control">Run</button>
|
|
275
|
+
</div>
|
|
215
276
|
</form>
|
|
216
277
|
</div>
|
|
217
278
|
</div>
|
|
@@ -220,12 +281,29 @@
|
|
|
220
281
|
<div class="col-lg-6 col-sm-12" id="code-panel" style="{{ '' if pause_status else 'display: none;'}}">
|
|
221
282
|
<p>
|
|
222
283
|
<h5>Progress:</h5>
|
|
223
|
-
{%
|
|
224
|
-
|
|
225
|
-
|
|
284
|
+
{% if "prep" in line_collection.keys() %} {% set stype = "cleanup" %}
|
|
285
|
+
{% set stype = "prep" %}
|
|
286
|
+
|
|
287
|
+
<h6>Preparation:</h6>
|
|
288
|
+
{% for code in line_collection["prep"] %}
|
|
226
289
|
<pre style="margin: 0; padding: 0; line-height: 1;"><code class="python" id="{{ stype }}-{{ loop.index0 }}" >{{code}}</code></pre>
|
|
227
290
|
{% endfor %}
|
|
228
|
-
{%
|
|
291
|
+
{% endif %}
|
|
292
|
+
{% if "script" in line_collection.keys() %}
|
|
293
|
+
{% set stype = "script" %}
|
|
294
|
+
|
|
295
|
+
<h6>Experiment:</h6>
|
|
296
|
+
{% for code in line_collection["script"] %}
|
|
297
|
+
<pre style="margin: 0; padding: 0; line-height: 1;"><code class="python" id="{{ stype }}-{{ loop.index0 }}" >{{code}}</code></pre>
|
|
298
|
+
{% endfor %}
|
|
299
|
+
{% endif %}
|
|
300
|
+
{% if "cleanup" in line_collection.keys() %}
|
|
301
|
+
{% set stype = "cleanup" %}
|
|
302
|
+
<h6>Experiment:</h6>
|
|
303
|
+
{% for code in line_collection["cleanup"] %}
|
|
304
|
+
<pre style="margin: 0; padding: 0; line-height: 1;"><code class="python" id="{{ stype }}-{{ loop.index0 }}" >{{code}}</code></pre>
|
|
305
|
+
{% endfor %}
|
|
306
|
+
{% endif %}
|
|
229
307
|
</p>
|
|
230
308
|
</div>
|
|
231
309
|
<div class="col-lg-6 col-sm-12 logging-panel">
|
|
@@ -263,28 +341,28 @@
|
|
|
263
341
|
</div>
|
|
264
342
|
</div>
|
|
265
343
|
</div>
|
|
266
|
-
<div class="accordion-item design-control"
|
|
267
|
-
<h2 class="accordion-header"
|
|
268
|
-
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#data" aria-expanded="false" aria-controls="script"
|
|
269
|
-
Download experiment data csv
|
|
270
|
-
</button
|
|
271
|
-
</h2
|
|
272
|
-
<div id="data" class="accordion-collapse collapse"
|
|
273
|
-
<div class="accordion-body"
|
|
274
|
-
{% if session["most_recent_result"] %}
|
|
275
|
-
<p><a href="{{ url_for('design.download_results', filename=session["most_recent_result"]) }}">Download the latest data <i class="bi bi-download"></i></a></p
|
|
276
|
-
{% endif %}
|
|
277
|
-
<p
|
|
278
|
-
<h5>All data files</h5
|
|
279
|
-
{% for datafile in data_list %}
|
|
280
|
-
<div
|
|
281
|
-
{{ datafile }} <a href="{{ url_for('design.download_results', filename=datafile) }} "><i class="bi bi-download"></i></a
|
|
282
|
-
</div
|
|
283
|
-
{% endfor %}
|
|
284
|
-
</p
|
|
285
|
-
</div
|
|
286
|
-
</div
|
|
287
|
-
</div
|
|
344
|
+
{# <div class="accordion-item design-control">#}
|
|
345
|
+
{# <h2 class="accordion-header">#}
|
|
346
|
+
{# <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#data" aria-expanded="false" aria-controls="script">#}
|
|
347
|
+
{# Download experiment data csv#}
|
|
348
|
+
{# </button>#}
|
|
349
|
+
{# </h2>#}
|
|
350
|
+
{# <div id="data" class="accordion-collapse collapse">#}
|
|
351
|
+
{# <div class="accordion-body">#}
|
|
352
|
+
{# {% if session["most_recent_result"] %}#}
|
|
353
|
+
{# <p><a href="{{ url_for('design.download_results', filename=session["most_recent_result"]) }}">Download the latest data <i class="bi bi-download"></i></a></p>#}
|
|
354
|
+
{# {% endif %}#}
|
|
355
|
+
{# <p>#}
|
|
356
|
+
{# <h5>All data files</h5>#}
|
|
357
|
+
{# {% for datafile in data_list %}#}
|
|
358
|
+
{# <div>#}
|
|
359
|
+
{# {{ datafile }} <a href="{{ url_for('design.download_results', filename=datafile) }} "><i class="bi bi-download"></i></a>#}
|
|
360
|
+
{# </div>#}
|
|
361
|
+
{# {% endfor %}#}
|
|
362
|
+
{# </p>#}
|
|
363
|
+
{# </div>#}
|
|
364
|
+
{# </div>#}
|
|
365
|
+
{# </div>#}
|
|
288
366
|
<div class="accordion-item design-control">
|
|
289
367
|
<h2 class="accordion-header">
|
|
290
368
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#script" aria-expanded="false" aria-controls="script">
|