gmicloud 0.1.5__py3-none-any.whl → 0.1.6__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.
@@ -31,3 +31,8 @@ class TaskStatus(str, Enum):
31
31
  RUNNING = "running"
32
32
  NEEDSTOP = "needstop"
33
33
  ARCHIVED = "archived"
34
+
35
+ class ModelParameterType(str, Enum):
36
+ NUMERIC = "numeric"
37
+ TEXT = "text"
38
+ BOOLEAN = "boolean"
@@ -1,4 +1,5 @@
1
1
  import os
2
+ import time
2
3
  from typing import List
3
4
  import mimetypes
4
5
 
@@ -7,6 +8,9 @@ from .._client._artifact_client import ArtifactClient
7
8
  from .._client._file_upload_client import FileUploadClient
8
9
  from .._models import *
9
10
 
11
+ import logging
12
+
13
+ logger = logging.getLogger(__name__)
10
14
 
11
15
  class ArtifactManager:
12
16
  """
@@ -86,6 +90,41 @@ class ArtifactManager:
86
90
  raise ValueError("Failed to create artifact from template.")
87
91
 
88
92
  return resp.artifact_id
93
+
94
+ def create_artifact_from_template_name(self, artifact_template_name: str) -> tuple[str, ReplicaResource]:
95
+ """
96
+ Create an artifact from a template.
97
+ :param artifact_template_name: The name of the template to use.
98
+ :return: A tuple containing the artifact ID and the recommended replica resources.
99
+ :rtype: tuple[str, ReplicaResource]
100
+ """
101
+
102
+ recommended_replica_resources = None
103
+ template_id = None
104
+ try:
105
+ templates = self.get_public_templates()
106
+ except Exception as e:
107
+ logger.error(f"Failed to get artifact templates, Error: {e}")
108
+ for template in templates:
109
+ if template.template_data and template.template_data.name == artifact_template_name:
110
+ resources_template = template.template_data.resources
111
+ recommended_replica_resources = ReplicaResource(
112
+ cpu=resources_template.cpu,
113
+ ram_gb=resources_template.memory,
114
+ gpu=resources_template.gpu,
115
+ gpu_name=resources_template.gpu_name,
116
+ )
117
+ template_id = template.template_id
118
+ break
119
+ if not template_id:
120
+ raise ValueError(f"Template with name {artifact_template_name} not found.")
121
+ try:
122
+ artifact_id = self.create_artifact_from_template(template_id)
123
+ self.wait_for_artifact_ready(artifact_id)
124
+ return artifact_id, recommended_replica_resources
125
+ except Exception as e:
126
+ logger.error(f"Failed to create artifact from template, Error: {e}")
127
+ raise e
89
128
 
90
129
  def rebuild_artifact(self, artifact_id: str) -> RebuildArtifactResponse:
91
130
  """
@@ -240,7 +279,31 @@ class ArtifactManager:
240
279
  FileUploadClient.upload_large_file(bigfile_upload_url_resp.upload_link, model_file_path)
241
280
 
242
281
  return artifact_id
243
-
282
+
283
+
284
+ def wait_for_artifact_ready(self, artifact_id: str, timeout_s: int = 900) -> None:
285
+ """
286
+ Wait for an artifact to be ready.
287
+
288
+ :param artifact_id: The ID of the artifact to wait for.
289
+ :param timeout_s: The timeout in seconds.
290
+ :return: None
291
+ """
292
+ start_time = time.time()
293
+ while True:
294
+ try:
295
+ artifact = self.get_artifact(artifact_id)
296
+ if artifact.build_status == BuildStatus.SUCCESS:
297
+ return
298
+ elif artifact.build_status in [BuildStatus.FAILED, BuildStatus.TIMEOUT, BuildStatus.CANCELLED]:
299
+ raise Exception(f"Artifact build failed, status: {artifact.build_status}")
300
+ except Exception as e:
301
+ logger.error(f"Failed to get artifact, Error: {e}")
302
+ if time.time() - start_time > timeout_s:
303
+ raise Exception(f"Artifact build takes more than {timeout_s // 60} minutes. Testing aborted.")
304
+ time.sleep(10)
305
+
306
+
244
307
  def get_public_templates(self) -> List[ArtifactTemplate]:
245
308
  """
246
309
  Fetch all artifact templates.
@@ -249,6 +312,26 @@ class ArtifactManager:
249
312
  :rtype: List[ArtifactTemplate]
250
313
  """
251
314
  return self.artifact_client.get_public_templates()
315
+
316
+
317
+ def list_public_template_names(self) -> list[str]:
318
+ """
319
+ List all public templates.
320
+
321
+ :return: A list of template names.
322
+ :rtype: list[str]
323
+ """
324
+ template_names = []
325
+ try:
326
+ templates = self.get_public_templates()
327
+ for template in templates:
328
+ if template.template_data and template.template_data.name:
329
+ template_names.append(template.template_data.name)
330
+ return template_names
331
+ except Exception as e:
332
+ logger.error(f"Failed to get artifact templates, Error: {e}")
333
+ return []
334
+
252
335
 
253
336
  @staticmethod
254
337
  def _validate_file_name(file_name: str) -> None:
@@ -4,6 +4,10 @@ from .._client._iam_client import IAMClient
4
4
  from .._client._task_client import TaskClient
5
5
  from .._models import *
6
6
 
7
+ import time
8
+ import logging
9
+
10
+ logger = logging.getLogger(__name__)
7
11
 
8
12
  class TaskManager:
