ai4ce-helpers 0.1.1__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.
@@ -0,0 +1,15 @@
1
+ Metadata-Version: 2.1
2
+ Name: ai4ce-helpers
3
+ Version: 0.1.1
4
+ Summary: Functions to help interact with the AI4CE backend
5
+ Author: Your Name
6
+ Author-email: you@example.com
7
+ Requires-Python: >=3.12,<3.14
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.12
10
+ Requires-Dist: httpx (>=0.28,<0.29)
11
+ Requires-Dist: streamlit (>=1.47,<2.0)
12
+ Requires-Dist: toml (>=0.10,<0.11)
13
+ Description-Content-Type: text/markdown
14
+
15
+ empty
@@ -0,0 +1 @@
1
+ empty
@@ -0,0 +1,19 @@
1
+ [tool.poetry]
2
+ name = "ai4ce-helpers"
3
+ version = "0.1.1"
4
+ description = "Functions to help interact with the AI4CE backend"
5
+ authors = ["Your Name <you@example.com>"]
6
+ readme = "README.md"
7
+ packages = [{include = "ai4ce_helpers", from = "src"}]
8
+
9
+ [tool.poetry.dependencies]
10
+ python = ">=3.12,<3.14"
11
+ toml = "^0.10"
12
+ httpx = "^0.28"
13
+ streamlit = "^1.47"
14
+
15
+
16
+
17
+ [build-system]
18
+ requires = ["poetry-core"]
19
+ build-backend = "poetry.core.masonry.api"
@@ -0,0 +1,52 @@
1
+ from _backend_calls import _backend_POST, _backend_PUT, _backend_GET, check_backend_availability
2
+ from functions import (load_file,
3
+ create_new_project,
4
+ get_list_of_all_project_infos,
5
+ get_project_info,
6
+ set_project_name,
7
+ get_recent_project,
8
+ get_mission_info,
9
+ set_mission_orbit,
10
+ get_enabled_components,
11
+ traverse_and_modify,
12
+ enable_component,
13
+ set_sys_arch,
14
+ get_sys_arch,
15
+ set_sys_generator,
16
+ update_sys_generator,
17
+ set_trained_model,
18
+ get_prepared_system_generator_info,
19
+ get_tags_from_string,
20
+ translate_tomlsystem_to_backend,
21
+ comp_create,
22
+ get_all_decisions,
23
+ get_comp_statistics
24
+ )
25
+
26
+ __all__ = (
27
+ "_backend_POST",
28
+ "_backend_PUT",
29
+ "_backend_GET",
30
+ "load_file",
31
+ "create_new_project",
32
+ "get_list_of_all_project_infos",
33
+ "get_project_info",
34
+ "set_project_name",
35
+ "get_recent_project",
36
+ "get_mission_info",
37
+ "set_mission_orbit",
38
+ "get_enabled_components",
39
+ "traverse_and_modify",
40
+ "enable_component",
41
+ "set_sys_arch",
42
+ "get_sys_arch",
43
+ "set_sys_generator",
44
+ "update_sys_generator",
45
+ "set_trained_model",
46
+ "get_prepared_system_generator_info",
47
+ "get_tags_from_string",
48
+ "translate_tomlsystem_to_backend",
49
+ "comp_create",
50
+ "get_all_decisions",
51
+ "get_comp_statistics"
52
+ )
@@ -0,0 +1,182 @@
1
+ import os
2
+ from pathlib import Path
3
+ import time
4
+ import httpx
5
+ import toml
6
+ import streamlit as st
7
+
8
+ # Set backend base url, depending on whether the app is running in
9
+ # a docker container (which is most likely the unified interface.)
10
+ def check_if_backend_in_docker(PORT: int = 8000) -> str:
11
+ """Check if the backend is running in a Docker container.
12
+ If streamlit is started as part of docker, it will most likely have an environment variable set for the backend URL.
13
+ If not, the backend is assumed to be running on localhost.
14
+
15
+ Args:
16
+ PORT (int): The port on which the backend is running.
17
+ Returns:
18
+ str: The URL of the backend.
19
+ """
20
+ if os.environ.get("BACKEND_URL"):
21
+ return f"{os.environ.get("BACKEND_URL")}/api"
22
+ if Path("/.dockerenv").exists():
23
+ return f"http://backend:{PORT}/api"
24
+ return f"http://localhost:{PORT}/api"
25
+
26
+ BACKEND_URL = check_if_backend_in_docker()
27
+
28
+
29
+ def check_backend_availability():
30
+ """Check check every 5 seconds if the backend is available.
31
+ Wait a max of 30 seconds before giving up. Display loading message
32
+ during check, remove loading message once backend is available. Display
33
+ error message if backend is not available.
34
+ """
35
+ backend_available = False
36
+ timeout = 30
37
+
38
+ backend_url = check_if_backend_in_docker().removesuffix("/api")
39
+
40
+ # display loading message
41
+ checking = st.warning("Waiting for backend...")
42
+
43
+ while not backend_available and timeout > 0:
44
+ try:
45
+ response = httpx.get(backend_url, timeout=1)
46
+ if response.status_code == 200:
47
+ backend_available = True
48
+ except httpx.TimeoutException:
49
+ time.sleep(5)
50
+
51
+ timeout -= 5
52
+ if not backend_available:
53
+ checking.empty()
54
+ st.error(f"Backend is not available at {backend_url}")
55
+ else:
56
+ # remove loading message
57
+ checking.empty()
58
+
59
+
60
+ def _backend_GET(
61
+ endpoint: str,
62
+ headers: dict = {"accept": "application/json, application/toml"}
63
+ ) -> tuple[int, dict | str]:
64
+ """An internal function to make the development of get functions easier.
65
+
66
+ Params:
67
+ endpoint(str): the URL of the backend endpoint to post to
68
+
69
+ Returns:
70
+ dict: json response from the backend
71
+ """
72
+
73
+
74
+ try:
75
+ response = httpx.get(url=f"{BACKEND_URL}{endpoint}", headers=headers, follow_redirects=True)
76
+ # print(response.url) # For Debugging
77
+ # print(response.json()) # For Debugging
78
+ # print(response.status_code) # For Debugging
79
+
80
+ # Raises an HTTPError if the response status code is 4xx or 5xx
81
+ response.raise_for_status()
82
+ if response.status_code == 200:
83
+ return (response.status_code, toml.loads(response.text) if response.headers['content-type'] == 'application/toml' else response.json())
84
+ except httpx.HTTPStatusError as e:
85
+ if e.response.status_code == 500:
86
+ print(f"Server Error (500):{e.response.text}")
87
+ return (e.response.status_code, "Server Error: 500")
88
+ elif e.response.status_code == 422:
89
+ print(f"Unprocessable Content (422): {e.response.text}")
90
+ return (e.response.status_code, "A problem with the payload itself.")
91
+ else:
92
+ print(f"Error ({e.response.status_code}): {e.response.text}")
93
+ return (e.response.status_code, e.response.json())
94
+ except httpx.RequestError as e:
95
+ print(f"An error occurred while requesting {e.request.url!r}.")
96
+ return (500, f"Request Error: {e}")
97
+ return (500, "An unknown error occurred.")
98
+
99
+ def _backend_POST(
100
+ endpoint: str,
101
+ data: dict,
102
+ headers: dict = {"Content-Type": "application/json", "accept": "application/json"}
103
+ ) -> tuple[int, dict | str]:
104
+ """An internal function to make the development of posting functions easier.
105
+
106
+ Params:
107
+ endpoint(str): the URL of the backend endpoint to post to
108
+ data(dict): the concent to put into the backend
109
+
110
+ Returns:
111
+ dict: json response from the backend
112
+
113
+ Catches:
114
+ httpx.HTTPStatusError: if the response status code is 4xx or 5xx
115
+ httpx.RequestError: if there is a problem with the request
116
+ """
117
+
118
+ # Make the POST request
119
+ try:
120
+ response = httpx.post(url=f"{BACKEND_URL}{endpoint}",
121
+ json=data,
122
+ headers=headers,
123
+ follow_redirects=True
124
+ )
125
+ response.raise_for_status()
126
+ if response.status_code == 201:
127
+ return (response.status_code, response.json())
128
+ except httpx.HTTPStatusError as e:
129
+ if e.response.status_code == 500:
130
+ print(f"Server Error (500):{e.response.text}")
131
+ return (e.response.status_code, "Server Error: 500")
132
+ elif e.response.status_code == 422:
133
+ print(f"Unprocessable Content (422): {e.response.text}")
134
+ return (e.response.status_code, "A problem with the payload itself.")
135
+ else:
136
+ print(f"Error ({e.response.status_code}): {e.response.text}")
137
+ return (e.response.status_code, e.response.json())
138
+ except httpx.RequestError as e:
139
+ print(f"An error occurred while requesting {e.request.url!r}.")
140
+ return (500, f"Request Error: {e}")
141
+ return (500, "An unknown error occurred.")
142
+
143
+ def _backend_PUT(
144
+ endpoint: str,
145
+ data: dict,
146
+ headers: dict = {"Content-Type": "application/json", "accept": "application/json"}
147
+ ) -> tuple[int, dict | str]:
148
+ """An internal function to make the development of PUT functions/update easier.
149
+
150
+ Params:
151
+ endpoint(str): the URL of the backend endpoint to post to
152
+ data(dict): the concent to put into the backend
153
+ headers(dict | None): headers to include in the request
154
+
155
+ Returns:
156
+ dict: html response from the backend
157
+ """
158
+
159
+
160
+ # Make the PUT request
161
+ try:
162
+ response = httpx.put(url=f"{BACKEND_URL}{endpoint}",
163
+ json=data,
164
+ headers=headers
165
+ )
166
+ response.raise_for_status()
167
+ if response.status_code == 200:
168
+ return (response.status_code, toml.loads(response.text) if response.headers['content-type'] == 'application/toml' else response.json())
169
+ except httpx.HTTPStatusError as e:
170
+ if e.response.status_code == 500:
171
+ print(f"Server Error (500):{e.response.text}")
172
+ return (e.response.status_code, "Server Error: 500")
173
+ elif e.response.status_code == 422:
174
+ print(f"Unprocessable Content (422): {e.response.text}")
175
+ return (e.response.status_code, "A problem with the payload itself.")
176
+ else:
177
+ print(f"Error ({e.response.status_code}): {e.response.text}")
178
+ return (e.response.status_code, e.response.json())
179
+ except httpx.RequestError as e:
180
+ print(f"An error occurred while requesting {e.request.url!r}.")
181
+ return (500, f"Request Error: {e}")
182
+ return (500, "An unknown error occurred.")
@@ -0,0 +1,422 @@
1
+ # Here is the place to but general helper functions
2
+
3
+ import ast
4
+ import json
5
+ from pathlib import Path
6
+ from pprint import pprint
7
+ from typing import List, Tuple
8
+ import toml
9
+ import pandas as pd
10
+
11
+ from _backend_calls import _backend_POST, _backend_PUT, _backend_GET
12
+
13
+
14
+ def load_file(filename: Path) -> dict | pd.DataFrame:
15
+ """
16
+ Load data from a file. The function currently supports JSON files.
17
+
18
+ Parameters:
19
+ filename (Path): The path to the file.
20
+
21
+ Returns:
22
+ dict: The data loaded from the file if it's a JSON.
23
+ """
24
+ if filename.suffix == '.csv':
25
+ df = pd.read_csv(filename, sep=',', header=0,
26
+ index_col=None, na_values=['NA', '?'])
27
+ return df
28
+
29
+ elif filename.suffix == '.json':
30
+ with open(filename, 'r') as file:
31
+ return json.load(file)
32
+
33
+ elif filename.suffix == '.toml':
34
+ with open(filename, 'r') as file:
35
+ return toml.load(file)
36
+
37
+ else:
38
+ raise ValueError(
39
+ "You need to add the file format to the load_file function.")
40
+
41
+
42
+
43
+ def create_new_project(project_info: dict):
44
+ """Create a new project in the backend.
45
+ Params:
46
+ project_info(dict):
47
+ Returns:
48
+ dict:
49
+ """
50
+ status_code, message = _backend_POST(
51
+ endpoint=f"/v2/projects/", data=project_info)
52
+ if status_code == 200:
53
+ return message
54
+ else:
55
+ print(f"Error creating project: {message}")
56
+ return {"error": message}
57
+
58
+
59
+ def get_list_of_all_project_infos() -> list[tuple[int, str, str]]:
60
+ """A function to connect to the backend and get a list of all projects
61
+ in the current project data base.
62
+
63
+ Params:
64
+ None
65
+
66
+ Retruns:
67
+ all_project (list): List of tuples of id and name for all projects in the projectDB
68
+ project_id (int): The project Identification Number
69
+ project_name (str): The name of the project/mission
70
+ """
71
+
72
+ status_code, projects = _backend_GET(endpoint=f"/v2/projects/")
73
+ project_ids: list[tuple[int, str, str]] = []
74
+ if status_code == 200:
75
+ for project in projects:
76
+ project_ids.append((project["id"], project["project_name"], project["modified"]))
77
+ return project_ids
78
+ else:
79
+ print(f"Error fetching projects: {projects}")
80
+ return []
81
+
82
+ def get_project_info(project_id: int) -> dict:
83
+ status_code, project_info = _backend_GET(endpoint=f"/v2/projects/{project_id}/")
84
+ return project_info
85
+
86
+
87
+ def set_project_name(project_id: int, project_name: str) -> dict:
88
+ """A function to set the project name of a specific project, identified by its ID.
89
+
90
+ Params:
91
+ project_id (int): The project Identification Number
92
+ project_name(str): Name of the project/mission, eg OPS-Sat
93
+ Returns:
94
+ dict: html response from the backend to indicate success (200) or problems
95
+ """
96
+
97
+ data = {
98
+ "project_id": project_id,
99
+ "project_name": project_name,
100
+ }
101
+
102
+ # status, msg = _backend_put(endpoint=f"/v2/projects/{project_id}", data=data)
103
+ # return (status, msg)
104
+ status_code, msg = _backend_PUT(endpoint=f"/v2/projects/{project_id}/", data=data)
105
+ if status_code == 200:
106
+ return msg
107
+ else:
108
+ print(f"Error setting project name: {msg}")
109
+ return {"error": msg}
110
+
111
+
112
+ def get_recent_project() -> tuple[int, str, str]:
113
+ status_code, msg = _backend_GET(endpoint=f"/v2/projects/recent/")
114
+ if status_code != 200:
115
+ print(f"Error fetching recent project: {msg}")
116
+ return (None, "No recent project found.")
117
+ return (msg["id"], msg["project_name"], msg["modified"])
118
+
119
+
120
+ def get_mission_info(project_id: int) -> dict:
121
+ """A function to get the mission/orbit info for a specific project based on its ID.
122
+ Params:
123
+ project_id (int): The project Identification Number
124
+
125
+ Returns:
126
+ dict: Keplerian elements to define the orbit
127
+ """
128
+
129
+ response = _backend_GET(
130
+ endpoint=f"/v2/projects/{project_id}/mission/")
131
+ return response["orbit"]
132
+
133
+
134
+ def set_mission_orbit(project_id: int, orbit_info: dict) -> dict:
135
+ """A function to set the orbit in the project database.
136
+ Params:
137
+ project_id (int): The project Identification Number
138
+ orbit_info(dict): Information about the satelllite's orbit
139
+ Returns:
140
+ dict: html response from the backend to indicate success (200) or problems
141
+ """
142
+
143
+ data = {
144
+ "mission_name": "string", # TODO remove?
145
+ "description": "string", # TODO remove?
146
+ "launch_date": "string",
147
+ "purpose": "string", # TODO remove?
148
+ "website": "string", # TODO remove?
149
+ "picture_web": "string", # TODO remove?
150
+ "project_id": 0,
151
+ "orbit": orbit_info,
152
+ # "orbit": {
153
+ # "celestial_object": "string",
154
+ # "orbit_shell": "string",
155
+ # "altitude_km": 0,
156
+ # "epoch_utc": "string",
157
+ # "semi_major_axis_km": 0,
158
+ # "eccentricity": 0,
159
+ # "inclination_degrees": 0,
160
+ # "perigee_height_km": 0,
161
+ # "apogee_height_km": 0,
162
+ # "raan_degrees": 0,
163
+ # "argument_of_perigee_degrees": 0,
164
+ # "mean_anomaly_at_epoch_degrees": 0,
165
+ # "revolutions_per_day": 0,
166
+ # "orbit_number_at_epoch": 0,
167
+ # "time_eclipse_min": 0,
168
+ # "mission_id": 0 # TODO remove?
169
+ # }
170
+ }
171
+
172
+ # {
173
+ # "Celestical_Object": "Earth", # Earth, Luna, Sun, Mars
174
+ # "Orbit_shell" : "LEO", # LEO, MEO, GEO
175
+ # "Altitude_km" : 515,
176
+ # "Epoch_UTC" : datetime.strptime("2024-05-27T07:32:00", "%Y-%m-%dT%H:%M:%S"),
177
+ # "Semi_major_Axis_km" : 6_786,
178
+ # "Eccentricity" : 0.0005551,
179
+ # "Inclination_degrees" : 97.4540,
180
+ # "Perigee_Height_km" : 385,
181
+ # "Apogee_Height_km" : 392,
182
+ # "RAAN_degrees" : 267.4498,
183
+ # "Argument_of_Perigee_degrees" : 256.8657,
184
+ # "Mean_Anomaly_at_Epoch_degrees" : 103.1980,
185
+ # "Revolutions_per_Day" : 15.59560910,
186
+ # "Orbit_Number_at_Epoch" : 23_446,
187
+ # "Time_Eclipse_min" : 38.512, # calculated by AI4CE software
188
+ # }
189
+
190
+ status, msg = _backend_POST(endpoint=f"/v2/projects/{project_id}/mission/", data=data)
191
+ if status == 201:
192
+ return msg
193
+ else:
194
+ print(f"Error setting mission/orbit info: {msg}")
195
+ return {"error": msg}
196
+
197
+
198
+ def get_enabled_components(nested_dict, enabled_components=None) -> list:
199
+ """
200
+ Recursively traverses a nested dictionary to find and return a list of components that are enabled.
201
+
202
+ Parameters:
203
+ nested_dict (dict): The nested dictionary to traverse.
204
+ enabled_components (list, optional): A list to store the names of the enabled components.
205
+ Defaults to None, in which case a new list is created.
206
+
207
+ Returns:
208
+ list: A list of the names of the enabled components.
209
+ """
210
+
211
+ if enabled_components is None:
212
+ enabled_components = []
213
+
214
+ for key, value in nested_dict.items():
215
+ if isinstance(value, dict):
216
+ if value.get('Enabled') == True:
217
+ enabled_components.append(key)
218
+ pass
219
+ get_enabled_components(value, enabled_components)
220
+
221
+ return enabled_components
222
+
223
+
224
+ def traverse_and_modify(d: dict, sys_config_enabled: dict):
225
+ for key, value in d.items():
226
+ if isinstance(value, dict):
227
+ component = key
228
+ traverse_and_modify(d=value, sys_config_enabled=sys_config_enabled)
229
+ else:
230
+ # This block executes only if `value` is not a dict, i.e., at the deepest level
231
+ # if d["Enabled"] is True or d["Enable"] is True or :
232
+ try:
233
+ if d["Enabled"] is True:
234
+ sys_config_enabled.update(enable_component(
235
+ component_name=key, data=load_file(Path("ai4ce/backend_sys_default.json"))))
236
+ except KeyError as e:
237
+ print("Error: ", e)
238
+
239
+
240
+ def enable_component(component_name: str, data: dict) -> dict:
241
+ """Recursively search for a component in the nested dictionary from the backend
242
+ and set 'enabled' to True if the feature name matches any key or value (case-insensitive).
243
+
244
+ Parameters:
245
+ data (dict): The nested dictionary to search within.
246
+ feature_name (str): The feature name to search for, case-insensitively.
247
+
248
+ Returns:
249
+ dict: edited dict
250
+ """
251
+
252
+ for key, value in data.items():
253
+ # print(key, value)
254
+ if isinstance(value, dict):
255
+ enable_component(component_name, value)
256
+ elif isinstance(value, list):
257
+ for item in value:
258
+ if isinstance(item, dict):
259
+ enable_component(component_name, item)
260
+ if key.lower() == component_name.lower() or str(value).lower() == component_name.lower():
261
+ data['enabled'] = True
262
+ return data
263
+
264
+
265
+ def set_sys_arch(project_id: int, sys_arch: dict) -> dict:
266
+ """A function to set the system architecture in the project database.
267
+ Params:
268
+ project_id (int): The project Identification Number
269
+ sys_arch(dict): Information about the satelllite's modules, which form the system architecture
270
+ Returns:
271
+ dict: html response from the backend to indicate success (200) or problems
272
+ """
273
+
274
+ sys_arch_example = {
275
+ "system": {
276
+ "eps": {
277
+ "enabled": True,
278
+ "battery": {
279
+ "enabled": True,
280
+ }
281
+ },
282
+ "payload": {
283
+ "camera": {
284
+ "enabled": True,
285
+ }
286
+ }
287
+ }
288
+ }
289
+
290
+ response: dict = _backend_POST(
291
+ endpoint=f"/v2/projects/{project_id}/system/", data=sys_arch)
292
+ return response
293
+
294
+
295
+ def get_sys_arch(project_id: int) -> dict:
296
+ """A function to get the system configuration info for a specific project based on its ID.
297
+ Params:
298
+ project_id (int): The project Identification Number
299
+
300
+ Returns:
301
+ dict: System information
302
+ """
303
+
304
+ response = _backend_GET(
305
+ endpoint=f"/v2/projects/{project_id}/system/")
306
+ return response
307
+
308
+ # set_comp_list(project: int, not_yet_defined: dict)
309
+ # For each selected system generator, we need a place to store the corresponding found comp lists
310
+ # Every generator can produce n sets of components
311
+
312
+
313
+ def set_sys_generator(project_id: int, sys_gen_info: dict) -> dict:
314
+ response = _backend_POST(
315
+ endpoint=f"/v2/projects/{project_id}/sysgen/", data=sys_gen_info)
316
+ return response
317
+
318
+
319
+ def update_sys_generator(project_id: int, sys_gen_info: dict) -> dict:
320
+ response = _backend_PUT(
321
+ endpoint=f"/v2/projects/{project_id}/sysgen/", data=sys_gen_info)
322
+ return response
323
+
324
+
325
+ def set_trained_model(project_id: int, model_info: dict) -> dict:
326
+ """A function to upload a trained AI model.
327
+ Params:
328
+ project_id (int): The project Identification Number
329
+ model (ASKYOUNES): info about model
330
+
331
+ Returns:
332
+ dict: Upload server response
333
+ """
334
+
335
+ sta, msg = _backend_POST(endpoint=f"/v2/projects/{project_id}/sysgen/",
336
+ data=model_info)
337
+
338
+ return msg
339
+
340
+
341
+ def get_prepared_system_generator_info(project_id: int) -> list:
342
+ """A function to get all prepared system generators.
343
+ Params:
344
+ project_id (int): The project Identification Number
345
+
346
+ Returns:
347
+ list: list of dictionaries with infos for the prepared system generators
348
+ """
349
+
350
+ response = _backend_GET(
351
+ endpoint=f"/v2/projects/{project_id}/sysgen/")
352
+ return response
353
+
354
+
355
+ # def get_trained_model(project_id: int) -> mode: ASKYOUNES
356
+ # pass
357
+
358
+
359
+ # def set_train_log(project_id: int, logs: ASKYOUNES) -> DB_response: ASKALEX
360
+ # pass
361
+
362
+
363
+ # def get_train_logs(project_id: int) -> logs: ASKYOUNE pass
364
+
365
+
366
+ def get_tags_from_string(str_of_tags: str) -> List[str]:
367
+ """
368
+ example_tags_str = "['satellite', 'power', 'solar-panels']"
369
+ """
370
+ # The string representation of a list of tags
371
+
372
+ # Convert the string to an actual list using ast.literal_eval
373
+ tags: list = ast.literal_eval(str_of_tags)
374
+ return tags
375
+
376
+
377
+ def translate_tomlsystem_to_backend(system: dict, project_id: int) -> dict:
378
+ """Translate a system configuration from a TOML file to a format that can be uploaded to the backend.
379
+
380
+ Parameters:
381
+ system (dict): The system configuration in TOML format.
382
+
383
+ Returns:
384
+ dict: The system configuration in a format that can be uploaded to the backend.
385
+ """
386
+
387
+ sys_config_enabled = {}
388
+ # Loading System Configuration
389
+ for key, value in system.items():
390
+ if isinstance(value, dict):
391
+ traverse_and_modify(d=value, sys_config_enabled=sys_config_enabled)
392
+
393
+ resp = set_sys_arch(project_id=project_id, sys_arch=sys_config_enabled)
394
+ pass
395
+ return resp
396
+
397
+
398
+ def comp_create(comp_info: dict) -> dict:
399
+ """Create a new component in the backend.
400
+ Params:
401
+ comp_info(dict): Information about the component
402
+ Returns:
403
+ dict:
404
+ """
405
+ status_code, msg = _backend_POST(
406
+ endpoint=f"/v2/components/", data=comp_info)
407
+ return status_code, msg
408
+
409
+ def get_all_decisions() -> dict:
410
+ """Fetches all decisions from the DecisionDB and returns them as a dictionary.
411
+
412
+ Returns:
413
+ dict: A dictionary containing all decisions fetched from the DecisionDB.
414
+ """
415
+ response = _backend_GET(endpoint="/v2/components/export/")
416
+ return response
417
+
418
+ def get_comp_statistics() -> dict:
419
+
420
+ response =_backend_GET(endpoint="/v2/streamlit/db/stats/components")
421
+ return response
422
+