ivoryos 1.2.0b1__py3-none-any.whl → 1.2.2__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.

Files changed (82) hide show
  1. ivoryos/__init__.py +22 -1
  2. ivoryos/config.py +1 -0
  3. ivoryos/optimizer/ax_optimizer.py +164 -0
  4. ivoryos/optimizer/base_optimizer.py +65 -0
  5. ivoryos/optimizer/baybe_optimizer.py +183 -0
  6. ivoryos/optimizer/registry.py +9 -0
  7. ivoryos/routes/auth/auth.py +3 -1
  8. ivoryos/routes/data/data.py +2 -0
  9. ivoryos/routes/design/design.py +4 -4
  10. ivoryos/routes/library/library.py +4 -4
  11. ivoryos/utils/script_runner.py +1 -1
  12. ivoryos/utils/serilize.py +4 -6
  13. ivoryos/utils/utils.py +2 -1
  14. ivoryos/version.py +1 -1
  15. {ivoryos-1.2.0b1.dist-info → ivoryos-1.2.2.dist-info}/METADATA +60 -35
  16. ivoryos-1.2.2.dist-info/RECORD +47 -0
  17. {ivoryos-1.2.0b1.dist-info → ivoryos-1.2.2.dist-info}/WHEEL +1 -1
  18. {ivoryos-1.2.0b1.dist-info → ivoryos-1.2.2.dist-info}/top_level.txt +0 -1
  19. ivoryos/routes/auth/templates/login.html +0 -25
  20. ivoryos/routes/auth/templates/signup.html +0 -32
  21. ivoryos/routes/control/templates/controllers.html +0 -166
  22. ivoryos/routes/control/templates/controllers_new.html +0 -112
  23. ivoryos/routes/data/templates/components/step_card.html +0 -13
  24. ivoryos/routes/data/templates/workflow_database.html +0 -109
  25. ivoryos/routes/data/templates/workflow_view.html +0 -130
  26. ivoryos/routes/design/templates/components/action_form.html +0 -53
  27. ivoryos/routes/design/templates/components/actions_panel.html +0 -25
  28. ivoryos/routes/design/templates/components/autofill_toggle.html +0 -10
  29. ivoryos/routes/design/templates/components/canvas.html +0 -5
  30. ivoryos/routes/design/templates/components/canvas_footer.html +0 -9
  31. ivoryos/routes/design/templates/components/canvas_header.html +0 -75
  32. ivoryos/routes/design/templates/components/canvas_main.html +0 -34
  33. ivoryos/routes/design/templates/components/deck_selector.html +0 -10
  34. ivoryos/routes/design/templates/components/edit_action_form.html +0 -38
  35. ivoryos/routes/design/templates/components/instruments_panel.html +0 -66
  36. ivoryos/routes/design/templates/components/modals/drop_modal.html +0 -17
  37. ivoryos/routes/design/templates/components/modals/json_modal.html +0 -22
  38. ivoryos/routes/design/templates/components/modals/new_script_modal.html +0 -17
  39. ivoryos/routes/design/templates/components/modals/rename_modal.html +0 -23
  40. ivoryos/routes/design/templates/components/modals/saveas_modal.html +0 -27
  41. ivoryos/routes/design/templates/components/modals.html +0 -6
  42. ivoryos/routes/design/templates/components/python_code_overlay.html +0 -39
  43. ivoryos/routes/design/templates/components/sidebar.html +0 -15
  44. ivoryos/routes/design/templates/components/text_to_code_panel.html +0 -20
  45. ivoryos/routes/design/templates/experiment_builder.html +0 -41
  46. ivoryos/routes/execute/templates/components/error_modal.html +0 -20
  47. ivoryos/routes/execute/templates/components/logging_panel.html +0 -31
  48. ivoryos/routes/execute/templates/components/progress_panel.html +0 -27
  49. ivoryos/routes/execute/templates/components/run_panel.html +0 -9
  50. ivoryos/routes/execute/templates/components/run_tabs.html +0 -17
  51. ivoryos/routes/execute/templates/components/tab_bayesian.html +0 -399
  52. ivoryos/routes/execute/templates/components/tab_configuration.html +0 -98
  53. ivoryos/routes/execute/templates/components/tab_repeat.html +0 -14
  54. ivoryos/routes/execute/templates/experiment_run.html +0 -294
  55. ivoryos/routes/library/templates/library.html +0 -91
  56. ivoryos/routes/main/templates/help.html +0 -141
  57. ivoryos/routes/main/templates/home.html +0 -103
  58. ivoryos/static/favicon.ico +0 -0
  59. ivoryos/static/gui_annotation/Slide1.png +0 -0
  60. ivoryos/static/gui_annotation/Slide2.PNG +0 -0
  61. ivoryos/static/js/action_handlers.js +0 -213
  62. ivoryos/static/js/db_delete.js +0 -23
  63. ivoryos/static/js/overlay.js +0 -12
  64. ivoryos/static/js/script_metadata.js +0 -39
  65. ivoryos/static/js/socket_handler.js +0 -125
  66. ivoryos/static/js/sortable_card.js +0 -24
  67. ivoryos/static/js/sortable_design.js +0 -138
  68. ivoryos/static/js/ui_state.js +0 -113
  69. ivoryos/static/logo.webp +0 -0
  70. ivoryos/static/style.css +0 -211
  71. ivoryos/templates/base.html +0 -157
  72. ivoryos-1.2.0b1.dist-info/RECORD +0 -105
  73. tests/__init__.py +0 -0
  74. tests/conftest.py +0 -133
  75. tests/integration/__init__.py +0 -0
  76. tests/integration/test_route_auth.py +0 -80
  77. tests/integration/test_route_control.py +0 -94
  78. tests/integration/test_route_database.py +0 -61
  79. tests/integration/test_route_design.py +0 -36
  80. tests/integration/test_route_main.py +0 -35
  81. tests/integration/test_sockets.py +0 -26
  82. {ivoryos-1.2.0b1.dist-info → ivoryos-1.2.2.dist-info/licenses}/LICENSE +0 -0