9
13
  """
@@ -132,6 +136,50 @@ class TaskManager:
132
136
  self._validate_not_empty(task_id, "Task ID")
133
137
 
134
138
  return self.task_client.start_task(task_id)
139
+
140
+
141
+ def start_task_and_wait(self, task_id: str, timeout_s: int = 900) -> Task:
142
+ """
143
+ Start a task and wait for it to be ready.
144
+
145
+ :param task_id: The ID of the task to start.
146
+ :param timeout_s: The timeout in seconds.
147
+ :return: The task object.
148
+ :rtype: Task
149
+ """
150
+ # trigger start task
151
+ try:
152
+ self.start_task(task_id)
153
+ logger.info(f"Started task ID: {task_id}")
154
+ except Exception as e:
155
+ logger.error(f"Failed to start task, Error: {e}")
156
+ raise e
157
+
158
+ start_time = time.time()
159
+ while True:
160
+ try:
161
+ task = self.get_task(task_id)
162
+ if task.task_status == TaskStatus.RUNNING:
163
+ return task
164
+ elif task.task_status in [TaskStatus.NEEDSTOP, TaskStatus.ARCHIVED]:
165
+ raise Exception(f"Unexpected task status after starting: {task.task_status}")
166
+ # Also check endpoint status.
167
+ elif task.task_status == TaskStatus.RUNNING:
168
+ if task.endpoint_info and task.endpoint_info.endpoint_status == TaskEndpointStatus.RUNNING:
169
+ return task
170
+ elif task.endpoint_info and task.endpoint_info.endpoint_status in [TaskEndpointStatus.UNKNOWN, TaskEndpointStatus.ARCHIVED]:
171
+ raise Exception(f"Unexpected endpoint status after starting: {task.endpoint_info.endpoint_status}")
172
+ else:
173
+ logger.info(f"Pending endpoint starting. endpoint status: {task.endpoint_info.endpoint_status}")
174
+ else:
175
+ logger.info(f"Pending task starting. Task status: {task.task_status}")
176
+
177
+ except Exception as e:
178
+ logger.error(f"Failed to get task, Error: {e}")
179
+ if time.time() - start_time > timeout_s:
180
+ raise Exception(f"Task creation takes more than {timeout_s // 60} minutes. Testing aborted.")
181
+ time.sleep(10)
182
+
135
183
 
136
184
  def stop_task(self, task_id: str) -> bool:
137
185
  """
@@ -143,6 +191,27 @@ class TaskManager:
143
191
  """
144
192
  self._validate_not_empty(task_id, "Task ID")
145
193
 
194
+
195
+ def stop_task_and_wait(self, task_id: str, timeout_s: int = 900):
196
+ task_manager = self.task_manager
197
+ try:
198
+ self.task_manager.stop_task(task_id)
199
+ logger.info(f"Stopping task ID: {task_id}")
200
+ except Exception as e:
201
+ logger.error(f"Failed to stop task, Error: {e}")
202
+ task_manager = self.task_manager
203
+ start_time = time.time()
204
+ while True:
205
+ try:
206
+ task = self.get_task(task_id)
207
+ if task.task_status == TaskStatus.IDLE:
208
+ break
209
+ except Exception as e:
210
+ logger.error(f"Failed to get task, Error: {e}")
211
+ if time.time() - start_time > timeout_s:
212
+ raise Exception(f"Task stopping takes more than {timeout_s // 60} minutes. Testing aborted.")
213
+ time.sleep(10)
214
+
146
215
  return self.task_client.stop_task(task_id)
147
216
 
148
217
  def get_usage_data(self, start_timestamp: str, end_timestamp: str) -> GetUsageDataResponse:
@@ -1,8 +1,8 @@
1
- from typing import Optional, List
1
+ from typing import Optional, List, Union
2
2
  from datetime import datetime
3
3
 
4
4
  from pydantic import BaseModel
5
- from gmicloud._internal._enums import BuildStatus, TaskStatus, TaskEndpointStatus
5
+ from gmicloud._internal._enums import BuildStatus, TaskStatus, TaskEndpointStatus, ModelParameterType
6
6
 
7
7
 
8
8
  class BigFileMetadata(BaseModel):
@@ -70,6 +70,7 @@ class CreateArtifactRequest(BaseModel):
70
70
  artifact_name: str # The name of the artifact to create.
71
71
  artifact_description: Optional[str] = "" # Description of the artifact.
72
72
  artifact_tags: Optional[List[str]] = None # Tags for the artifact, separated by commas.
73
+ model_parameters: Optional[List["ModelParameter"]] = None # Parameters for the artifact.
73
74
 
74
75
 
75
76
  class CreateArtifactResponse(BaseModel):
@@ -158,6 +159,7 @@ class TemplateMetadata(BaseModel):
158
159
  update_at: Optional[str] = None # Timestamp when the template was last updated.
159
160
  update_by: Optional[str] = "" # ID of the user who last updated the template.
160
161
 
162
+
161
163
  class TemplateData(BaseModel):
162
164
  """
163
165
  Data for an artifact template.
@@ -165,6 +167,7 @@ class TemplateData(BaseModel):
165
167
  description: Optional[str] = "" # Description of the artifact template.
166
168
  icon_link: Optional[str] = "" # Link to the icon for the artifact template.
167
169
  image_link: Optional[str] = "" # Link to the image for the artifact template.
170
+ model_parameters: Optional[List["ModelParameter"]] = None # Parameters for the artifact template.
168
171
  name: Optional[str] = "" # Name of the artifact template.
169
172
  ray: Optional["RayContent"] = None # Template for Ray-based artifacts.
170
173
  resources: Optional["ResourcesTemplate"] = None # Resource allocation template.
@@ -172,6 +175,19 @@ class TemplateData(BaseModel):
172
175
  volume_path: Optional[str] = "" # Path to the volume where the artifact is stored.
173
176
 
174
177
 
