intellif-aihub 0.1.5__py3-none-any.whl → 0.1.7__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 intellif-aihub might be problematic. Click here for more details.

Files changed (34) hide show
  1. aihub/__init__.py +1 -1
  2. aihub/client.py +35 -12
  3. aihub/models/data_warehouse.py +95 -0
  4. aihub/models/dataset_management.py +99 -61
  5. aihub/models/document_center.py +26 -18
  6. aihub/models/eval.py +20 -11
  7. aihub/models/labelfree.py +12 -38
  8. aihub/models/model_center.py +141 -0
  9. aihub/models/model_training_platform.py +182 -149
  10. aihub/models/quota_schedule_management.py +196 -150
  11. aihub/models/tag_resource_management.py +30 -24
  12. aihub/models/task_center.py +43 -38
  13. aihub/models/user_system.py +159 -125
  14. aihub/models/workflow_center.py +461 -0
  15. aihub/services/artifact.py +22 -15
  16. aihub/services/data_warehouse.py +97 -0
  17. aihub/services/dataset_management.py +142 -23
  18. aihub/services/document_center.py +24 -5
  19. aihub/services/eval.py +14 -7
  20. aihub/services/labelfree.py +11 -0
  21. aihub/services/model_center.py +183 -0
  22. aihub/services/model_training_platform.py +132 -59
  23. aihub/services/quota_schedule_management.py +104 -7
  24. aihub/services/tag_resource_management.py +33 -2
  25. aihub/services/task_center.py +23 -9
  26. aihub/services/user_system.py +237 -2
  27. aihub/services/workflow_center.py +522 -0
  28. aihub/utils/download.py +19 -3
  29. {intellif_aihub-0.1.5.dist-info → intellif_aihub-0.1.7.dist-info}/METADATA +4 -4
  30. intellif_aihub-0.1.7.dist-info/RECORD +42 -0
  31. intellif_aihub-0.1.5.dist-info/RECORD +0 -36
  32. {intellif_aihub-0.1.5.dist-info → intellif_aihub-0.1.7.dist-info}/WHEEL +0 -0
  33. {intellif_aihub-0.1.5.dist-info → intellif_aihub-0.1.7.dist-info}/licenses/LICENSE +0 -0
  34. {intellif_aihub-0.1.5.dist-info → intellif_aihub-0.1.7.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,16 @@
1
+ # !/usr/bin/env python
2
+ # -*- coding:utf-8 -*-
3
+ """模型训练平台服务模块
4
+
5
+ 对接 **model‑training‑platform** 后端,以 **训练任务** 为核心提供常用业务能力,包括:
6
+
7
+ - **创建训练任务**
8
+ - **分页查询 / 获取训练详情**
9
+ - **停止训练任务**
10
+ - **查询训练 Pod 及其 Logs / Events / Spec**
11
+ - **查询训练相关用户、容器等辅助信息**
12
+ """
13
+
1
14
  from __future__ import annotations
2
15
 
3
16
  import httpx
@@ -20,15 +33,18 @@ from ..models.model_training_platform import (
20
33
  ListTrainingUsersResponse,
21
34
  ListTrainingContainersResponse,
22
35
  Pod,
36
+ ListStoragesResponse,
23
37
  )
24
38
 
25
39
  _BASE = "/model-training-platform/api/v1"
26
40
 
27
41
 
28
42
  class ModelTrainingPlatformService:
43
+ """训练任务业务封装"""
29
44
 
30
45
  def __init__(self, http: httpx.Client):
31
46
  self._training = _Training(http)
47
+ self._storage = _Storage(http)
32
48
 
33
49
  def create_training(self, payload: CreateTrainingRequest) -> int:
34
50
  """创建训练任务
@@ -42,65 +58,133 @@ class ModelTrainingPlatformService:
42
58
  return self._training.create(payload)
43
59
 
44
60
  def list_trainings(self, payload: ListTrainingsRequest) -> ListTrainingsResponse:
61
+ """分页查询训练任务
62
+
63
+ Args:
64
+ payload: 分页与过滤条件,详见 ``ListTrainingsRequest``
65
+
66
+ Returns:
67
+ ListTrainingsResponse: 训练任务分页结果
68
+ """
45
69
  return self._training.list(payload)
46
70
 
47
71
  def get_training(self, training_id: int) -> Training:
48
72
  """获取训练任务详情
49
73
 
50
74
  Args:
51
- training_id (int): 训练任务ID
52
- Returns:
53
- Training
75
+ training_id: 训练任务 ID
54
76
 
77
+ Returns:
78
+ Training: 训练任务完整信息
55
79
  """
56
80
  return self._training.get(training_id)
57
81
 
58
82
  def stop_training(self, training_id: int) -> None:
59
- """停止训练瑞文
83
+ """停止训练任务
60
84
 
61
85
  Args:
62
- training_id (int): 训练任务ID
63
-
64
- Returns:
65
-
86
+ training_id: 训练任务 ID
66
87
  """
67
88
  self._training.stop(training_id)
68
89
 
69
- def list_training_pods(
70
- self, training_id: int, payload: ListTrainingPodsRequest
71
- ) -> ListTrainingPodsResponse:
90
+ def list_training_pods(self, training_id: int, payload: ListTrainingPodsRequest) -> ListTrainingPodsResponse:
91
+ """查询训练任务的 Pod 列表
92
+
93
+ Args:
94
+ training_id: 训练任务 ID
95
+ payload: 分页参数,详见 ``ListTrainingPodsRequest``
96
+
97
+ Returns:
98
+ ListTrainingPodsResponse: Pod 分页结果
99
+ """
72
100
  return self._training.list_training_pods(training_id, payload)
73
101
 
74
102
  def get_training_pod(self, training_id: int, pod_id: int) -> Pod:
103
+ """获取单个 Pod 详情
104
+
105
+ Args:
106
+ training_id: 训练任务 ID
107
+ pod_id: Pod ID
108
+
109
+ Returns:
110
+ Pod: Pod 详细信息
111
+ """
75
112
  return self._training.get_training_pod(training_id, pod_id)
76
113
 
77
- def get_pod_logs_new(
78
- self, training_id: int, pod_id: int
79
- ) -> GetTrainingPodLogsNewResponse:
114
+ def get_pod_logs_new(self, training_id: int, pod_id: int) -> GetTrainingPodLogsNewResponse:
115
+ """获取 Pod 日志
116
+
117
+ Args:
118
+ training_id: 训练任务 ID
119
+ pod_id: Pod ID
120
+
121
+ Returns:
122
+ GetTrainingPodLogsNewResponse: 日志文件信息(名称 / URL 列表)
123
+ """
80
124
  return self._training.get_training_logs_new(training_id, pod_id)
81
125
 
82
126
  def get_pod_spec(self, training_id: int, pod_id: int) -> GetTrainingPodSpecResponse:
127
+ """获取 Pod Spec
128
+
129
+ Args:
130
+ training_id: 训练任务 ID
131
+ pod_id: Pod ID
132
+
133
+ Returns:
134
+ GetTrainingPodSpecResponse: Pod Spec 字符串
135
+ """
83
136
  return self._training.get_training_spec(training_id, pod_id)
84
137
 
85
- def get_pod_events(
86
- self, training_id: int, pod_id: int
87
- ) -> GetTrainingPodEventsResponse:
138
+ def get_pod_events(self, training_id: int, pod_id: int) -> GetTrainingPodEventsResponse:
139
+ """获取 Pod Events
140
+
141
+ Args:
142
+ training_id: 训练任务 ID
143
+ pod_id: Pod ID
144
+
145
+ Returns:
146
+ GetTrainingPodEventsResponse: 事件文本
147
+ """
88
148
  return self._training.get_training_events(training_id, pod_id)
89
149
 
90
- def list_training_users(
91
- self, payload: ListTrainingUsersRequest
92
- ) -> ListTrainingUsersResponse:
150
+ def list_training_users(self, payload: ListTrainingUsersRequest) -> ListTrainingUsersResponse:
151
+ """查询训练任务的用户列表
152
+
153
+ Args:
154
+ payload: 分页参数 ``ListTrainingUsersRequest``
155
+
156
+ Returns:
157
+ ListTrainingUsersResponse: 用户分页结果
158
+ """
93
159
  return self._training.list_training_users(payload)
94
160
 
95
- def list_training_containers(
96
- self, payload: ListTrainingContainersRequest
97
- ) -> ListTrainingContainersResponse:
161
+ def list_training_containers(self, payload: ListTrainingContainersRequest) -> ListTrainingContainersResponse:
162
+ """查询训练容器信息
163
+
164
+ Args:
165
+ payload: 分页参数 ``ListTrainingContainersRequest``
166
+
167
+ Returns:
168
+ ListTrainingContainersResponse: 训练容器列表
169
+ """
98
170
  return self._training.list_training_containers(payload)
99
171
 
172
+ def list_storages(self) -> ListStoragesResponse:
173
+ """获取存储列表
174
+
175
+ Returns:
176
+ ListStoragesResponse: 存储列表
177
+ """
178
+ return self._storage.list_storages()
179
+
100
180
  @property
101
181
  def training(self) -> _Training:
102
182
  return self._training
103
183
 
184
+ @property
185
+ def storage(self) -> _Storage:
186
+ return self._storage
187
+
104
188
 
105
189
  class _Training:
106
190
 
@@ -108,20 +192,14 @@ class _Training:
108
192
  self._http = http
109
193
 
110
194
  def create(self, payload: CreateTrainingRequest) -> int:
111
- resp = self._http.post(
112
- f"{_BASE}/trainings",
113
- json=payload.model_dump(by_alias=True, exclude_none=True),
114
- )
195
+ resp = self._http.post(f"{_BASE}/trainings", json=payload.model_dump(by_alias=True, exclude_none=True))
115
196
  wrapper = APIWrapper[CreateTrainingResponse].model_validate(resp.json())
116
197
  if wrapper.code != 0:
117
198
  raise APIError(f"backend code {wrapper.code}: {wrapper.msg}")
118
199
  return wrapper.data.id
119
200
 
120
201
  def list(self, payload: ListTrainingsRequest) -> ListTrainingsResponse:
121
- resp = self._http.get(
122
- f"{_BASE}/trainings",
123
- params=payload.model_dump(by_alias=True, exclude_none=True),
124
- )
202
+ resp = self._http.get(f"{_BASE}/trainings", params=payload.model_dump(by_alias=True, exclude_none=True))
125
203
  wrapper = APIWrapper[ListTrainingsResponse].model_validate(resp.json())
126
204
  if wrapper.code != 0:
127
205
  raise APIError(f"backend code {wrapper.code}: {wrapper.msg}")
@@ -140,13 +218,9 @@ class _Training:
140
218
  if wrapper.code != 0:
141
219
  raise APIError(f"backend code {wrapper.code}: {wrapper.msg}")
142
220
 
143
- def list_training_pods(
144
- self, training_id: int, payload: ListTrainingPodsRequest
145
- ) -> ListTrainingPodsResponse:
146
- resp = self._http.get(
147
- f"{_BASE}/trainings/{training_id}/pods",
148
- params=payload.model_dump(by_alias=True, exclude_none=True),
149
- )
221
+ def list_training_pods(self, training_id: int, payload: ListTrainingPodsRequest) -> ListTrainingPodsResponse:
222
+ resp = self._http.get(f"{_BASE}/trainings/{training_id}/pods",
223
+ params=payload.model_dump(by_alias=True, exclude_none=True))
150
224
  wrapper = APIWrapper[ListTrainingPodsResponse].model_validate(resp.json())
151
225
  if wrapper.code != 0:
152
226
  raise APIError(f"backend code {wrapper.code}: {wrapper.msg}")
@@ -159,51 +233,50 @@ class _Training:
159
233
  raise APIError(f"backend code {wrapper.code}: {wrapper.msg}")
160
234
  return wrapper.data
161
235
 
162
- def get_training_logs_new(
163
- self, training_id: int, pod_id: int
164
- ) -> GetTrainingPodLogsNewResponse:
236
+ def get_training_logs_new(self, training_id: int, pod_id: int) -> GetTrainingPodLogsNewResponse:
165
237
  resp = self._http.get(f"{_BASE}/trainings/{training_id}/pods/{pod_id}/logs/new")
166
238
  wrapper = APIWrapper[GetTrainingPodLogsNewResponse].model_validate(resp.json())
167
239
  if wrapper.code != 0:
168
240
  raise APIError(f"backend code {wrapper.code}: {wrapper.msg}")
169
241
  return wrapper.data
170
242
 
171
- def get_training_spec(
172
- self, training_id: int, pod_id: int
173
- ) -> GetTrainingPodSpecResponse:
243
+ def get_training_spec(self, training_id: int, pod_id: int) -> GetTrainingPodSpecResponse:
174
244
  resp = self._http.get(f"{_BASE}/trainings/{training_id}/pods/{pod_id}/spec")
175
245
  wrapper = APIWrapper[GetTrainingPodSpecResponse].model_validate(resp.json())
176
246
  if wrapper.code != 0:
177
247
  raise APIError(f"backend code {wrapper.code}: {wrapper.msg}")
178
248
  return wrapper.data
179
249
 
180
- def get_training_events(
181
- self, training_id: int, pod_id: int
182
- ) -> GetTrainingPodEventsResponse:
250
+ def get_training_events(self, training_id: int, pod_id: int) -> GetTrainingPodEventsResponse:
183
251
  resp = self._http.get(f"{_BASE}/trainings/{training_id}/pods/{pod_id}/events")
184
252
  wrapper = APIWrapper[GetTrainingPodEventsResponse].model_validate(resp.json())
185
253
  if wrapper.code != 0:
186
254
  raise APIError(f"backend code {wrapper.code}: {wrapper.msg}")
187
255
  return wrapper.data
188
256
 
189
- def list_training_users(
190
- self, payload: ListTrainingUsersRequest
191
- ) -> ListTrainingUsersResponse:
192
- resp = self._http.get(
193
- f"{_BASE}/training-users", params=payload.model_dump(by_alias=True)
194
- )
257
+ def list_training_users(self, payload: ListTrainingUsersRequest) -> ListTrainingUsersResponse:
258
+ resp = self._http.get(f"{_BASE}/training-users", params=payload.model_dump(by_alias=True))
195
259
  wrapper = APIWrapper[ListTrainingUsersResponse].model_validate(resp.json())
196
260
  if wrapper.code != 0:
197
261
  raise APIError(f"backend code {wrapper.code}: {wrapper.msg}")
198
262
  return wrapper.data
199
263
 
200
- def list_training_containers(
201
- self, payload: ListTrainingContainersRequest
202
- ) -> ListTrainingContainersResponse:
203
- resp = self._http.get(
204
- f"{_BASE}/training-containers", params=payload.model_dump(by_alias=True)
205
- )
264
+ def list_training_containers(self, payload: ListTrainingContainersRequest) -> ListTrainingContainersResponse:
265
+ resp = self._http.get(f"{_BASE}/training-containers", params=payload.model_dump(by_alias=True))
206
266
  wrapper = APIWrapper[ListTrainingContainersResponse].model_validate(resp.json())
207
267
  if wrapper.code != 0:
208
268
  raise APIError(f"backend code {wrapper.code}: {wrapper.msg}")
209
269
  return wrapper.data
270
+
271
+
272
+ class _Storage:
273
+
274
+ def __init__(self, http: httpx.Client):
275
+ self._http = http
276
+
277
+ def list_storages(self) -> ListStoragesResponse:
278
+ resp = self._http.get(f"{_BASE}/storages")
279
+ wrapper = APIWrapper[ListStoragesResponse].model_validate(resp.json())
280
+ if wrapper.code != 0:
281
+ raise APIError(f"backend code {wrapper.code}: {wrapper.msg}")
282
+ return wrapper.data
@@ -1,13 +1,43 @@
1
+ # !/usr/bin/env python
2
+ # -*- coding:utf-8 -*-
3
+ """配额调度服务模块
4
+
5
+ 封装 **quota‑schedule‑management** 后端接口,围绕 **配额调度任务** 提供常用能力:
6
+
7
+ - **创建 / 查询 / 停止调度任务**
8
+ - **Pod 维度信息**(列表 / Logs / Spec / Events)
9
+ - **GPU 资源概览、活跃用户、容器信息** 等辅助查询
10
+ - **Pre‑Stop** 机制:进程内检测平台下发的优雅终止信号
11
+ """
12
+
1
13
  from __future__ import annotations
2
14
 
3
15
  import os
4
16
  from pathlib import Path
17
+ from typing import List
5
18
 
6
19
  import httpx
7
20
 
8
21
  from ..exceptions import APIError
9
22
  from ..models.common import APIWrapper
10
- from ..models.quota_schedule_management import *
23
+ from ..models.quota_schedule_management import (
24
+ CreateTaskRequest,
25
+ CreateTaskResponse,
26
+ ListTasksRequest,
27
+ ListTasksResponse,
28
+ Task,
29
+ ListTaskPodsRequest,
30
+ ListTaskPodsResponse,
31
+ Pod,
32
+ PodLogInfo,
33
+ GetTaskPodLogsNewResponse,
34
+ GetTaskPodSpecResponse,
35
+ GetTaskPodEventsResponse,
36
+ ListTaskUsersRequest,
37
+ ListTaskUsersResponse,
38
+ GetMetricsOverviewRequest,
39
+ GetMetricsOverviewResponse,
40
+ )
11
41
 
12
42
  _ENV_KEY = "PRE_STOP_SENTINEL_FILE"
13
43
  _DEFAULT_SENTINEL = "/tmp/pre_stop_sentinel_file"
@@ -16,6 +46,14 @@ _BASE = "/quota-schedule-management/api/v1"
16
46
 
17
47
 
18
48
  def is_pre_stopped() -> bool:
49
+ """判断当前进程是否已收到 *pre‑stop* 信号
50
+
51
+ 该信号由调度平台通过创建哨兵文件的方式下发。文件路径可通过环境变量 ``PRE_STOP_SENTINEL_FILE`` 覆盖,
52
+ 默认为``/tmp/pre_stop_sentinel_file``。
53
+
54
+ Returns:
55
+ bool: 若哨兵文件存在,返回 ``True``,表示应尽快停止任务。
56
+ """
19
57
  return _SENTINEL_PATH.exists()
20
58
 
21
59
 
@@ -26,6 +64,7 @@ class PreStopService:
26
64
 
27
65
 
28
66
  class QuotaScheduleManagementService:
67
+ """配额调度任务业务封装"""
29
68
 
30
69
  def __init__(self, http: httpx.Client):
31
70
  self._task = _Task(http)
@@ -34,7 +73,7 @@ class QuotaScheduleManagementService:
34
73
  """创建调度任务
35
74
 
36
75
  Args:
37
- payload: 创建任务的各项参数
76
+ payload: 创建任务的各项参数,详见 ``CreateTaskRequest``
38
77
 
39
78
  Returns:
40
79
  int: 后端生成的任务 ID
@@ -45,10 +84,10 @@ class QuotaScheduleManagementService:
45
84
  """分页查询任务列表
46
85
 
47
86
  Args:
48
- payload: 查询条件(分页 / 过滤)
87
+ payload: 分页 / 过滤参数,详见 ``ListTasksRequest``
49
88
 
50
89
  Returns:
51
- ListTasksResponse: 列表及分页信息
90
+ ListTasksResponse: 任务分页结果
52
91
  """
53
92
  return self._task.list(payload)
54
93
 
@@ -68,31 +107,89 @@ class QuotaScheduleManagementService:
68
107
 
69
108
  Args:
70
109
  task_id: 任务 ID
71
-
72
- Returns:
73
- None
74
110
  """
75
111
  self._task.stop(task_id)
76
112
 
77
113
  def list_task_pods(self, task_id: int, payload: ListTaskPodsRequest) -> ListTaskPodsResponse:
114
+ """分页查询任务的 Pod 列表
115
+
116
+ Args:
117
+ task_id: 调度任务 ID
118
+ payload: 分页参数,见 :class:`ListTaskPodsRequest`
119
+
120
+ Returns:
121
+ ListTaskPodsResponse: Pod 列表及分页信息
122
+ """
78
123
  return self._task.list_pods(task_id, payload)
79
124
 
80
125
  def get_task_pod(self, task_id: int, pod_id: int) -> Pod:
126
+ """获取单个 Pod 详情
127
+
128
+ Args:
129
+ task_id: 调度任务 ID
130
+ pod_id: Pod ID(数据库主键)
131
+
132
+ Returns:
133
+ Pod: Pod 详细信息
134
+ """
81
135
  return self._task.get_pod(task_id, pod_id)
82
136
 
83
137
  def get_pod_logs_new(self, task_id: int, pod_id: int) -> List[PodLogInfo]:
138
+ """获取新版日志
139
+
140
+ Args:
141
+ task_id: 调度任务 ID
142
+ pod_id: Pod ID
143
+
144
+ Returns:
145
+ list[PodLogInfo]: 每条日志文件的名称与下载地址
146
+ """
84
147
  return self._task.get_logs_new(task_id, pod_id).logs
85
148
 
86
149
  def get_pod_spec(self, task_id: int, pod_id: int) -> str:
150
+ """获取 Pod 运行时 Spec(YAML)
151
+
152
+ Args:
153
+ task_id: 调度任务 ID
154
+ pod_id: Pod ID
155
+
156
+ Returns:
157
+ str: Pod 描述 YAML 字符串
158
+ """
87
159
  return self._task.get_spec(task_id, pod_id).spec
88
160
 
89
161
  def get_pod_events(self, task_id: int, pod_id: int) -> str:
162
+ """获取 Pod 事件
163
+
164
+ Args:
165
+ task_id: 调度任务 ID
166
+ pod_id: Pod ID
167
+
168
+ Returns:
169
+ str: 事件文本(kubectl describe events)
170
+ """
90
171
  return self._task.get_events(task_id, pod_id).events
91
172
 
92
173
  def list_task_users(self, payload: ListTaskUsersRequest) -> ListTaskUsersResponse:
174
+ """查询任务的用户列表
175
+
176
+ Args:
177
+ payload: 分页参数,见 :class:`ListTaskUsersRequest`
178
+
179
+ Returns:
180
+ ListTaskUsersResponse: 用户列表及分页信息
181
+ """
93
182
  return self._task.list_users(payload)
94
183
 
95
184
  def get_metrics_overview(self, payload: GetMetricsOverviewRequest) -> GetMetricsOverviewResponse:
185
+ """获取虚拟集群维度的 GPU 使用概览
186
+
187
+ Args:
188
+ payload: 分页参数,见 :class:`GetMetricsOverviewRequest`
189
+
190
+ Returns:
191
+ GetMetricsOverviewResponse: 各虚拟集群资源统计
192
+ """
96
193
  return self._task.get_metrics_overview(payload)
97
194
 
98
195
  @property
@@ -1,25 +1,56 @@
1
1
  # !/usr/bin/env python
2
- # -*-coding:utf-8 -*-
2
+ # -*- coding:utf-8 -*-
3
+ """标签资源管理服务模块
4
+
5
+ 封装 **tag‑resource‑management** 相关接口,提供两组下拉选项:
6
+
7
+ - **选择项目(Project)下拉列表**
8
+ - **选择虚拟集群(Virtual‑Cluster)下拉列表**
9
+ """
10
+
3
11
  from __future__ import annotations
4
12
 
13
+ from typing import List
14
+
5
15
  import httpx
6
16
 
7
17
  from ..exceptions import APIError
8
18
  from ..models.common import APIWrapper
9
- from ..models.tag_resource_management import *
19
+ from ..models.tag_resource_management import (
20
+ Project,
21
+ ProjectListData,
22
+ SelectVirtualClustersRequest,
23
+ SelectVirtualClustersResponse,
24
+ VirtualClusterBrief,
25
+ )
10
26
 
11
27
  _BASE = "/tag-resource-management/api/v1"
12
28
 
13
29
 
14
30
  class TagResourceManagementService:
31
+ """标签资源管理服务"""
32
+
15
33
  def __init__(self, http: httpx.Client):
16
34
  self._project = _Project(http)
17
35
  self._virtual_cluster = _VirtualCluster(http)
18
36
 
19
37
  def select_projects(self) -> List[Project]:
38
+ """获取全部项目下拉选项
39
+
40
+ Returns:
41
+ list[Project]: 项目列表,每项仅包含 `id` / `name`
42
+ """
20
43
  return self._project.select_projects()
21
44
 
22
45
  def select_virtual_clusters(self, payload: SelectVirtualClustersRequest) -> List[VirtualClusterBrief]:
46
+ """获取虚拟集群下拉选项
47
+
48
+ Args:
49
+ payload: 查询参数,包含用户 ID / 模块类型等过滤条件,详见 :class:`SelectVirtualClustersRequest`
50
+
51
+ Returns:
52
+ list[VirtualClusterBrief]: 过滤后的虚拟集群简要列表
53
+ """
23
54
  return self._virtual_cluster.select(payload).data
24
55
 
25
56
  @property
@@ -1,3 +1,13 @@
1
+ # !/usr/bin/env python
2
+ # -*- coding:utf-8 -*-
3
+ """任务中心服务模块
4
+
5
+ 封装 **task‑center** 常用能力:
6
+
7
+ - **创建 / 查询任务**
8
+ - **一键创建标注任务**(高阶封装)
9
+ """
10
+
1
11
  from __future__ import annotations
2
12
 
3
13
  import datetime
@@ -28,31 +38,37 @@ def date_str_to_timestamp(date_str: str) -> int:
28
38
 
29
39
 
30
40
  class TaskCenterService:
41
+ """任务中心服务"""
31
42
 
32
43
  def __init__(self, http: httpx.Client):
33
44
  self._TaskCenter = _TaskCenter(http)
34
45
  self._http = http
35
46
 
36
47
  def create(self, payload: CreateTaskReq) -> int:
48
+ """创建任务
49
+
50
+ Args:
51
+ payload: 任务创建请求体,详见 :class:`CreateTaskReq`
52
+
53
+ Returns:
54
+ int: 后端生成的任务 ID
55
+ """
37
56
  return self._TaskCenter.create(payload)
38
57
 
39
58
  def get(self, task_id: int) -> LabelTaskDetail:
40
- """获取任务信息
59
+ """根据任务 ID 获取详情
41
60
 
42
61
  Args:
43
- task_id (int): 任务ID
44
-
62
+ task_id: 任务 ID
45
63
 
46
64
  Returns:
47
- LabelTaskDetail: 任务信息
48
-
65
+ LabelTaskDetail: 任务完整信息
49
66
  """
50
-
51
67
  return self._TaskCenter.get(task_id)
52
68
 
53
69
  # 如果想要访问子对象,也保留属性
54
70
  @property
55
- def TaskCenter(self) -> _TaskCenter:
71
+ def task_center(self) -> _TaskCenter:
56
72
  return self._TaskCenter
57
73
 
58
74
  def create_label_task(
@@ -160,7 +176,6 @@ class _TaskCenter:
160
176
  self._http = http
161
177
 
162
178
  def create(self, payload: CreateTaskReq) -> int:
163
- """创建任务"""
164
179
  logger.debug(f"create task: {payload}")
165
180
  resp = self._http.post(
166
181
  f"{_BASE}/tasks",
@@ -176,7 +191,6 @@ class _TaskCenter:
176
191
  return wrapper.data.id
177
192
 
178
193
  def get(self, task_id: int) -> LabelTaskDetail:
179
- """获取任务"""
180
194
  logger.debug(f"get task: {task_id}")
181
195
  resp = self._http.get(
182
196
  f"{_BASE}/tasks/{task_id}",