supervisely 6.73.298__py3-none-any.whl → 6.73.300__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 supervisely might be problematic. Click here for more details.
- supervisely/api/module_api.py +2 -0
- supervisely/api/task_api.py +61 -0
- supervisely/app/fastapi/index.html +1 -1
- supervisely/app/fastapi/templating.py +1 -1
- supervisely/app/widgets/__init__.py +2 -1
- supervisely/app/widgets/button/button.py +3 -1
- supervisely/app/widgets/button/template.html +4 -0
- supervisely/app/widgets/custom_models_selector/custom_models_selector.py +2 -2
- supervisely/app/widgets/experiment_selector/experiment_selector.py +2 -3
- supervisely/app/widgets/run_app_button/__init__.py +0 -0
- supervisely/app/widgets/run_app_button/run_app_button.py +300 -0
- supervisely/app/widgets/run_app_button/script.js +46 -0
- supervisely/app/widgets/run_app_button/template.html +10 -0
- supervisely/nn/artifacts/artifacts.py +3 -3
- supervisely/nn/benchmark/base_benchmark.py +14 -10
- supervisely/nn/experiments.py +42 -26
- supervisely/nn/inference/inference.py +91 -0
- supervisely/nn/training/gui/training_artifacts.py +13 -11
- supervisely/nn/training/gui/training_logs.py +39 -5
- supervisely/nn/training/gui/utils.py +11 -1
- supervisely/nn/training/train_app.py +70 -18
- {supervisely-6.73.298.dist-info → supervisely-6.73.300.dist-info}/METADATA +1 -1
- {supervisely-6.73.298.dist-info → supervisely-6.73.300.dist-info}/RECORD +27 -23
- {supervisely-6.73.298.dist-info → supervisely-6.73.300.dist-info}/LICENSE +0 -0
- {supervisely-6.73.298.dist-info → supervisely-6.73.300.dist-info}/WHEEL +0 -0
- {supervisely-6.73.298.dist-info → supervisely-6.73.300.dist-info}/entry_points.txt +0 -0
- {supervisely-6.73.298.dist-info → supervisely-6.73.300.dist-info}/top_level.txt +0 -0
supervisely/api/module_api.py
CHANGED
supervisely/api/task_api.py
CHANGED
|
@@ -1136,3 +1136,64 @@ class TaskApi(ModuleApiBase, ModuleWithStatus):
|
|
|
1136
1136
|
f"Invalid status value: {status}. Allowed values: {self.Status.values()}"
|
|
1137
1137
|
)
|
|
1138
1138
|
self._api.post("tasks.status.update", {ApiField.ID: task_id, ApiField.STATUS: status})
|
|
1139
|
+
|
|
1140
|
+
def set_output_experiment(self, task_id: int, experiment_info: dict) -> Dict:
|
|
1141
|
+
"""
|
|
1142
|
+
Sets output for the task with experiment info.
|
|
1143
|
+
|
|
1144
|
+
:param task_id: Task ID in Supervisely.
|
|
1145
|
+
:type task_id: int
|
|
1146
|
+
:param experiment_info: Experiment info from TrainApp.
|
|
1147
|
+
:type experiment_info: dict
|
|
1148
|
+
:return: None
|
|
1149
|
+
:rtype: :class:`NoneType`
|
|
1150
|
+
|
|
1151
|
+
Example of experiment_info:
|
|
1152
|
+
|
|
1153
|
+
experiment_info = {
|
|
1154
|
+
'experiment_name': '247_Lemons_RT-DETRv2-M',
|
|
1155
|
+
'framework_name': 'RT-DETRv2',
|
|
1156
|
+
'model_name': 'RT-DETRv2-M',
|
|
1157
|
+
'task_type': 'object detection',
|
|
1158
|
+
'project_id': 76,
|
|
1159
|
+
'task_id': 247,
|
|
1160
|
+
'model_files': {'config': 'model_config.yml'},
|
|
1161
|
+
'checkpoints': ['checkpoints/best.pth', 'checkpoints/checkpoint0025.pth', 'checkpoints/checkpoint0050.pth', 'checkpoints/last.pth'],
|
|
1162
|
+
'best_checkpoint': 'best.pth',
|
|
1163
|
+
'export': {'ONNXRuntime': 'export/best.onnx'},
|
|
1164
|
+
'app_state': 'app_state.json',
|
|
1165
|
+
'model_meta': 'model_meta.json',
|
|
1166
|
+
'train_val_split': 'train_val_split.json',
|
|
1167
|
+
'train_size': 4,
|
|
1168
|
+
'val_size': 2,
|
|
1169
|
+
'hyperparameters': 'hyperparameters.yaml',
|
|
1170
|
+
'hyperparameters_id': 45234,
|
|
1171
|
+
'artifacts_dir': '/experiments/76_Lemons/247_RT-DETRv2/',
|
|
1172
|
+
'datetime': '2025-01-22 18:13:43',
|
|
1173
|
+
'evaluation_report_id': 12961,
|
|
1174
|
+
'evaluation_report_link': 'https://app.supervisely.com/model-benchmark?id=12961',
|
|
1175
|
+
'evaluation_metrics': {
|
|
1176
|
+
'mAP': 0.994059405940594,
|
|
1177
|
+
'AP50': 1.0, 'AP75': 1.0,
|
|
1178
|
+
'f1': 0.9944444444444445,
|
|
1179
|
+
'precision': 0.9944444444444445,
|
|
1180
|
+
'recall': 0.9944444444444445,
|
|
1181
|
+
'iou': 0.9726227736959404,
|
|
1182
|
+
'classification_accuracy': 1.0,
|
|
1183
|
+
'calibration_score': 0.8935745942476048,
|
|
1184
|
+
'f1_optimal_conf': 0.500377893447876,
|
|
1185
|
+
'expected_calibration_error': 0.10642540575239527,
|
|
1186
|
+
'maximum_calibration_error': 0.499622106552124
|
|
1187
|
+
},
|
|
1188
|
+
'primary_metric': 'mAP'
|
|
1189
|
+
'logs': {
|
|
1190
|
+
'type': 'tensorboard',
|
|
1191
|
+
'link': '/experiments/76_Lemons/247_RT-DETRv2/logs/'
|
|
1192
|
+
},
|
|
1193
|
+
}
|
|
1194
|
+
"""
|
|
1195
|
+
output = {ApiField.EXPERIMENT: {ApiField.DATA: {**experiment_info}}}
|
|
1196
|
+
resp = self._api.post(
|
|
1197
|
+
"tasks.output.set", {ApiField.TASK_ID: task_id, ApiField.OUTPUT: output}
|
|
1198
|
+
)
|
|
1199
|
+
return resp.json()
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
|
|
87
87
|
<div id="sly-app">
|
|
88
88
|
<sly-app>
|
|
89
|
-
<template v-slot="{ post, state, data, session }">
|
|
89
|
+
<template v-slot="{ post, state, data, session, isStaticVersion, publicApiInstance }">
|
|
90
90
|
<div
|
|
91
91
|
:style="{'padding': `${state.app_body_padding} ${state.app_body_padding} 0`, 'display': 'flex', 'flex-direction': 'row', 'place-items': 'center'}"
|
|
92
92
|
{% if __app_session_info_solid__ %} {% if __app_session_info_extra_content__ %}
|
|
@@ -14,7 +14,7 @@ from supervisely.app.widgets_context import JinjaWidgets
|
|
|
14
14
|
js_bundle_version = "2.1.98"
|
|
15
15
|
|
|
16
16
|
# https://github.com/supervisely-ecosystem/supervisely-app-frontend-js
|
|
17
|
-
js_frontend_version = "v0.0.
|
|
17
|
+
js_frontend_version = "v0.0.55"
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
pyodide_version = "v0.25.0"
|
|
@@ -148,4 +148,5 @@ from supervisely.app.widgets.select_dataset_tree.select_dataset_tree import Sele
|
|
|
148
148
|
from supervisely.app.widgets.grid_gallery_v2.grid_gallery_v2 import GridGalleryV2
|
|
149
149
|
from supervisely.app.widgets.report_thumbnail.report_thumbnail import ReportThumbnail
|
|
150
150
|
from supervisely.app.widgets.experiment_selector.experiment_selector import ExperimentSelector
|
|
151
|
-
from supervisely.app.widgets.bokeh.bokeh import Bokeh
|
|
151
|
+
from supervisely.app.widgets.bokeh.bokeh import Bokeh
|
|
152
|
+
from supervisely.app.widgets.run_app_button.run_app_button import RunAppButton
|
|
@@ -67,6 +67,7 @@ class Button(Widget):
|
|
|
67
67
|
emit_on_click: Optional[str] = None,
|
|
68
68
|
style: Optional[str] = None,
|
|
69
69
|
call_on_click: Optional[str] = None,
|
|
70
|
+
visible_by_vue_field: Optional[str] = "",
|
|
70
71
|
):
|
|
71
72
|
self._widget_routes = {}
|
|
72
73
|
|
|
@@ -88,6 +89,7 @@ class Button(Widget):
|
|
|
88
89
|
self._emit_on_click = emit_on_click
|
|
89
90
|
self._style = style
|
|
90
91
|
self._call_on_click = call_on_click
|
|
92
|
+
self._visible_by_vue_field = visible_by_vue_field
|
|
91
93
|
|
|
92
94
|
super().__init__(widget_id=widget_id, file_path=__file__)
|
|
93
95
|
|
|
@@ -117,7 +119,7 @@ class Button(Widget):
|
|
|
117
119
|
|
|
118
120
|
def get_json_state(self) -> None:
|
|
119
121
|
"""Button widget doesn't have state, so this method returns None."""
|
|
120
|
-
return
|
|
122
|
+
return {"visible_by_vue_field": self._visible_by_vue_field}
|
|
121
123
|
|
|
122
124
|
@property
|
|
123
125
|
def text(self) -> str:
|
|
@@ -6,7 +6,11 @@ if widget._link is not none
|
|
|
6
6
|
{%
|
|
7
7
|
endif
|
|
8
8
|
%}
|
|
9
|
+
|
|
9
10
|
<el-button
|
|
11
|
+
{% if widget._visible_by_vue_field %}
|
|
12
|
+
v-show="{{{widget._visible_by_vue_field}}}"
|
|
13
|
+
{% endif %}
|
|
10
14
|
:type="data.{{{widget.widget_id}}}.button_type"
|
|
11
15
|
:plain="data.{{{widget.widget_id}}}.plain"
|
|
12
16
|
:loading="data.{{{widget.widget_id}}}.loading"
|
|
@@ -4,6 +4,7 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
|
4
4
|
from datetime import datetime
|
|
5
5
|
from typing import Callable, Dict, List, Union
|
|
6
6
|
|
|
7
|
+
import supervisely.io.env as sly_env
|
|
7
8
|
from supervisely import env, logger
|
|
8
9
|
from supervisely._utils import abs_url, is_development
|
|
9
10
|
from supervisely.api.api import Api
|
|
@@ -25,7 +26,6 @@ from supervisely.app.widgets import (
|
|
|
25
26
|
)
|
|
26
27
|
from supervisely.io.fs import get_file_name_with_ext
|
|
27
28
|
from supervisely.nn.artifacts.artifacts import TrainInfo
|
|
28
|
-
import supervisely.io.env as sly_env
|
|
29
29
|
|
|
30
30
|
WEIGHTS_DIR = "weights"
|
|
31
31
|
|
|
@@ -427,7 +427,7 @@ class CustomModelsSelector(Widget):
|
|
|
427
427
|
)
|
|
428
428
|
return train_info.task_type, model_row
|
|
429
429
|
except Exception as e:
|
|
430
|
-
logger.
|
|
430
|
+
logger.debug(f"Failed to process train info: {train_info}. Error: {repr(e)}")
|
|
431
431
|
return None, None
|
|
432
432
|
|
|
433
433
|
table_rows = defaultdict(list)
|
|
@@ -21,7 +21,6 @@ from supervisely.io.fs import get_file_name_with_ext
|
|
|
21
21
|
from supervisely.nn.experiments import ExperimentInfo
|
|
22
22
|
from supervisely.nn.utils import ModelSource
|
|
23
23
|
|
|
24
|
-
|
|
25
24
|
WEIGHTS_DIR = "weights"
|
|
26
25
|
|
|
27
26
|
COL_ID = "task id".upper()
|
|
@@ -272,7 +271,7 @@ class ExperimentSelector(Widget):
|
|
|
272
271
|
benchmark_report_link = f"/model-benchmark?id={self._benchmark_report_id}"
|
|
273
272
|
|
|
274
273
|
benchmark_widget = Text(
|
|
275
|
-
f"<i class='zmdi zmdi-chart' style='color: #7f858e'></i> <a href='{benchmark_report_link}' target='_blank'>
|
|
274
|
+
f"<i class='zmdi zmdi-chart' style='color: #7f858e'></i> <a href='{benchmark_report_link}' target='_blank'>Evaluation report</a>",
|
|
276
275
|
"text",
|
|
277
276
|
)
|
|
278
277
|
return benchmark_widget
|
|
@@ -378,7 +377,7 @@ class ExperimentSelector(Widget):
|
|
|
378
377
|
)
|
|
379
378
|
return experiment_info.task_type, model_row
|
|
380
379
|
except Exception as e:
|
|
381
|
-
logger.
|
|
380
|
+
logger.debug(f"Failed to process experiment info: {experiment_info}")
|
|
382
381
|
return None, None
|
|
383
382
|
|
|
384
383
|
table_rows = defaultdict(list)
|
|
File without changes
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
try:
|
|
2
|
+
from typing import Literal
|
|
3
|
+
except ImportError:
|
|
4
|
+
from typing_extensions import Literal
|
|
5
|
+
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
from supervisely.app import DataJson, StateJson
|
|
9
|
+
from supervisely.app.widgets import Widget
|
|
10
|
+
from supervisely.app.widgets_context import JinjaWidgets
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class RunAppButton(Widget):
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
workspace_id: int,
|
|
17
|
+
module_id: int,
|
|
18
|
+
payload: dict = None,
|
|
19
|
+
text: Optional[str] = "Button",
|
|
20
|
+
button_type: Optional[
|
|
21
|
+
Literal["primary", "info", "warning", "danger", "success", "text"]
|
|
22
|
+
] = "primary",
|
|
23
|
+
button_size: Optional[Literal["mini", "small", "large"]] = None,
|
|
24
|
+
plain: Optional[bool] = False,
|
|
25
|
+
icon: Optional[str] = None,
|
|
26
|
+
icon_gap: Optional[int] = 5,
|
|
27
|
+
available_in_offline: Optional[bool] = False,
|
|
28
|
+
visible_by_vue_field: Optional[str] = "",
|
|
29
|
+
widget_id: Optional[str] = None,
|
|
30
|
+
):
|
|
31
|
+
"""
|
|
32
|
+
Button the runs an app on Supervisely instance.
|
|
33
|
+
|
|
34
|
+
:param workspace_id: Workspace ID.
|
|
35
|
+
:type workspace_id: int
|
|
36
|
+
:param module_id: Module ID.
|
|
37
|
+
:type module_id: int
|
|
38
|
+
:param payload: Payload to be sent to the app.
|
|
39
|
+
:type payload: dict, optional
|
|
40
|
+
:param text: Text to be displayed on the button.
|
|
41
|
+
:type text: str, optional
|
|
42
|
+
:param button_type: Type of the button.
|
|
43
|
+
:type button_type: Literal["primary", "info", "warning", "danger", "success", "text"], optional
|
|
44
|
+
:param button_size: Size of the button.
|
|
45
|
+
:type button_size: Literal["mini", "small", "large"], optional
|
|
46
|
+
:param plain: If True, the button will be plain.
|
|
47
|
+
:type plain: bool, optional
|
|
48
|
+
:param icon: Icon to be displayed on the button.
|
|
49
|
+
:type icon: str, optional
|
|
50
|
+
:param icon_gap: Gap between the icon and the text.
|
|
51
|
+
:type icon_gap: int, optional
|
|
52
|
+
:param available_in_offline: If True, the button will be available in offline session.
|
|
53
|
+
:type available_in_offline: bool, optional
|
|
54
|
+
:param visible_by_vue_field: Vue field that controls the button visibility. If set to "isStaticVersion", the button will be visible only in offline session.
|
|
55
|
+
:type visible_by_vue_field: str, optional
|
|
56
|
+
:param widget_id: Widget ID.
|
|
57
|
+
:type widget_id: str, optional
|
|
58
|
+
|
|
59
|
+
:Usage example:
|
|
60
|
+
.. code-block:: python
|
|
61
|
+
from supervisely.app.widgets import RunAppButton
|
|
62
|
+
|
|
63
|
+
workspace_id = 123
|
|
64
|
+
project_id = 555
|
|
65
|
+
app_module_id = 777
|
|
66
|
+
|
|
67
|
+
run_app_button = RunAppButton(
|
|
68
|
+
workspace_id=workspace_id,
|
|
69
|
+
module_id=app_module_id,
|
|
70
|
+
payload={"state": {"slyProjectId": project_id}},
|
|
71
|
+
text="Run App",
|
|
72
|
+
button_type="info",
|
|
73
|
+
plain=True,
|
|
74
|
+
icon="zmdi zmdi-chart",
|
|
75
|
+
available_in_offline=True,
|
|
76
|
+
visible_by_vue_field="isStaticVersion",
|
|
77
|
+
)
|
|
78
|
+
"""
|
|
79
|
+
self._text = text
|
|
80
|
+
self._button_type = button_type
|
|
81
|
+
self._button_size = button_size
|
|
82
|
+
self._plain = plain
|
|
83
|
+
self._icon_gap = icon_gap
|
|
84
|
+
if icon is None:
|
|
85
|
+
self._icon = ""
|
|
86
|
+
else:
|
|
87
|
+
self._icon = f'<i class="{icon}" style="margin-right: {icon_gap}px"></i>'
|
|
88
|
+
|
|
89
|
+
self._available_in_offline = available_in_offline
|
|
90
|
+
self._visible_by_vue_field = visible_by_vue_field
|
|
91
|
+
|
|
92
|
+
self._loading = False
|
|
93
|
+
self._disabled = False
|
|
94
|
+
self._workspace_id = workspace_id
|
|
95
|
+
self._module_id = module_id
|
|
96
|
+
self._payload = payload
|
|
97
|
+
|
|
98
|
+
super().__init__(widget_id=widget_id, file_path=__file__)
|
|
99
|
+
|
|
100
|
+
script_path = "./sly/css/app/widgets/run_app_button/script.js"
|
|
101
|
+
JinjaWidgets().context["__widget_scripts__"][self.__class__.__name__] = script_path
|
|
102
|
+
|
|
103
|
+
def get_json_data(self):
|
|
104
|
+
"""Returns dictionary with widget data, which defines the appearance and behavior of the widget.
|
|
105
|
+
|
|
106
|
+
Dictionary contains the following fields:
|
|
107
|
+
- text: Text to be displayed on the button.
|
|
108
|
+
- button_type: Type of the button.
|
|
109
|
+
- plain: If True, the button will be plain.
|
|
110
|
+
- button_size: Size of the button.
|
|
111
|
+
- loading: If True, the button will show loading animation.
|
|
112
|
+
- disabled: If True, the button will be disabled.
|
|
113
|
+
- icon: Icon to be displayed on the button.
|
|
114
|
+
- available_in_offline: If True, the button will be available in offline session.
|
|
115
|
+
"""
|
|
116
|
+
return {
|
|
117
|
+
"options": {
|
|
118
|
+
"text": self._text,
|
|
119
|
+
"button_type": self._button_type,
|
|
120
|
+
"plain": self._plain,
|
|
121
|
+
"button_size": self._button_size,
|
|
122
|
+
"loading": self._loading,
|
|
123
|
+
"disabled": self._disabled,
|
|
124
|
+
"icon": self._icon,
|
|
125
|
+
"available_in_offline": self._available_in_offline,
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
def get_json_state(self) -> None:
|
|
130
|
+
"""Button widget doesn't have state, so this method returns None."""
|
|
131
|
+
return {
|
|
132
|
+
"workspace_id": self._workspace_id,
|
|
133
|
+
"module_id": self._module_id,
|
|
134
|
+
"payload": self._payload,
|
|
135
|
+
"visible_by_vue_field": self._visible_by_vue_field,
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def workspace_id(self) -> int:
|
|
140
|
+
"""Returns the workspace ID.
|
|
141
|
+
|
|
142
|
+
:return: Workspace ID.
|
|
143
|
+
:rtype: int
|
|
144
|
+
"""
|
|
145
|
+
return self._workspace_id
|
|
146
|
+
|
|
147
|
+
@workspace_id.setter
|
|
148
|
+
def workspace_id(self, value: int) -> None:
|
|
149
|
+
"""Sets the workspace ID.
|
|
150
|
+
|
|
151
|
+
:param value: Workspace ID.
|
|
152
|
+
:type value: int
|
|
153
|
+
"""
|
|
154
|
+
self._workspace_id = value
|
|
155
|
+
StateJson()[self.widget_id]["workspace_id"] = self._workspace_id
|
|
156
|
+
StateJson().send_changes()
|
|
157
|
+
|
|
158
|
+
@property
|
|
159
|
+
def text(self) -> str:
|
|
160
|
+
"""Returns the text to be displayed on the button.
|
|
161
|
+
|
|
162
|
+
:return: Text to be displayed on the button.
|
|
163
|
+
:rtype: str
|
|
164
|
+
"""
|
|
165
|
+
return self._text
|
|
166
|
+
|
|
167
|
+
@text.setter
|
|
168
|
+
def text(self, value: str) -> None:
|
|
169
|
+
"""Sets the text to be displayed on the button.
|
|
170
|
+
|
|
171
|
+
:param value: Text to be displayed on the button.
|
|
172
|
+
:type value: str
|
|
173
|
+
"""
|
|
174
|
+
self._text = value
|
|
175
|
+
DataJson()[self.widget_id]["options"]["text"] = self._text
|
|
176
|
+
DataJson().send_changes()
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def payload(self) -> dict:
|
|
180
|
+
"""Returns the payload to be sent to the app.
|
|
181
|
+
|
|
182
|
+
:return: Payload to be sent to the app.
|
|
183
|
+
:rtype: dict
|
|
184
|
+
"""
|
|
185
|
+
return self._payload
|
|
186
|
+
|
|
187
|
+
@payload.setter
|
|
188
|
+
def payload(self, value: dict) -> None:
|
|
189
|
+
"""Sets the payload to be sent to the app.
|
|
190
|
+
|
|
191
|
+
:param value: Payload to be sent to the app.
|
|
192
|
+
:type value: dict
|
|
193
|
+
"""
|
|
194
|
+
self._payload = value
|
|
195
|
+
StateJson()[self.widget_id]["payload"] = self._payload
|
|
196
|
+
StateJson().send_changes()
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def icon(self) -> str:
|
|
200
|
+
"""Returns the icon to be displayed on the button.
|
|
201
|
+
|
|
202
|
+
:return: Icon to be displayed on the button.
|
|
203
|
+
:rtype: str
|
|
204
|
+
"""
|
|
205
|
+
return self._icon
|
|
206
|
+
|
|
207
|
+
@icon.setter
|
|
208
|
+
def icon(self, value: str) -> None:
|
|
209
|
+
"""Sets the icon to be displayed on the button.
|
|
210
|
+
|
|
211
|
+
:param value: Icon to be displayed on the button.
|
|
212
|
+
:type value: str
|
|
213
|
+
"""
|
|
214
|
+
if value is None:
|
|
215
|
+
self._icon = ""
|
|
216
|
+
else:
|
|
217
|
+
self._icon = f'<i class="{value}" style="margin-right: {self._icon_gap}px"></i>'
|
|
218
|
+
DataJson()[self.widget_id]["options"]["icon"] = self._icon
|
|
219
|
+
DataJson().send_changes()
|
|
220
|
+
|
|
221
|
+
@property
|
|
222
|
+
def button_type(self) -> str:
|
|
223
|
+
"""Returns the type of the button.
|
|
224
|
+
|
|
225
|
+
:return: Type of the button.
|
|
226
|
+
:rtype: str
|
|
227
|
+
"""
|
|
228
|
+
return self._button_type
|
|
229
|
+
|
|
230
|
+
@button_type.setter
|
|
231
|
+
def button_type(
|
|
232
|
+
self, value: Literal["primary", "info", "warning", "danger", "success", "text"]
|
|
233
|
+
) -> None:
|
|
234
|
+
"""Sets the type of the button.
|
|
235
|
+
|
|
236
|
+
:param value: Type of the button.
|
|
237
|
+
:type value: Literal["primary", "info", "warning", "danger", "success", "text"]
|
|
238
|
+
"""
|
|
239
|
+
self._button_type = value
|
|
240
|
+
DataJson()[self.widget_id]["options"]["button_type"] = self._button_type
|
|
241
|
+
DataJson().send_changes()
|
|
242
|
+
|
|
243
|
+
@property
|
|
244
|
+
def plain(self) -> bool:
|
|
245
|
+
"""Returns True if the button is plain, False otherwise.
|
|
246
|
+
|
|
247
|
+
:return: True if the button is plain, False otherwise.
|
|
248
|
+
:rtype: bool
|
|
249
|
+
"""
|
|
250
|
+
return self._plain
|
|
251
|
+
|
|
252
|
+
@plain.setter
|
|
253
|
+
def plain(self, value: bool) -> None:
|
|
254
|
+
"""Sets the button to be plain or not.
|
|
255
|
+
|
|
256
|
+
:param value: If True, the button will be plain.
|
|
257
|
+
:type value: bool
|
|
258
|
+
"""
|
|
259
|
+
self._plain = value
|
|
260
|
+
DataJson()[self.widget_id]["options"]["plain"] = self._plain
|
|
261
|
+
DataJson().send_changes()
|
|
262
|
+
|
|
263
|
+
@property
|
|
264
|
+
def loading(self) -> bool:
|
|
265
|
+
"""Returns True if the button shows loading animation, False otherwise.
|
|
266
|
+
|
|
267
|
+
:return: True if the button shows loading animation, False otherwise.
|
|
268
|
+
:rtype: bool
|
|
269
|
+
"""
|
|
270
|
+
return self._loading
|
|
271
|
+
|
|
272
|
+
@loading.setter
|
|
273
|
+
def loading(self, value: bool) -> None:
|
|
274
|
+
"""Sets the button loading animation.
|
|
275
|
+
|
|
276
|
+
:param value: If True, the animation will be enabled, otherwise disabled.
|
|
277
|
+
:type value: bool
|
|
278
|
+
"""
|
|
279
|
+
self._loading = value
|
|
280
|
+
DataJson()[self.widget_id]["options"]["loading"] = self._loading
|
|
281
|
+
DataJson().send_changes()
|
|
282
|
+
|
|
283
|
+
@property
|
|
284
|
+
def disabled(self) -> bool:
|
|
285
|
+
"""Returns True if the button is disabled, False otherwise.
|
|
286
|
+
|
|
287
|
+
:return: True if the button is disabled, False otherwise.
|
|
288
|
+
:rtype: bool
|
|
289
|
+
"""
|
|
290
|
+
return self._disabled
|
|
291
|
+
|
|
292
|
+
@disabled.setter
|
|
293
|
+
def disabled(self, value: bool) -> None:
|
|
294
|
+
"""Sets the button to be disabled or not.
|
|
295
|
+
|
|
296
|
+
:param value: If True, the button will be disabled.
|
|
297
|
+
:type value: bool
|
|
298
|
+
"""
|
|
299
|
+
self._disabled = value
|
|
300
|
+
DataJson()[self.widget_id]["options"]["disabled"] = self._disabled
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Vue.component('sly-run-app-button', {
|
|
2
|
+
props: {
|
|
3
|
+
'publicApiInstance': { 'type': Object },
|
|
4
|
+
'workspaceId': { 'type': Number }, 'moduleId': { 'type': Number }, 'payload': { 'type': Object }, 'options': { 'type': Object }
|
|
5
|
+
},
|
|
6
|
+
data() {
|
|
7
|
+
return {
|
|
8
|
+
loading: false,
|
|
9
|
+
};
|
|
10
|
+
},
|
|
11
|
+
methods: {
|
|
12
|
+
async runApp() {
|
|
13
|
+
try {
|
|
14
|
+
this.loading = true;
|
|
15
|
+
|
|
16
|
+
const tasks = await this.publicApiInstance.post('tasks.run.app', {
|
|
17
|
+
params: this.payload,
|
|
18
|
+
workspaceId: this.workspaceId,
|
|
19
|
+
moduleId: this.moduleId,
|
|
20
|
+
nodeId: null,
|
|
21
|
+
}).then(response => response.data);
|
|
22
|
+
|
|
23
|
+
const task = tasks[0];
|
|
24
|
+
const origin = new URL(this.publicApiInstance.defaults.baseURL).origin;
|
|
25
|
+
window.open(`${origin}/apps/${task.appId}/sessions/${task.taskId}`, '_blank');
|
|
26
|
+
} finally {
|
|
27
|
+
this.loading = false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
template: `
|
|
32
|
+
<el-button
|
|
33
|
+
:class="{'available-in-offline': options.available_in_offline}"
|
|
34
|
+
@click="runApp"
|
|
35
|
+
v-loading="options.loading || loading"
|
|
36
|
+
:type="options.button_type"
|
|
37
|
+
:plain="options.plain"
|
|
38
|
+
:size="options.button_size"
|
|
39
|
+
:disabled="options.disabled"
|
|
40
|
+
|
|
41
|
+
>
|
|
42
|
+
<span v-html="options.icon"></span>
|
|
43
|
+
<span v-html="options.text"></span>
|
|
44
|
+
</el-button>
|
|
45
|
+
`,
|
|
46
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<sly-run-app-button
|
|
2
|
+
:public-api-instance="publicApiInstance"
|
|
3
|
+
:workspace-id="state.{{{widget.widget_id}}}.workspace_id"
|
|
4
|
+
:module-id="state.{{{widget.widget_id}}}.module_id"
|
|
5
|
+
:payload="state.{{{widget.widget_id}}}.payload"
|
|
6
|
+
:options="data.{{{widget.widget_id}}}.options"
|
|
7
|
+
{% if widget._visible_by_vue_field %}
|
|
8
|
+
v-show="{{{widget._visible_by_vue_field}}}"
|
|
9
|
+
{% endif %}
|
|
10
|
+
></sly-run-app-button>
|
|
@@ -372,7 +372,7 @@ class BaseTrainArtifacts:
|
|
|
372
372
|
_upload_metadata(train_json)
|
|
373
373
|
logger.info(f"Metadata for '{artifacts_folder}' was generated")
|
|
374
374
|
else:
|
|
375
|
-
logger.
|
|
375
|
+
logger.debug(f"Invalid metadata for '{artifacts_folder}'")
|
|
376
376
|
train_json = None
|
|
377
377
|
return train_json
|
|
378
378
|
|
|
@@ -436,7 +436,7 @@ class BaseTrainArtifacts:
|
|
|
436
436
|
)
|
|
437
437
|
is_valid = self._validate_train_json(json_data)
|
|
438
438
|
if not is_valid:
|
|
439
|
-
logger.
|
|
439
|
+
logger.debug(f"Invalid metadata for '{artifacts_folder}'")
|
|
440
440
|
json_data = None
|
|
441
441
|
return json_data
|
|
442
442
|
|
|
@@ -590,7 +590,7 @@ class BaseTrainArtifacts:
|
|
|
590
590
|
|
|
591
591
|
return ExperimentInfo(**experiment_info_data)
|
|
592
592
|
except Exception as e:
|
|
593
|
-
logger.
|
|
593
|
+
logger.debug(f"Failed to build experiment info: {e}")
|
|
594
594
|
return None
|
|
595
595
|
|
|
596
596
|
train_infos = self.get_list(sort)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from typing import Callable, List, Optional, Tuple,
|
|
3
|
+
from typing import Callable, List, Optional, Tuple, Type, Union
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
|
|
@@ -96,7 +96,7 @@ class BaseBenchmark:
|
|
|
96
96
|
def key_metrics(self):
|
|
97
97
|
eval_results = self.get_eval_result()
|
|
98
98
|
return eval_results.key_metrics
|
|
99
|
-
|
|
99
|
+
|
|
100
100
|
@property
|
|
101
101
|
def primary_metric_name(self) -> str:
|
|
102
102
|
return self._get_evaluator_class().eval_result_cls.PRIMARY_METRIC
|
|
@@ -415,7 +415,6 @@ class BaseBenchmark:
|
|
|
415
415
|
"id": app_info["id"],
|
|
416
416
|
}
|
|
417
417
|
else:
|
|
418
|
-
logger.warning("session.task_id is not set. App info will not be fetched.")
|
|
419
418
|
app_info = None
|
|
420
419
|
model_info = {
|
|
421
420
|
**deploy_info,
|
|
@@ -561,15 +560,20 @@ class BaseBenchmark:
|
|
|
561
560
|
def lnk(self):
|
|
562
561
|
return self.visualizer.renderer.lnk
|
|
563
562
|
|
|
564
|
-
def upload_report_link(self, remote_dir: str):
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
563
|
+
def upload_report_link(self, remote_dir: str, report_id: int = None, local_dir: str = None):
|
|
564
|
+
if report_id is None:
|
|
565
|
+
template_path = os.path.join(remote_dir, "template.vue")
|
|
566
|
+
vue_template_info = self.api.file.get_info_by_path(self.team_id, template_path)
|
|
567
|
+
self.report_id = vue_template_info.id
|
|
568
|
+
report_id = vue_template_info.id
|
|
570
569
|
|
|
570
|
+
report_link = "/model-benchmark?id=" + str(report_id)
|
|
571
571
|
lnk_name = "Model Evaluation Report.lnk"
|
|
572
|
-
|
|
572
|
+
|
|
573
|
+
if local_dir is None:
|
|
574
|
+
local_dir = self.get_layout_results_dir()
|
|
575
|
+
local_path = os.path.join(local_dir, lnk_name)
|
|
576
|
+
|
|
573
577
|
with open(local_path, "w") as file:
|
|
574
578
|
file.write(report_link)
|
|
575
579
|
|