178
+ class ModelParameter(BaseModel):
179
+ """
180
+ Parameter for an artifact template.
181
+ """
182
+ category: Optional[str] = "" # Category of the parameter.
183
+ display_name: Optional[str] = "" # Display name of the parameter.
184
+ key: Optional[str] = "" # Key for the parameter.
185
+ max: Optional[float] = 0 # Maximum value for the parameter.
186
+ min: Optional[float] = 0 # Minimum value for the parameter.
187
+ step: Optional[float] = 0 # Step value for the parameter.
188
+ type: Optional[ModelParameterType] = ModelParameterType.TEXT # Type of the parameter (e.g., numeric, bool, text).
189
+ value: Optional[Union[int, float, bool, str]] = "" # Default value for the parameter.
190
+
175
191
  class RayContent(BaseModel):
176
192
  deployment_name: Optional[str] = "" # Name of the deployment.
177
193
  file_path: Optional[str] = "" # Path to the task file in storage.
@@ -234,7 +250,6 @@ class RayTaskConfig(BaseModel):
234
250
  Configuration settings for Ray tasks.
235
251
  """
236
252
  artifact_id: Optional[str] = "" # Associated artifact ID.
237
- ray_version: Optional[str] = "" # Version of Ray used.
238
253
  ray_cluster_image: Optional[str] = "" # Docker image for the Ray cluster.
239
254
  file_path: Optional[str] = "" # Path to the task file in storage.
240
255
  deployment_name: Optional[str] = "" # Name of the deployment.
@@ -282,6 +297,7 @@ class TaskConfig(BaseModel):
282
297
  """
283
298
  Configuration data for a task.
284
299
  """
300
+ task_name: Optional[str] = "" # Name of the task.
285
301
  ray_task_config: Optional[RayTaskConfig] = None # Configuration for a Ray-based task.
286
302
  task_scheduling: Optional[TaskScheduling] = None # Scheduling configuration for the task.
287
303
  create_timestamp: Optional[int] = 0 # Timestamp when the task was created.
gmicloud/client.py CHANGED
@@ -8,7 +8,7 @@ from ._internal._client._iam_client import IAMClient
8
8
  from ._internal._manager._artifact_manager import ArtifactManager
9
9
  from ._internal._manager._task_manager import TaskManager
10
10
  from ._internal._manager._iam_manager import IAMManager
11
- from ._internal._enums import BuildStatus
11
+ from ._internal._enums import BuildStatus, TaskStatus, TaskEndpointStatus
12
12
  from ._internal._models import Task, TaskConfig, RayTaskConfig, TaskScheduling, ReplicaResource
13
13
 
14
14
  logger = logging.getLogger(__name__)
@@ -38,80 +38,6 @@ class Client:
38
38
  self._task_manager = None
39
39
  self._iam_manager = None
40
40
 
41
- def create_task_from_artifact_template(self, artifact_template_id: str, task_scheduling: TaskScheduling) -> Task:
42
- """
43
- Create a task from a template.
44
-
45
- :param artifact_template_id: The ID of the artifact template to use.
46
- :param task_scheduling: The scheduling configuration for the task.
47
- :return: A `Task` object containing the details of the created task.
48
- :rtype: Task
49
- """
50
- if not artifact_template_id or not artifact_template_id.strip():
51
- raise ValueError("Artifact Template ID must be provided.")
52
- if not task_scheduling:
53
- raise ValueError("Task Scheduling must be provided.")
54
-
55
- artifact_manager = self.artifact_manager
56
- task_manager = self.task_manager
57
-
58
- templates = artifact_manager.get_public_templates()
59
- template = None
60
- for v in templates:
61
- if v.template_id == artifact_template_id:
62
- template = v
63
- if not template:
64
- raise ValueError(f"Template with ID {artifact_template_id} not found.")
65
- if not template.template_data:
66
- raise ValueError("Template does not contain template data.")
67
- if not template.template_data.ray:
68
- raise ValueError("Template does not contain Ray configuration.")
69
- if not template.template_data.resources:
70
- raise ValueError("Template does not contain resource configuration.")
71
-
72
- artifact_id = artifact_manager.create_artifact_from_template(artifact_template_id)
73
-
74
- logger.info(f"Successfully created artifact from template, artifact_id: {artifact_id}")
75
- # Wait for the artifact to be ready
76
- while True:
77
- try:
78
- artifact = artifact_manager.get_artifact(artifact_id)
79
- logger.info(f"Successfully got artifact info, artifact status: {artifact.build_status}")
80
- # Wait until the artifact is ready
81
- if artifact.build_status == BuildStatus.SUCCESS:
82
- break
83
- except Exception as e:
84
- raise e
85
- # Wait for 2 seconds
86
- time.sleep(2)
87
- try:
88
- # Create a task
89
- task = task_manager.create_task(Task(
90
- config=TaskConfig(
91
- ray_task_config=RayTaskConfig(
92
- ray_version=template.ray.version,
93
- file_path=template.ray.file_path,
94
- artifact_id=artifact_id,
95
- deployment_name=template.ray.deployment_name,
96
- replica_resource=ReplicaResource(
97
- cpu=template.resources.cpu,
98
- ram_gb=template.resources.memory,
99
- gpu=template.resources.gpu,
100
- ),
101
- ),
102
- task_scheduling=task_scheduling,
103
- ),
104
- ))
105
-
106
- logger.info(f"Successfully created task, task_id: {task.task_id}")
107
- # Start the task
108
- task_manager.start_task(task.task_id)
109
- logger.info(f"Successfully started task, task_id: {task.task_id}")
110
- except Exception as e:
111
- raise e
112
-
113
- return task
114
-
115
41
  @property
116
42
  def artifact_manager(self):
117
43
  """
