ivoryos 1.2.7__tar.gz → 1.2.8__tar.gz
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-1.2.7 → ivoryos-1.2.8}/PKG-INFO +1 -1
- ivoryos-1.2.8/ivoryos/__init__.py +13 -0
- ivoryos-1.2.8/ivoryos/app.py +94 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/control/control.py +8 -6
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/control/templates/controllers.html +18 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/control/utils.py +2 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/design.py +11 -4
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/action_form.html +2 -2
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/instruments_panel.html +23 -1
- ivoryos-1.2.7/ivoryos/__init__.py → ivoryos-1.2.8/ivoryos/server.py +18 -98
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/static/js/socket_handler.js +39 -4
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/static/js/sortable_design.js +28 -11
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/utils/db_models.py +40 -5
- ivoryos-1.2.8/ivoryos/utils/decorators.py +33 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/utils/form.py +4 -2
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/utils/global_config.py +10 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/utils/script_runner.py +21 -2
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/utils/task_runner.py +7 -2
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/utils/utils.py +20 -1
- ivoryos-1.2.8/ivoryos/version.py +1 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos.egg-info/PKG-INFO +1 -1
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos.egg-info/SOURCES.txt +3 -0
- ivoryos-1.2.7/ivoryos/version.py +0 -1
- {ivoryos-1.2.7 → ivoryos-1.2.8}/LICENSE +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/README.md +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/config.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/optimizer/ax_optimizer.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/optimizer/base_optimizer.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/optimizer/baybe_optimizer.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/optimizer/registry.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/__init__.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/api/api.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/auth/__init__.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/auth/auth.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/auth/templates/login.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/auth/templates/signup.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/control/__init__.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/control/control_file.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/control/control_new_device.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/control/templates/controllers_new.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/data/__init__.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/data/data.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/data/templates/components/step_card.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/data/templates/workflow_database.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/data/templates/workflow_view.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/__init__.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/design_file.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/design_step.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/actions_panel.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/autofill_toggle.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/canvas.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/canvas_footer.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/canvas_header.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/canvas_main.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/deck_selector.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/edit_action_form.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/modals/drop_modal.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/modals/json_modal.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/modals/new_script_modal.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/modals/rename_modal.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/modals/saveas_modal.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/modals.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/python_code_overlay.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/sidebar.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/text_to_code_panel.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/experiment_builder.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/execute/__init__.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/execute/execute.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/execute/execute_file.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/execute/templates/components/error_modal.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/execute/templates/components/logging_panel.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/execute/templates/components/progress_panel.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/execute/templates/components/run_panel.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/execute/templates/components/run_tabs.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/execute/templates/components/tab_bayesian.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/execute/templates/components/tab_configuration.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/execute/templates/components/tab_repeat.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/execute/templates/experiment_run.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/library/__init__.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/library/library.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/library/templates/library.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/main/__init__.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/main/main.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/main/templates/help.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/main/templates/home.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/socket_handlers.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/static/favicon.ico +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/static/gui_annotation/Slide1.png +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/static/gui_annotation/Slide2.PNG +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/static/js/action_handlers.js +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/static/js/db_delete.js +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/static/js/overlay.js +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/static/js/script_metadata.js +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/static/js/sortable_card.js +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/static/js/ui_state.js +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/static/logo.webp +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/static/style.css +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/templates/base.html +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/utils/__init__.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/utils/bo_campaign.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/utils/client_proxy.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/utils/llm_agent.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/utils/py_to_json.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/utils/serilize.py +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos.egg-info/dependency_links.txt +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos.egg-info/requires.txt +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos.egg-info/top_level.txt +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/pyproject.toml +0 -0
- {ivoryos-1.2.7 → ivoryos-1.2.8}/setup.cfg +0 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from ivoryos.server import run
|
|
2
|
+
from ivoryos.optimizer.registry import OPTIMIZER_REGISTRY
|
|
3
|
+
from ivoryos.version import __version__ as ivoryos_version
|
|
4
|
+
from ivoryos.utils.decorators import block, BUILDING_BLOCKS
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"block",
|
|
9
|
+
"BUILDING_BLOCKS",
|
|
10
|
+
"OPTIMIZER_REGISTRY",
|
|
11
|
+
"run",
|
|
12
|
+
"ivoryos_version",
|
|
13
|
+
]
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import uuid
|
|
3
|
+
|
|
4
|
+
from flask import Flask, session, g, redirect, url_for
|
|
5
|
+
from flask_login import AnonymousUserMixin
|
|
6
|
+
|
|
7
|
+
from ivoryos.utils import utils
|
|
8
|
+
from ivoryos.utils.db_models import db
|
|
9
|
+
from ivoryos.config import Config, get_config
|
|
10
|
+
from ivoryos.routes.auth.auth import auth, login_manager
|
|
11
|
+
from ivoryos.routes.control.control import control
|
|
12
|
+
from ivoryos.routes.data.data import data
|
|
13
|
+
from ivoryos.routes.library.library import library
|
|
14
|
+
from ivoryos.routes.design.design import design
|
|
15
|
+
from ivoryos.routes.execute.execute import execute
|
|
16
|
+
from ivoryos.routes.api.api import api
|
|
17
|
+
from ivoryos.socket_handlers import socketio
|
|
18
|
+
from ivoryos.routes.main.main import main
|
|
19
|
+
from ivoryos.version import __version__ as ivoryos_version
|
|
20
|
+
|
|
21
|
+
def create_app(config_class=None):
|
|
22
|
+
"""
|
|
23
|
+
create app, init database
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
url_prefix = os.getenv('URL_PREFIX', "/ivoryos")
|
|
27
|
+
app = Flask(__name__, static_url_path=f'{url_prefix}/static', static_folder='static')
|
|
28
|
+
app.register_blueprint(main, url_prefix=url_prefix)
|
|
29
|
+
app.register_blueprint(auth, url_prefix=f'{url_prefix}/{auth.name}')
|
|
30
|
+
app.register_blueprint(library, url_prefix=f'{url_prefix}/{library.name}')
|
|
31
|
+
app.register_blueprint(control, url_prefix=f'{url_prefix}/instruments')
|
|
32
|
+
app.register_blueprint(design, url_prefix=f'{url_prefix}')
|
|
33
|
+
app.register_blueprint(execute, url_prefix=f'{url_prefix}')
|
|
34
|
+
app.register_blueprint(data, url_prefix=f'{url_prefix}')
|
|
35
|
+
app.register_blueprint(api, url_prefix=f'{url_prefix}/{api.name}')
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
app.config.from_object(config_class or 'config.get_config()')
|
|
39
|
+
os.makedirs(app.config["OUTPUT_FOLDER"], exist_ok=True)
|
|
40
|
+
# Initialize extensions
|
|
41
|
+
socketio.init_app(app, cors_allowed_origins="*", cookie=None)
|
|
42
|
+
login_manager.init_app(app)
|
|
43
|
+
login_manager.login_view = "auth.login"
|
|
44
|
+
db.init_app(app)
|
|
45
|
+
|
|
46
|
+
# Create database tables
|
|
47
|
+
with app.app_context():
|
|
48
|
+
db.create_all()
|
|
49
|
+
|
|
50
|
+
# Additional setup
|
|
51
|
+
utils.create_gui_dir(app.config['OUTPUT_FOLDER'])
|
|
52
|
+
|
|
53
|
+
# logger_list = app.config["LOGGERS"]
|
|
54
|
+
logger_path = os.path.join(app.config["OUTPUT_FOLDER"], app.config["LOGGERS_PATH"])
|
|
55
|
+
logger = utils.start_logger(socketio, 'gui_logger', logger_path)
|
|
56
|
+
|
|
57
|
+
@app.before_request
|
|
58
|
+
def before_request():
|
|
59
|
+
"""
|
|
60
|
+
Called before
|
|
61
|
+
|
|
62
|
+
"""
|
|
63
|
+
g.logger = logger
|
|
64
|
+
g.socketio = socketio
|
|
65
|
+
session.permanent = False
|
|
66
|
+
# DEMO_MODE: Simulate logged-in user per session
|
|
67
|
+
if app.config.get("DEMO_MODE", False):
|
|
68
|
+
if "demo_user_id" not in session:
|
|
69
|
+
session["demo_user_id"] = f"demo_{str(uuid.uuid4())[:8]}"
|
|
70
|
+
|
|
71
|
+
class SessionDemoUser(AnonymousUserMixin):
|
|
72
|
+
@property
|
|
73
|
+
def is_authenticated(self):
|
|
74
|
+
return True
|
|
75
|
+
|
|
76
|
+
def get_id(self):
|
|
77
|
+
return session.get("demo_user_id")
|
|
78
|
+
|
|
79
|
+
login_manager.anonymous_user = SessionDemoUser
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@app.route('/')
|
|
84
|
+
def redirect_to_prefix():
|
|
85
|
+
return redirect(url_for('main.index', version=ivoryos_version)) # Assuming 'index' is a route in your blueprint
|
|
86
|
+
|
|
87
|
+
@app.template_filter('format_name')
|
|
88
|
+
def format_name(name):
|
|
89
|
+
name = name.split(".")[-1]
|
|
90
|
+
text = ' '.join(word for word in name.split('_'))
|
|
91
|
+
return text.capitalize()
|
|
92
|
+
|
|
93
|
+
# app.config.setdefault("DEMO_MODE", False)
|
|
94
|
+
return app
|
|
@@ -5,7 +5,7 @@ from ivoryos.routes.control.control_file import control_file
|
|
|
5
5
|
from ivoryos.routes.control.control_new_device import control_temp
|
|
6
6
|
from ivoryos.routes.control.utils import post_session_by_instrument, get_session_by_instrument, find_instrument_by_name
|
|
7
7
|
from ivoryos.utils.global_config import GlobalConfig
|
|
8
|
-
from ivoryos.utils.form import create_form_from_module
|
|
8
|
+
from ivoryos.utils.form import create_form_from_module, create_form_from_pseudo
|
|
9
9
|
from ivoryos.utils.task_runner import TaskRunner
|
|
10
10
|
|
|
11
11
|
global_config = GlobalConfig()
|
|
@@ -48,7 +48,10 @@ def deck_controllers(instrument: str = None):
|
|
|
48
48
|
forms = None
|
|
49
49
|
if instrument:
|
|
50
50
|
inst_object = find_instrument_by_name(instrument)
|
|
51
|
-
|
|
51
|
+
if instrument.startswith("blocks"):
|
|
52
|
+
forms = create_form_from_pseudo(pseudo=inst_object, autofill=False, design=False)
|
|
53
|
+
else:
|
|
54
|
+
forms = create_form_from_module(sdl_module=inst_object, autofill=False, design=False)
|
|
52
55
|
order = get_session_by_instrument('card_order', instrument)
|
|
53
56
|
hidden_functions = get_session_by_instrument('hidden_functions', instrument)
|
|
54
57
|
functions = list(forms.keys())
|
|
@@ -99,12 +102,11 @@ def deck_controllers(instrument: str = None):
|
|
|
99
102
|
function_data["signature"] = str(function_data["signature"])
|
|
100
103
|
return jsonify(snapshot)
|
|
101
104
|
|
|
102
|
-
deck_variables = global_config.deck_snapshot.keys()
|
|
103
|
-
temp_variables = global_config.defined_variables.keys()
|
|
104
105
|
return render_template(
|
|
105
106
|
"controllers.html",
|
|
106
|
-
defined_variables=
|
|
107
|
-
|
|
107
|
+
defined_variables=global_config.deck_snapshot.keys(),
|
|
108
|
+
block_variables=global_config.building_blocks.keys(),
|
|
109
|
+
temp_variables=global_config.defined_variables.keys(),
|
|
108
110
|
instrument=instrument,
|
|
109
111
|
forms=forms,
|
|
110
112
|
session=session
|
|
@@ -49,6 +49,24 @@
|
|
|
49
49
|
</div>
|
|
50
50
|
</div>
|
|
51
51
|
{% endif %}
|
|
52
|
+
|
|
53
|
+
{% if block_variables %}
|
|
54
|
+
<div class="mb-4">
|
|
55
|
+
<h6 class="fw-bold text-secondary mb-2" style="letter-spacing: 1px;">Methods</h6>
|
|
56
|
+
<div class="list-group">
|
|
57
|
+
{% for inst in block_variables %}
|
|
58
|
+
<a class="list-group-item list-group-item-action d-flex align-items-center {% if instrument == inst %}active bg-warning text-dark border-0{% else %}bg-light{% endif %}"
|
|
59
|
+
href="{{ url_for('control.deck_controllers') }}?instrument={{ inst }}"
|
|
60
|
+
style="border-radius: 0.5rem; margin-bottom: 0.5rem; transition: background 0.2s;">
|
|
61
|
+
<span class="flex-grow-1">{{ inst | format_name }}</span>
|
|
62
|
+
{% if instrument == inst %}
|
|
63
|
+
<span class="ms-auto">></span>
|
|
64
|
+
{% endif %}
|
|
65
|
+
</a>
|
|
66
|
+
{% endfor %}
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
{% endif %}
|
|
52
70
|
<!-- Action Buttons -->
|
|
53
71
|
<div class="mb-4">
|
|
54
72
|
<a href="{{ url_for('control.file.download_proxy', filetype='proxy') }}" class="btn btn-outline-primary w-100 mb-2">
|
|
@@ -13,6 +13,8 @@ def find_instrument_by_name(name: str):
|
|
|
13
13
|
if name.startswith("deck"):
|
|
14
14
|
name = name.replace("deck.", "")
|
|
15
15
|
return getattr(global_config.deck, name)
|
|
16
|
+
elif name.startswith("blocks"):
|
|
17
|
+
return global_config.building_blocks[name]
|
|
16
18
|
elif name in global_config.defined_variables:
|
|
17
19
|
return global_config.defined_variables[name]
|
|
18
20
|
elif name in globals():
|
|
@@ -35,6 +35,9 @@ def _create_forms(instrument, script, autofill, pseudo_deck = None):
|
|
|
35
35
|
_object = global_config.defined_variables.get(instrument)
|
|
36
36
|
functions = utils._inspect_class(_object)
|
|
37
37
|
forms = create_form_from_pseudo(pseudo=functions, autofill=autofill, script=script)
|
|
38
|
+
elif instrument.startswith("blocks"):
|
|
39
|
+
forms = create_form_from_pseudo(pseudo=global_config.building_blocks[instrument], autofill=autofill, script=script)
|
|
40
|
+
functions = global_config.building_blocks[instrument]
|
|
38
41
|
else:
|
|
39
42
|
if deck:
|
|
40
43
|
functions = global_config.deck_snapshot.get(instrument, {})
|
|
@@ -92,7 +95,7 @@ def experiment_builder():
|
|
|
92
95
|
|
|
93
96
|
return render_template('experiment_builder.html', off_line=off_line, history=deck_list,
|
|
94
97
|
script=script, defined_variables=deck_variables, buttons_dict=design_buttons,
|
|
95
|
-
local_variables=global_config.defined_variables)
|
|
98
|
+
local_variables=global_config.defined_variables, block_variables=global_config.building_blocks)
|
|
96
99
|
|
|
97
100
|
|
|
98
101
|
@design.route("/draft/meta", methods=["PATCH"])
|
|
@@ -192,7 +195,8 @@ def update_ui_state():
|
|
|
192
195
|
deck_variables = list(pseudo_deck.keys()) if pseudo_deck else []
|
|
193
196
|
deck_variables.remove("deck_name") if len(deck_variables) > 0 else deck_variables
|
|
194
197
|
html = render_template("components/sidebar.html", history=deck_list,
|
|
195
|
-
defined_variables=deck_variables, local_variables = global_config.defined_variables
|
|
198
|
+
defined_variables=deck_variables, local_variables = global_config.defined_variables,
|
|
199
|
+
block_variables=global_config.building_blocks)
|
|
196
200
|
return jsonify({"html": html})
|
|
197
201
|
return jsonify({"error": "Invalid request"}), 400
|
|
198
202
|
|
|
@@ -310,6 +314,7 @@ def methods_handler(instrument: str = ''):
|
|
|
310
314
|
|
|
311
315
|
success = True
|
|
312
316
|
msg = ""
|
|
317
|
+
request.form
|
|
313
318
|
if "hidden_name" in request.form:
|
|
314
319
|
method_name = request.form.get("hidden_name", None)
|
|
315
320
|
form = forms.get(method_name) if forms else None
|
|
@@ -322,7 +327,7 @@ def methods_handler(instrument: str = ''):
|
|
|
322
327
|
primitive_arg_types = utils.get_arg_type(kwargs, functions[function_name])
|
|
323
328
|
|
|
324
329
|
# todo
|
|
325
|
-
print(primitive_arg_types)
|
|
330
|
+
# print(primitive_arg_types)
|
|
326
331
|
|
|
327
332
|
script.eval_list(kwargs, primitive_arg_types)
|
|
328
333
|
kwargs = script.validate_variables(kwargs)
|
|
@@ -422,7 +427,9 @@ def get_operation_sidebar(instrument: str = ''):
|
|
|
422
427
|
# edit_action_info = session.get("edit_action")
|
|
423
428
|
html = render_template("components/sidebar.html", off_line=off_line, history=deck_list,
|
|
424
429
|
defined_variables=deck_variables,
|
|
425
|
-
local_variables=global_config.defined_variables
|
|
430
|
+
local_variables=global_config.defined_variables,
|
|
431
|
+
block_variables=global_config.building_blocks,
|
|
432
|
+
)
|
|
426
433
|
return jsonify({"html": html})
|
|
427
434
|
|
|
428
435
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{# Action form component #}
|
|
2
|
-
<div class="accordion-item design-control"
|
|
3
|
-
<h2 class="accordion-header">
|
|
2
|
+
<div class="accordion-item design-control">
|
|
3
|
+
<h2 class="accordion-header" >
|
|
4
4
|
<button class="accordion-button collapsed draggable-action"
|
|
5
5
|
type="button" data-bs-toggle="collapse"
|
|
6
6
|
data-bs-target="#{{name}}" aria-expanded="false"
|
{ivoryos-1.2.7 → ivoryos-1.2.8}/ivoryos/routes/design/templates/components/instruments_panel.html
RENAMED
|
@@ -39,7 +39,29 @@
|
|
|
39
39
|
</ul>
|
|
40
40
|
</div>
|
|
41
41
|
</div>
|
|
42
|
-
|
|
42
|
+
{% if block_variables %}
|
|
43
|
+
<div class="accordion-item design-control">
|
|
44
|
+
<h5 class="accordion-header">
|
|
45
|
+
<button class="accordion-button" data-bs-toggle="collapse" data-bs-target="#block" role="button" aria-expanded="false" aria-controls="collapseExample">
|
|
46
|
+
Methods
|
|
47
|
+
</button>
|
|
48
|
+
</h5>
|
|
49
|
+
<div class="accordion-collapse collapse show" id="block">
|
|
50
|
+
<ul class="list-group">
|
|
51
|
+
{% for category in block_variables %}
|
|
52
|
+
<button class="list-group-item list-group-item-action"
|
|
53
|
+
type="button"
|
|
54
|
+
name="device"
|
|
55
|
+
value="{{category}}"
|
|
56
|
+
data-get-url="{{ url_for('design.get_operation_sidebar', instrument=category) }}"
|
|
57
|
+
onclick="updateInstrumentPanel(this)">
|
|
58
|
+
{{ category|format_name }}
|
|
59
|
+
</button>
|
|
60
|
+
{% endfor%}
|
|
61
|
+
</ul>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
{% endif %}
|
|
43
65
|
{% if local_variables %}
|
|
44
66
|
<div class="accordion-item design-control">
|
|
45
67
|
<h5 class="accordion-header">
|
|
@@ -1,37 +1,24 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import sqlite3
|
|
2
3
|
import sys
|
|
3
|
-
import uuid
|
|
4
4
|
from typing import Union
|
|
5
5
|
|
|
6
|
-
from flask import
|
|
7
|
-
from flask_login import AnonymousUserMixin
|
|
6
|
+
from flask import Blueprint
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
from sqlalchemy import Engine, event
|
|
10
9
|
|
|
10
|
+
# from ivoryos import BUILDING_BLOCKS
|
|
11
|
+
from ivoryos.app import create_app
|
|
11
12
|
from ivoryos.config import Config, get_config
|
|
12
|
-
from ivoryos.
|
|
13
|
-
from ivoryos.routes.
|
|
14
|
-
from ivoryos.routes.
|
|
15
|
-
from ivoryos.routes.library.library import library
|
|
16
|
-
from ivoryos.routes.design.design import design
|
|
17
|
-
from ivoryos.routes.execute.execute import execute
|
|
18
|
-
from ivoryos.routes.api.api import api
|
|
13
|
+
from ivoryos.optimizer.registry import OPTIMIZER_REGISTRY
|
|
14
|
+
from ivoryos.routes.auth.auth import login_manager
|
|
15
|
+
from ivoryos.routes.control.control import global_config
|
|
19
16
|
from ivoryos.socket_handlers import socketio
|
|
20
|
-
from ivoryos.routes.main.main import main
|
|
21
|
-
# from ivoryos.routes.monitor.monitor import monitor
|
|
22
17
|
from ivoryos.utils import utils
|
|
23
18
|
from ivoryos.utils.db_models import db, User
|
|
24
|
-
from ivoryos.utils.global_config import GlobalConfig
|
|
25
|
-
from ivoryos.optimizer.registry import OPTIMIZER_REGISTRY
|
|
26
|
-
from ivoryos.utils.script_runner import ScriptRunner
|
|
27
|
-
from ivoryos.version import __version__ as ivoryos_version
|
|
28
|
-
# from importlib.metadata import entry_points
|
|
29
19
|
|
|
30
|
-
global_config = GlobalConfig()
|
|
31
|
-
from sqlalchemy import event
|
|
32
|
-
from sqlalchemy.engine import Engine
|
|
33
|
-
import sqlite3
|
|
34
20
|
|
|
21
|
+
url_prefix = os.getenv('URL_PREFIX', "/ivoryos")
|
|
35
22
|
|
|
36
23
|
@event.listens_for(Engine, "connect")
|
|
37
24
|
def enforce_sqlite_foreign_keys(dbapi_connection, connection_record):
|
|
@@ -41,16 +28,6 @@ def enforce_sqlite_foreign_keys(dbapi_connection, connection_record):
|
|
|
41
28
|
cursor.close()
|
|
42
29
|
|
|
43
30
|
|
|
44
|
-
url_prefix = os.getenv('URL_PREFIX', "/ivoryos")
|
|
45
|
-
app = Flask(__name__, static_url_path=f'{url_prefix}/static', static_folder='static')
|
|
46
|
-
app.register_blueprint(main, url_prefix=url_prefix)
|
|
47
|
-
app.register_blueprint(auth, url_prefix=f'{url_prefix}/{auth.name}')
|
|
48
|
-
app.register_blueprint(library, url_prefix=f'{url_prefix}/{library.name}')
|
|
49
|
-
app.register_blueprint(control, url_prefix=f'{url_prefix}/instruments')
|
|
50
|
-
app.register_blueprint(design, url_prefix=f'{url_prefix}')
|
|
51
|
-
app.register_blueprint(execute, url_prefix=f'{url_prefix}')
|
|
52
|
-
app.register_blueprint(data, url_prefix=f'{url_prefix}')
|
|
53
|
-
app.register_blueprint(api, url_prefix=f'{url_prefix}/{api.name}')
|
|
54
31
|
|
|
55
32
|
@login_manager.user_loader
|
|
56
33
|
def load_user(user_id):
|
|
@@ -62,68 +39,8 @@ def load_user(user_id):
|
|
|
62
39
|
return db.session.get(User, user_id)
|
|
63
40
|
|
|
64
41
|
|
|
65
|
-
def create_app(config_class=None):
|
|
66
|
-
"""
|
|
67
|
-
create app, init database
|
|
68
|
-
"""
|
|
69
|
-
app.config.from_object(config_class or 'config.get_config()')
|
|
70
|
-
os.makedirs(app.config["OUTPUT_FOLDER"], exist_ok=True)
|
|
71
|
-
# Initialize extensions
|
|
72
|
-
socketio.init_app(app, cors_allowed_origins="*", cookie=None)
|
|
73
|
-
login_manager.init_app(app)
|
|
74
|
-
login_manager.login_view = "auth.login"
|
|
75
|
-
db.init_app(app)
|
|
76
|
-
|
|
77
|
-
# Create database tables
|
|
78
|
-
with app.app_context():
|
|
79
|
-
db.create_all()
|
|
80
|
-
|
|
81
|
-
# Additional setup
|
|
82
|
-
utils.create_gui_dir(app.config['OUTPUT_FOLDER'])
|
|
83
|
-
|
|
84
|
-
# logger_list = app.config["LOGGERS"]
|
|
85
|
-
logger_path = os.path.join(app.config["OUTPUT_FOLDER"], app.config["LOGGERS_PATH"])
|
|
86
|
-
logger = utils.start_logger(socketio, 'gui_logger', logger_path)
|
|
87
|
-
|
|
88
|
-
@app.before_request
|
|
89
|
-
def before_request():
|
|
90
|
-
"""
|
|
91
|
-
Called before
|
|
92
|
-
|
|
93
|
-
"""
|
|
94
|
-
g.logger = logger
|
|
95
|
-
g.socketio = socketio
|
|
96
|
-
session.permanent = False
|
|
97
|
-
# DEMO_MODE: Simulate logged-in user per session
|
|
98
|
-
if app.config.get("DEMO_MODE", False):
|
|
99
|
-
if "demo_user_id" not in session:
|
|
100
|
-
session["demo_user_id"] = f"demo_{str(uuid.uuid4())[:8]}"
|
|
101
|
-
|
|
102
|
-
class SessionDemoUser(AnonymousUserMixin):
|
|
103
|
-
@property
|
|
104
|
-
def is_authenticated(self):
|
|
105
|
-
return True
|
|
106
|
-
|
|
107
|
-
def get_id(self):
|
|
108
|
-
return session.get("demo_user_id")
|
|
109
|
-
|
|
110
|
-
login_manager.anonymous_user = SessionDemoUser
|
|
111
|
-
|
|
112
42
|
|
|
113
43
|
|
|
114
|
-
@app.route('/')
|
|
115
|
-
def redirect_to_prefix():
|
|
116
|
-
return redirect(url_for('main.index', version=ivoryos_version)) # Assuming 'index' is a route in your blueprint
|
|
117
|
-
|
|
118
|
-
@app.template_filter('format_name')
|
|
119
|
-
def format_name(name):
|
|
120
|
-
name = name.split(".")[-1]
|
|
121
|
-
text = ' '.join(word for word in name.split('_'))
|
|
122
|
-
return text.capitalize()
|
|
123
|
-
|
|
124
|
-
# app.config.setdefault("DEMO_MODE", False)
|
|
125
|
-
return app
|
|
126
|
-
|
|
127
44
|
|
|
128
45
|
def run(module=None, host="0.0.0.0", port=None, debug=None, llm_server=None, model=None,
|
|
129
46
|
config: Config = None,
|
|
@@ -182,6 +99,8 @@ def run(module=None, host="0.0.0.0", port=None, debug=None, llm_server=None, mod
|
|
|
182
99
|
save=True,
|
|
183
100
|
exclude_names=exclude_names
|
|
184
101
|
)
|
|
102
|
+
global_config.building_blocks = utils.create_block_snapshot()
|
|
103
|
+
|
|
185
104
|
else:
|
|
186
105
|
app.config["OFF_LINE"] = True
|
|
187
106
|
if model:
|
|
@@ -200,12 +119,12 @@ def run(module=None, host="0.0.0.0", port=None, debug=None, llm_server=None, mod
|
|
|
200
119
|
for log in logger:
|
|
201
120
|
utils.start_logger(socketio, log_filename=logger_path, logger_name=log)
|
|
202
121
|
|
|
203
|
-
# in case Python 3.12 or higher doesn't log URL
|
|
204
|
-
if sys.version_info >= (3, 12):
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
122
|
+
# TODO in case Python 3.12 or higher doesn't log URL
|
|
123
|
+
# if sys.version_info >= (3, 12):
|
|
124
|
+
# ip = utils.get_local_ip()
|
|
125
|
+
# print(f"Server running at http://localhost:{port}")
|
|
126
|
+
# if not ip == "127.0.0.1":
|
|
127
|
+
# print(f"Server running at http://{ip}:{port}")
|
|
209
128
|
socketio.run(app, host=host, port=port, debug=debug, use_reloader=False, allow_unsafe_werkzeug=True)
|
|
210
129
|
# return app
|
|
211
130
|
|
|
@@ -246,3 +165,4 @@ def load_plugins(blueprints: Union[list, Blueprint], app, socketio):
|
|
|
246
165
|
plugin_names.append(blueprint.name)
|
|
247
166
|
app.register_blueprint(blueprint, url_prefix=f"{url_prefix}/{blueprint.name}")
|
|
248
167
|
return plugin_names
|
|
168
|
+
|
|
@@ -37,13 +37,43 @@ document.addEventListener("DOMContentLoaded", function() {
|
|
|
37
37
|
console.error("Error received:", errorData);
|
|
38
38
|
var progressBar = document.getElementById('progress-bar-inner');
|
|
39
39
|
|
|
40
|
-
progressBar.classList.remove('bg-success');
|
|
41
|
-
progressBar.classList.add('bg-danger');
|
|
42
|
-
|
|
40
|
+
progressBar.classList.remove('bg-success', 'bg-warning');
|
|
41
|
+
progressBar.classList.add('bg-danger');
|
|
42
|
+
|
|
43
43
|
var errorModal = new bootstrap.Modal(document.getElementById('error-modal'));
|
|
44
|
-
document.getElementById('
|
|
44
|
+
document.getElementById('errorModalLabel').innerText = "Error Detected";
|
|
45
|
+
document.getElementById('error-message').innerText =
|
|
46
|
+
"An error occurred: " + errorData.message;
|
|
47
|
+
|
|
48
|
+
// Show all buttons again
|
|
49
|
+
document.getElementById('retry-btn').style.display = "inline-block";
|
|
50
|
+
document.getElementById('continue-btn').style.display = "inline-block";
|
|
51
|
+
document.getElementById('stop-btn').style.display = "inline-block";
|
|
52
|
+
|
|
45
53
|
errorModal.show();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
socket.on('human_intervention', function(data) {
|
|
58
|
+
console.warn("Human intervention required:", data);
|
|
59
|
+
var progressBar = document.getElementById('progress-bar-inner');
|
|
46
60
|
|
|
61
|
+
// Set progress bar to yellow
|
|
62
|
+
progressBar.classList.remove('bg-success', 'bg-danger');
|
|
63
|
+
progressBar.classList.add('bg-warning');
|
|
64
|
+
|
|
65
|
+
// Reuse error modal but update content
|
|
66
|
+
var errorModal = new bootstrap.Modal(document.getElementById('error-modal'));
|
|
67
|
+
document.getElementById('errorModalLabel').innerText = "Human Intervention Required";
|
|
68
|
+
document.getElementById('error-message').innerText =
|
|
69
|
+
"Workflow paused: " + (data.message || "Please check and manually resume.");
|
|
70
|
+
|
|
71
|
+
// Optionally: hide retry button, since it may not apply
|
|
72
|
+
document.getElementById('retry-btn').style.display = "none";
|
|
73
|
+
document.getElementById('continue-btn').style.display = "inline-block";
|
|
74
|
+
document.getElementById('stop-btn').style.display = "inline-block";
|
|
75
|
+
|
|
76
|
+
errorModal.show();
|
|
47
77
|
});
|
|
48
78
|
|
|
49
79
|
// Handle Pause/Resume Button
|
|
@@ -71,6 +101,11 @@ document.addEventListener("DOMContentLoaded", function() {
|
|
|
71
101
|
document.getElementById('continue-btn').addEventListener('click', function() {
|
|
72
102
|
socket.emit('pause'); // Resume execution
|
|
73
103
|
console.log("Execution resumed.");
|
|
104
|
+
|
|
105
|
+
// Reset progress bar color to running (blue)
|
|
106
|
+
var progressBar = document.getElementById('progress-bar-inner');
|
|
107
|
+
progressBar.classList.remove('bg-danger', 'bg-warning');
|
|
108
|
+
progressBar.classList.add('bg-primary');
|
|
74
109
|
});
|
|
75
110
|
|
|
76
111
|
document.getElementById('retry-btn').addEventListener('click', function() {
|
|
@@ -115,20 +115,37 @@ function insertDropPlaceholder($target) {
|
|
|
115
115
|
|
|
116
116
|
// Add this function to sortable_design.js
|
|
117
117
|
function initializeDragHandlers() {
|
|
118
|
-
$(".accordion-item
|
|
119
|
-
let formHtml = $(this).find(".accordion-body form").prop('outerHTML');
|
|
120
|
-
|
|
121
|
-
if (!formHtml) {
|
|
122
|
-
console.error("Form not found in accordion-body");
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
118
|
+
const $cards = $(".accordion-item.design-control");
|
|
125
119
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
120
|
+
// Toggle draggable based on mouse/touch position
|
|
121
|
+
$cards.off("mousedown touchstart").on("mousedown touchstart", function (event) {
|
|
122
|
+
this.setAttribute("draggable", $(event.target).closest(".input-group").length ? "false" : "true");
|
|
123
|
+
});
|
|
129
124
|
|
|
130
|
-
|
|
125
|
+
// Handle the actual drag
|
|
126
|
+
$cards.off("dragstart dragend").on({
|
|
127
|
+
dragstart: function (event) {
|
|
128
|
+
if (this.getAttribute("draggable") !== "true") {
|
|
129
|
+
event.preventDefault();
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const formHtml = $(this).find(".accordion-body form").prop("outerHTML");
|
|
134
|
+
if (!formHtml) return false;
|
|
135
|
+
|
|
136
|
+
event.originalEvent.dataTransfer.setData("form", formHtml);
|
|
137
|
+
event.originalEvent.dataTransfer.setData("action", $(this).find(".draggable-action").data("action"));
|
|
138
|
+
event.originalEvent.dataTransfer.setData("id", $(this).find(".draggable-action").attr("id"));
|
|
139
|
+
|
|
140
|
+
$(this).addClass("dragging");
|
|
141
|
+
},
|
|
142
|
+
dragend: function () {
|
|
143
|
+
$(this).removeClass("dragging").attr("draggable", "false");
|
|
144
|
+
}
|
|
131
145
|
});
|
|
146
|
+
|
|
147
|
+
// Prevent form inputs from being draggable
|
|
148
|
+
$(".accordion-item input, .accordion-item select").attr("draggable", "false");
|
|
132
149
|
}
|
|
133
150
|
|
|
134
151
|
// Make sure it's called in the document ready function
|
|
@@ -318,6 +318,12 @@ class Script(db.Model):
|
|
|
318
318
|
{"id": current_len + 2, "instrument": 'repeat', "action": 'endrepeat',
|
|
319
319
|
"args": {}, "return": '', "uuid": uid},
|
|
320
320
|
],
|
|
321
|
+
"pause":
|
|
322
|
+
[
|
|
323
|
+
{"id": current_len + 1, "instrument": 'pause', "action": "pause",
|
|
324
|
+
"args": {"statement": 1 if statement == '' else statement}, "return": '', "uuid": uid,
|
|
325
|
+
"arg_types": {"statement": "str"}}
|
|
326
|
+
],
|
|
321
327
|
}
|
|
322
328
|
action_list = logic_dict[logic_type]
|
|
323
329
|
self.currently_editing_script.extend(action_list)
|
|
@@ -443,6 +449,9 @@ class Script(db.Model):
|
|
|
443
449
|
Compile the current script to a Python file.
|
|
444
450
|
:return: String to write to a Python file.
|
|
445
451
|
"""
|
|
452
|
+
self.needs_call_human = False
|
|
453
|
+
self.blocks_included = False
|
|
454
|
+
|
|
446
455
|
self.sort_actions()
|
|
447
456
|
run_name = self.name if self.name else "untitled"
|
|
448
457
|
run_name = self.validate_function_name(run_name)
|
|
@@ -524,6 +533,9 @@ class Script(db.Model):
|
|
|
524
533
|
return f"{self.indent(indent_unit)}time.sleep({statement})", indent_unit
|
|
525
534
|
elif instrument == 'repeat':
|
|
526
535
|
return self._process_repeat(indent_unit, action_name, statement, next_action)
|
|
536
|
+
elif instrument == 'pause':
|
|
537
|
+
self.needs_call_human = True
|
|
538
|
+
return f"{self.indent(indent_unit)}pause('{statement}')", indent_unit
|
|
527
539
|
#todo
|
|
528
540
|
# elif instrument == 'registered_workflows':
|
|
529
541
|
# return inspect.getsource(my_function)
|
|
@@ -592,14 +604,18 @@ class Script(db.Model):
|
|
|
592
604
|
"""
|
|
593
605
|
Process actions related to instruments.
|
|
594
606
|
"""
|
|
607
|
+
function_call = f"{instrument}.{action}"
|
|
608
|
+
if instrument.startswith("blocks"):
|
|
609
|
+
self.blocks_included = True
|
|
610
|
+
function_call = action
|
|
595
611
|
|
|
596
|
-
if isinstance(args, dict):
|
|
612
|
+
if isinstance(args, dict) and args != {}:
|
|
597
613
|
args_str = self._process_dict_args(args)
|
|
598
|
-
single_line = f"{
|
|
614
|
+
single_line = f"{function_call}(**{args_str})"
|
|
599
615
|
elif isinstance(args, str):
|
|
600
|
-
single_line = f"{
|
|
616
|
+
single_line = f"{function_call} = {args}"
|
|
601
617
|
else:
|
|
602
|
-
single_line = f"{
|
|
618
|
+
single_line = f"{function_call}()"
|
|
603
619
|
|
|
604
620
|
if save_data:
|
|
605
621
|
save_data += " = "
|
|
@@ -640,7 +656,7 @@ class Script(db.Model):
|
|
|
640
656
|
"""
|
|
641
657
|
return arg in self.script_dict and self.script_dict[arg].get("arg_types") == "variable"
|
|
642
658
|
|
|
643
|
-
def _write_to_file(self, script_path, run_name, exec_string):
|
|
659
|
+
def _write_to_file(self, script_path, run_name, exec_string, call_human=False):
|
|
644
660
|
"""
|
|
645
661
|
Write the compiled script to a file.
|
|
646
662
|
"""
|
|
@@ -650,9 +666,28 @@ class Script(db.Model):
|
|
|
650
666
|
else:
|
|
651
667
|
s.write("deck = None")
|
|
652
668
|
s.write("\nimport time")
|
|
669
|
+
if self.blocks_included:
|
|
670
|
+
s.write(f"\n{self._create_block_import()}")
|
|
671
|
+
if self.needs_call_human:
|
|
672
|
+
s.write("""\n\ndef pause(reason="Manual intervention required"):\n\tprint(f"\\nHUMAN INTERVENTION REQUIRED: {reason}")\n\tinput("Press Enter to continue...\\n")""")
|
|
673
|
+
|
|
653
674
|
for i in exec_string.values():
|
|
654
675
|
s.write(f"\n\n\n{i}")
|
|
655
676
|
|
|
677
|
+
def _create_block_import(self):
|
|
678
|
+
imports = {}
|
|
679
|
+
from ivoryos.utils.decorators import BUILDING_BLOCKS
|
|
680
|
+
for category, methods in BUILDING_BLOCKS.items():
|
|
681
|
+
for method_name, meta in methods.items():
|
|
682
|
+
func = meta["func"]
|
|
683
|
+
module = meta["path"]
|
|
684
|
+
name = func.__name__
|
|
685
|
+
imports.setdefault(module, set()).add(name)
|
|
686
|
+
lines = []
|
|
687
|
+
for module, funcs in imports.items():
|
|
688
|
+
lines.append(f"from {module} import {', '.join(sorted(funcs))}")
|
|
689
|
+
return "\n".join(lines)
|
|
690
|
+
|
|
656
691
|
class WorkflowRun(db.Model):
|
|
657
692
|
__tablename__ = 'workflow_runs'
|
|
658
693
|
|