gmicloud 0.1.6__py3-none-any.whl → 0.1.9__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.
- gmicloud/__init__.py +2 -2
- gmicloud/_internal/_client/_artifact_client.py +40 -7
- gmicloud/_internal/_client/_auth_config.py +78 -0
- gmicloud/_internal/_client/_file_upload_client.py +10 -7
- gmicloud/_internal/_client/_iam_client.py +57 -38
- gmicloud/_internal/_client/_video_client.py +111 -0
- gmicloud/_internal/_config.py +9 -3
- gmicloud/_internal/_enums.py +19 -1
- gmicloud/_internal/_manager/_artifact_manager.py +137 -20
- gmicloud/_internal/_manager/_task_manager.py +61 -27
- gmicloud/_internal/_manager/_video_manager.py +91 -0
- gmicloud/_internal/_manager/serve_command_utils.py +125 -0
- gmicloud/_internal/_models.py +219 -32
- gmicloud/client.py +12 -0
- gmicloud/tests/test_artifacts.py +6 -22
- gmicloud-0.1.9.dist-info/METADATA +264 -0
- gmicloud-0.1.9.dist-info/RECORD +31 -0
- {gmicloud-0.1.6.dist-info → gmicloud-0.1.9.dist-info}/WHEEL +1 -1
- gmicloud-0.1.6.dist-info/METADATA +0 -147
- gmicloud-0.1.6.dist-info/RECORD +0 -27
- {gmicloud-0.1.6.dist-info → gmicloud-0.1.9.dist-info}/top_level.txt +0 -0
gmicloud/__init__.py
CHANGED
@@ -15,7 +15,7 @@ from ._internal._models import (
|
|
15
15
|
OneOffScheduling,
|
16
16
|
DailyScheduling,
|
17
17
|
DailyTrigger,
|
18
|
-
|
18
|
+
Template,
|
19
19
|
)
|
20
20
|
from ._internal._enums import (
|
21
21
|
BuildStatus,
|
@@ -39,7 +39,7 @@ __all__ = [
|
|
39
39
|
"OneOffScheduling",
|
40
40
|
"DailyScheduling",
|
41
41
|
"DailyTrigger",
|
42
|
-
"
|
42
|
+
"Template",
|
43
43
|
"BuildStatus",
|
44
44
|
"TaskEndpointStatus",
|
45
45
|
]
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from typing import List
|
2
2
|
import logging
|
3
3
|
from requests.exceptions import RequestException
|
4
|
-
|
4
|
+
import json
|
5
5
|
from ._http_client import HTTPClient
|
6
6
|
from ._iam_client import IAMClient
|
7
7
|
from ._decorator import handle_refresh_token
|
@@ -120,6 +120,39 @@ class ArtifactClient:
|
|
120
120
|
logger.error(f"Failed to rebuild artifact {artifact_id}: {e}")
|
121
121
|
return None
|
122
122
|
|
123
|
+
@handle_refresh_token
|
124
|
+
def add_env_parameters_to_artifact(self, artifact_id: str, env_parameters: dict[str, str]) -> None:
|
125
|
+
"""
|
126
|
+
Updates an artifact by its ID.
|
127
|
+
|
128
|
+
:param artifact_id: The ID of the artifact to update.
|
129
|
+
:param request: The request object containing the updated artifact details.
|
130
|
+
"""
|
131
|
+
try:
|
132
|
+
old_artifact = self.get_artifact(artifact_id)
|
133
|
+
if not old_artifact:
|
134
|
+
logger.error(f"Artifact {artifact_id} not found")
|
135
|
+
return
|
136
|
+
request = UpdateArtifactRequestBody(
|
137
|
+
artifact_description=old_artifact.artifact_metadata.artifact_description,
|
138
|
+
artifact_name=old_artifact.artifact_metadata.artifact_name,
|
139
|
+
artifact_tags=old_artifact.artifact_metadata.artifact_tags,
|
140
|
+
env_parameters=old_artifact.artifact_parameters.env_parameters,
|
141
|
+
model_parameters=old_artifact.artifact_parameters.model_parameters
|
142
|
+
)
|
143
|
+
new_env_parameters = [EnvParameter(key=k, value=v) for k, v in env_parameters.items()]
|
144
|
+
if not request.env_parameters:
|
145
|
+
request.env_parameters = []
|
146
|
+
request.env_parameters.extend(new_env_parameters)
|
147
|
+
response = self.client.put(
|
148
|
+
f"/update_artifact?artifact_id={artifact_id}",
|
149
|
+
self.iam_client.get_custom_headers(),
|
150
|
+
request.model_dump()
|
151
|
+
)
|
152
|
+
except (RequestException, ValueError) as e:
|
153
|
+
logger.error(f"Failed to add env parameters to artifact {artifact_id}: {e}")
|
154
|
+
return
|
155
|
+
|
123
156
|
@handle_refresh_token
|
124
157
|
def delete_artifact(self, artifact_id: str) -> Optional[DeleteArtifactResponse]:
|
125
158
|
"""
|
@@ -140,7 +173,7 @@ class ArtifactClient:
|
|
140
173
|
return None
|
141
174
|
|
142
175
|
@handle_refresh_token
|
143
|
-
def get_bigfile_upload_url(self, request:
|
176
|
+
def get_bigfile_upload_url(self, request: ResumableUploadLinkRequest) -> Optional[ResumableUploadLinkResponse]:
|
144
177
|
"""
|
145
178
|
Generates a pre-signed URL for uploading a large file.
|
146
179
|
|
@@ -156,7 +189,7 @@ class ArtifactClient:
|
|
156
189
|
logger.error("Empty response from /get_bigfile_upload_url")
|
157
190
|
return None
|
158
191
|
|
159
|
-
return
|
192
|
+
return ResumableUploadLinkResponse.model_validate(response)
|
160
193
|
|
161
194
|
except (RequestException, ValueError) as e:
|
162
195
|
logger.error(f"Failed to generate upload URL: {e}")
|
@@ -186,12 +219,12 @@ class ArtifactClient:
|
|
186
219
|
return None
|
187
220
|
|
188
221
|
@handle_refresh_token
|
189
|
-
def get_public_templates(self) -> List[
|
222
|
+
def get_public_templates(self) -> List[Template]:
|
190
223
|
"""
|
191
224
|
Fetches all artifact templates.
|
192
225
|
|
193
|
-
:return: A list of
|
194
|
-
:rtype: List[
|
226
|
+
:return: A list of Template objects.
|
227
|
+
:rtype: List[Template]
|
195
228
|
"""
|
196
229
|
try:
|
197
230
|
response = self.client.get("/get_public_templates", self.iam_client.get_custom_headers())
|
@@ -201,7 +234,7 @@ class ArtifactClient:
|
|
201
234
|
return []
|
202
235
|
|
203
236
|
try:
|
204
|
-
result =
|
237
|
+
result = GetTemplatesResponse.model_validate(response)
|
205
238
|
return result.artifact_templates
|
206
239
|
except ValueError as ve:
|
207
240
|
logger.error(f"Failed to validate response data: {ve}")
|
@@ -0,0 +1,78 @@
|
|
1
|
+
import os
|
2
|
+
import jwt
|
3
|
+
import time
|
4
|
+
import json
|
5
|
+
import logging
|
6
|
+
import threading
|
7
|
+
from pathlib import Path
|
8
|
+
|
9
|
+
logger = logging.getLogger(__name__)
|
10
|
+
|
11
|
+
CONFIG_FILE_NAME = ".gmicloud.config.json"
|
12
|
+
|
13
|
+
# create the thread lock object56
|
14
|
+
lock = threading.Lock()
|
15
|
+
|
16
|
+
def _read_config_file()->dict|None:
|
17
|
+
"""Read the config file."""
|
18
|
+
base_dir = Path.home()
|
19
|
+
config_file_path =os.path.join(base_dir,CONFIG_FILE_NAME)
|
20
|
+
if not os.path.exists(config_file_path):
|
21
|
+
return None
|
22
|
+
with lock:
|
23
|
+
# open the config file, read mode with lock
|
24
|
+
with open(config_file_path,"r") as fr:
|
25
|
+
return json.loads(fr.read())
|
26
|
+
|
27
|
+
|
28
|
+
def _write_config_file(config_file_path:str,config_dic:dict)->None:
|
29
|
+
"""Write the config file."""
|
30
|
+
with lock:
|
31
|
+
# open the config file, write mode with lock
|
32
|
+
with open(config_file_path,"w") as fw:
|
33
|
+
# transform the config dictionary to JSON format and write it to the file
|
34
|
+
fw.write(json.dumps(config_dic))
|
35
|
+
|
36
|
+
|
37
|
+
def write_user_refresh_token_to_system_config(email:str,refresh_token:str)->bool:
|
38
|
+
"""Write the user refresh token to the system config file."""
|
39
|
+
base_dir = Path.home()
|
40
|
+
config_file_path = os.path.join(base_dir,CONFIG_FILE_NAME)
|
41
|
+
try:
|
42
|
+
# check the config file is exists. if not, create it, if yes, update the refresh token
|
43
|
+
if not os.path.exists(config_file_path):
|
44
|
+
config_dic = { email : {"refresh_token": refresh_token} }
|
45
|
+
_write_config_file(config_file_path,config_dic)
|
46
|
+
else:
|
47
|
+
config_dic = _read_config_file()
|
48
|
+
if not config_dic.get(email):
|
49
|
+
config_dic[email] = dict()
|
50
|
+
config_dic[email] = {"refresh_token": refresh_token}
|
51
|
+
_write_config_file(config_file_path,config_dic)
|
52
|
+
except Exception as e:
|
53
|
+
logger.error("write file wrong :", e)
|
54
|
+
return False
|
55
|
+
return True
|
56
|
+
|
57
|
+
|
58
|
+
def get_user_refresh_token_from_system_config(email:str)->str|None:
|
59
|
+
"""Get the user refresh token from the system config file."""
|
60
|
+
config_dic = _read_config_file()
|
61
|
+
if not config_dic or not config_dic.get(email):
|
62
|
+
return None
|
63
|
+
return config_dic[email]["refresh_token"]
|
64
|
+
|
65
|
+
|
66
|
+
def _parese_refresh_token(refresh_token:str)->dict:
|
67
|
+
"""Parse the refresh token."""
|
68
|
+
return jwt.decode(refresh_token, options={"verify_signature": False})
|
69
|
+
|
70
|
+
|
71
|
+
def is_refresh_token_expired(refresh_token:str)->bool:
|
72
|
+
"""Check the refresh token is expired. if expired, return True, else return False."""
|
73
|
+
try:
|
74
|
+
refresh_token_time = _parese_refresh_token(refresh_token)['exp']
|
75
|
+
except Exception as e:
|
76
|
+
logger.error("parse refresh token wrong :", e)
|
77
|
+
return True
|
78
|
+
return refresh_token_time < time.time()
|
@@ -1,8 +1,10 @@
|
|
1
1
|
import os
|
2
2
|
import requests
|
3
|
+
import logging
|
3
4
|
|
4
5
|
from .._exceptions import UploadFileError
|
5
6
|
|
7
|
+
logger = logging.getLogger()
|
6
8
|
|
7
9
|
class FileUploadClient:
|
8
10
|
CHUNK_SIZE = 10 * 1024 * 1024 # 10MB Default Chunk Size
|
@@ -45,13 +47,13 @@ class FileUploadClient:
|
|
45
47
|
"""
|
46
48
|
try:
|
47
49
|
file_size = os.path.getsize(file_path)
|
48
|
-
|
50
|
+
logger.info(f"File {file_path} size: {file_size} bytes")
|
49
51
|
|
50
52
|
start_byte = 0
|
51
53
|
uploaded_range = FileUploadClient._check_file_status(upload_url, file_size)
|
52
54
|
if uploaded_range:
|
53
55
|
start_byte = int(uploaded_range.split("-")[1]) + 1
|
54
|
-
|
56
|
+
logger.info(f"Resuming uploading {file_path} from {start_byte} bytes")
|
55
57
|
|
56
58
|
with open(file_path, "rb") as file:
|
57
59
|
while start_byte < file_size:
|
@@ -74,14 +76,15 @@ class FileUploadClient:
|
|
74
76
|
# Ensure upload is successful for this chunk
|
75
77
|
if resp.status_code not in (200, 201, 308):
|
76
78
|
raise UploadFileError(
|
77
|
-
f"Failed to upload file, code:{resp.status_code} ,message: {resp.text}")
|
79
|
+
f"Failed to upload file {file_path}, code:{resp.status_code} ,message: {resp.text}")
|
78
80
|
|
79
81
|
start_byte = end_byte + 1
|
80
|
-
|
82
|
+
percentage = (start_byte / file_size) * 100
|
83
|
+
logger.info(f"File {file_path} uploaded {end_byte + 1:,}/{file_size:,} bytes ({percentage:.2f}%)")
|
81
84
|
|
82
|
-
|
85
|
+
logger.info(f"File {file_path} uploaded successfully.")
|
83
86
|
except Exception as e:
|
84
|
-
raise UploadFileError(f"Failed to upload file: {str(e)}")
|
87
|
+
raise UploadFileError(f"Failed to upload file {file_path}, got error: {str(e)}")
|
85
88
|
|
86
89
|
@staticmethod
|
87
90
|
def _check_file_status(upload_url: str, file_size: int) -> str:
|
@@ -104,7 +107,7 @@ class FileUploadClient:
|
|
104
107
|
if resp.status_code == 308:
|
105
108
|
range_header = resp.headers.get("Range")
|
106
109
|
if range_header:
|
107
|
-
|
110
|
+
logger.info(f"Server reports partial upload range: {range_header}")
|
108
111
|
return range_header
|
109
112
|
|
110
113
|
if resp.status_code in (200, 201):
|
@@ -6,7 +6,11 @@ from ._http_client import HTTPClient
|
|
6
6
|
from .._config import IAM_SERVICE_BASE_URL
|
7
7
|
from .._models import *
|
8
8
|
from .._constants import CLIENT_ID_HEADER, AUTHORIZATION_HEADER
|
9
|
-
|
9
|
+
from ._auth_config import (
|
10
|
+
get_user_refresh_token_from_system_config,
|
11
|
+
write_user_refresh_token_to_system_config,
|
12
|
+
is_refresh_token_expired
|
13
|
+
)
|
10
14
|
logger = logging.getLogger(__name__)
|
11
15
|
|
12
16
|
|
@@ -38,42 +42,50 @@ class IAMClient:
|
|
38
42
|
Returns True if login is successful, otherwise False.
|
39
43
|
"""
|
40
44
|
try:
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
logger.error("Login failed: Received empty response from auth-tokens endpoint")
|
47
|
-
return False
|
48
|
-
|
49
|
-
auth_tokens_resp = AuthTokenResponse.model_validate(auth_tokens_result)
|
50
|
-
|
51
|
-
# Handle 2FA
|
52
|
-
if auth_tokens_resp.is2FARequired:
|
53
|
-
for attempt in range(3):
|
54
|
-
code = input(f"Attempt {attempt + 1}/3: Please enter the 2FA code: ")
|
55
|
-
create_session_req = CreateSessionRequest(
|
56
|
-
type="native", authToken=auth_tokens_resp.authToken, otpCode=code
|
57
|
-
)
|
58
|
-
try:
|
59
|
-
session_result = self.client.post("/me/sessions", custom_headers,
|
60
|
-
create_session_req.model_dump())
|
61
|
-
if session_result:
|
62
|
-
break
|
63
|
-
except RequestException:
|
64
|
-
logger.warning("Invalid 2FA code, please try again.")
|
65
|
-
if attempt == 2:
|
66
|
-
logger.error("Failed to create session after 3 incorrect 2FA attempts.")
|
67
|
-
return False
|
45
|
+
# Check config refresh token is available and is not expired, if yes ,refresh it
|
46
|
+
temp_refresh_token = get_user_refresh_token_from_system_config(self._email)
|
47
|
+
if temp_refresh_token and not is_refresh_token_expired(temp_refresh_token):
|
48
|
+
self._refresh_token = temp_refresh_token
|
49
|
+
self.refresh_token()
|
68
50
|
else:
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
51
|
+
custom_headers = {CLIENT_ID_HEADER: self._client_id}
|
52
|
+
req = AuthTokenRequest(email=self._email, password=self._password)
|
53
|
+
auth_tokens_result = self.client.post("/me/auth-tokens", custom_headers, req.model_dump())
|
54
|
+
|
55
|
+
if not auth_tokens_result:
|
56
|
+
logger.error("Login failed: Received empty response from auth-tokens endpoint")
|
57
|
+
return False
|
58
|
+
|
59
|
+
auth_tokens_resp = AuthTokenResponse.model_validate(auth_tokens_result)
|
60
|
+
|
61
|
+
# Handle 2FA
|
62
|
+
if auth_tokens_resp.is2FARequired:
|
63
|
+
for attempt in range(3):
|
64
|
+
code = input(f"Attempt {attempt + 1}/3: Please enter the 2FA code: ")
|
65
|
+
create_session_req = CreateSessionRequest(
|
66
|
+
type="native", authToken=auth_tokens_resp.authToken, otpCode=code
|
67
|
+
)
|
68
|
+
try:
|
69
|
+
session_result = self.client.post("/me/sessions", custom_headers,
|
70
|
+
create_session_req.model_dump())
|
71
|
+
if session_result:
|
72
|
+
break
|
73
|
+
except RequestException:
|
74
|
+
logger.warning("Invalid 2FA code, please try again.")
|
75
|
+
if attempt == 2:
|
76
|
+
logger.error("Failed to create session after 3 incorrect 2FA attempts.")
|
77
|
+
return False
|
78
|
+
else:
|
79
|
+
create_session_req = CreateSessionRequest(type="native", authToken=auth_tokens_resp.authToken,
|
80
|
+
otpCode=None)
|
81
|
+
session_result = self.client.post("/me/sessions", custom_headers, create_session_req.model_dump())
|
82
|
+
|
83
|
+
create_session_resp = CreateSessionResponse.model_validate(session_result)
|
84
|
+
|
85
|
+
self._access_token = create_session_resp.accessToken
|
86
|
+
self._refresh_token = create_session_resp.refreshToken
|
87
|
+
# first login write refresh token to system config
|
88
|
+
write_user_refresh_token_to_system_config(self._email,self._refresh_token)
|
77
89
|
self._user_id = self.parse_user_id()
|
78
90
|
|
79
91
|
# Fetch profile to get organization ID
|
@@ -96,7 +108,12 @@ class IAMClient:
|
|
96
108
|
"""
|
97
109
|
try:
|
98
110
|
custom_headers = {CLIENT_ID_HEADER: self._client_id}
|
99
|
-
|
111
|
+
try:
|
112
|
+
result = self.client.patch("/me/sessions", custom_headers, {"refreshToken": self._refresh_token})
|
113
|
+
except Exception as err:
|
114
|
+
logger.error(f"{str(err)}, please re-login.")
|
115
|
+
write_user_refresh_token_to_system_config(self._email,"")
|
116
|
+
return False
|
100
117
|
|
101
118
|
if not result:
|
102
119
|
logger.error("Failed to refresh token: Empty response received")
|
@@ -105,7 +122,9 @@ class IAMClient:
|
|
105
122
|
resp = CreateSessionResponse.model_validate(result)
|
106
123
|
self._access_token = resp.accessToken
|
107
124
|
self._refresh_token = resp.refreshToken
|
108
|
-
|
125
|
+
# the _refresh_token will be updated when call this function
|
126
|
+
# so write it to system config file for update the _refresh_token expired time
|
127
|
+
write_user_refresh_token_to_system_config(self._email,self._refresh_token)
|
109
128
|
return True
|
110
129
|
except (RequestException, ValueError) as e:
|
111
130
|
logger.error(f"Token refresh failed: {e}")
|
@@ -0,0 +1,111 @@
|
|
1
|
+
|
2
|
+
import logging
|
3
|
+
from requests.exceptions import RequestException
|
4
|
+
|
5
|
+
from ._http_client import HTTPClient
|
6
|
+
from ._decorator import handle_refresh_token
|
7
|
+
from ._iam_client import IAMClient
|
8
|
+
from .._config import IAM_SERVICE_BASE_URL
|
9
|
+
from .._models import *
|
10
|
+
|
11
|
+
|
12
|
+
logger = logging.getLogger(__name__)
|
13
|
+
|
14
|
+
|
15
|
+
class VideoClient:
|
16
|
+
"""
|
17
|
+
A client for interacting with the video service API.
|
18
|
+
|
19
|
+
This client provides methods to retrieve, create, update, and stop video tasks
|
20
|
+
through HTTP calls to the video service.
|
21
|
+
"""
|
22
|
+
|
23
|
+
def __init__(self, iam_client: IAMClient):
|
24
|
+
"""
|
25
|
+
Initializes the VideoClient with the given base URL for the video service.
|
26
|
+
"""
|
27
|
+
self.client = HTTPClient(IAM_SERVICE_BASE_URL+ "/ie/requestqueue")
|
28
|
+
self.iam_client = iam_client
|
29
|
+
|
30
|
+
|
31
|
+
@handle_refresh_token
|
32
|
+
def get_request_detail(self, request_id: str) -> GetRequestResponse:
|
33
|
+
"""
|
34
|
+
Retrieves detailed information about a specific request by its ID. This endpoint requires authentication with a bearer token and only returns requests belonging to the authenticated organization.
|
35
|
+
|
36
|
+
:param request_id: The ID of the request to be retrieved.
|
37
|
+
:return: Details of the GetRequestResponse successfully retrieved
|
38
|
+
"""
|
39
|
+
try:
|
40
|
+
response = self.client.get(f"/requests/{request_id}", self.iam_client.get_custom_headers())
|
41
|
+
return GetRequestResponse.model_validate(response) if response else None
|
42
|
+
except (RequestException, ValueError) as e:
|
43
|
+
logger.error(f"Failed to retrieve request details for {request_id}: {e}")
|
44
|
+
return None
|
45
|
+
|
46
|
+
|
47
|
+
@handle_refresh_token
|
48
|
+
def get_requests(self, model_id: str) -> List[GetRequestResponse]:
|
49
|
+
"""
|
50
|
+
Retrieves a list of requests submitted by the authenticated user for a specific model. This endpoint requires authentication with a bearer token and filters results by the authenticated organization.
|
51
|
+
|
52
|
+
:param model_id: The ID of the model to be retrieved.
|
53
|
+
:return: List of GetRequestResponse successfully retrieved
|
54
|
+
"""
|
55
|
+
try:
|
56
|
+
response = self.client.get("/requests", self.iam_client.get_custom_headers(), {"model_id": model_id})
|
57
|
+
requests = response.get('requests', []) if response else []
|
58
|
+
return [GetRequestResponse.model_validate(req) for req in requests] if requests else None
|
59
|
+
except (RequestException, ValueError) as e:
|
60
|
+
logger.error(f"Failed to retrieve requests for model {model_id}: {e}")
|
61
|
+
return None
|
62
|
+
|
63
|
+
|
64
|
+
@handle_refresh_token
|
65
|
+
def create_request(self, request: SubmitRequestRequest) -> SubmitRequestResponse:
|
66
|
+
"""
|
67
|
+
Submits a new asynchronous request to process a specified model with provided parameters. This endpoint requires authentication with a bearer token.
|
68
|
+
|
69
|
+
:param request: The request data to be created by SubmitRequestRequest model.
|
70
|
+
:return: The created request data as SubmitRequestResponse model.
|
71
|
+
"""
|
72
|
+
try:
|
73
|
+
response = self.client.post("/requests", self.iam_client.get_custom_headers(), request.model_dump())
|
74
|
+
return SubmitRequestResponse.model_validate(response) if response else None
|
75
|
+
except (RequestException, ValueError) as e:
|
76
|
+
logger.error(f"Failed to create request: {e}")
|
77
|
+
return None
|
78
|
+
|
79
|
+
|
80
|
+
@handle_refresh_token
|
81
|
+
def get_model_detail(self, model_id: str) -> GetModelResponse:
|
82
|
+
"""
|
83
|
+
Retrieves detailed information about a specific model by its ID.
|
84
|
+
|
85
|
+
:param model_id: The ID of the model to be retrieved.
|
86
|
+
:return: Details of the GetModelResponse model successfully retrieved.
|
87
|
+
"""
|
88
|
+
try:
|
89
|
+
response = self.client.get(f"/models/{model_id}", self.iam_client.get_custom_headers())
|
90
|
+
return GetModelResponse.model_validate(response) if response else None
|
91
|
+
except (RequestException, ValueError) as e:
|
92
|
+
logger.error(f"Failed to retrieve model details for {model_id}: {e}")
|
93
|
+
return None
|
94
|
+
|
95
|
+
|
96
|
+
@handle_refresh_token
|
97
|
+
def get_models(self) -> List[GetModelResponse]:
|
98
|
+
"""
|
99
|
+
Retrieves a list of available models from the video service.
|
100
|
+
|
101
|
+
:return: A list of GetModelResponse model successfully retrieved.
|
102
|
+
"""
|
103
|
+
try:
|
104
|
+
response = self.client.get("/models", self.iam_client.get_custom_headers())
|
105
|
+
models = response.get('models', []) if response else []
|
106
|
+
return [GetModelResponse.model_validate(model) for model in models] if models else None
|
107
|
+
except (RequestException, ValueError) as e:
|
108
|
+
logger.error(f"Failed to retrieve models: {e}")
|
109
|
+
return None
|
110
|
+
|
111
|
+
|
gmicloud/_internal/_config.py
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
# Dev environment
|
2
|
+
# ARTIFACT_SERVICE_BASE_URL = "https://ce-tot.gmicloud-dev.com/api/v1/ie/artifact"
|
3
|
+
# TASK_SERVICE_BASE_URL = "https://ce-tot.gmicloud-dev.com/api/v1/ie/task"
|
4
|
+
# IAM_SERVICE_BASE_URL = "https://ce-tot.gmicloud-dev.com/api/v1"
|
5
|
+
|
6
|
+
# Prod environment
|
7
|
+
ARTIFACT_SERVICE_BASE_URL = "https://inference-engine.gmicloud.ai/api/v1/ie/artifact"
|
8
|
+
TASK_SERVICE_BASE_URL = "https://inference-engine.gmicloud.ai/api/v1/ie/task"
|
9
|
+
IAM_SERVICE_BASE_URL = "https://inference-engine.gmicloud.ai/api/v1"
|
gmicloud/_internal/_enums.py
CHANGED
@@ -24,6 +24,7 @@ class TaskEndpointStatus(str, Enum):
|
|
24
24
|
UNREADY = "unready"
|
25
25
|
NEW = "new"
|
26
26
|
|
27
|
+
|
27
28
|
class TaskStatus(str, Enum):
|
28
29
|
IDLE = "idle"
|
29
30
|
STARTING = "starting"
|
@@ -32,7 +33,24 @@ class TaskStatus(str, Enum):
|
|
32
33
|
NEEDSTOP = "needstop"
|
33
34
|
ARCHIVED = "archived"
|
34
35
|
|
36
|
+
|
35
37
|
class ModelParameterType(str, Enum):
|
36
38
|
NUMERIC = "numeric"
|
37
39
|
TEXT = "text"
|
38
|
-
BOOLEAN = "boolean"
|
40
|
+
BOOLEAN = "boolean"
|
41
|
+
|
42
|
+
|
43
|
+
class RequestStatus(Enum):
|
44
|
+
CREATED = "created"
|
45
|
+
QUEUED = "queued"
|
46
|
+
DISPATCHED = "dispatched"
|
47
|
+
PROCESSING = "processing"
|
48
|
+
SUCCESS = "success"
|
49
|
+
FAILED = "failed"
|
50
|
+
CANCELLED = "cancelled"
|
51
|
+
|
52
|
+
|
53
|
+
class HostType(Enum):
|
54
|
+
DEFAULT = ""
|
55
|
+
INTERNAL = "internal"
|
56
|
+
EXTERNAL = "external"
|