ivoryos/__init__.py CHANGED
@@ -1,8 +1,11 @@
1
1
  import os
2
2
  import sys
3
+ import uuid
3
4
  from typing import Union
4
5
 
5
- from flask import Flask, redirect, url_for, g, Blueprint
6
+ from flask import Flask, redirect, url_for, g, Blueprint, session
7
+ from flask_login import AnonymousUserMixin
8
+
6
9
  sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
7
10
 
8
11
  from ivoryos.config import Config, get_config
@@ -90,6 +93,23 @@ def create_app(config_class=None):
90
93
  """
91
94
  g.logger = logger
92
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
+
93
113
 
94
114
  @app.route('/')
95
115
  def redirect_to_prefix():
@@ -101,6 +121,7 @@ def create_app(config_class=None):
101
121
  text = ' '.join(word for word in name.split('_'))
102
122
  return text.capitalize()
103
123
 
124
+ # app.config.setdefault("DEMO_MODE", False)
104
125
  return app
105
126
 
106
127
 
ivoryos/config.py CHANGED
@@ -43,6 +43,7 @@ class TestingConfig(Config):
43
43
 
44
44
  class DemoConfig(Config):
45
45
  DEBUG = False
46
+ DEMO_MODE = True
46
47
  SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
47
48
  OUTPUT_FOLDER = os.path.join(os.path.abspath(os.curdir), '/tmp/ivoryos_data')
48
49
  CSV_FOLDER = os.path.join(OUTPUT_FOLDER, 'config_csv/')
@@ -0,0 +1,164 @@
1
+ # optimizers/ax_optimizer.py
2
+ from typing import Dict
3
+
4
+
5
+
6
+ from ivoryos.optimizer.base_optimizer import OptimizerBase
7
+ from ivoryos.utils.utils import install_and_import
8
+
9
+ class AxOptimizer(OptimizerBase):
10
+ def __init__(self, experiment_name, parameter_space, objective_config, optimizer_config=None):
11
+ try:
12
+ from ax.api.client import Client
13
+ except ImportError as e:
14
+ install_and_import("ax", "ax-platform")
15
+ raise ImportError("Please install Ax with pip install ax-platform to use AxOptimizer. Attempting to install Ax...")
16
+ super().__init__(experiment_name, parameter_space, objective_config, optimizer_config)
17
+
18
+ self.client = Client()
19
+ # 2. Configure where Ax will search.
20
+ self.client.configure_experiment(
21
+ name=experiment_name,
22
+ parameters=self._convert_parameter_to_ax_format(parameter_space)
23
+ )
24
+ # 3. Configure the objective function.
25
+ self.client.configure_optimization(objective=self._convert_objective_to_ax_format(objective_config))
26
+ if optimizer_config:
27
+ self.client.set_generation_strategy(self._convert_generator_to_ax_format(optimizer_config))
28
+ self.generators = self._create_generator_mapping()
29
+
30
+ @staticmethod
31
+ def _create_generator_mapping():
32
+ """Create a mapping from string values to Generator enum members."""
33
+ from ax.modelbridge import Generators
34
+ return {member.value: member for member in Generators}
35
+
36
+ def _convert_parameter_to_ax_format(self, parameter_space):
37
+ """
38
+ Converts the parameter space configuration to Baybe format.
39
+ :param parameter_space: The parameter space configuration.
40
+ [
41
+ {"name": "param_1", "type": "range", "bounds": [1.0, 2.0], "value_type": "float"},
42
+ {"name": "param_2", "type": "choice", "bounds": ["a", "b", "c"], "value_type": "str"},
43
+ {"name": "param_3", "type": "range", "bounds": [0 10], "value_type": "int"},
44
+ ]
45
+ :return: A list of Baybe parameters.
46
+ """
47
+ from ax import RangeParameterConfig, ChoiceParameterConfig
48
+ ax_params = []
49
+ for p in parameter_space:
50
+ if p["type"] == "range":
51
+ ax_params.append(
52
+ RangeParameterConfig(
53
+ name=p["name"],
54
+ bounds=tuple(p["bounds"]),
55
+ parameter_type=p["value_type"]
56
+ ))
57
+ elif p["type"] == "choice":
58
+ ax_params.append(
59
+ ChoiceParameterConfig(
60
+ name=p["name"],
61
+ values=p["bounds"],
62
+ parameter_type=p["value_type"],
63
+ )
64
+ )
65
+ return ax_params
66
+
67
+ def _convert_objective_to_ax_format(self, objective_config: list):
68
+ """
69
+ Converts the objective configuration to Baybe format.
70
+ :param parameter_space: The parameter space configuration.
71
+ [
72
+ {"name": "obj_1", "minimize": True, "weight": 1},
73
+ {"name": "obj_2", "minimize": False, "weight": 2}
74
+ ]
75
+ :return: Ax objective configuration. "-cost, utility"
76
+ """
77
+ objectives = []
78
+ for obj in objective_config:
79
+ obj_name = obj.get("name")
80
+ minimize = obj.get("minimize", True)
81
+ weight = obj.get("weight", 1)
82
+ sign = "-" if minimize else ""
83
+ objectives.append(f"{sign}{weight} * {obj_name}")
84
+ return ", ".join(objectives)
85
+
86
+ def _convert_generator_to_ax_format(self, optimizer_config):
87
+ """
88
+ Converts the optimizer configuration to Ax format.
89
+ :param optimizer_config: The optimizer configuration.
90
+ :return: Ax generator configuration.
91
+ """
92
+ from ax.generation_strategy.generation_node import GenerationStep
93
+ from ax.generation_strategy.generation_strategy import GenerationStrategy
94
+ generators = self._create_generator_mapping()
95
+ step_1 = optimizer_config.get("step_1", {})
96
+ step_2 = optimizer_config.get("step_2", {})
97
+ step_1_generator = step_1.get("model", "Sobol")
98
+ step_2_generator = step_2.get("model", "BOTorch")
99
+ generator_1 = GenerationStep(model=generators.get(step_1_generator), num_trials=step_1.get("num_samples", 5))
100
+ generator_2 = GenerationStep(model=generators.get(step_2_generator), num_trials=step_2.get("num_samples", -1))
101
+ return GenerationStrategy(steps=[generator_1, generator_2])
102
+
103
+ def suggest(self, n=1):
104
+ trial_index, params = self.client.get_next_trials(1).popitem()
105
+ self.trial_index = trial_index
106
+ return params
107
+
108
+ def observe(self, results):
109
+ self.client.complete_trial(
110
+ trial_index=self.trial_index,
111
+ raw_data=results
112
+ )
113
+
114
+ @staticmethod
115
+ def get_schema():
116
+ return {
117
+ "parameter_types": ["range", "choice"],
118
+ "multiple_objectives": True,
119
+ # "objective_weights": True,
120
+ "optimizer_config": {
121
+ "step_1": {"model": ["Sobol", "Uniform", "Factorial", "Thompson"], "num_samples": 5},
122
+ "step_2": {"model": ["BoTorch", "SAASBO", "SAAS_MTGP", "Legacy_GPEI", "EB", "EB_Ashr", "ST_MTGP", "BO_MIXED", "Contextual_SACBO"]}
123
+ },
124
+ }
125
+
126
+ def append_existing_data(self, existing_data):
127
+ """
128
+ Append existing data to the Ax experiment.
129
+ :param existing_data: A dictionary containing existing data.
130
+ """
131
+ from pandas import DataFrame
132
+ if not existing_data:
133
+ return
134
+ if isinstance(existing_data, DataFrame):
135
+ existing_data = existing_data.to_dict(orient="records")
136
+ parameter_names = [i.get("name") for i in self.parameter_space]
137
+ objective_names = [i.get("name") for i in self.objective_config]
138
+ for name, value in existing_data.items():
139
+ # First attach the trial and note the trial index
140
+ parameters = {name: value for name in existing_data if name in parameter_names}
141
+ trial_index = self.client.attach_trial(parameters=parameters)
142
+ raw_data = {name: value for name in existing_data if name in objective_names}
143
+ # Then complete the trial with the existing data
144
+ self.client.complete_trial(trial_index=trial_index, raw_data=raw_data)
145
+
146
+
147
+ if __name__ == "__main__":
148
+ # Example usage
149
+ optimizer = AxOptimizer(
150
+ experiment_name="example_experiment",
151
+ parameter_space=[
152
+ {"name": "param_1", "type": "range", "bounds": [0.0, 1.0], "value_type": "float"},
153
+ {"name": "param_2", "type": "choice", "bounds": ["a", "b", "c"], "value_type": "str"}
154
+ ],
155
+ objective_config=[
156
+ {"name": "objective_1", "minimize": True},
157
+ {"name": "objective_2", "minimize": False}
158
+ ],
159
+ optimizer_config={
160
+ "step_1": {"model": "Sobol", "num_samples": 5},
161
+ "step_2": {"model": "BoTorch"}
162
+ }
163
+ )
164
+ print(optimizer._create_generator_mapping())
@@ -0,0 +1,65 @@
1
+ ### ivoryos/optimizers/base.py
2
+
3
+ from abc import ABC, abstractmethod
4
+
5
+
6
+
7
+ class OptimizerBase(ABC):
8
+ def __init__(self, experiment_name:str, parameter_space: list, objective_config: dict, optimizer_config: dict):
9
+ """
10
+ :param experiment_name: arbitrary name
11
+ :param parameter_space: list of parameter names
12
+ [
13
+ {"name": "param_1", "type": "range", "bounds": [1.0, 2.0], "value_type": "float"},
14
+ {"name": "param_2", "type": "choice", "bounds": ["a", "b", "c"], "value_type": "str"},
15
+ {"name": "param_3", "type": "range", "bounds": [0 10], "value_type": "int"},
16
+ ]
17
+ :param objective_config: objective configuration
18
+ [
19
+ {"name": "obj_1", "minimize": True, "weight": 1},
20
+ {"name": "obj_2", "minimize": False, "weight": 1}
21
+ ]
22
+ :param optimizer_config: optimizer configuration
23
+ optimizer_config={
24
+ "step_1": {"model": "Random", "num_samples": 10},
25
+ "step_2": {"model": "BOTorch"}
26
+ }
27
+ """
28
+ self.experiment_name = experiment_name
29
+ self.parameter_space = parameter_space
30
+ self.objective_config = objective_config
31
+ self.optimizer_config = optimizer_config
32
+
33
+ @abstractmethod
34
+ def suggest(self, n=1):
35
+ pass
36
+
37
+ @abstractmethod
38
+ def observe(self, results: dict):
39
+ """
40
+ observe
41
+ :param results: {"objective_name": "value"}
42
+ """
43
+ pass
44
+
45
+ @abstractmethod
46
+ def append_existing_data(self, existing_data):
47
+ pass
48
+
49
+ @staticmethod
50
+ def get_schema():
51
+ """
52
+ Returns a template for the optimizer configuration.
53
+ """
54
+ return {
55
+ "parameter_types": ["range", "choice"],
56
+ "multiple_objectives": True,
57
+ # "objective_weights": True,
58
+ "optimizer_config": {
59
+ "step_1": {"model": [], "num_samples": 10},
60
+ "step_2": {"model": []}
61
+ },
62
+ }
63
+
64
+
65
+
@@ -0,0 +1,183 @@
1
+ ### Directory: ivoryos/optimizers/baybe_optimizer.py
2
+ from typing import Dict
3
+
4
+
5
+ from ivoryos.utils.utils import install_and_import
6
+ from ivoryos.optimizer.base_optimizer import OptimizerBase
7
+
8
+ class BaybeOptimizer(OptimizerBase):
9
+ def __init__(self, experiment_name, parameter_space, objective_config, optimizer_config):
10
+ try:
11
+ from baybe import Campaign
12
+ except ImportError:
13
+ install_and_import("baybe")
14
+ print("Please install Baybe with pip install baybe to before register BaybeOptimizer.")
15
+
16
+ super().__init__(experiment_name, parameter_space, objective_config, optimizer_config)
17
+ self._trial_id = 0
18
+ self._trials = {}
19
+
20
+ self.experiment = Campaign(
21
+ searchspace=self._convert_parameter_to_searchspace(parameter_space),
22
+ objective=self._convert_objective_to_baybe_format(objective_config),
23
+ recommender=self._convert_recommender_to_baybe_format(optimizer_config),
24
+ )
25
+
26
+
27
+ def suggest(self, n=1):
28
+ self.df = self.experiment.recommend(batch_size=n)
29
+ return self.df.to_dict(orient="records")[0]
30
+
31
+ def observe(self, results, index=None):
32
+ """
33
+ Observes the results of a trial and updates the experiment.
34
+ :param results: A dictionary containing the results of the trial.
35
+ :param index: The index of the trial in the DataFrame, if applicable.
36
+
37
+ """
38
+ for name, value in results.items():
39
+ self.df[name] = [value]
40
+ self.experiment.add_measurements(self.df)
41
+
42
+ def append_existing_data(self, existing_data: Dict):
43
+ """
44
+ Append existing data to the Ax experiment.
45
+ :param existing_data: A dictionary containing existing data.
46
+ """
47
+ import pandas as pd
48
+ if not existing_data:
49
+ return
50
+ # parameter_names = [i.get("name") for i in self.parameter_space]
51
+ # objective_names = [i.get("name") for i in self.objective_config]
52
+ self.experiment.add_measurements(pd.DataFrame(existing_data))
53
+ # for name, value in existing_data.items():
54
+ # # First attach the trial and note the trial index
55
+ # parameters = {name: value for name in existing_data if name in parameter_names}
56
+ # trial_index = self.client.attach_trial(parameters=parameters)
57
+ # raw_data = {name: value for name in existing_data if name in objective_names}
58
+ # # Then complete the trial with the existing data
59
+ # self.client.complete_trial(trial_index=trial_index, raw_data=raw_data)
60
+
61
+
62
+ def _convert_parameter_to_searchspace(self, parameter_space):
63
+ """
64
+ Converts the parameter space configuration to Baybe format.
65
+ :param parameter_space: The parameter space configuration.
66
+ [
67
+ {"name": "param_1", "type": "range", "bounds": [1.0, 2.0], "value_type": "float"},
68
+ {"name": "param_2", "type": "choice", "bounds": ["a", "b", "c"], "value_type": "str"},
69
+ {"name": "param_3", "type": "range", "bounds": [0 10], "value_type": "int"},
70
+ {"name": "param_4", "type": "substance", "bounds": ["methanol", "water", "toluene"], "value_type": "str"} #TODO
71
+ ]
72
+ :return: A list of Baybe parameters.
73
+ """
74
+ from baybe.parameters.categorical import CategoricalParameter
75
+ from baybe.parameters.numerical import NumericalContinuousParameter, NumericalDiscreteParameter
76
+ from baybe.searchspace import SearchSpace
77
+ parameters = []
78
+ for p in parameter_space:
79
+ if p["type"] == "range":
80
+ if p["value_type"] == "float":
81
+ parameters.append(NumericalContinuousParameter(name=p["name"], bounds=p["bounds"]))
82
+ elif p["value_type"] == "int":
83
+ values = tuple([int(v) for v in range(p["bounds"][0], p["bounds"][1] + 1)])
84
+ parameters.append(NumericalDiscreteParameter(name=p["name"], values=values))
85
+
86
+ elif p["type"] == "choice":
87
+ if p["value_type"] == "str":
88
+ parameters.append(CategoricalParameter(name=p["name"], values=p["bounds"]))
89
+ elif p["value_type"] in ["int", "float"]:
90
+ parameters.append(NumericalDiscreteParameter(name=p["name"], values=p["bounds"]))
91
+ return SearchSpace.from_product(parameters)
92
+
93
+ def _convert_objective_to_baybe_format(self, objective_config):
94
+ """
95
+ Converts the objective configuration to Baybe format.
96
+ :param parameter_space: The parameter space configuration.
97
+ [
98
+ {"name": "obj_1", "minimize": True},
99
+ {"name": "obj_2", "minimize": False}
100
+ ]
101
+ :return: A Baybe objective configuration.
102
+ """
103
+ from baybe.targets import NumericalTarget
104
+ from baybe.objectives import SingleTargetObjective, DesirabilityObjective, ParetoObjective
105
+ targets = []
106
+ weights = []
107
+ for obj in objective_config:
108
+ obj_name = obj.get("name")
109
+ minimize = obj.get("minimize", False)
110
+ weight = obj.get("weight", 1)
111
+ weights.append(weight)
112
+ targets.append(NumericalTarget(name=obj_name, mode="MAX" if minimize else "MIN"))
113
+
114
+ if len(targets) == 1:
115
+ return SingleTargetObjective(target=targets[0])
116
+ else:
117
+ # Handle multiple objectives
118
+ return ParetoObjective(targets=targets)
119
+
120
+
121
+ def _convert_recommender_to_baybe_format(self, recommender_config):
122
+ """
123
+ Converts the recommender configuration to Baybe format.
124
+ :param recommender_config: The recommender configuration.
125
+ :return: A Baybe recommender configuration.
126
+ """
127
+ from baybe.recommenders import (
128
+ BotorchRecommender,
129
+ FPSRecommender,
130
+ TwoPhaseMetaRecommender,
131
+ RandomRecommender,
132
+ NaiveHybridSpaceRecommender
133
+ )
134
+ step_1 = recommender_config.get("step_1", {})
135
+ step_2 = recommender_config.get("step_2", {})
136
+ step_1_recommender = step_1.get("model", "Random")
137
+ step_2_recommender = step_2.get("model", "BOTorch")
138
+ if step_1.get("model") == "Random":
139
+ step_1_recommender = RandomRecommender()
140
+ elif step_1.get("model") == "FPS":
141
+ step_1_recommender = FPSRecommender()
142
+ if step_2.get("model") == "Naive Hybrid Space":
143
+ step_2_recommender = NaiveHybridSpaceRecommender()
144
+ elif step_2.get("model") == "BOTorch":
145
+ step_2_recommender = BotorchRecommender()
146
+ return TwoPhaseMetaRecommender(
147
+ initial_recommender=step_1_recommender,
148
+ recommender=step_2_recommender
149
+ )
150
+
151
+ @staticmethod
152
+ def get_schema():
153
+ """
154
+ Returns a template for the optimizer configuration.
155
+ """
156
+ return {
157
+ "parameter_types": ["range", "choice", "substance"],
158
+ "multiple_objectives": True,
159
+ "optimizer_config": {
160
+ "step_1": {"model": ["Random", "FPS"], "num_samples": 10},
161
+ "step_2": {"model": ["BOTorch", "Naive Hybrid Space"]}
162
+ },
163
+ }
164
+
165
+ if __name__ == "__main__":
166
+ # Example usage
167
+ baybe_optimizer = BaybeOptimizer(
168
+ experiment_name="example_experiment",
169
+ parameter_space=[
170
+ {"name": "param_1", "type": "range", "bounds": [1.0, 2.0], "value_type": "float"},
171
+ {"name": "param_2", "type": "choice", "bounds": ["a", "b", "c"], "value_type": "str"},
172
+ {"name": "param_3", "type": "range", "bounds": [0, 10], "value_type": "int"}
173
+ ],
174
+ objective_config=[
175
+ {"name": "obj_1", "minimize": True},
176
+ {"name": "obj_2", "minimize": False}
177
+ ],
178
+ optimizer_config={
179
+ "step_1": {"model": "Random", "num_samples": 10},
180
+ "step_2": {"model": "BOTorch"}
181
+ }
182
+ )
183
+ print(baybe_optimizer.suggest(5))
@@ -0,0 +1,9 @@
1
+ # optimizers/registry.py
2
+
3
+ from ivoryos.optimizer.ax_optimizer import AxOptimizer
4
+ from ivoryos.optimizer.baybe_optimizer import BaybeOptimizer
5
+
6
+ OPTIMIZER_REGISTRY = {
7
+ "ax": AxOptimizer,
8
+ "baybe": BaybeOptimizer
9
+ }
@@ -5,6 +5,7 @@ import bcrypt
5
5
  from ivoryos.utils.db_models import Script, User, db
6
6
  from ivoryos.utils.utils import post_script_file
7
7
  login_manager = LoginManager()
8
+ # from flask import g
8
9
 
9
10
  auth = Blueprint('auth', __name__, template_folder='templates')
10
11
 
@@ -37,7 +38,8 @@ def login():
37
38
  # password.encode("utf-8")
38
39
  # user = User(username, password.encode("utf-8"))
39
40
  login_user(user)
40
- session['user'] = username
41
+ # g.user = user
42
+ # session['user'] = username
41
43
  script_file = Script(author=username)
42
44
  session["script"] = script_file.as_dict()
43
45
  session['hidden_functions'], session['card_order'], session['prompt'] = {}, {}, {}
@@ -10,6 +10,7 @@ data = Blueprint('data', __name__, template_folder='templates')
10
10
 
11
11
 
12
12
  @data.route('/executions/records')
13
+ @login_required
13
14
  def list_workflows():
14
15
  """