@@ -141,3 +67,181 @@ class Client:
141
67
  if self._iam_manager is None:
142
68
  self._iam_manager = IAMManager(self.iam_client)
143
69
  return self._iam_manager
70
+
71
+ # def list_templates(self) -> list[str]:
72
+ # """
73
+ # List all public templates.
74
+
75
+ # :return: A list of template names.
76
+ # :rtype: list[str]
77
+ # """
78
+ # template_names = []
79
+ # try:
80
+ # templates = self.artifact_manager.get_public_templates()
81
+ # for template in templates:
82
+ # if template.template_data and template.template_data.name:
83
+ # template_names.append(template.template_data.name)
84
+ # return template_names
85
+ # except Exception as e:
86
+ # logger.error(f"Failed to get artifact templates, Error: {e}")
87
+ # return []
88
+
89
+ # def wait_for_artifact_ready(self, artifact_id: str, timeout_s: int = 900) -> None:
90
+ # """
91
+ # Wait for an artifact to be ready.
92
+
93
+ # :param artifact_id: The ID of the artifact to wait for.
94
+ # :param timeout_s: The timeout in seconds.
95
+ # :return: None
96
+ # """
97
+ # artifact_manager = self.artifact_manager
98
+ # start_time = time.time()
99
+ # while True:
100
+ # try:
101
+ # artifact = artifact_manager.get_artifact(artifact_id)
102
+ # if artifact.build_status == BuildStatus.SUCCESS:
103
+ # return
104
+ # elif artifact.build_status in [BuildStatus.FAILED, BuildStatus.TIMEOUT, BuildStatus.CANCELLED]:
105
+ # raise Exception(f"Artifact build failed, status: {artifact.build_status}")
106
+ # except Exception as e:
107
+ # logger.error(f"Failed to get artifact, Error: {e}")
108
+ # if time.time() - start_time > timeout_s:
109
+ # raise Exception(f"Artifact build takes more than {timeout_s // 60} minutes. Testing aborted.")
110
+ # time.sleep(10)
111
+
112
+ # def create_artifact_from_template(self, artifact_template_name: str) -> tuple[str, ReplicaResource]:
113
+ # """
114
+ # Create an artifact from a template.
115
+
116
+ # :param artifact_template_name: The name of the template to use.
117
+ # :return: A tuple containing the artifact ID and the recommended replica resources.
118
+ # :rtype: tuple[str, ReplicaResource]
119
+ # """
120
+ # artifact_manager = self.artifact_manager
121
+
122
+ # recommended_replica_resources = None
123
+ # template_id = None
124
+ # try:
125
+ # templates = artifact_manager.get_public_templates()
126
+ # except Exception as e:
127
+ # logger.error(f"Failed to get artifact templates, Error: {e}")
128
+ # for template in templates:
129
+ # if template.template_data and template.template_data.name == artifact_template_name:
130
+ # resources_template = template.template_data.resources
131
+ # recommended_replica_resources = ReplicaResource(
132
+ # cpu=resources_template.cpu,
133
+ # ram_gb=resources_template.memory,
134
+ # gpu=resources_template.gpu,
135
+ # gpu_name=resources_template.gpu_name,
136
+ # )
137
+ # template_id = template.template_id
138
+ # break
139
+ # if not template_id:
140
+ # raise ValueError(f"Template with name {artifact_template_name} not found.")
141
+ # try:
142
+ # artifact_id = artifact_manager.create_artifact_from_template(template_id)
143
+ # self.wait_for_artifact_ready(artifact_id)
144
+ # return artifact_id, recommended_replica_resources
145
+ # except Exception as e:
146
+ # logger.error(f"Failed to create artifact from template, Error: {e}")
147
+ # raise e
148
+
149
+ # def create_task(self, artifact_id: str, replica_resources: ReplicaResource, task_scheduling: TaskScheduling) -> str:
150
+ # """
151
+ # Create a task.
152
+
153
+ # :param artifact_id: The ID of the artifact to use.
154
+ # :param replica_resources: The recommended replica resources.
155
+ # :param task_scheduling: The scheduling configuration for the task.
156
+ # :return: The ID of the created task.
157
+ # :rtype: str
158
+ # """
159
+ # task_manager = self.task_manager
160
+ # task = None
161
+ # try:
162
+ # task = task_manager.create_task(Task(
163
+ # config=TaskConfig(
164
+ # ray_task_config=RayTaskConfig(
165
+ # artifact_id=artifact_id,
166
+ # file_path="serve",
167
+ # deployment_name="app",
168
+ # replica_resource=replica_resources,
169
+ # ),
170
+ # task_scheduling = task_scheduling,
171
+ # ),
172
+ # ))
173
+ # except Exception as e:
174
+ # logger.error(f"Failed to create task, Error: {e}")
175
+ # raise e
176
+ # return task.task_id
177
+
178
+ # def start_task_and_wait(self, task_id: str, timeout_s: int = 900) -> Task:
179
+ # """
180
+ # Start a task and wait for it to be ready.
181
+
182
+ # :param task_id: The ID of the task to start.
183
+ # :param timeout_s: The timeout in seconds.
184
+ # :return: The task object.
185
+ # :rtype: Task
186
+ # """
187
+ # task_manager = self.task_manager
188
+ # # trigger start task
189
+ # try:
190
+ # task_manager.start_task(task_id)
191
+ # logger.info(f"Started task ID: {task_id}")
192
+ # except Exception as e:
193
+ # logger.error(f"Failed to start task, Error: {e}")
194
+ # raise e
195
+
196
+ # start_time = time.time()
197
+ # while True:
198
+ # try:
199
+ # task = task_manager.get_task(task_id)
200
+ # if task.task_status == TaskStatus.RUNNING:
201
+ # return task
202
+ # elif task.task_status in [TaskStatus.NEEDSTOP, TaskStatus.ARCHIVED]:
203
+ # raise Exception(f"Unexpected task status after starting: {task.task_status}")
204
+ # # Also check endpoint status.
205
+ # elif task.task_status == TaskStatus.RUNNING:
206
+ # if task.endpoint_info and task.endpoint_info.endpoint_status == TaskEndpointStatus.RUNNING:
207
+ # return task
208
+ # elif task.endpoint_info and task.endpoint_info.endpoint_status in [TaskEndpointStatus.UNKNOWN, TaskEndpointStatus.ARCHIVED]:
209
+ # raise Exception(f"Unexpected endpoint status after starting: {task.endpoint_info.endpoint_status}")
210
+ # else:
211
+ # logger.info(f"Pending endpoint starting. endpoint status: {task.endpoint_info.endpoint_status}")
212
+ # else:
213
+ # logger.info(f"Pending task starting. Task status: {task.task_status}")
214
+
215
+ # except Exception as e:
216
+ # logger.error(f"Failed to get task, Error: {e}")
217
+ # if time.time() - start_time > timeout_s:
218
+ # raise Exception(f"Task creation takes more than {timeout_s // 60} minutes. Testing aborted.")
219
+ # time.sleep(10)
220
+
221
+ # def stop_task(self, task_id: str, timeout_s: int = 900):
222
+ # task_manager = self.task_manager
223
+ # try:
224
+ # self.task_manager.stop_task(task_id)
225
+ # logger.info(f"Stopping task ID: {task_id}")
226
+ # except Exception as e:
227
+ # logger.error(f"Failed to stop task, Error: {e}")
228
+ # task_manager = self.task_manager
229
+ # start_time = time.time()
230
+ # while True:
231
+ # try:
232
+ # task = task_manager.get_task(task_id)
233
+ # if task.task_status == TaskStatus.IDLE:
234
+ # break
235
+ # except Exception as e:
236
+ # logger.error(f"Failed to get task, Error: {e}")
237
+ # if time.time() - start_time > timeout_s:
238
+ # raise Exception(f"Task stopping takes more than {timeout_s // 60} minutes. Testing aborted.")
239
+ # time.sleep(10)
240
+
241
+ # def archive_task(self, task_id: str, timeout_s: int = 900):
242
+ # task_manager = self.task_manager
243
+ # try:
244
+ # self.task_manager.archive_task(task_id)
245
+ # logger.info(f"Archived task ID: {task_id}")
246
+ # except Exception as e:
247
+ # logger.error(f"Failed to archive task, Error: {e}")
@@ -0,0 +1,147 @@
1
+ Metadata-Version: 2.2
2
+ Name: gmicloud
3
+ Version: 0.1.6
4
+ Summary: GMI Cloud Python SDK
5
+ Author-email: GMI <support@gmicloud.ai>
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.6
11
+ Description-Content-Type: text/markdown
12
+
13
+ # GMICloud SDK (Beta)
14
+
15
+ ## Overview
16
+ Before you start: Our service and GPU resource is currenly invite-only so please contact our team (getstarted@gmicloud.ai) to get invited if you don't have one yet.
17
+
18
+ The GMI Inference Engine SDK provides a Python interface for deploying and managing machine learning models in production environments. It allows users to create model artifacts, schedule tasks for serving models, and call inference APIs easily.
19
+
20
+ This SDK streamlines the process of utilizing GMI Cloud capabilities such as deploying models with Kubernetes-based Ray services, managing resources automatically, and accessing model inference endpoints. With minimal setup, developers can focus on building ML solutions instead of infrastructure.
21
+
22
+ ## Features
23
+
24
+ - Artifact Management: Easily create, update, and manage ML model artifacts.
25
+ - Task Management: Quickly create, schedule, and manage deployment tasks for model inference.
26
+ - Usage Data Retrieval : Fetch and analyze usage data to optimize resource allocation.
27
+
28
+ ## Installation
29
+
30
+ To install the SDK, use pip:
31
+
32
+ ```bash
33
+ pip install gmicloud
34
+ ```
35
+
36
+ ## Setup
37
+
38
+ You must configure authentication credentials for accessing the GMI Cloud API.
39
+ To create account and get log in info please visit **GMI inference platform: https://inference-engine.gmicloud.ai/**.
40
+
41
+ There are two ways to configure the SDK:
42
+
43
+ ### Option 1: Using Environment Variables
44
+
45
+ Set the following environment variables:
46
+
47
+ ```shell
48
+ export GMI_CLOUD_CLIENT_ID=<YOUR_CLIENT_ID>
49
+ export GMI_CLOUD_EMAIL=<YOUR_EMAIL>
50
+ export GMI_CLOUD_PASSWORD=<YOUR_PASSWORD>
51
+ ```
52
+
53
+ ### Option 2: Passing Credentials as Parameters
54
+
55
+ Pass `client_id`, `email`, and `password` directly to the Client object when initializing it in your script:
56
+
57
+ ```python
58
+ from gmicloud import Client
59
+
60
+ client = Client(client_id="<YOUR_CLIENT_ID>", email="<YOUR_EMAIL>", password="<YOUR_PASSWORD>")
61
+ ```
62
+
63
+ ## Quick Start
64
+
65
+ ### 1. How to run the code in the example folder
66
+ ```bash
67
+ cd path/to/gmicloud-sdk
68
+ # Create a virtual environment
69
+ python -m venv venv
70
+ source venv/bin/activate
71
+
72
+ pip install -r requirements.txt
73
+ python -m examples.create_task_from_artifact_template.py
74
+ ```
75
+
76
+ ### 2. Create an inference task from an artifact template
77
+
78
+ This is the simplest example to deploy an inference task using an existing artifact template:
79
+
80
+ Up-to-date code in /examples/create_task_from_artifact_template.py
81
+
82
+ ```python
83
+ from datetime import datetime
84
+ import os
85
+ import sys
86
+
87
+ from gmicloud import *
88
+ from examples.completion import call_chat_completion
89
+
90
+ cli = Client()
91
+
92
+ # List templates offered by GMI cloud
93
+ templates = cli.list_templates()
94
+ print(f"Found {len(templates)} templates: {templates}")
95
+
96
+ # Pick a template from the list
97
+ pick_template = "Llama-3.1-8B"
98
+
99
+ # Create Artifact from template
100
+ artifact_id, recommended_replica_resources = cli.create_artifact_from_template(templates[0])
101
+ print(f"Created artifact {artifact_id} with recommended replica resources: {recommended_replica_resources}")
102
+
103
+ # Create Task based on Artifact
104
+ task_id = cli.create_task(artifact_id, recommended_replica_resources, TaskScheduling(
105
+ scheduling_oneoff=OneOffScheduling(
106
+ trigger_timestamp=int(datetime.now().timestamp()),
107
+ min_replicas=1,
108
+ max_replicas=1,
109
+ )
110
+ ))
111
+ task = cli.task_manager.get_task(task_id)
112
+ print(f"Task created: {task.config.task_name}. You can check details at https://inference-engine.gmicloud.ai/user-console/task")
113
+
114
+ # Start Task and wait for it to be ready
115
+ cli.start_task_and_wait(task.task_id)
116
+
117
+ # Testing with calling chat completion
118
+ print(call_chat_completion(cli, task.task_id))
119
+
120
+ ```
121
+
122
+ ## API Reference
123
+
124
+ ### Client
125
+
126
+ Represents the entry point to interact with GMI Cloud APIs.
127
+ Client(
128
+ client_id: Optional[str] = "",
129
+ email: Optional[str] = "",
130
+ password: Optional[str] = ""
131
+ )
132
+
133
+ ### Artifact Management
134
+
135
+ * get_artifact_templates(): Fetch a list of available artifact templates.
136
+ * create_artifact_from_template(template_id: str): Create a model artifact from a given template.
137
+ * get_artifact(artifact_id: str): Get details of a specific artifact.
138
+
139
+ ### Task Management
140
+
141
+ * create_task_from_artifact_template(template_id: str, scheduling: TaskScheduling): Create and schedule a task using an
142
+ artifact template.
143
+ * start_task(task_id: str): Start a task.
144
+ * get_task(task_id: str): Retrieve the status and details of a specific task.
145
+
146
+ ## Notes & Troubleshooting
147
+ k
@@ -1,11 +1,11 @@
1
1
  gmicloud/__init__.py,sha256=aIgu4MAw4nExv781-pzSZLG8MscqAMZ5lM5fGyqg7QU,984
