supervisely 6.73.372__py3-none-any.whl → 6.73.374__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.
- supervisely/_utils.py +11 -0
- supervisely/api/labeling_job_api.py +5 -0
- supervisely/api/labeling_queue_api.py +26 -0
- supervisely/api/module_api.py +2 -0
- supervisely/app/widgets/run_app_button/run_app_button.py +22 -2
- supervisely/app/widgets/run_app_button/script.js +105 -45
- supervisely/app/widgets/run_app_button/template.html +5 -10
- supervisely/nn/training/gui/training_logs.py +4 -1
- supervisely/nn/training/gui/utils.py +23 -0
- supervisely/nn/training/train_app.py +13 -3
- {supervisely-6.73.372.dist-info → supervisely-6.73.374.dist-info}/METADATA +1 -1
- {supervisely-6.73.372.dist-info → supervisely-6.73.374.dist-info}/RECORD +16 -16
- {supervisely-6.73.372.dist-info → supervisely-6.73.374.dist-info}/LICENSE +0 -0
- {supervisely-6.73.372.dist-info → supervisely-6.73.374.dist-info}/WHEEL +0 -0
- {supervisely-6.73.372.dist-info → supervisely-6.73.374.dist-info}/entry_points.txt +0 -0
- {supervisely-6.73.372.dist-info → supervisely-6.73.374.dist-info}/top_level.txt +0 -0
supervisely/_utils.py
CHANGED
|
@@ -575,3 +575,14 @@ def removesuffix(string, suffix):
|
|
|
575
575
|
if string.endswith(suffix):
|
|
576
576
|
return string[: -len(suffix)]
|
|
577
577
|
return string
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
def remove_non_printable(text: str) -> str:
|
|
581
|
+
"""Remove non-printable characters from a string.
|
|
582
|
+
|
|
583
|
+
:param text: Input string
|
|
584
|
+
:type text: str
|
|
585
|
+
:return: String with non-printable characters removed
|
|
586
|
+
:rtype: str
|
|
587
|
+
"""
|
|
588
|
+
return "".join(char for char in text if char.isprintable()).strip()
|
|
@@ -340,6 +340,7 @@ class LabelingJobApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
340
340
|
disable_confirm: Optional[bool] = None,
|
|
341
341
|
disable_submit: Optional[bool] = None,
|
|
342
342
|
toolbox_settings: Optional[Dict] = None,
|
|
343
|
+
enable_quality_check: Optional[bool] = None,
|
|
343
344
|
) -> List[LabelingJobInfo]:
|
|
344
345
|
"""
|
|
345
346
|
Creates Labeling Job and assigns given Users to it.
|
|
@@ -382,6 +383,8 @@ class LabelingJobApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
382
383
|
:type disable_submit: bool, optional
|
|
383
384
|
:param toolbox_settings: Settings for the labeling tool. Only video projects are supported.
|
|
384
385
|
:type toolbox_settings: Dict, optional
|
|
386
|
+
:param enable_quality_check: If True, adds an intermediate step between "review" and completing the Labeling Job.
|
|
387
|
+
:type enable_quality_check: bool, optional
|
|
385
388
|
:return: List of information about new Labeling Job. See :class:`info_sequence<info_sequence>`
|
|
386
389
|
:rtype: :class:`List[LabelingJobInfo]`
|
|
387
390
|
:Usage example:
|
|
@@ -499,6 +502,8 @@ class LabelingJobApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
499
502
|
meta.update({"disableConfirm": disable_confirm})
|
|
500
503
|
if disable_submit is not None:
|
|
501
504
|
meta.update({"disableSubmit": disable_submit})
|
|
505
|
+
if enable_quality_check is not None:
|
|
506
|
+
meta.update({"enableIntermediateReview": enable_quality_check})
|
|
502
507
|
|
|
503
508
|
data = {
|
|
504
509
|
ApiField.NAME: name,
|
|
@@ -198,6 +198,8 @@ class LabelingQueueApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
198
198
|
hide_figure_author: Optional[bool] = False,
|
|
199
199
|
allow_review_own_annotations: Optional[bool] = False,
|
|
200
200
|
skip_complete_job_on_empty: Optional[bool] = False,
|
|
201
|
+
enable_quality_check: Optional[bool] = None,
|
|
202
|
+
quality_check_user_ids: Optional[List[int]] = None,
|
|
201
203
|
) -> int:
|
|
202
204
|
"""
|
|
203
205
|
Creates Labeling Queue and assigns given Users to it.
|
|
@@ -210,6 +212,8 @@ class LabelingQueueApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
210
212
|
:type collection_id: int, optional
|
|
211
213
|
:param user_ids: User IDs in Supervisely to assign Users as labelers to Labeling Queue.
|
|
212
214
|
:type user_ids: List[int]
|
|
215
|
+
:param reviewer_ids: User IDs in Supervisely to assign Users as reviewers to Labeling Queue.
|
|
216
|
+
:type reviewer_ids: List[int]
|
|
213
217
|
:param readme: Additional information about Labeling Queue.
|
|
214
218
|
:type readme: str, optional
|
|
215
219
|
:param description: Description of Labeling Queue.
|
|
@@ -242,6 +246,16 @@ class LabelingQueueApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
242
246
|
:type disable_submit: bool, optional
|
|
243
247
|
:param toolbox_settings: Settings for the labeling tool. Only video projects are supported.
|
|
244
248
|
:type toolbox_settings: Dict, optional
|
|
249
|
+
:param hide_figure_author: If True, hides the author of the figure in the labeling tool.
|
|
250
|
+
:type hide_figure_author: bool, optional
|
|
251
|
+
:param allow_review_own_annotations: If True, allows labelers to review their own annotations.
|
|
252
|
+
:type allow_review_own_annotations: bool, optional
|
|
253
|
+
:param skip_complete_job_on_empty: If True, skips completing the Labeling Queue if there are no images to label.
|
|
254
|
+
:type skip_complete_job_on_empty: bool, optional
|
|
255
|
+
:param enable_quality_check: If True, adds an intermediate step between "review" and completing the Labeling Queue.
|
|
256
|
+
:type enable_quality_check: bool, optional
|
|
257
|
+
:param quality_check_user_ids: List of User IDs in Supervisely to assign Users as Quality Checkers to Labeling Queue.
|
|
258
|
+
:type quality_check_user_ids: List[int], optional
|
|
245
259
|
:return: Labeling Queue ID in Supervisely.
|
|
246
260
|
:rtype: int
|
|
247
261
|
:Usage example:
|
|
@@ -348,6 +362,12 @@ class LabelingQueueApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
348
362
|
meta.update({"disableConfirm": disable_confirm})
|
|
349
363
|
if disable_submit is not None:
|
|
350
364
|
meta.update({"disableSubmit": disable_submit})
|
|
365
|
+
if enable_quality_check is not None:
|
|
366
|
+
if quality_check_user_ids is None:
|
|
367
|
+
raise RuntimeError(
|
|
368
|
+
"quality_check_user_ids must be provided if enable_quality_check is True"
|
|
369
|
+
)
|
|
370
|
+
meta.update({"enableIntermediateReview": enable_quality_check})
|
|
351
371
|
|
|
352
372
|
queue_meta = {}
|
|
353
373
|
if allow_review_own_annotations is True:
|
|
@@ -366,6 +386,12 @@ class LabelingQueueApi(RemoveableBulkModuleApi, ModuleWithStatus):
|
|
|
366
386
|
data[ApiField.DATASET_ID] = dataset_id
|
|
367
387
|
if collection_id is not None:
|
|
368
388
|
data[ApiField.COLLECTION_ID] = collection_id
|
|
389
|
+
if quality_check_user_ids is not None:
|
|
390
|
+
if enable_quality_check is not True:
|
|
391
|
+
raise RuntimeError(
|
|
392
|
+
"quality_check_user_ids can be set only if enable_quality_check is True"
|
|
393
|
+
)
|
|
394
|
+
data[ApiField.QUALITY_CHECK_USER_IDS] = quality_check_user_ids
|
|
369
395
|
|
|
370
396
|
if len(queue_meta) > 0:
|
|
371
397
|
data[ApiField.QUEUE_META] = queue_meta
|
supervisely/api/module_api.py
CHANGED
|
@@ -13,6 +13,7 @@ from supervisely.app.widgets_context import JinjaWidgets
|
|
|
13
13
|
class RunAppButton(Widget):
|
|
14
14
|
def __init__(
|
|
15
15
|
self,
|
|
16
|
+
team_id: int,
|
|
16
17
|
workspace_id: int,
|
|
17
18
|
module_id: int,
|
|
18
19
|
payload: dict = None,
|
|
@@ -26,11 +27,14 @@ class RunAppButton(Widget):
|
|
|
26
27
|
icon_gap: Optional[int] = 5,
|
|
27
28
|
available_in_offline: Optional[bool] = False,
|
|
28
29
|
visible_by_vue_field: Optional[str] = "",
|
|
30
|
+
check_existing_task_cb: Optional[str] = "null",
|
|
29
31
|
widget_id: Optional[str] = None,
|
|
30
32
|
):
|
|
31
33
|
"""
|
|
32
34
|
Button the runs an app on Supervisely instance.
|
|
33
35
|
|
|
36
|
+
:param team_id: Team ID.
|
|
37
|
+
:type team_id: int
|
|
34
38
|
:param workspace_id: Workspace ID.
|
|
35
39
|
:type workspace_id: int
|
|
36
40
|
:param module_id: Module ID.
|
|
@@ -53,6 +57,8 @@ class RunAppButton(Widget):
|
|
|
53
57
|
:type available_in_offline: bool, optional
|
|
54
58
|
: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
59
|
:type visible_by_vue_field: str, optional
|
|
60
|
+
:param check_existing_task_cb: Sets the callback function for checking existing tasks. Function should be a string (docstring) of JavaScript code.
|
|
61
|
+
:type check_existing_task_cb: str, optional
|
|
56
62
|
:param widget_id: Widget ID.
|
|
57
63
|
:type widget_id: str, optional
|
|
58
64
|
|
|
@@ -88,12 +94,13 @@ class RunAppButton(Widget):
|
|
|
88
94
|
|
|
89
95
|
self._available_in_offline = available_in_offline
|
|
90
96
|
self._visible_by_vue_field = visible_by_vue_field
|
|
91
|
-
|
|
92
97
|
self._loading = False
|
|
93
98
|
self._disabled = False
|
|
99
|
+
self._team_id = team_id
|
|
94
100
|
self._workspace_id = workspace_id
|
|
95
101
|
self._module_id = module_id
|
|
96
102
|
self._payload = payload
|
|
103
|
+
self._check_existing_task_cb = check_existing_task_cb
|
|
97
104
|
|
|
98
105
|
super().__init__(widget_id=widget_id, file_path=__file__)
|
|
99
106
|
|
|
@@ -114,6 +121,7 @@ class RunAppButton(Widget):
|
|
|
114
121
|
- available_in_offline: If True, the button will be available in offline session.
|
|
115
122
|
"""
|
|
116
123
|
return {
|
|
124
|
+
"check_existing_task_cb": self._check_existing_task_cb,
|
|
117
125
|
"options": {
|
|
118
126
|
"text": self._text,
|
|
119
127
|
"button_type": self._button_type,
|
|
@@ -123,12 +131,13 @@ class RunAppButton(Widget):
|
|
|
123
131
|
"disabled": self._disabled,
|
|
124
132
|
"icon": self._icon,
|
|
125
133
|
"available_in_offline": self._available_in_offline,
|
|
126
|
-
}
|
|
134
|
+
},
|
|
127
135
|
}
|
|
128
136
|
|
|
129
137
|
def get_json_state(self) -> None:
|
|
130
138
|
"""Button widget doesn't have state, so this method returns None."""
|
|
131
139
|
return {
|
|
140
|
+
"team_id": self._team_id,
|
|
132
141
|
"workspace_id": self._workspace_id,
|
|
133
142
|
"module_id": self._module_id,
|
|
134
143
|
"payload": self._payload,
|
|
@@ -298,3 +307,14 @@ class RunAppButton(Widget):
|
|
|
298
307
|
"""
|
|
299
308
|
self._disabled = value
|
|
300
309
|
DataJson()[self.widget_id]["options"]["disabled"] = self._disabled
|
|
310
|
+
|
|
311
|
+
def set_check_existing_task_cb(self, function: str) -> None:
|
|
312
|
+
"""Sets the callback function for checking existing tasks.
|
|
313
|
+
Function should be a string (docstring) of JavaScript code.
|
|
314
|
+
|
|
315
|
+
:param function: Callback function for checking existing tasks.
|
|
316
|
+
:type function: str
|
|
317
|
+
"""
|
|
318
|
+
self._check_existing_task_cb = function
|
|
319
|
+
DataJson()[self.widget_id]["check_existing_task_cb"] = self._check_existing_task_cb
|
|
320
|
+
DataJson().send_changes()
|
|
@@ -1,46 +1,106 @@
|
|
|
1
|
-
Vue.component(
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
1
|
+
Vue.component("sly-run-app-button", {
|
|
2
|
+
props: {
|
|
3
|
+
publicApiInstance: { type: Function },
|
|
4
|
+
workspaceId: { type: Number },
|
|
5
|
+
moduleId: { type: Number },
|
|
6
|
+
payload: { type: Object },
|
|
7
|
+
options: { type: Object, default: () => ({}) },
|
|
8
|
+
groupId: { type: Number },
|
|
9
|
+
checkExistingTaskCb: { type: Function, default: null },
|
|
10
|
+
},
|
|
11
|
+
data() {
|
|
12
|
+
return {
|
|
13
|
+
loading: false,
|
|
14
|
+
};
|
|
15
|
+
},
|
|
16
|
+
methods: {
|
|
17
|
+
async runApp() {
|
|
18
|
+
try {
|
|
19
|
+
this.loading = true;
|
|
20
|
+
|
|
21
|
+
if (this.checkExistingTaskCb) {
|
|
22
|
+
let checkExistingTaskCb =
|
|
23
|
+
typeof this.checkExistingTaskCb === "function"
|
|
24
|
+
? this.checkExistingTaskCb
|
|
25
|
+
: null;
|
|
26
|
+
|
|
27
|
+
if (typeof this.checkExistingTaskCb === "string") {
|
|
28
|
+
console.log("checkExistingTaskCb", this.checkExistingTaskCb);
|
|
29
|
+
try {
|
|
30
|
+
checkExistingTaskCb = new Function(
|
|
31
|
+
"task",
|
|
32
|
+
this.checkExistingTaskCb
|
|
33
|
+
);
|
|
34
|
+
} catch (err) {
|
|
35
|
+
console.log("Error parsing checkExistingTaskCb string:", err);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
console.log("Before check checkExistingTaskCb", checkExistingTaskCb);
|
|
40
|
+
if (checkExistingTaskCb) {
|
|
41
|
+
const allEntities = await this.publicApiInstance
|
|
42
|
+
.post("apps.list", {
|
|
43
|
+
withShared: true,
|
|
44
|
+
onlyRunning: true,
|
|
45
|
+
groupId: this.groupId,
|
|
46
|
+
filter: [
|
|
47
|
+
{ field: "moduleId", operator: "=", value: this.moduleId },
|
|
48
|
+
],
|
|
49
|
+
})
|
|
50
|
+
.then((res) => res.data?.entities || []);
|
|
51
|
+
|
|
52
|
+
const existTasks = allEntities.flatMap(
|
|
53
|
+
(entity) => entity.tasks || []
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
if (existTasks.length) {
|
|
57
|
+
const foundTask = existTasks.find((t) => checkExistingTaskCb(t));
|
|
58
|
+
console.log("foundTask", foundTask);
|
|
59
|
+
|
|
60
|
+
if (foundTask) {
|
|
61
|
+
window.open(
|
|
62
|
+
`/apps/${foundTask.meta.app.id}/sessions/${foundTask.id}`,
|
|
63
|
+
"_blank"
|
|
64
|
+
);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const tasks = await this.publicApiInstance
|
|
72
|
+
.post("tasks.run.app", {
|
|
73
|
+
params: this.payload,
|
|
74
|
+
workspaceId: this.workspaceId,
|
|
75
|
+
moduleId: this.moduleId,
|
|
76
|
+
nodeId: null,
|
|
77
|
+
})
|
|
78
|
+
.then((response) => response.data);
|
|
79
|
+
|
|
80
|
+
const task = tasks[0];
|
|
81
|
+
const origin = new URL(this.publicApiInstance.defaults.baseURL).origin;
|
|
82
|
+
window.open(
|
|
83
|
+
`${origin}/apps/${task.appId}/sessions/${task.taskId}`,
|
|
84
|
+
"_blank"
|
|
85
|
+
);
|
|
86
|
+
} finally {
|
|
87
|
+
this.loading = false;
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
template: `
|
|
92
|
+
<el-button
|
|
93
|
+
:class="{'available-in-offline': options.available_in_offline}"
|
|
94
|
+
@click="runApp"
|
|
95
|
+
v-loading="options.loading || loading"
|
|
96
|
+
:type="options.button_type"
|
|
97
|
+
:plain="options.plain"
|
|
98
|
+
:size="options.button_size"
|
|
99
|
+
:disabled="options.disabled"
|
|
100
|
+
|
|
101
|
+
>
|
|
102
|
+
<span v-html="options.icon"></span>
|
|
103
|
+
<span v-html="options.text"></span>
|
|
104
|
+
</el-button>
|
|
105
|
+
`,
|
|
46
106
|
});
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
<sly-run-app-button
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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>
|
|
1
|
+
<sly-run-app-button :public-api-instance="publicApiInstance" :group-id="state.{{{widget.widget_id}}}.team_id"
|
|
2
|
+
:workspace-id="state.{{{widget.widget_id}}}.workspace_id" :module-id="state.{{{widget.widget_id}}}.module_id"
|
|
3
|
+
:payload="state.{{{widget.widget_id}}}.payload" :options="data.{{{widget.widget_id}}}.options" {% if
|
|
4
|
+
widget._visible_by_vue_field %} v-show="{{{widget._visible_by_vue_field}}}" {% endif %}
|
|
5
|
+
:check-existing-task-cb="data.{{{widget.widget_id}}}.check_existing_task_cb"></sly-run-app-button>
|
|
@@ -36,6 +36,7 @@ class TrainingLogs:
|
|
|
36
36
|
self.display_widgets = []
|
|
37
37
|
self.app_options = app_options
|
|
38
38
|
api = Api.from_env()
|
|
39
|
+
team_id = sly_env.team_id()
|
|
39
40
|
|
|
40
41
|
# GUI Components
|
|
41
42
|
self.validator_text = Text("")
|
|
@@ -73,6 +74,7 @@ class TrainingLogs:
|
|
|
73
74
|
module_info = gui_utils.get_module_info_by_name(api, app_name)
|
|
74
75
|
if module_info is not None:
|
|
75
76
|
self.tensorboard_offline_button = RunAppButton(
|
|
77
|
+
team_id=team_id,
|
|
76
78
|
workspace_id=workspace_id,
|
|
77
79
|
module_id=module_info["id"],
|
|
78
80
|
payload={},
|
|
@@ -81,9 +83,10 @@ class TrainingLogs:
|
|
|
81
83
|
plain=True,
|
|
82
84
|
icon="zmdi zmdi-chart",
|
|
83
85
|
available_in_offline=True,
|
|
84
|
-
visible_by_vue_field=
|
|
86
|
+
visible_by_vue_field=None,
|
|
85
87
|
)
|
|
86
88
|
self.tensorboard_offline_button.disable()
|
|
89
|
+
self.tensorboard_offline_button.hide()
|
|
87
90
|
self.display_widgets.extend([self.tensorboard_offline_button])
|
|
88
91
|
else:
|
|
89
92
|
logger.warning(
|
|
@@ -136,3 +136,26 @@ def get_module_info_by_name(api: Api, app_name: str) -> Union[Dict, None]:
|
|
|
136
136
|
if module["name"] == app_name:
|
|
137
137
|
app_info = api.app.get_info(module["id"])
|
|
138
138
|
return app_info
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def generate_task_check_function_js(folder: str) -> str:
|
|
142
|
+
"""
|
|
143
|
+
Returns JavaScript function code for checking existing tasks.
|
|
144
|
+
|
|
145
|
+
:param folder: Remote folder to check.
|
|
146
|
+
:type folder: str
|
|
147
|
+
:return: JavaScript function code for checking existing tasks.
|
|
148
|
+
:rtype: str
|
|
149
|
+
"""
|
|
150
|
+
escaped_folder = folder.replace("'", "\\'")
|
|
151
|
+
js_code = f"""
|
|
152
|
+
if (!task || !task.meta || !task.meta.params || !task.meta.params.state) {{
|
|
153
|
+
return false;
|
|
154
|
+
}}
|
|
155
|
+
const taskFolder = task.meta.params.state.slyFolder;
|
|
156
|
+
if (!taskFolder || typeof taskFolder !== 'string') {{
|
|
157
|
+
return false;
|
|
158
|
+
}}
|
|
159
|
+
return taskFolder === '{escaped_folder}';
|
|
160
|
+
"""
|
|
161
|
+
return js_code
|
|
@@ -10,6 +10,7 @@ import subprocess
|
|
|
10
10
|
from datetime import datetime
|
|
11
11
|
from os import getcwd, listdir, walk
|
|
12
12
|
from os.path import basename, dirname, exists, expanduser, isdir, isfile, join
|
|
13
|
+
from time import sleep
|
|
13
14
|
from typing import Any, Dict, List, Literal, Optional, Union
|
|
14
15
|
from urllib.request import urlopen
|
|
15
16
|
|
|
@@ -57,6 +58,7 @@ from supervisely.nn.inference import RuntimeType, SessionJSON
|
|
|
57
58
|
from supervisely.nn.inference.inference import Inference
|
|
58
59
|
from supervisely.nn.task_type import TaskType
|
|
59
60
|
from supervisely.nn.training.gui.gui import TrainGUI
|
|
61
|
+
from supervisely.nn.training.gui.utils import generate_task_check_function_js
|
|
60
62
|
from supervisely.nn.training.loggers import setup_train_logger, train_logger
|
|
61
63
|
from supervisely.nn.utils import ModelSource, _get_model_name
|
|
62
64
|
from supervisely.output import set_directory
|
|
@@ -1949,11 +1951,15 @@ class TrainApp:
|
|
|
1949
1951
|
self.progress_bar_main.hide()
|
|
1950
1952
|
|
|
1951
1953
|
file_info = self._api.file.get_info_by_path(self.team_id, join(remote_dir, "open_app.lnk"))
|
|
1954
|
+
|
|
1952
1955
|
# Set offline tensorboard button payload
|
|
1953
1956
|
if is_production():
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
+
remote_log_dir = join(remote_dir, "logs")
|
|
1958
|
+
tb_btn_payload = {"state": {"slyFolder": remote_log_dir}}
|
|
1959
|
+
self.gui.training_logs.tensorboard_offline_button.payload = tb_btn_payload
|
|
1960
|
+
self.gui.training_logs.tensorboard_offline_button.set_check_existing_task_cb(
|
|
1961
|
+
generate_task_check_function_js(remote_log_dir)
|
|
1962
|
+
)
|
|
1957
1963
|
self.gui.training_logs.tensorboard_offline_button.enable()
|
|
1958
1964
|
|
|
1959
1965
|
return remote_dir, file_info
|
|
@@ -2608,6 +2614,10 @@ class TrainApp:
|
|
|
2608
2614
|
self.gui.training_process.start_button.loading = False
|
|
2609
2615
|
|
|
2610
2616
|
# Shutdown the app after training is finished
|
|
2617
|
+
|
|
2618
|
+
self.gui.training_logs.tensorboard_button.hide()
|
|
2619
|
+
self.gui.training_logs.tensorboard_offline_button.show()
|
|
2620
|
+
sleep(1) # wait for the button to be shown
|
|
2611
2621
|
self.app.shutdown()
|
|
2612
2622
|
except Exception as e:
|
|
2613
2623
|
message = f"Error occurred during finalizing and uploading training artifacts. {check_logs_text}"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
supervisely/README.md,sha256=XM-DiMC6To3I9RjQZ0c61905EFRR_jnCUx2q3uNR-X8,3331
|
|
2
2
|
supervisely/__init__.py,sha256=_qphKFT0_toEQmF5IjB1sWjztbF4lP1tLY29PBJhArY,10917
|
|
3
|
-
supervisely/_utils.py,sha256=
|
|
3
|
+
supervisely/_utils.py,sha256=J0-qYN8YAEGJO4mmE5ErNdRx9mSVEYf5oIgqM4efegU,18926
|
|
4
4
|
supervisely/function_wrapper.py,sha256=R5YajTQ0GnRp2vtjwfC9hINkzQc0JiyGsu8TER373xY,1912
|
|
5
5
|
supervisely/sly_logger.py,sha256=z92Vu5hmC0GgTIJO1n6kPDayRW9__8ix8hL6poDZj-Y,6274
|
|
6
6
|
supervisely/tiny_timer.py,sha256=hkpe_7FE6bsKL79blSs7WBaktuPavEVu67IpEPrfmjE,183
|
|
@@ -33,9 +33,9 @@ supervisely/api/image_annotation_tool_api.py,sha256=YcUo78jRDBJYvIjrd-Y6FJAasLta
|
|
|
33
33
|
supervisely/api/image_api.py,sha256=zwyHsphaclKFU2a5gpHy6Cas_kpitViSCMV6vcPqR0s,224592
|
|
34
34
|
supervisely/api/import_storage_api.py,sha256=BDCgmR0Hv6OoiRHLCVPKt3iDxSVlQp1WrnKhAK_Zl84,460
|
|
35
35
|
supervisely/api/issues_api.py,sha256=BqDJXmNoTzwc3xe6_-mA7FDFC5QQ-ahGbXk_HmpkSeQ,17925
|
|
36
|
-
supervisely/api/labeling_job_api.py,sha256=
|
|
37
|
-
supervisely/api/labeling_queue_api.py,sha256=
|
|
38
|
-
supervisely/api/module_api.py,sha256=
|
|
36
|
+
supervisely/api/labeling_job_api.py,sha256=G2_BV_WtA2lAhfw_nAQmWmv1P-pwimD0ba9GVKoGjiA,55537
|
|
37
|
+
supervisely/api/labeling_queue_api.py,sha256=ilNjAL1d9NSa9yabQn6E-W26YdtooT3ZGXIFZtGnAvY,30158
|
|
38
|
+
supervisely/api/module_api.py,sha256=u-xm7DEkmIGJjhJKehCAs3w0GiC3xxNeLvQ_hTyGAF4,45363
|
|
39
39
|
supervisely/api/object_class_api.py,sha256=7-npNFMYjWNtSXYZg6syc6bX56_oCzDU2kFRPGQWCwA,10399
|
|
40
40
|
supervisely/api/plugin_api.py,sha256=SFm0IlTTOjuHBLUMgG4d4k6U3cWJocE-SVb-f08fwMQ,5286
|
|
41
41
|
supervisely/api/project_api.py,sha256=WNTMqAa0ZedYesfiZEkZtaFr5huxIpJ8TFYygTnlAWQ,80309
|
|
@@ -427,9 +427,9 @@ supervisely/app/widgets/report_thumbnail/__init__.py,sha256=47DEQpj8HBSa-_TImW-5
|
|
|
427
427
|
supervisely/app/widgets/report_thumbnail/report_thumbnail.py,sha256=JYEoNi9tXslx9nlxdFcklxk-4ONtb_F46H5FRxZD1p0,2163
|
|
428
428
|
supervisely/app/widgets/report_thumbnail/template.html,sha256=7dGngqwO_xxWZLOre0f6Vml3B_qXWu0l1P96L3opJ84,429
|
|
429
429
|
supervisely/app/widgets/run_app_button/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
430
|
-
supervisely/app/widgets/run_app_button/run_app_button.py,sha256=
|
|
431
|
-
supervisely/app/widgets/run_app_button/script.js,sha256=
|
|
432
|
-
supervisely/app/widgets/run_app_button/template.html,sha256
|
|
430
|
+
supervisely/app/widgets/run_app_button/run_app_button.py,sha256=cr07jabP1vF-rvH0_swVTuzpWXsvI9tHy_oQbJrHxSU,11044
|
|
431
|
+
supervisely/app/widgets/run_app_button/script.js,sha256=6rlluiW1hbHN7swtNSoFX9Gmrz2U-nRNOwoUpnSBmiw,2736
|
|
432
|
+
supervisely/app/widgets/run_app_button/template.html,sha256=rFIYPC9hl2b9H_LR1Kr_1RCpzfAAd-FBcmTmt75YXnE,511
|
|
433
433
|
supervisely/app/widgets/scatter_chart/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
434
434
|
supervisely/app/widgets/scatter_chart/scatter_chart.py,sha256=nX7fZbWsDiMjOek5FvIHgKbnBwQ-ol_V3XvnoAnz59c,4832
|
|
435
435
|
supervisely/app/widgets/select/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -994,7 +994,7 @@ supervisely/nn/tracking/__init__.py,sha256=Ld1ed7ZZQZPkhX-5Xr-UbHZx5zLCm2-tInHnP
|
|
|
994
994
|
supervisely/nn/tracking/boxmot.py,sha256=H9cQjYGL9nX_TLrfKDChhljTIiE9lffcgbwWCf_4PJU,4277
|
|
995
995
|
supervisely/nn/tracking/tracking.py,sha256=WNrNm02B1pspA3d_AmzSJ-54RZTqWV2NZiC7FHe88bo,857
|
|
996
996
|
supervisely/nn/training/__init__.py,sha256=gY4PCykJ-42MWKsqb9kl-skemKa8yB6t_fb5kzqR66U,111
|
|
997
|
-
supervisely/nn/training/train_app.py,sha256
|
|
997
|
+
supervisely/nn/training/train_app.py,sha256=-NbFxj0MMPGJ8ysQcIxYd3j7oKutEcOYL9-9oO-bCiU,116587
|
|
998
998
|
supervisely/nn/training/gui/__init__.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
|
|
999
999
|
supervisely/nn/training/gui/classes_selector.py,sha256=Bpp-RFDQqcZ0kLJmS6ZnExkdscWwRusvF4vbWjEsKlQ,3926
|
|
1000
1000
|
supervisely/nn/training/gui/gui.py,sha256=Z68uMPNkOyb70rpxfVDfJuGSzcoOhrqqDog8PABF2JQ,43312
|
|
@@ -1004,9 +1004,9 @@ supervisely/nn/training/gui/model_selector.py,sha256=I6KRKyylpwUEC3CApEnzDKkWe5x
|
|
|
1004
1004
|
supervisely/nn/training/gui/tags_selector.py,sha256=ZirVXm5NNuIDjXO3wuHDnpYTWgFVLn-W7voBudh5bP0,3772
|
|
1005
1005
|
supervisely/nn/training/gui/train_val_splits_selector.py,sha256=V8aMe0l-CaoHxP0y6GeCBGDMd7L3epQ3KqeFsMY43rs,11191
|
|
1006
1006
|
supervisely/nn/training/gui/training_artifacts.py,sha256=c0GH70ZByvnL413KWHjSKcSX8V5DStXM5sjFVZafSZo,10519
|
|
1007
|
-
supervisely/nn/training/gui/training_logs.py,sha256=
|
|
1007
|
+
supervisely/nn/training/gui/training_logs.py,sha256=GgEQMj9p98Z3p2b_-3BkHOhY7WQYELxctsRKmkbg3JY,4966
|
|
1008
1008
|
supervisely/nn/training/gui/training_process.py,sha256=2F65cuu5ypKWkdaO4uVpNLMkwXjM8dpprd7Km5aedds,3192
|
|
1009
|
-
supervisely/nn/training/gui/utils.py,sha256=
|
|
1009
|
+
supervisely/nn/training/gui/utils.py,sha256=cEOsYItxgGTGKxFAvn7zQcTpwHgcGRO_UNGBn8idMUI,4983
|
|
1010
1010
|
supervisely/nn/training/loggers/__init__.py,sha256=DOqR-4NJv25C4Y1HCWggvGNM5mgo1CbwQOdvROOL-60,777
|
|
1011
1011
|
supervisely/nn/training/loggers/base_train_logger.py,sha256=Gf_TKwSfQdSVG6P3wAeWf5t2_EJWJqOPqt_TsJ5jpBY,1914
|
|
1012
1012
|
supervisely/nn/training/loggers/tensorboard_logger.py,sha256=s6dNFHIaucRTRMEdDM8mHT7v8bUdl13oDK78kPeCW8U,1116
|
|
@@ -1097,9 +1097,9 @@ supervisely/worker_proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
1097
1097
|
supervisely/worker_proto/worker_api_pb2.py,sha256=VQfi5JRBHs2pFCK1snec3JECgGnua3Xjqw_-b3aFxuM,59142
|
|
1098
1098
|
supervisely/worker_proto/worker_api_pb2_grpc.py,sha256=3BwQXOaP9qpdi0Dt9EKG--Lm8KGN0C5AgmUfRv77_Jk,28940
|
|
1099
1099
|
supervisely_lib/__init__.py,sha256=7-3QnN8Zf0wj8NCr2oJmqoQWMKKPKTECvjH9pd2S5vY,159
|
|
1100
|
-
supervisely-6.73.
|
|
1101
|
-
supervisely-6.73.
|
|
1102
|
-
supervisely-6.73.
|
|
1103
|
-
supervisely-6.73.
|
|
1104
|
-
supervisely-6.73.
|
|
1105
|
-
supervisely-6.73.
|
|
1100
|
+
supervisely-6.73.374.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
1101
|
+
supervisely-6.73.374.dist-info/METADATA,sha256=CZQRzlek6lQZ0EeIc-BYmKKPqE-p-nVIGMMm7eh4Aws,35154
|
|
1102
|
+
supervisely-6.73.374.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
|
|
1103
|
+
supervisely-6.73.374.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
|
|
1104
|
+
supervisely-6.73.374.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
|
|
1105
|
+
supervisely-6.73.374.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|