15
16
  .. :quickref: Workflow Execution Database; list all workflow execution records
@@ -113,6 +114,7 @@ def delete_workflow_record(workflow_id: int):
113
114
 
114
115
 
115
116
  @data.route('/files/execution-data/<string:filename>')
117
+ @login_required
116
118
  def download_results(filename:str):
117
119
  """
118
120
  .. :quickref: Workflow data; download a workflow data file (.CSV)
@@ -1,7 +1,7 @@
1
1
  import os
2
2
 
3
3
  from flask import Blueprint, redirect, url_for, flash, jsonify, request, render_template, session, current_app
4
- from flask_login import login_required
4
+ from flask_login import login_required, current_user
5
5
 
6
6
  from ivoryos.routes.library.library import publish
7
7
  from ivoryos.utils import utils
@@ -64,7 +64,7 @@ def experiment_builder():
64
64
  if deck and script.deck is None:
65
65
  script.deck = os.path.splitext(os.path.basename(deck.__file__))[
66
66
  0] if deck.__name__ == "__main__" else deck.__name__
67
-
67
+ utils.post_script_file(script)
68
68
  pseudo_deck_name = session.get('pseudo_deck', '')
69
69
  pseudo_deck_path = os.path.join(current_app.config["DUMMY_DECK"], pseudo_deck_name)
70
70
  off_line = current_app.config["OFF_LINE"]
@@ -238,7 +238,7 @@ def clear_draft():
238
238
  0] if deck.__name__ == "__main__" else deck.__name__
239
239
  else:
240
240
  deck_name = session.get("pseudo_deck", "")
241
- script = Script(deck=deck_name, author=session.get('username'))
241
+ script = Script(deck=deck_name, author=current_user.get_id())
242
242
  utils.post_script_file(script)
243
243
  exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
244
244
  session['python_code'] = exec_string
@@ -265,7 +265,7 @@ def submit_script():
265
265
  """