2
- gmicloud/client.py,sha256=RzI-T5FHMxb_OrDFadmi_WJ5EP6S1on3tR-z1ajyuPo,5598
2
+ gmicloud/client.py,sha256=G0tD0xQnpqDKS-3l-AAU-K3FAHOsqsTzsAq2NVxiamY,10539
3
3
  gmicloud/_internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  gmicloud/_internal/_config.py,sha256=qIH76TSyS3MQWe62LHI46RJhDnklNFisdajY75oUAqE,218
5
5
  gmicloud/_internal/_constants.py,sha256=Y085dwFlqdFkCf39iBfxz39QiiB7lX59ayNJjB86_m4,378
6
- gmicloud/_internal/_enums.py,sha256=5Z0MZksO1rjHVu24ZF29yYorYJjrYR45WKGL7_EGKUE,686
6
+ gmicloud/_internal/_enums.py,sha256=5d6Z8TFJYCmhNI1TDbPpBbG1tNe96StIEH4tEw20RZk,789
7
7
  gmicloud/_internal/_exceptions.py,sha256=hScBq7n2fOit4_umlkabZJchY8zVbWSRfWM2Y0rLCbw,306
8
- gmicloud/_internal/_models.py,sha256=OsgRTdzFaMC8EdqLZGH9g66vPjgntV6Jg2eJo-P7SZE,16962
8
+ gmicloud/_internal/_models.py,sha256=eArBzdhiMosLVZVUyoE_mvfxRS8yKPkuqhlDaa57Iog,17863
9
9
  gmicloud/_internal/_client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  gmicloud/_internal/_client/_artifact_client.py,sha256=-CyMdTauVovuv3whs8yUqmv3-WW2e9m2GoEG9D6eNbc,8374
