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
ivoryos/utils/form.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
1
3
|
from wtforms.fields.choices import SelectField
|
|
2
4
|
from wtforms.fields.core import Field
|
|
3
|
-
from wtforms.validators import InputRequired
|
|
5
|
+
from wtforms.validators import InputRequired, ValidationError
|
|
4
6
|
from wtforms.widgets.core import TextInput
|
|
5
7
|
|
|
6
8
|
from flask_wtf import FlaskForm
|
|
@@ -187,6 +189,30 @@ class VariableOrBoolField(BooleanField):
|
|
|
187
189
|
return "y"
|
|
188
190
|
|
|
189
191
|
|
|
192
|
+
class FlexibleEnumField(StringField):
|
|
193
|
+
def __init__(self, label=None, validators=None, choices=None, script=None, **kwargs):
|
|
194
|
+
super().__init__(label, validators, **kwargs)
|
|
195
|
+
self.script = script
|
|
196
|
+
self.enum_class = choices
|
|
197
|
+
self.choices = [e.name for e in self.enum_class]
|
|
198
|
+
# self.value_list = [e.name for e in self.enum_class]
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def process_formdata(self, valuelist):
|
|
202
|
+
if valuelist:
|
|
203
|
+
key = valuelist[0]
|
|
204
|
+
if key in self.choices:
|
|
205
|
+
# Convert the string key to Enum instance
|
|
206
|
+
self.data = self.enum_class[key].value
|
|
207
|
+
elif self.data.startswith("#"):
|
|
208
|
+
if not self.script.editing_type == "script":
|
|
209
|
+
raise ValueError(self.gettext("Variable is not supported in prep/cleanup"))
|
|
210
|
+
self.data = self.data
|
|
211
|
+
else:
|
|
212
|
+
raise ValidationError(
|
|
213
|
+
f"Invalid choice: '{key}'. Must match one of {list(self.enum_class.__members__.keys())}")
|
|
214
|
+
|
|
215
|
+
|
|
190
216
|
def format_name(name):
|
|
191
217
|
"""Converts 'example_name' to 'Example Name'."""
|
|
192
218
|
name = name.split(".")[-1]
|
|
@@ -218,20 +244,39 @@ def create_form_for_method(method, autofill, script=None, design=True):
|
|
|
218
244
|
if param.name == 'self':
|
|
219
245
|
continue
|
|
220
246
|
formatted_param_name = format_name(param.name)
|
|
247
|
+
|
|
248
|
+
default_value = None
|
|
249
|
+
if autofill:
|
|
250
|
+
default_value = f'#{param.name}'
|
|
251
|
+
else:
|
|
252
|
+
if param.default is not param.empty:
|
|
253
|
+
if isinstance(param.default, Enum):
|
|
254
|
+
default_value = param.default.name
|
|
255
|
+
else:
|
|
256
|
+
default_value = param.default
|
|
257
|
+
|
|
221
258
|
field_kwargs = {
|
|
222
259
|
"label": formatted_param_name,
|
|
223
|
-
"default":
|
|
260
|
+
"default": default_value,
|
|
224
261
|
"validators": [InputRequired()] if param.default is param.empty else None,
|
|
225
262
|
**({"script": script} if (autofill or design) else {})
|
|
226
263
|
}
|
|
227
|
-
|
|
228
|
-
param.annotation
|
|
229
|
-
|
|
230
|
-
|
|
264
|
+
if isinstance(param.annotation, type) and issubclass(param.annotation, Enum):
|
|
265
|
+
# enum_class = [(e.name, e.value) for e in param.annotation]
|
|
266
|
+
field_class = FlexibleEnumField
|
|
267
|
+
placeholder_text = f"Choose or type a value for {param.annotation.__name__} (start with # for custom)"
|
|
268
|
+
extra_kwargs = {"choices": param.annotation}
|
|
269
|
+
else:
|
|
270
|
+
field_class, placeholder_text = annotation_mapping.get(
|
|
271
|
+
param.annotation,
|
|
272
|
+
(VariableOrStringField if design else StringField, f'Enter {param.annotation} value')
|
|
273
|
+
)
|
|
274
|
+
extra_kwargs = {}
|
|
275
|
+
|
|
231
276
|
render_kwargs = {"placeholder": placeholder_text}
|
|
232
277
|
|
|
233
278
|
# Create the field with additional rendering kwargs for placeholder text
|
|
234
|
-
field = field_class(**field_kwargs, render_kw=render_kwargs)
|
|
279
|
+
field = field_class(**field_kwargs, render_kw=render_kwargs, **extra_kwargs)
|
|
235
280
|
setattr(DynamicForm, param.name, field)
|
|
236
281
|
|
|
237
282
|
# setattr(DynamicForm, f'add', fname)
|
ivoryos/utils/llm_agent.py
CHANGED
|
@@ -162,7 +162,7 @@ can you also help find the default value you can't find the info from my request
|
|
|
162
162
|
|
|
163
163
|
if __name__ == "__main__":
|
|
164
164
|
from pprint import pprint
|
|
165
|
-
from example.
|
|
165
|
+
from example.abstract_sdl_example.abstract_sdl import deck
|
|
166
166
|
|
|
167
167
|
from utils import parse_functions
|
|
168
168
|
|
ivoryos/utils/script_runner.py
CHANGED
|
@@ -6,15 +6,18 @@ import time
|
|
|
6
6
|
from datetime import datetime
|
|
7
7
|
|
|
8
8
|
from ivoryos.utils import utils
|
|
9
|
-
from ivoryos.utils.db_models import Script
|
|
9
|
+
from ivoryos.utils.db_models import Script, WorkflowRun, WorkflowStep, db
|
|
10
10
|
from ivoryos.utils.global_config import GlobalConfig
|
|
11
11
|
|
|
12
12
|
global_config = GlobalConfig()
|
|
13
13
|
global deck
|
|
14
14
|
deck = None
|
|
15
|
+
# global deck, registered_workflows
|
|
16
|
+
# deck, registered_workflows = None, None
|
|
15
17
|
|
|
16
18
|
class ScriptRunner:
|
|
17
19
|
def __init__(self, globals_dict=None):
|
|
20
|
+
self.retry = False
|
|
18
21
|
if globals_dict is None:
|
|
19
22
|
globals_dict = globals()
|
|
20
23
|
self.globals_dict = globals_dict
|
|
@@ -57,7 +60,8 @@ class ScriptRunner:
|
|
|
57
60
|
self.abort_pending()
|
|
58
61
|
|
|
59
62
|
def run_script(self, script, repeat_count=1, run_name=None, logger=None, socketio=None, config=None, bo_args=None,
|
|
60
|
-
output_path=""):
|
|
63
|
+
output_path="", current_app=None):
|
|
64
|
+
# Get run.id
|
|
61
65
|
global deck
|
|
62
66
|
if deck is None:
|
|
63
67
|
deck = global_config.deck
|
|
@@ -71,14 +75,13 @@ class ScriptRunner:
|
|
|
71
75
|
self.reset_stop_event()
|
|
72
76
|
|
|
73
77
|
thread = threading.Thread(target=self._run_with_stop_check,
|
|
74
|
-
args=(script, repeat_count, run_name, logger, socketio, config, bo_args, output_path))
|
|
78
|
+
args=(script, repeat_count, run_name, logger, socketio, config, bo_args, output_path, current_app))
|
|
75
79
|
thread.start()
|
|
76
80
|
return thread
|
|
77
81
|
|
|
78
|
-
def
|
|
82
|
+
def exec_steps(self, script, section_name, logger, socketio, run_id, i_progress, **kwargs):
|
|
79
83
|
"""
|
|
80
|
-
Executes a function defined in a string line by line
|
|
81
|
-
|
|
84
|
+
Executes a function defined in a string line by line
|
|
82
85
|
:param func_str: The function as a string
|
|
83
86
|
:param kwargs: Arguments to pass to the function
|
|
84
87
|
:return: The final result of the function execution
|
|
@@ -86,8 +89,15 @@ class ScriptRunner:
|
|
|
86
89
|
_func_str = script.compile()
|
|
87
90
|
step_list: list = script.convert_to_lines(_func_str).get(section_name, [])
|
|
88
91
|
global deck
|
|
92
|
+
# global deck, registered_workflows
|
|
89
93
|
if deck is None:
|
|
90
94
|
deck = global_config.deck
|
|
95
|
+
# if registered_workflows is None:
|
|
96
|
+
# registered_workflows = global_config.registered_workflows
|
|
97
|
+
|
|
98
|
+
# for i, line in enumerate(step_list):
|
|
99
|
+
# if line.startswith("registered_workflows"):
|
|
100
|
+
#
|
|
91
101
|
# func_str = script.compile()
|
|
92
102
|
# Parse function body from string
|
|
93
103
|
temp_connections = global_config.defined_variables
|
|
@@ -105,27 +115,65 @@ class ScriptRunner:
|
|
|
105
115
|
while index < len(step_list):
|
|
106
116
|
if self.stop_current_event.is_set():
|
|
107
117
|
logger.info(f'Stopping execution during {section_name}')
|
|
118
|
+
step = WorkflowStep(
|
|
119
|
+
workflow_id=run_id,
|
|
120
|
+
phase=section_name,
|
|
121
|
+
repeat_index=i_progress,
|
|
122
|
+
step_index=index,
|
|
123
|
+
method_name="stop",
|
|
124
|
+
start_time=datetime.now(),
|
|
125
|
+
end_time=datetime.now(),
|
|
126
|
+
run_error=False,
|
|
127
|
+
)
|
|
128
|
+
db.session.add(step)
|
|
108
129
|
break
|
|
109
130
|
line = step_list[index]
|
|
110
|
-
|
|
131
|
+
method_name = line.strip().split("(")[0] if "(" in line else line.strip()
|
|
132
|
+
start_time = datetime.now()
|
|
133
|
+
step = WorkflowStep(
|
|
134
|
+
workflow_id=run_id,
|
|
135
|
+
phase=section_name,
|
|
136
|
+
repeat_index=i_progress,
|
|
137
|
+
step_index=index,
|
|
138
|
+
method_name=method_name,
|
|
139
|
+
start_time=start_time,
|
|
140
|
+
)
|
|
141
|
+
logger.info(f"Executing: {line}")
|
|
111
142
|
socketio.emit('execution', {'section': f"{section_name}-{index}"})
|
|
112
143
|
# self._emit_progress(socketio, 100)
|
|
144
|
+
# if line.startswith("registered_workflows"):
|
|
145
|
+
# line = line.replace("registered_workflows.", "")
|
|
113
146
|
try:
|
|
114
|
-
|
|
147
|
+
if line.startswith("time.sleep("): # add safe sleep for time.sleep lines
|
|
148
|
+
duration_str = line[len("time.sleep("):-1]
|
|
149
|
+
duration = float(duration_str)
|
|
150
|
+
self.safe_sleep(duration)
|
|
151
|
+
else:
|
|
152
|
+
exec(line, exec_globals, exec_locals)
|
|
153
|
+
step.run_error = False
|
|
115
154
|
except Exception as e:
|
|
116
155
|
logger.error(f"Error during script execution: {e}")
|
|
117
|
-
socketio.emit('error', {'message': e
|
|
156
|
+
socketio.emit('error', {'message': str(e)})
|
|
157
|
+
|
|
158
|
+
step.run_error = True
|
|
118
159
|
self.toggle_pause()
|
|
160
|
+
step.end_time = datetime.now()
|
|
161
|
+
db.session.add(step)
|
|
162
|
+
db.session.commit()
|
|
163
|
+
|
|
119
164
|
self.pause_event.wait()
|
|
120
165
|
|
|
121
166
|
# todo update script during the run
|
|
122
167
|
# _func_str = script.compile()
|
|
123
168
|
# step_list: list = script.convert_to_lines(_func_str).get(section_name, [])
|
|
124
|
-
|
|
169
|
+
if not step.run_error:
|
|
170
|
+
index += 1
|
|
171
|
+
elif not self.retry:
|
|
172
|
+
index += 1
|
|
125
173
|
return exec_locals # Return the 'results' variable
|
|
126
174
|
|
|
127
175
|
def _run_with_stop_check(self, script: Script, repeat_count: int, run_name: str, logger, socketio, config, bo_args,
|
|
128
|
-
output_path):
|
|
176
|
+
output_path, current_app):
|
|
129
177
|
time.sleep(1)
|
|
130
178
|
# _func_str = script.compile()
|
|
131
179
|
# step_list_dict: dict = script.convert_to_lines(_func_str)
|
|
@@ -133,39 +181,49 @@ class ScriptRunner:
|
|
|
133
181
|
|
|
134
182
|
# Run "prep" section once
|
|
135
183
|
script_dict = script.script_dict
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
# Run "script" section multiple times
|
|
142
|
-
if repeat_count:
|
|
143
|
-
self._run_repeat_section(repeat_count, arg_type, bo_args, output_list, script,
|
|
144
|
-
run_name, return_list, logger, socketio)
|
|
145
|
-
elif config:
|
|
146
|
-
self._run_config_section(config, arg_type, output_list, script, run_name, logger,
|
|
147
|
-
socketio)
|
|
148
|
-
|
|
149
|
-
# Run "cleanup" section once
|
|
150
|
-
self._run_actions(script, section_name="cleanup", logger=logger, socketio=socketio)
|
|
151
|
-
# Reset the running flag when done
|
|
152
|
-
with self.lock:
|
|
153
|
-
self.is_running = False
|
|
154
|
-
# Save results if necessary
|
|
155
|
-
if output_list:
|
|
156
|
-
self._save_results(run_name, arg_type, return_list, output_list, logger, output_path)
|
|
157
|
-
self._emit_progress(socketio, 100)
|
|
184
|
+
with current_app.app_context():
|
|
185
|
+
|
|
186
|
+
run = WorkflowRun(name=script.name or "untitled", platform=script.deck,start_time=datetime.now())
|
|
187
|
+
db.session.add(run)
|
|
188
|
+
db.session.flush()
|
|
158
189
|
|
|
159
|
-
|
|
190
|
+
self._run_actions(script, section_name="prep", logger=logger, socketio=socketio, run_id=run.id)
|
|
191
|
+
output_list = []
|
|
192
|
+
_, arg_type = script.config("script")
|
|
193
|
+
_, return_list = script.config_return()
|
|
194
|
+
|
|
195
|
+
# Run "script" section multiple times
|
|
196
|
+
if repeat_count:
|
|
197
|
+
self._run_repeat_section(repeat_count, arg_type, bo_args, output_list, script,
|
|
198
|
+
run_name, return_list, logger, socketio, run_id=run.id)
|
|
199
|
+
elif config:
|
|
200
|
+
self._run_config_section(config, arg_type, output_list, script, run_name, logger,
|
|
201
|
+
socketio, run_id=run.id)
|
|
202
|
+
|
|
203
|
+
# Run "cleanup" section once
|
|
204
|
+
self._run_actions(script, section_name="cleanup", logger=logger, socketio=socketio,run_id=run.id)
|
|
205
|
+
# Reset the running flag when done
|
|
206
|
+
with self.lock:
|
|
207
|
+
self.is_running = False
|
|
208
|
+
# Save results if necessary
|
|
209
|
+
filename = None
|
|
210
|
+
if output_list:
|
|
211
|
+
filename = self._save_results(run_name, arg_type, return_list, output_list, logger, output_path)
|
|
212
|
+
self._emit_progress(socketio, 100)
|
|
213
|
+
run.end_time = datetime.now()
|
|
214
|
+
run.data_path = filename
|
|
215
|
+
db.session.commit()
|
|
216
|
+
|
|
217
|
+
def _run_actions(self, script, section_name="", logger=None, socketio=None, run_id=None):
|
|
160
218
|
_func_str = script.compile()
|
|
161
219
|
step_list: list = script.convert_to_lines(_func_str).get(section_name, [])
|
|
162
220
|
logger.info(f'Executing {section_name} steps') if step_list else logger.info(f'No {section_name} steps')
|
|
163
221
|
if self.stop_pending_event.is_set():
|
|
164
222
|
logger.info(f"Stopping execution during {section_name} section.")
|
|
165
223
|
return
|
|
166
|
-
self.
|
|
224
|
+
self.exec_steps(script, section_name, logger, socketio, run_id=run_id, i_progress=0)
|
|
167
225
|
|
|
168
|
-
def _run_config_section(self, config, arg_type, output_list, script, run_name, logger, socketio):
|
|
226
|
+
def _run_config_section(self, config, arg_type, output_list, script, run_name, logger, socketio, run_id):
|
|
169
227
|
compiled = True
|
|
170
228
|
for i in config:
|
|
171
229
|
try:
|
|
@@ -185,22 +243,22 @@ class ScriptRunner:
|
|
|
185
243
|
self._emit_progress(socketio, progress)
|
|
186
244
|
# fname = f"{run_name}_script"
|
|
187
245
|
# function = self.globals_dict[fname]
|
|
188
|
-
output = self.
|
|
246
|
+
output = self.exec_steps(script, "script", logger, socketio, run_id, i, **kwargs)
|
|
189
247
|
if output:
|
|
190
248
|
# kwargs.update(output)
|
|
191
249
|
output_list.append(output)
|
|
192
250
|
|
|
193
251
|
def _run_repeat_section(self, repeat_count, arg_types, bo_args, output_list, script, run_name, return_list,
|
|
194
|
-
logger, socketio):
|
|
252
|
+
logger, socketio, run_id):
|
|
195
253
|
if bo_args:
|
|
196
254
|
logger.info('Initializing optimizer...')
|
|
197
255
|
ax_client = utils.ax_initiation(bo_args, arg_types)
|
|
198
|
-
for
|
|
256
|
+
for i_progress in range(int(repeat_count)):
|
|
199
257
|
if self.stop_pending_event.is_set():
|
|
200
|
-
logger.info(f'Stopping execution during {run_name}: {
|
|
258
|
+
logger.info(f'Stopping execution during {run_name}: {i_progress + 1}/{int(repeat_count)}')
|
|
201
259
|
break
|
|
202
|
-
logger.info(f'Executing {run_name} experiment: {
|
|
203
|
-
progress = (
|
|
260
|
+
logger.info(f'Executing {run_name} experiment: {i_progress + 1}/{int(repeat_count)}')
|
|
261
|
+
progress = (i_progress + 1) * 100 / int(repeat_count) - 0.1
|
|
204
262
|
self._emit_progress(socketio, progress)
|
|
205
263
|
if bo_args:
|
|
206
264
|
try:
|
|
@@ -208,7 +266,7 @@ class ScriptRunner:
|
|
|
208
266
|
logger.info(f'Output value: {parameters}')
|
|
209
267
|
# fname = f"{run_name}_script"
|
|
210
268
|
# function = self.globals_dict[fname]
|
|
211
|
-
output = self.
|
|
269
|
+
output = self.exec_steps(script, "script", logger, socketio, run_id, i_progress, **parameters)
|
|
212
270
|
|
|
213
271
|
_output = {key: value for key, value in output.items() if key in return_list}
|
|
214
272
|
ax_client.complete_trial(trial_index=trial_index, raw_data=_output)
|
|
@@ -219,7 +277,7 @@ class ScriptRunner:
|
|
|
219
277
|
else:
|
|
220
278
|
# fname = f"{run_name}_script"
|
|
221
279
|
# function = self.globals_dict[fname]
|
|
222
|
-
output = self.
|
|
280
|
+
output = self.exec_steps(script, "script", logger, socketio, run_id, i_progress)
|
|
223
281
|
|
|
224
282
|
if output:
|
|
225
283
|
output_list.append(output)
|
|
@@ -237,7 +295,16 @@ class ScriptRunner:
|
|
|
237
295
|
writer.writeheader()
|
|
238
296
|
writer.writerows(output_list)
|
|
239
297
|
logger.info(f'Results saved to {file_path}')
|
|
298
|
+
return filename
|
|
240
299
|
|
|
241
300
|
@staticmethod
|
|
242
301
|
def _emit_progress(socketio, progress):
|
|
243
302
|
socketio.emit('progress', {'progress': progress})
|
|
303
|
+
|
|
304
|
+
def safe_sleep(self, duration: float):
|
|
305
|
+
interval = 1 # check every 1 second
|
|
306
|
+
end_time = time.time() + duration
|
|
307
|
+
while time.time() < end_time:
|
|
308
|
+
if self.stop_current_event.is_set():
|
|
309
|
+
return # Exit early if stop is requested
|
|
310
|
+
time.sleep(min(interval, end_time - time.time()))
|
ivoryos/utils/utils.py
CHANGED
|
@@ -407,3 +407,26 @@ def check_config_duplicate(config):
|
|
|
407
407
|
"""
|
|
408
408
|
hashable_data = [tuple(sorted(d.items())) for d in config]
|
|
409
409
|
return any(count > 1 for count in Counter(hashable_data).values())
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def get_method_from_workflow(function_string, func_name="workflow"):
|
|
413
|
+
"""Creates a function from a string and assigns it a new name."""
|
|
414
|
+
|
|
415
|
+
namespace = {}
|
|
416
|
+
exec(function_string, globals(), namespace) # Execute the string in a safe namespace
|
|
417
|
+
# func_name = next(iter(namespace))
|
|
418
|
+
# Get the function name dynamically
|
|
419
|
+
return namespace[func_name]
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
# def load_workflows(script):
|
|
423
|
+
#
|
|
424
|
+
# class RegisteredWorkflows:
|
|
425
|
+
# pass
|
|
426
|
+
# deck_name = script.deck
|
|
427
|
+
# workflows = Script.query.filter(Script.deck == deck_name, Script.name != script.name, Script.registered==True).all()
|
|
428
|
+
# for workflow in workflows:
|
|
429
|
+
# compiled_strs = workflow.compile().get('script', "")
|
|
430
|
+
# method = get_method_from_workflow(compiled_strs, func_name=workflow.name)
|
|
431
|
+
# setattr(RegisteredWorkflows, workflow.name, staticmethod(method))
|
|
432
|
+
# global_config.registered_workflows = RegisteredWorkflows()
|
ivoryos/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.23"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ivoryos
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.23
|
|
4
4
|
Summary: an open-source Python package enabling Self-Driving Labs (SDLs) interoperability
|
|
5
5
|
Home-page: https://gitlab.com/heingroup/ivoryos
|
|
6
6
|
Author: Ivory Zhang
|
|
@@ -36,7 +36,7 @@ Requires-Dist: python-dotenv
|
|
|
36
36
|
- [Instructions for use](#instructions-for-use)
|
|
37
37
|
- [Demo](#demo)
|
|
38
38
|
- [Roadmap](#roadmap)
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
|
|
41
41
|
## Description
|
|
42
42
|
Granting SDLs flexibility and modularity makes it almost impossible to design a UI, yet it's a necessity for allowing more people to interact with it (democratisation).
|
|
@@ -93,6 +93,10 @@ Create an account and login (local database)
|
|
|
93
93
|
- **Database**: manage workflows in _Library_ tab.
|
|
94
94
|
- **Info page**: additional info in _About_ tab.
|
|
95
95
|
|
|
96
|
+
[//]: # ()
|
|
97
|
+
|
|
98
|
+
[//]: # ()
|
|
99
|
+
|
|
96
100
|
|
|
97
101
|
### Additional settings
|
|
98
102
|
#### AI assistant
|
|
@@ -133,7 +137,7 @@ After one successful connection, a blueprint will be automatically saved and mad
|
|
|
133
137
|
ivoryos.run()
|
|
134
138
|
```
|
|
135
139
|
## Demo
|
|
136
|
-
In the [abstract_sdl.py](https://gitlab.com/heingroup/ivoryos/-/blob/main/example/
|
|
140
|
+
In the [abstract_sdl.py](https://gitlab.com/heingroup/ivoryos/-/blob/main/example/abstract_sdl_example/abstract_sdl.py), where instances of `AbstractSDL` is created as `sdl`,
|
|
137
141
|
addresses will be available on terminal.
|
|
138
142
|
```Python
|
|
139
143
|
ivoryos.run(__name__)
|
|
@@ -1,46 +1,50 @@
|
|
|
1
|
-
ivoryos/__init__.py,sha256=
|
|
1
|
+
ivoryos/__init__.py,sha256=pvQVtXOuDSaOwxMkcfgE00kEVXMFUsOsvjv49-Hy0Z4,6877
|
|
2
2
|
ivoryos/config.py,sha256=3FPBYTIBhQTKDvsEoR8ZeTmg65D-CSFEdGmOuIL4pSI,1311
|
|
3
|
-
ivoryos/version.py,sha256=
|
|
3
|
+
ivoryos/version.py,sha256=0byemO6n6WCv41u9vBG2AIsOkVbxLvok7puvwy8EhfU,23
|
|
4
4
|
ivoryos/routes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
ivoryos/routes/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
ivoryos/routes/auth/auth.py,sha256=7CdXjGAr1B_xsmwweakTWOoROgsOJf0MNTzlMP_5Nus,3240
|
|
7
7
|
ivoryos/routes/auth/templates/auth/login.html,sha256=WSRrKbdM_oobqSXFRTo-j9UlOgp6sYzS9tm7TqqPULI,1207
|
|
8
8
|
ivoryos/routes/auth/templates/auth/signup.html,sha256=b5LTXtpfTSkSS7X8u1ldwQbbgEFTk6UNMAediA5BwBY,1465
|
|
9
9
|
ivoryos/routes/control/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
ivoryos/routes/control/control.py,sha256=
|
|
10
|
+
ivoryos/routes/control/control.py,sha256=bxNYR-VAFA7tSswDt5k130AnIx1f64_R9N2B9kMridI,14160
|
|
11
11
|
ivoryos/routes/control/templates/control/controllers.html,sha256=iIp0h6WA68gQj9OsoiB7dU1BqH8CGomTueR73F4C8eY,4274
|
|
12
|
-
ivoryos/routes/control/templates/control/controllers_home.html,sha256=
|
|
12
|
+
ivoryos/routes/control/templates/control/controllers_home.html,sha256=VQ77HRvBlyBrQ3al5fcKF5Y6_vKtU8WeAhilqQQltAo,2997
|
|
13
13
|
ivoryos/routes/control/templates/control/controllers_new.html,sha256=uOQo9kYmwX2jk3KZDkMUF_ylfNUIs_oIWb_kk_MMVDM,4921
|
|
14
14
|
ivoryos/routes/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
ivoryos/routes/database/database.py,sha256=
|
|
16
|
-
ivoryos/routes/database/templates/database/experiment_database.html,sha256=
|
|
15
|
+
ivoryos/routes/database/database.py,sha256=uchoLXRx8ShJZIu20NZya6FJ4LMg2b9yvn6hjEq3dlU,7687
|
|
16
|
+
ivoryos/routes/database/templates/database/experiment_database.html,sha256=edlCcKfrS91gGG1dPFQjC9xD7F7nWNNqS3S6Oa7apzs,3460
|
|
17
|
+
ivoryos/routes/database/templates/database/experiment_step_view.html,sha256=u8_XYhiZ98PzglMzFEkuM1Tk9hVWf79xXIrpHVDxKa0,3618
|
|
18
|
+
ivoryos/routes/database/templates/database/step_card.html,sha256=F4JRfacrEQfk2rrEbcI_i7G84nzKKDmCrMSmStLb4W4,290
|
|
19
|
+
ivoryos/routes/database/templates/database/workflow_run_database.html,sha256=MczK9my9u0SyQsMFLbc6CXeZqKaBo5vk1SpwjkcZdqk,3571
|
|
17
20
|
ivoryos/routes/design/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
|
-
ivoryos/routes/design/design.py,sha256=
|
|
19
|
-
ivoryos/routes/design/templates/design/experiment_builder.html,sha256=
|
|
20
|
-
ivoryos/routes/design/templates/design/experiment_run.html,sha256=
|
|
21
|
+
ivoryos/routes/design/design.py,sha256=gO8FKuSdGD6EiN3cbspk7jv6y2Ar25A-ZdrCyUTInpE,25221
|
|
22
|
+
ivoryos/routes/design/templates/design/experiment_builder.html,sha256=rEdcHj5onJG_4MejdFBPnJVzsvCMp1KDteqNkpx24kQ,29430
|
|
23
|
+
ivoryos/routes/design/templates/design/experiment_run.html,sha256=Q7cYYTgvZ8SBzqkDEhAwR634-LLcYq4Gof4bpH_adt0,30397
|
|
21
24
|
ivoryos/routes/main/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
25
|
ivoryos/routes/main/main.py,sha256=yuVJzXAob1kc1dfflkTBIZQ0tdf6kChfuq-uQlN1e9Q,957
|
|
23
26
|
ivoryos/routes/main/templates/main/help.html,sha256=IOktMEsOPk0SCiMBXZ4mpffClERAyX8W82fel71M3M0,9370
|
|
24
|
-
ivoryos/routes/main/templates/main/home.html,sha256=
|
|
27
|
+
ivoryos/routes/main/templates/main/home.html,sha256=8AhQOWakD-1TyWA0s-B9ZK96L_f8ywYUEGHW1UzMGZA,4634
|
|
25
28
|
ivoryos/static/favicon.ico,sha256=RhlrPtfITOkzC9BjP1UB1V5L9Oyp6NwNtWeMcGOnpyc,15406
|
|
26
29
|
ivoryos/static/logo.webp,sha256=lXgfQR-4mHTH83k7VV9iB54-oC2ipe6uZvbwdOnLETc,14974
|
|
27
30
|
ivoryos/static/style.css,sha256=zQVx35A5g6JMJ-K84-6fSKtzXGjp_p5ZVG6KLHPM2IE,4021
|
|
28
31
|
ivoryos/static/gui_annotation/Slide1.png,sha256=Lm4gdOkUF5HIUFaB94tl6koQVkzpitKj43GXV_XYMMc,121727
|
|
29
32
|
ivoryos/static/gui_annotation/Slide2.PNG,sha256=z3wQ9oVgg4JTWVLQGKK_KhtepRHUYP1e05XUWGT2A0I,118761
|
|
30
33
|
ivoryos/static/js/overlay.js,sha256=dPxop19es0E0ZUSY3d_4exIk7CJuQEnlW5uTt5fZfzI,483
|
|
31
|
-
ivoryos/static/js/socket_handler.js,sha256=
|
|
34
|
+
ivoryos/static/js/socket_handler.js,sha256=YGwWlT8TqNBvvIzs2G9g1g7nM2-vUPZjCwmQt4Yv0Uw,5078
|
|
32
35
|
ivoryos/static/js/sortable_card.js,sha256=ifmlGe3yy0U_KzMphV4ClRhK2DLOvkELYMlq1vECuac,807
|
|
33
36
|
ivoryos/static/js/sortable_design.js,sha256=wwpKfIzZGDxfX3moNz0cvPvm9YyHmopZK3wmkUdnBiw,4333
|
|
34
|
-
ivoryos/templates/base.html,sha256=
|
|
37
|
+
ivoryos/templates/base.html,sha256=sDdwqOIUP2Get-py4E59PkieoGWLFpX6wAJe93s4aRo,8518
|
|
35
38
|
ivoryos/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
|
-
ivoryos/utils/
|
|
37
|
-
ivoryos/utils/
|
|
39
|
+
ivoryos/utils/client_proxy.py,sha256=AzcSQGMqeCqVULP1a7vEKNe135NZYryVX63ke0wgK04,2099
|
|
40
|
+
ivoryos/utils/db_models.py,sha256=1G2De1nLRCGwuY4zqgMeIQ-p1XJ_PkBxH1cd0fJ9YgY,26740
|
|
41
|
+
ivoryos/utils/form.py,sha256=b3JKxRc1jN45-bXyfzSJT1lcssUuxT86FhRmNUDv5-U,20973
|
|
38
42
|
ivoryos/utils/global_config.py,sha256=P0xs_33bZfNQ-D71lCkq7HJyT4ngQWPqUKnkoMrmM8c,1908
|
|
39
|
-
ivoryos/utils/llm_agent.py,sha256
|
|
40
|
-
ivoryos/utils/script_runner.py,sha256=
|
|
41
|
-
ivoryos/utils/utils.py,sha256=
|
|
42
|
-
ivoryos-0.1.
|
|
43
|
-
ivoryos-0.1.
|
|
44
|
-
ivoryos-0.1.
|
|
45
|
-
ivoryos-0.1.
|
|
46
|
-
ivoryos-0.1.
|
|
43
|
+
ivoryos/utils/llm_agent.py,sha256=-lVCkjPlpLues9sNTmaT7bT4sdhWvV2DiojNwzB2Lcw,6422
|
|
44
|
+
ivoryos/utils/script_runner.py,sha256=iyeYCTPWnukW3F8UsarIdZxFzDnHBq6MH0ydfVGNFaw,13286
|
|
45
|
+
ivoryos/utils/utils.py,sha256=VP-4Wf-slK2pMe659K5TJLbZXVNvyCD1-3kdfp_COxI,14990
|
|
46
|
+
ivoryos-0.1.23.dist-info/LICENSE,sha256=p2c8S8i-8YqMpZCJnadLz1-ofxnRMILzz6NCMIypRag,1084
|
|
47
|
+
ivoryos-0.1.23.dist-info/METADATA,sha256=_QVtGZkZfoLRYpUTX4qsJwO-rJEU5P7y3H_QnDp7Xok,6846
|
|
48
|
+
ivoryos-0.1.23.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
49
|
+
ivoryos-0.1.23.dist-info/top_level.txt,sha256=FRIWWdiEvRKqw-XfF_UK3XV0CrnNb6EmVbEgjaVazRM,8
|
|
50
|
+
ivoryos-0.1.23.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|