266
266
  deck = global_config.deck
267
267
  deck_name = os.path.splitext(os.path.basename(deck.__file__))[0] if deck.__name__ == "__main__" else deck.__name__
268
- script = Script(author=session.get('user'), deck=deck_name)
268
+ script = Script(author=current_user.get_id(), deck=deck_name)
269
269
  script_collection = request.get_json()
270
270
  workflow_name = script_collection.pop("workflow_name")
271
271
  script.python_script = script_collection
@@ -1,5 +1,5 @@
1
1
  from flask import Blueprint, redirect, url_for, flash, request, render_template, session, current_app, jsonify
2
- from flask_login import login_required
2
+ from flask_login import login_required, current_user
3
3
 
4
4
  from ivoryos.utils.db_models import Script, db, WorkflowRun, WorkflowStep
5
5
  from ivoryos.utils.utils import get_script_file, post_script_file
@@ -66,14 +66,14 @@ def publish():
66
66
  script = get_script_file()
67
67
 
68
68
  if script.author is None:
69
- script.author = session.get('user')
69
+ script.author = current_user.get_id()
70
70
  if not script.name or not script.deck:
71
71
  return {"success": False, "error": "Deck cannot be empty, try to re-submit deck configuration on the left panel"}
72
72
  row = Script.query.get(script.name)