11
11
  gmicloud/_internal/_client/_decorator.py,sha256=sy4gxzsUB6ORXHw5pqmMf7TTlK41Nmu1fhIhK2AIsbY,670
@@ -14,14 +14,14 @@ gmicloud/_internal/_client/_http_client.py,sha256=j--3emTjJ_l9CTdnkTbcpf7gYcUEl3
14
14
  gmicloud/_internal/_client/_iam_client.py,sha256=pgOXIqp9aJvcIUCEVkYPEyMUyxBftecojHAbs8Gbl94,7013
15
15
  gmicloud/_internal/_client/_task_client.py,sha256=69OqZC_kwSDkTSVVyi51Tn_OyUV6R0nin4z4gLfZ-Lg,6141
16
16
  gmicloud/_internal/_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
- gmicloud/_internal/_manager/_artifact_manager.py,sha256=yHNAcCPd-tFerSzDojdDuFDzk6SldbzLPGAW_hyDeF4,12568
17
+ gmicloud/_internal/_manager/_artifact_manager.py,sha256=TBvGps__Kk1Ym7jztY3tNZ3XomKPrDIFPV7XyyLwHuw,15941
18
18
  gmicloud/_internal/_manager/_iam_manager.py,sha256=nAqPCaUfSXTnx2MEQa8e0YUOBFYWDRiETgK1PImdf4o,1167
