ivoryos 0.1.21__py3-none-any.whl → 0.1.23__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 +36 -10
- ivoryos/routes/control/control.py +2 -2
- ivoryos/routes/control/templates/control/controllers_home.html +6 -1
- ivoryos/routes/database/database.py +59 -2
- ivoryos/routes/database/templates/database/experiment_database.html +3 -3
- ivoryos/routes/database/templates/database/experiment_step_view.html +130 -0
- ivoryos/routes/database/templates/database/step_card.html +7 -0
- ivoryos/routes/database/templates/database/workflow_run_database.html +81 -0
- ivoryos/routes/design/design.py +23 -2
- ivoryos/routes/design/templates/design/experiment_builder.html +57 -10
- ivoryos/routes/design/templates/design/experiment_run.html +162 -83
- ivoryos/routes/main/templates/main/home.html +80 -47
- ivoryos/static/js/socket_handler.js +5 -0
- ivoryos/templates/base.html +6 -3
- ivoryos/utils/client_proxy.py +57 -0
- ivoryos/utils/db_models.py +43 -1
- ivoryos/utils/form.py +52 -7
- ivoryos/utils/llm_agent.py +1 -1
- ivoryos/utils/script_runner.py +111 -44
- ivoryos/utils/utils.py +23 -0
- ivoryos/version.py +1 -1
- {ivoryos-0.1.21.dist-info → ivoryos-0.1.23.dist-info}/METADATA +7 -3
- {ivoryos-0.1.21.dist-info → ivoryos-0.1.23.dist-info}/RECORD +26 -22
- {ivoryos-0.1.21.dist-info → ivoryos-0.1.23.dist-info}/LICENSE +0 -0
- {ivoryos-0.1.21.dist-info → ivoryos-0.1.23.dist-info}/WHEEL +0 -0
- {ivoryos-0.1.21.dist-info → ivoryos-0.1.23.dist-info}/top_level.txt +0 -0
|
@@ -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">
|
|
@@ -345,8 +423,9 @@
|
|
|
345
423
|
<p>Do you want to continue execution or stop?</p>
|
|
346
424
|
</div>
|
|
347
425
|
<div class="modal-footer">
|
|
348
|
-
|
|
349
|
-
|
|
426
|
+
<button type="button" class="btn btn-primary" id="retry-btn" data-bs-dismiss="modal">Rerun Current Step</button>
|
|
427
|
+
<button type="button" class="btn btn-success" id="continue-btn" data-bs-dismiss="modal">Continue</button>
|
|
428
|
+
<button type="button" class="btn btn-danger" id="stop-btn" data-bs-dismiss="modal">Stop Execution</button>
|
|
350
429
|
</div>
|
|
351
430
|
</div>
|
|
352
431
|
</div>
|
|
@@ -1,70 +1,103 @@
|
|
|
1
1
|
{% extends 'base.html' %}
|
|
2
|
-
{% block title %}IvoryOS | Welcome
|
|
3
|
-
|
|
2
|
+
{% block title %}IvoryOS | Welcome{% endblock %}
|
|
4
3
|
|
|
5
4
|
{% block body %}
|
|
6
|
-
<div class="p-4"
|
|
7
|
-
<h1 style="
|
|
5
|
+
<div class="p-4">
|
|
6
|
+
<h1 class="mb-4" style="font-size: 3rem; font-weight: bold; color: #343a40;">
|
|
8
7
|
Welcome
|
|
9
8
|
</h1>
|
|
10
|
-
<p>Version: {{ version }}</p>
|
|
9
|
+
<p class="mb-5">Version: {{ version }}</p>
|
|
10
|
+
|
|
11
|
+
{% if enable_design %}
|
|
12
|
+
<!-- Workflow Design Section -->
|
|
13
|
+
<h4 class="mb-3">Workflow Design</h4>
|
|
11
14
|
<div class="row">
|
|
12
|
-
|
|
13
|
-
<div class="
|
|
14
|
-
<div class="card
|
|
15
|
-
<
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
<div class="col-lg-6 mb-3 d-flex align-items-stretch">
|
|
16
|
+
<div class="card rounded shadow-sm flex-fill">
|
|
17
|
+
<div class="card-body">
|
|
18
|
+
<h5 class="card-title">
|
|
19
|
+
<i class="bi bi-folder2-open me-2"></i>Browse designs
|
|
20
|
+
</h5>
|
|
21
|
+
<p class="card-text">View all saved workflows from the database.</p>
|
|
22
|
+
<a href="{{ url_for('database.load_from_database') }}" class="stretched-link"></a>
|
|
20
23
|
</div>
|
|
21
24
|
</div>
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
<
|
|
28
|
-
</
|
|
25
|
+
</div>
|
|
26
|
+
<div class="col-lg-6 mb-3 d-flex align-items-stretch">
|
|
27
|
+
<div class="card rounded shadow-sm flex-fill">
|
|
28
|
+
<div class="card-body">
|
|
29
|
+
<h5 class="card-title">
|
|
30
|
+
<i class="bi bi-pencil-square me-2"></i>Edit designs
|
|
31
|
+
</h5>
|
|
32
|
+
<p class="card-text">Create or modify workflows using available functions.</p>
|
|
33
|
+
<a href="{{ url_for('design.experiment_builder') }}" class="stretched-link"></a>
|
|
29
34
|
</div>
|
|
30
35
|
</div>
|
|
31
|
-
|
|
36
|
+
</div>
|
|
32
37
|
</div>
|
|
38
|
+
{% endif %}
|
|
33
39
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
<!-- Workflow Control and Monitor Section -->
|
|
41
|
+
<h4 class="mt-5 mb-3">Workflow Control & Monitoring</h4>
|
|
42
|
+
<div class="row">
|
|
43
|
+
<!-- Always visible: Experiment data -->
|
|
44
|
+
<div class="col-lg-6 mb-3 d-flex align-items-stretch">
|
|
45
|
+
<div class="card rounded shadow-sm flex-fill">
|
|
46
|
+
<div class="card-body">
|
|
47
|
+
<h5 class="card-title">
|
|
48
|
+
<i class="bi bi-graph-up-arrow me-2"></i>Experiment data
|
|
49
|
+
</h5>
|
|
50
|
+
<p class="card-text">Browse workflow logs and output data.</p>
|
|
51
|
+
<a href="{{ url_for('database.list_workflows') }}" class="stretched-link"></a>
|
|
45
52
|
</div>
|
|
46
53
|
</div>
|
|
47
|
-
|
|
54
|
+
</div>
|
|
48
55
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
<!-- Conditionally visible: Run current workflow -->
|
|
57
|
+
{% if not off_line %}
|
|
58
|
+
<div class="col-lg-6 mb-3 d-flex align-items-stretch">
|
|
59
|
+
<div class="card rounded shadow-sm flex-fill">
|
|
60
|
+
<div class="card-body">
|
|
61
|
+
<h5 class="card-title">
|
|
62
|
+
<i class="bi bi-play-circle me-2"></i>Run current workflow
|
|
63
|
+
</h5>
|
|
64
|
+
<p class="card-text">Execute workflows with configurable parameters.</p>
|
|
65
|
+
<a href="{{ url_for('design.experiment_run') }}" class="stretched-link"></a>
|
|
56
66
|
</div>
|
|
57
67
|
</div>
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
68
|
+
</div>
|
|
69
|
+
{% endif %}
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
{% if not off_line %}
|
|
75
|
+
<!-- Direct Control Section -->
|
|
76
|
+
<h4 class="mt-5 mb-3">Direct Control</h4>
|
|
77
|
+
<div class="row">
|
|
78
|
+
<div class="col-lg-6 mb-3 d-flex align-items-stretch">
|
|
79
|
+
<div class="card rounded shadow-sm flex-fill">
|
|
80
|
+
<div class="card-body">
|
|
81
|
+
<h5 class="card-title">
|
|
82
|
+
<i class="bi bi-toggle-on me-2"></i>Direct control
|
|
83
|
+
</h5>
|
|
84
|
+
<p class="card-text">Manually control individual components.</p>
|
|
85
|
+
<a href="{{ url_for('control.deck_controllers') }}" class="stretched-link"></a>
|
|
65
86
|
</div>
|
|
66
87
|
</div>
|
|
67
88
|
</div>
|
|
89
|
+
<div class="col-lg-6 mb-3 d-flex align-items-stretch">
|
|
90
|
+
<div class="card rounded shadow-sm flex-fill">
|
|
91
|
+
<div class="card-body">
|
|
92
|
+
<h5 class="card-title">
|
|
93
|
+
<i class="bi bi-usb-plug me-2"></i>Connect a new device
|
|
94
|
+
</h5>
|
|
95
|
+
<p class="card-text">Add new hardware temporarily or for testing purposes.</p>
|
|
96
|
+
<a href="{{ url_for('control.controllers_home') }}" class="stretched-link"></a>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
68
101
|
{% endif %}
|
|
69
102
|
</div>
|
|
70
103
|
{% endblock %}
|
|
@@ -68,6 +68,11 @@ document.addEventListener("DOMContentLoaded", function() {
|
|
|
68
68
|
console.log("Execution resumed.");
|
|
69
69
|
});
|
|
70
70
|
|
|
71
|
+
document.getElementById('retry-btn').addEventListener('click', function() {
|
|
72
|
+
socket.emit('retry'); // Resume execution
|
|
73
|
+
console.log("Execution resumed, retrying.");
|
|
74
|
+
});
|
|
75
|
+
|
|
71
76
|
document.getElementById('stop-btn').addEventListener('click', function() {
|
|
72
77
|
socket.emit('pause'); // Resume execution
|
|
73
78
|
socket.emit('abort_current'); // Stop execution
|
ivoryos/templates/base.html
CHANGED
|
@@ -46,14 +46,17 @@
|
|
|
46
46
|
<li class="nav-item">
|
|
47
47
|
<a class="nav-link" href="{{ url_for('design.experiment_run') }}">Compile/Run</a>
|
|
48
48
|
</li>
|
|
49
|
+
<li class="nav-item">
|
|
50
|
+
<a class="nav-link" href="{{ url_for('database.list_workflows') }}">Data</a>
|
|
51
|
+
</li>
|
|
49
52
|
{% endif %}
|
|
50
53
|
|
|
51
54
|
<li class="nav-item">
|
|
52
55
|
<a class="nav-link" href="{{ url_for('control.deck_controllers') }}">Devices</a></li>
|
|
53
56
|
</li>
|
|
54
|
-
<li class="nav-item"
|
|
55
|
-
<a class="nav-link" href="{{ url_for('control.controllers_home') }}">Temp Devices</a></li
|
|
56
|
-
</li
|
|
57
|
+
{# <li class="nav-item">#}
|
|
58
|
+
{# <a class="nav-link" href="{{ url_for('control.controllers_home') }}">Temp Devices</a></li>#}
|
|
59
|
+
{# </li>#}
|
|
57
60
|
{# <li class="nav-item">#}
|
|
58
61
|
{# <a class="nav-link" href="{{ url_for('main.help_info') }}">About</a>#}
|
|
59
62
|
{# </li>#}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# import argparse
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
# import requests
|
|
5
|
+
|
|
6
|
+
# session = requests.Session()
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# Function to create class and methods dynamically
|
|
10
|
+
def create_function(url, class_name, functions):
|
|
11
|
+
class_template = f'class {class_name.capitalize()}:\n url = "{url}ivoryos/backend_control/deck.{class_name}"\n'
|
|
12
|
+
|
|
13
|
+
for function_name, details in functions.items():
|
|
14
|
+
signature = details['signature']
|
|
15
|
+
docstring = details.get('docstring', '')
|
|
16
|
+
|
|
17
|
+
# Creating the function definition
|
|
18
|
+
method = f' def {function_name}{signature}:\n'
|
|
19
|
+
if docstring:
|
|
20
|
+
method += f' """{docstring}"""\n'
|
|
21
|
+
|
|
22
|
+
# Generating the session.post code for sending data
|
|
23
|
+
method += ' return session.post(self.url, data={'
|
|
24
|
+
method += f'"hidden_name": "{function_name}"'
|
|
25
|
+
|
|
26
|
+
# Extracting the parameters from the signature string for the data payload
|
|
27
|
+
param_str = signature[6:-1] # Remove the "(self" and final ")"
|
|
28
|
+
params = [param.strip() for param in param_str.split(',')] if param_str else []
|
|
29
|
+
|
|
30
|
+
for param in params:
|
|
31
|
+
param_name = param.split(':')[0].strip() # Split on ':' and get parameter name
|
|
32
|
+
method += f', "{param_name}": {param_name}'
|
|
33
|
+
|
|
34
|
+
method += '}).json()\n'
|
|
35
|
+
class_template += method + '\n'
|
|
36
|
+
|
|
37
|
+
return class_template
|
|
38
|
+
|
|
39
|
+
# Function to export the generated classes to a Python script
|
|
40
|
+
def export_to_python(class_definitions, path):
|
|
41
|
+
with open(os.path.join(path, "generated_proxy.py"), 'w') as f:
|
|
42
|
+
# Writing the imports at the top of the script
|
|
43
|
+
f.write('import requests\n\n')
|
|
44
|
+
f.write('session = requests.Session()\n\n')
|
|
45
|
+
|
|
46
|
+
# Writing each class definition to the file
|
|
47
|
+
for class_name, class_def in class_definitions.items():
|
|
48
|
+
f.write(class_def)
|
|
49
|
+
f.write('\n')
|
|
50
|
+
|
|
51
|
+
# Creating instances of the dynamically generated classes
|
|
52
|
+
for class_name in class_definitions.keys():
|
|
53
|
+
instance_name = class_name.lower() # Using lowercase for instance names
|
|
54
|
+
f.write(f'{instance_name} = {class_name.capitalize()}()\n')
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
ivoryos/utils/db_models.py
CHANGED
|
@@ -44,9 +44,12 @@ class Script(db.Model):
|
|
|
44
44
|
id_order = db.Column(JSONType, nullable=True)
|
|
45
45
|
editing_type = db.Column(db.String(50), nullable=True)
|
|
46
46
|
author = db.Column(db.String(50), nullable=False)
|
|
47
|
+
# registered = db.Column(db.Boolean, nullable=True, default=False)
|
|
47
48
|
|
|
48
49
|
def __init__(self, name=None, deck=None, status=None, script_dict: dict = None, id_order: dict = None,
|
|
49
|
-
time_created=None, last_modified=None, editing_type=None, author: str = None
|
|
50
|
+
time_created=None, last_modified=None, editing_type=None, author: str = None,
|
|
51
|
+
registered:bool=False,
|
|
52
|
+
):
|
|
50
53
|
if script_dict is None:
|
|
51
54
|
script_dict = {"prep": [], "script": [], "cleanup": []}
|
|
52
55
|
elif type(script_dict) is not dict:
|
|
@@ -73,6 +76,7 @@ class Script(db.Model):
|
|
|
73
76
|
self.id_order = id_order
|
|
74
77
|
self.editing_type = editing_type
|
|
75
78
|
self.author = author
|
|
79
|
+
# self.r = registered
|
|
76
80
|
|
|
77
81
|
def as_dict(self):
|
|
78
82
|
dict = self.__dict__
|
|
@@ -631,6 +635,44 @@ class Script(db.Model):
|
|
|
631
635
|
for i in exec_string.values():
|
|
632
636
|
s.write(f"\n\n\n{i}")
|
|
633
637
|
|
|
638
|
+
class WorkflowRun(db.Model):
|
|
639
|
+
__tablename__ = 'workflow_runs'
|
|
640
|
+
|
|
641
|
+
id = db.Column(db.Integer, primary_key=True)
|
|
642
|
+
name = db.Column(db.String(128), nullable=False)
|
|
643
|
+
platform = db.Column(db.String(128), nullable=False)
|
|
644
|
+
start_time = db.Column(db.DateTime, default=datetime.now())
|
|
645
|
+
end_time = db.Column(db.DateTime)
|
|
646
|
+
data_path = db.Column(db.String(256))
|
|
647
|
+
steps = db.relationship(
|
|
648
|
+
'WorkflowStep',
|
|
649
|
+
backref='workflow_runs',
|
|
650
|
+
cascade='all, delete-orphan',
|
|
651
|
+
passive_deletes=True
|
|
652
|
+
)
|
|
653
|
+
def as_dict(self):
|
|
654
|
+
dict = self.__dict__
|
|
655
|
+
dict.pop('_sa_instance_state', None)
|
|
656
|
+
return dict
|
|
657
|
+
|
|
658
|
+
class WorkflowStep(db.Model):
|
|
659
|
+
__tablename__ = 'workflow_steps'
|
|
660
|
+
|
|
661
|
+
id = db.Column(db.Integer, primary_key=True)
|
|
662
|
+
workflow_id = db.Column(db.Integer, db.ForeignKey('workflow_runs.id', ondelete='CASCADE'), nullable=False)
|
|
663
|
+
|
|
664
|
+
phase = db.Column(db.String(64), nullable=False) # 'prep', 'main', 'cleanup'
|
|
665
|
+
repeat_index = db.Column(db.Integer, default=0) # Only applies to 'main' phase
|
|
666
|
+
step_index = db.Column(db.Integer, default=0)
|
|
667
|
+
method_name = db.Column(db.String(128), nullable=False)
|
|
668
|
+
start_time = db.Column(db.DateTime)
|
|
669
|
+
end_time = db.Column(db.DateTime)
|
|
670
|
+
run_error = db.Column(db.Boolean, default=False)
|
|
671
|
+
|
|
672
|
+
def as_dict(self):
|
|
673
|
+
dict = self.__dict__
|
|
674
|
+
dict.pop('_sa_instance_state', None)
|
|
675
|
+
return dict
|
|
634
676
|
|
|
635
677
|
if __name__ == "__main__":
|
|
636
678
|
a = Script()
|