73
73
  if row and row.status == "finalized":
74
74
  return {"success": False, "error": "This is a protected script, use save as to rename."}
75
75
 
76
- elif row and session.get('user') != row.author:
76
+ elif row and current_user.get_id() != row.author:
77
77
  return {"success": False, "error": "You are not the author, use save as to rename."}
78
78
  else:
79
79
  db.session.merge(script)
@@ -145,7 +145,7 @@ def save_as():
145
145
  script = get_script_file()
146
146
  script.save_as(run_name)
147
147
  script.registered = register_workflow == "on"
148
- script.author = session.get('user')
148
+ script.author = current_user.get_id()
149
149
  post_script_file(script)
150
150
  status = publish()
151
151
  if request.accept_mimetypes.best_match(['application/json', 'text/html']) == 'application/json':
@@ -66,7 +66,7 @@ class ScriptRunner:
66
66
  global deck
67
67
  if deck is None:
68
68
  deck = global_config.deck
69
- print("history", history)
69
+ # print("history", history)
70
70
  if self.current_app is None:
71
71
  self.current_app = current_app
72
72
  # time.sleep(1) # Optional: may help ensure deck readiness
ivoryos/utils/serilize.py CHANGED
@@ -7,8 +7,8 @@ import sys
7
7
 
8
8
  import flask