19
- gmicloud/_internal/_manager/_task_manager.py,sha256=6dQ4yr22F3vljWkpa5hR5PQ3QuFGVU-pOnN1XwZQEBY,8304
19
+ gmicloud/_internal/_manager/_task_manager.py,sha256=YDUcAdRkJhGumA1LLfpXfYs6jmLnev8P27UItPZHUBs,11268
20
20
  gmicloud/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  gmicloud/tests/test_artifacts.py,sha256=q1jiTk5DN4G3LCLCO_8KbWArdc6RG3sETe1MCEt-vbI,16979
22
22
  gmicloud/tests/test_tasks.py,sha256=yL-aFf80ShgTyxEONTWh-xbWDf5XnUNtIeA5hYvhKM0,10963
23
23
  gmicloud/utils/uninstall_packages.py,sha256=zzuuaJPf39oTXWZ_7tUAGseoxocuCbbkoglJSD5yDrE,1127
24
- gmicloud-0.1.5.dist-info/METADATA,sha256=0lXsAQuoEisnxbuT9EfUbi42qlDL6IcZl7fggJNwIx4,7757
25
- gmicloud-0.1.5.dist-info/WHEEL,sha256=nn6H5-ilmfVryoAQl3ZQ2l8SH5imPWFpm1A5FgEuFV4,91
26
- gmicloud-0.1.5.dist-info/top_level.txt,sha256=AZimLw3y0WPpLiSiOidZ1gD0dxALh-jQNk4fxC05hYE,9
27
- gmicloud-0.1.5.dist-info/RECORD,,
24
+ gmicloud-0.1.6.dist-info/METADATA,sha256=rqwbl1_3RfzhdBpn9eb3u1My3pk10k7T3r23oEiTshY,4675
25
+ gmicloud-0.1.6.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
26
+ gmicloud-0.1.6.dist-info/top_level.txt,sha256=AZimLw3y0WPpLiSiOidZ1gD0dxALh-jQNk4fxC05hYE,9
27
+ gmicloud-0.1.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.1)
2
+ Generator: setuptools (76.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,246 +0,0 @@
1
- Metadata-Version: 2.2
2
- Name: gmicloud
3
- Version: 0.1.5
4
- Summary: GMI Cloud Python SDK
5
- Author-email: GMI <gmi@gmitec.net>
6
- License: MIT
7
- Classifier: Programming Language :: Python :: 3
8
- Classifier: License :: OSI Approved :: MIT License
9
- Classifier: Operating System :: OS Independent
10
- Requires-Python: >=3.6
11
- Description-Content-Type: text/markdown
12
-
13
- # GMICloud SDK (Beta)
14
-
15
- ## Overview
16
- Before you start: Our service and GPU resource is currenly invite-only so please contact our team (getstarted@gmicloud.ai) to get invited if you don't have one yet.
17
-
18
- The GMI Inference Engine SDK provides a Python interface for deploying and managing machine learning models in production environments. It allows users to create model artifacts, schedule tasks for serving models, and call inference APIs easily.
19
-
20
- This SDK streamlines the process of utilizing GMI Cloud capabilities such as deploying models with Kubernetes-based Ray services, managing resources automatically, and accessing model inference endpoints. With minimal setup, developers can focus on building ML solutions instead of infrastructure.
21
-
22
- ## Features
23
-
24
- - Artifact Management: Easily create, update, and manage ML model artifacts.
25
- - Task Management: Quickly create, schedule, and manage deployment tasks for model inference.
26
- - Usage Data Retrieval : Fetch and analyze usage data to optimize resource allocation.
27
-
28
- ## Installation
29
-
30
- To install the SDK, use pip:
31
-
32
- ```bash
33
- pip install gmicloud
34
- ```
35
-
36
- ## Setup
37
-
38
- You must configure authentication credentials for accessing the GMI Cloud API. There are two ways to configure the SDK:
39
-
40
- ### Option 1: Using Environment Variables
41
-
42
- Set the following environment variables:
43
-
44
- ```shell
45
- export GMI_CLOUD_CLIENT_ID=<YOUR_CLIENT_ID>
46
- export GMI_CLOUD_EMAIL=<YOUR_EMAIL>
47
- export GMI_CLOUD_PASSWORD=<YOUR_PASSWORD>
48
- export GMI_CLOUD_API_KEY=<YOUR_API_KEY>
49
- ```
50
-
51
- ### Option 2: Passing Credentials as Parameters
52
-
53
- Pass `client_id`, `email`, and `password` directly to the Client object when initializing it in your script:
54
-
55
- ```python
56
- from gmicloud import Client
57
-
58
- client = Client(client_id="<YOUR_CLIENT_ID>", email="<YOUR_EMAIL>", password="<YOUR_PASSWORD>")
59
- ```
60
-
61
- ## Quick Start
62
-
63
- ### 1. How to run the code in the example folder
64
- ```bash
65
- cd path/to/gmicloud-sdk
66
- # Create a virtual environment
67
- python -m venv venv
68
- source venv/bin/activate
69
-
70
- pip install -r requirements.txt
71
- python -m examples.create_task_from_artifact_template.py
72
- ```
73
-
74
- ### 2. Create a Task from an Artifact Template
75
-
76
- This is the simplest example to deploy an existing artifact template:
77
-
78
- ```python
79
- from datetime import datetime
80
- from gmicloud import Client, TaskScheduling, OneOffScheduling
81
- from examples.completion import call_chat_completion
82
-
83
- # Initialize the client
84
- client = Client()
85
-
86
- # Schedule and start a task from an artifact template
87
- task = client.create_task_from_artifact_template(
88
- "qwen_2.5_14b_instruct_template_001",
89
- TaskScheduling(
90
- scheduling_oneoff=OneOffScheduling(
91
- trigger_timestamp=int(datetime.now().timestamp()) + 10, # Delay by 10 seconds
92
- min_replicas=1,
93
- max_replicas=10,
94
- )
95
- )
96
- )
97
-
98
- # Make a chat completion request via the task endpoint
99
- response = call_chat_completion(client, task.task_id)
100
- print(response)
101
- ```
102
-
103
- ### 3. Step-by-Step Example: Create Artifact, Task, and Query the Endpoint
104
-
105
- #### (a) Create an Artifact from a Template
106
-
107
- First, you’ll retrieve all templates and create an artifact based on the desired template (e.g., "Llama3.1 8B"):
108
-
109
- ```python
110
- from gmicloud import *
111
-
112
-
113
- def create_artifact_from_template(client: Client) -> str:
114
- artifact_manager = client.artifact_manager
115
-
116
- # Get all artifact templates
117
- templates = artifact_manager.get_public_templates()
118
- for template in templates:
119
- if template.artifact_template_id == "qwen_2.5_14b_instruct_template_001":
120
- # Create an artifact from a template
121
- artifact_id = artifact_manager.create_artifact_from_template(
122
- artifact_template_id=template.artifact_template_id,
123
- )
124
-
125
- return artifact_id
126
-
127
- return ""
128
- ```
129
-
130
- #### (b) Create a Task from the Artifact
131
-
132
- Wait until the artifact becomes "ready" and then deploy it using task scheduling:
133
-
134
- ```python
135
- from gmicloud import *
136
- import time
137
- from datetime import datetime
138
-
139
- def create_task_and_start(client: Client, artifact_id: str) -> str:
140
- artifact_manager = client.artifact_manager
141
- # Wait for the artifact to be ready
142
- while True:
143
- try:
144
- artifact = artifact_manager.get_artifact(artifact_id)
145
- print(f"Artifact status: {artifact.build_status}")
146
- # Wait until the artifact is ready
147
- if artifact.build_status == BuildStatus.SUCCESS:
148
- break
149
- except Exception as e:
150
- raise e
151
- # Wait for 2 seconds
152
- time.sleep(2)
153
- try:
154
- task_manager = client.task_manager
155
- # Create a task
156
- task = task_manager.create_task(Task(
157
- config=TaskConfig(
158
- ray_task_config=RayTaskConfig(
159
- ray_version="2.40.0-py310-gpu",
160
- file_path="serve",
161
- artifact_id=artifact_id,
162
- deployment_name="app",
163
- replica_resource=ReplicaResource(
164
- cpu=10,
165
- ram_gb=100,
166
- gpu=1,
167
- ),
168
- ),
169
- task_scheduling=TaskScheduling(
170
- scheduling_oneoff=OneOffScheduling(
171
- trigger_timestamp=int(datetime.now().timestamp()) + 10,
172
- min_replicas=1,
173
- max_replicas=10,
174
- )
175
- ),
176
- ),
177
- ))
178
-
179
- # Start the task
180
- task_manager.start_task(task.task_id)
181
- except Exception as e:
182
- raise e
183
-
184
- return task.task_id
185
- ```
186
-
187
- ### (c) Query the Model Endpoint
188
-
189
- Once the task is running, use the endpoint for inference:
190
-
191
- ```python
192
- from gmicloud import *
193
- from examples.completion import call_chat_completion
194
-
195
- # Initialize the Client
196
- cli = Client()
197
-
198
- # Create an artifact from a template
199
- artifact_id = create_artifact_from_template(cli)
200
-
201
- # Create a task and start it
202
- task_id = create_task_and_start(cli, artifact_id)
203
-
204
- # Call chat completion
205
- print(call_chat_completion(cli, task_id))
206
- ```
207
-
208
- ## API Reference
209
-
210
- ### Client
211
-
212
- Represents the entry point to interact with GMI Cloud APIs.
213
- Client(
214
- client_id: Optional[str] = "",
215
- email: Optional[str] = "",
216
- password: Optional[str] = ""
217
- )
218
-
219
- ### Artifact Management
220
-
221
- * get_artifact_templates(): Fetch a list of available artifact templates.
222
- * create_artifact_from_template(template_id: str): Create a model artifact from a given template.
223
- * get_artifact(artifact_id: str): Get details of a specific artifact.
224
-
225
- ### Task Management
226
-
227
- * create_task_from_artifact_template(template_id: str, scheduling: TaskScheduling): Create and schedule a task using an
228
- artifact template.
229
- * start_task(task_id: str): Start a task.
230
- * get_task(task_id: str): Retrieve the status and details of a specific task.
231
-
232
- ## Notes & Troubleshooting
233
-
234
- * Ensure Credentials are Correct: Double-check your environment variables or parameters passed into the Client object.
235
- * Artifact Status: It may take a few minutes for an artifact or task to transition to the "running" state.
236
- * Inference Endpoint Readiness: Use the task endpoint only after the task status changes to "running".
237
- * Default OpenAI Key: By default, the OpenAI API base URL is derived from the endpoint provided by GMI.
238
-
239
- ## Contributing
240
-
241
- We welcome contributions to enhance the SDK. Please follow these steps:
242
-
243
- 1. Fork the repository.
244
- 2. Create a new branch for your feature or bugfix.
245
- 3. Commit changes with clear messages.
246
- 4. Submit a pull request for review.