9
9
 
10
- from example.abstract_sdl_example.abstract_balance import AbstractBalance
11
- from example.abstract_sdl_example.abstract_pump import AbstractPump
10
+ from example.abstract_sdl_example import abstract_sdl as deck
11
+
12
12
 
13
13
 
14
14
  class ScriptAnalyzer:
@@ -179,14 +179,12 @@ class ScriptAnalyzer:
179
179
  print(f" {name}: {error}")
180
180
 
181
181
  if __name__ == "__main__":
182
- balance = AbstractBalance("re")
183
- pump = AbstractPump("re")
184
182
 
185
183
  _analyzer = ScriptAnalyzer()
186
- module = sys.modules[__name__]
184
+ # module = sys.modules[deck]
187
185
  try:
188
186
 
189
- result, with_warnings, failed, _ = _analyzer.analyze_module(module)
187
+ result, with_warnings, failed, _ = _analyzer.analyze_module(deck)
190
188
 
191
189
  output_path = f"analysis.json"
192
190
  _analyzer.save_to_json(result, output_path)
ivoryos/utils/utils.py CHANGED
@@ -11,6 +11,7 @@ from collections import Counter
11
11
 
12
12
  import flask
13
13
  from flask import session
14
+ from flask_login import current_user
14
15
  from flask_socketio import SocketIO
15
16
 
16
17
  from ivoryos.utils.db_models import Script
@@ -24,7 +25,7 @@ def get_script_file():
24
25
  s.__dict__.update(**session_script)
25
26
  return s
26
27
  else:
27
- return Script(author=session.get('user'))
28
+ return Script(author=current_user.get_id(),)
28
29
 
29
30
 
30
31
  def post_script_file(script, is_dict=False):
ivoryos/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "1.2.0b1"
1
+ __version__ = "1.2.2"