oracle-ads 2.11.15__py3-none-any.whl → 2.11.17__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.
- ads/aqua/app.py +5 -6
- ads/aqua/common/entities.py +17 -0
- ads/aqua/common/enums.py +14 -1
- ads/aqua/common/utils.py +160 -3
- ads/aqua/config/config.py +1 -1
- ads/aqua/config/deployment_config_defaults.json +29 -1
- ads/aqua/config/resource_limit_names.json +1 -0
- ads/aqua/constants.py +6 -1
- ads/aqua/evaluation/entities.py +0 -1
- ads/aqua/evaluation/evaluation.py +47 -14
- ads/aqua/extension/common_handler.py +75 -5
- ads/aqua/extension/common_ws_msg_handler.py +57 -0
- ads/aqua/extension/deployment_handler.py +16 -13
- ads/aqua/extension/deployment_ws_msg_handler.py +54 -0
- ads/aqua/extension/errors.py +1 -1
- ads/aqua/extension/evaluation_ws_msg_handler.py +28 -6
- ads/aqua/extension/model_handler.py +134 -8
- ads/aqua/extension/models/ws_models.py +78 -3
- ads/aqua/extension/models_ws_msg_handler.py +49 -0
- ads/aqua/extension/ui_websocket_handler.py +7 -1
- ads/aqua/model/entities.py +28 -0
- ads/aqua/model/model.py +544 -129
- ads/aqua/modeldeployment/deployment.py +102 -43
- ads/aqua/modeldeployment/entities.py +9 -20
- ads/aqua/ui.py +152 -28
- ads/common/object_storage_details.py +2 -5
- ads/common/serializer.py +2 -3
- ads/jobs/builders/infrastructure/dsc_job.py +41 -12
- ads/jobs/builders/infrastructure/dsc_job_runtime.py +74 -27
- ads/jobs/builders/runtimes/container_runtime.py +83 -4
- ads/opctl/operator/lowcode/anomaly/const.py +1 -0
- ads/opctl/operator/lowcode/anomaly/model/base_model.py +23 -7
- ads/opctl/operator/lowcode/anomaly/operator_config.py +1 -0
- ads/opctl/operator/lowcode/anomaly/schema.yaml +4 -0
- ads/opctl/operator/lowcode/common/errors.py +6 -0
- ads/opctl/operator/lowcode/forecast/model/arima.py +3 -1
- ads/opctl/operator/lowcode/forecast/model/base_model.py +21 -13
- ads/opctl/operator/lowcode/forecast/model_evaluator.py +11 -2
- ads/pipeline/ads_pipeline_run.py +13 -2
- {oracle_ads-2.11.15.dist-info → oracle_ads-2.11.17.dist-info}/METADATA +2 -1
- {oracle_ads-2.11.15.dist-info → oracle_ads-2.11.17.dist-info}/RECORD +44 -40
- {oracle_ads-2.11.15.dist-info → oracle_ads-2.11.17.dist-info}/LICENSE.txt +0 -0
- {oracle_ads-2.11.15.dist-info → oracle_ads-2.11.17.dist-info}/WHEEL +0 -0
- {oracle_ads-2.11.15.dist-info → oracle_ads-2.11.17.dist-info}/entry_points.txt +0 -0
@@ -3,9 +3,10 @@
|
|
3
3
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
4
4
|
|
5
5
|
import logging
|
6
|
-
from typing import Dict, List, Union
|
6
|
+
from typing import Dict, List, Optional, Union
|
7
7
|
|
8
8
|
from ads.aqua.app import AquaApp, logger
|
9
|
+
from ads.aqua.common.entities import ContainerSpec
|
9
10
|
from ads.aqua.common.enums import (
|
10
11
|
InferenceContainerTypeFamily,
|
11
12
|
Tags,
|
@@ -25,6 +26,7 @@ from ads.aqua.common.utils import (
|
|
25
26
|
load_config,
|
26
27
|
)
|
27
28
|
from ads.aqua.constants import (
|
29
|
+
AQUA_MODEL_ARTIFACT_FILE,
|
28
30
|
AQUA_MODEL_TYPE_CUSTOM,
|
29
31
|
AQUA_MODEL_TYPE_SERVICE,
|
30
32
|
MODEL_BY_REFERENCE_OSS_PATH_KEY,
|
@@ -37,8 +39,8 @@ from ads.aqua.model import AquaModelApp
|
|
37
39
|
from ads.aqua.modeldeployment.entities import (
|
38
40
|
AquaDeployment,
|
39
41
|
AquaDeploymentDetail,
|
40
|
-
ContainerSpec,
|
41
42
|
)
|
43
|
+
from ads.aqua.ui import ModelFormat
|
42
44
|
from ads.common.object_storage_details import ObjectStorageDetails
|
43
45
|
from ads.common.utils import get_log_links
|
44
46
|
from ads.config import (
|
@@ -85,23 +87,26 @@ class AquaDeploymentApp(AquaApp):
|
|
85
87
|
|
86
88
|
@telemetry(entry_point="plugin=deployment&action=create", name="aqua")
|
87
89
|
def create(
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
90
|
+
self,
|
91
|
+
model_id: str,
|
92
|
+
instance_shape: str,
|
93
|
+
display_name: str,
|
94
|
+
instance_count: int = None,
|
95
|
+
log_group_id: str = None,
|
96
|
+
access_log_id: str = None,
|
97
|
+
predict_log_id: str = None,
|
98
|
+
compartment_id: str = None,
|
99
|
+
project_id: str = None,
|
100
|
+
description: str = None,
|
101
|
+
bandwidth_mbps: int = None,
|
102
|
+
web_concurrency: int = None,
|
103
|
+
server_port: int = None,
|
104
|
+
health_check_port: int = None,
|
105
|
+
env_var: Dict = None,
|
106
|
+
container_family: str = None,
|
107
|
+
memory_in_gbs: Optional[float] = None,
|
108
|
+
ocpus: Optional[float] = None,
|
109
|
+
model_file: Optional[str] = None,
|
105
110
|
) -> "AquaDeployment":
|
106
111
|
"""
|
107
112
|
Creates a new Aqua deployment
|
@@ -142,6 +147,12 @@ class AquaDeploymentApp(AquaApp):
|
|
142
147
|
Environment variable for the deployment, by default None.
|
143
148
|
container_family: str
|
144
149
|
The image family of model deployment container runtime. Required for unverified Aqua models.
|
150
|
+
memory_in_gbs: float
|
151
|
+
The memory in gbs for the shape selected.
|
152
|
+
ocpus: float
|
153
|
+
The ocpu count for the shape selected.
|
154
|
+
model_file: str
|
155
|
+
The file used for model deployment.
|
145
156
|
Returns
|
146
157
|
-------
|
147
158
|
AquaDeployment
|
@@ -239,7 +250,7 @@ class AquaDeploymentApp(AquaApp):
|
|
239
250
|
try:
|
240
251
|
# Check if the container override flag is set. If set, then the user has chosen custom image
|
241
252
|
if aqua_model.custom_metadata_list.get(
|
242
|
-
|
253
|
+
AQUA_DEPLOYMENT_CONTAINER_OVERRIDE_FLAG_METADATA_NAME
|
243
254
|
).value:
|
244
255
|
is_custom_container = True
|
245
256
|
except Exception:
|
@@ -258,8 +269,36 @@ class AquaDeploymentApp(AquaApp):
|
|
258
269
|
f"Aqua Image used for deploying {aqua_model.id} : {container_image}"
|
259
270
|
)
|
260
271
|
|
272
|
+
model_formats_str = aqua_model.freeform_tags.get(
|
273
|
+
Tags.MODEL_FORMAT, ModelFormat.SAFETENSORS.value
|
274
|
+
).upper()
|
275
|
+
model_format = model_formats_str.split(",")
|
276
|
+
|
277
|
+
# Figure out a better way to handle this in future release
|
278
|
+
if ModelFormat.GGUF.value in model_format and container_type_key.lower() == InferenceContainerTypeFamily.AQUA_LLAMA_CPP_CONTAINER_FAMILY:
|
279
|
+
if model_file is not None:
|
280
|
+
logger.info(
|
281
|
+
f"Overriding {model_file} as model_file for model {aqua_model.id}."
|
282
|
+
)
|
283
|
+
else:
|
284
|
+
try:
|
285
|
+
model_file = aqua_model.custom_metadata_list.get(
|
286
|
+
AQUA_MODEL_ARTIFACT_FILE
|
287
|
+
).value
|
288
|
+
except ValueError as err:
|
289
|
+
raise AquaValueError(
|
290
|
+
f"{AQUA_MODEL_ARTIFACT_FILE} key is not available in the custom metadata field "
|
291
|
+
f"for model {aqua_model.id}. Either register the model with a default model_file or pass "
|
292
|
+
f"as a parameter when creating a deployment."
|
293
|
+
) from err
|
294
|
+
|
295
|
+
env_var.update({"BASE_MODEL_FILE": f"{model_file}"})
|
296
|
+
tags.update({Tags.MODEL_ARTIFACT_FILE: model_file})
|
297
|
+
|
298
|
+
# todo: use AquaContainerConfig.from_container_index_json instead.
|
261
299
|
# Fetch the startup cli command for the container
|
262
|
-
# container_index.json will have "containerSpec" section which will provide the cli params for
|
300
|
+
# container_index.json will have "containerSpec" section which will provide the cli params for
|
301
|
+
# a given container family
|
263
302
|
container_config = get_container_config()
|
264
303
|
container_spec = container_config.get(ContainerSpec.CONTAINER_SPEC, {}).get(
|
265
304
|
container_type_key, {}
|
@@ -285,6 +324,18 @@ class AquaDeploymentApp(AquaApp):
|
|
285
324
|
# validate user provided params
|
286
325
|
user_params = env_var.get("PARAMS", UNKNOWN)
|
287
326
|
if user_params:
|
327
|
+
# todo: remove this check in the future version, logic to be moved to container_index
|
328
|
+
if (
|
329
|
+
container_type_key.lower()
|
330
|
+
== InferenceContainerTypeFamily.AQUA_LLAMA_CPP_CONTAINER_FAMILY
|
331
|
+
):
|
332
|
+
# AQUA_LLAMA_CPP_CONTAINER_FAMILY container uses uvicorn that required model/server params
|
333
|
+
# to be set as env vars
|
334
|
+
raise AquaValueError(
|
335
|
+
f"Currently, parameters cannot be overridden for the container: {container_image}. Please proceed "
|
336
|
+
f"with deployment without parameter overrides."
|
337
|
+
)
|
338
|
+
|
288
339
|
restricted_params = self._find_restricted_params(
|
289
340
|
params, user_params, container_type_key
|
290
341
|
)
|
@@ -296,13 +347,15 @@ class AquaDeploymentApp(AquaApp):
|
|
296
347
|
|
297
348
|
deployment_params = get_combined_params(config_params, user_params)
|
298
349
|
|
299
|
-
|
300
|
-
|
350
|
+
params = f"{params} {deployment_params}".strip()
|
351
|
+
if params:
|
352
|
+
env_var.update({"PARAMS": params})
|
301
353
|
|
302
|
-
env_var.update({"PARAMS": params})
|
303
354
|
for env in container_spec.get(ContainerSpec.ENV_VARS, []):
|
304
355
|
if isinstance(env, dict):
|
305
|
-
|
356
|
+
for key, _items in env.items():
|
357
|
+
if key not in env_var:
|
358
|
+
env_var.update(env)
|
306
359
|
|
307
360
|
logging.info(f"Env vars used for deploying {aqua_model.id} :{env_var}")
|
308
361
|
|
@@ -325,6 +378,11 @@ class AquaDeploymentApp(AquaApp):
|
|
325
378
|
log_id=predict_log_id,
|
326
379
|
)
|
327
380
|
)
|
381
|
+
if memory_in_gbs and ocpus and infrastructure.shape_name.endswith("Flex"):
|
382
|
+
infrastructure.with_shape_config_details(
|
383
|
+
ocpus=ocpus,
|
384
|
+
memory_in_gbs=memory_in_gbs,
|
385
|
+
)
|
328
386
|
# configure model deployment runtime
|
329
387
|
container_runtime = (
|
330
388
|
ModelDeploymentContainerRuntime()
|
@@ -338,6 +396,7 @@ class AquaDeploymentApp(AquaApp):
|
|
338
396
|
.with_overwrite_existing_artifact(True)
|
339
397
|
.with_remove_existing_artifact(True)
|
340
398
|
)
|
399
|
+
|
341
400
|
# configure model deployment and deploy model on container runtime
|
342
401
|
deployment = (
|
343
402
|
ModelDeployment()
|
@@ -401,8 +460,8 @@ class AquaDeploymentApp(AquaApp):
|
|
401
460
|
for model_deployment in model_deployments:
|
402
461
|
oci_aqua = (
|
403
462
|
(
|
404
|
-
|
405
|
-
|
463
|
+
Tags.AQUA_TAG in model_deployment.freeform_tags
|
464
|
+
or Tags.AQUA_TAG.lower() in model_deployment.freeform_tags
|
406
465
|
)
|
407
466
|
if model_deployment.freeform_tags
|
408
467
|
else False
|
@@ -456,8 +515,8 @@ class AquaDeploymentApp(AquaApp):
|
|
456
515
|
|
457
516
|
oci_aqua = (
|
458
517
|
(
|
459
|
-
|
460
|
-
|
518
|
+
Tags.AQUA_TAG in model_deployment.freeform_tags
|
519
|
+
or Tags.AQUA_TAG.lower() in model_deployment.freeform_tags
|
461
520
|
)
|
462
521
|
if model_deployment.freeform_tags
|
463
522
|
else False
|
@@ -474,8 +533,8 @@ class AquaDeploymentApp(AquaApp):
|
|
474
533
|
log_group_name = ""
|
475
534
|
|
476
535
|
logs = (
|
477
|
-
|
478
|
-
|
536
|
+
model_deployment.category_log_details.access
|
537
|
+
or model_deployment.category_log_details.predict
|
479
538
|
)
|
480
539
|
if logs:
|
481
540
|
log_id = logs.log_id
|
@@ -530,9 +589,9 @@ class AquaDeploymentApp(AquaApp):
|
|
530
589
|
return config
|
531
590
|
|
532
591
|
def get_deployment_default_params(
|
533
|
-
|
534
|
-
|
535
|
-
|
592
|
+
self,
|
593
|
+
model_id: str,
|
594
|
+
instance_shape: str,
|
536
595
|
) -> List[str]:
|
537
596
|
"""Gets the default params set in the deployment configs for the given model and instance shape.
|
538
597
|
|
@@ -564,8 +623,8 @@ class AquaDeploymentApp(AquaApp):
|
|
564
623
|
)
|
565
624
|
|
566
625
|
if (
|
567
|
-
|
568
|
-
|
626
|
+
container_type_key
|
627
|
+
and container_type_key in InferenceContainerTypeFamily.values()
|
569
628
|
):
|
570
629
|
deployment_config = self.get_deployment_config(model_id)
|
571
630
|
config_params = (
|
@@ -588,10 +647,10 @@ class AquaDeploymentApp(AquaApp):
|
|
588
647
|
return default_params
|
589
648
|
|
590
649
|
def validate_deployment_params(
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
650
|
+
self,
|
651
|
+
model_id: str,
|
652
|
+
params: List[str] = None,
|
653
|
+
container_family: str = None,
|
595
654
|
) -> Dict:
|
596
655
|
"""Validate if the deployment parameters passed by the user can be overridden. Parameter values are not
|
597
656
|
validated, only param keys are validated.
|
@@ -650,9 +709,9 @@ class AquaDeploymentApp(AquaApp):
|
|
650
709
|
|
651
710
|
@staticmethod
|
652
711
|
def _find_restricted_params(
|
653
|
-
|
654
|
-
|
655
|
-
|
712
|
+
default_params: Union[str, List[str]],
|
713
|
+
user_params: Union[str, List[str]],
|
714
|
+
container_family: str,
|
656
715
|
) -> List[str]:
|
657
716
|
"""Returns a list of restricted params that user chooses to override when creating an Aqua deployment.
|
658
717
|
The default parameters coming from the container index json file cannot be overridden.
|
@@ -1,12 +1,14 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
|
-
# -*- coding: utf-8 -*-
|
3
2
|
# Copyright (c) 2024 Oracle and/or its affiliates.
|
4
3
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
5
4
|
|
6
5
|
from dataclasses import dataclass, field
|
7
6
|
from typing import Union
|
8
7
|
|
9
|
-
from oci.data_science.models import
|
8
|
+
from oci.data_science.models import (
|
9
|
+
ModelDeployment,
|
10
|
+
ModelDeploymentSummary,
|
11
|
+
)
|
10
12
|
|
11
13
|
from ads.aqua.common.enums import Tags
|
12
14
|
from ads.aqua.constants import UNKNOWN, UNKNOWN_DICT
|
@@ -24,18 +26,6 @@ class ModelParams:
|
|
24
26
|
model: str = None
|
25
27
|
|
26
28
|
|
27
|
-
class ContainerSpec:
|
28
|
-
"""
|
29
|
-
Class to hold to hold keys within the container spec.
|
30
|
-
"""
|
31
|
-
|
32
|
-
CONTAINER_SPEC = "containerSpec"
|
33
|
-
CLI_PARM = "cliParam"
|
34
|
-
SERVER_PORT = "serverPort"
|
35
|
-
HEALTH_CHECK_PORT = "healthCheckPort"
|
36
|
-
ENV_VARS = "envVars"
|
37
|
-
|
38
|
-
|
39
29
|
@dataclass
|
40
30
|
class ShapeInfo:
|
41
31
|
instance_shape: str = None
|
@@ -61,6 +51,7 @@ class AquaDeployment(DataClassSerializable):
|
|
61
51
|
lifecycle_details: str = None
|
62
52
|
shape_info: field(default_factory=ShapeInfo) = None
|
63
53
|
tags: dict = None
|
54
|
+
environment_variables: dict = None
|
64
55
|
|
65
56
|
@classmethod
|
66
57
|
def from_oci_model_deployment(
|
@@ -83,15 +74,12 @@ class AquaDeployment(DataClassSerializable):
|
|
83
74
|
AquaDeployment:
|
84
75
|
The instance of the Aqua model deployment.
|
85
76
|
"""
|
86
|
-
instance_configuration =
|
87
|
-
oci_model_deployment.model_deployment_configuration_details.model_configuration_details.instance_configuration
|
88
|
-
)
|
77
|
+
instance_configuration = oci_model_deployment.model_deployment_configuration_details.model_configuration_details.instance_configuration
|
89
78
|
instance_shape_config_details = (
|
90
79
|
instance_configuration.model_deployment_instance_shape_config_details
|
91
80
|
)
|
92
|
-
instance_count =
|
93
|
-
|
94
|
-
)
|
81
|
+
instance_count = oci_model_deployment.model_deployment_configuration_details.model_configuration_details.scaling_policy.instance_count
|
82
|
+
environment_variables = oci_model_deployment.model_deployment_configuration_details.environment_configuration_details.environment_variables
|
95
83
|
shape_info = ShapeInfo(
|
96
84
|
instance_shape=instance_configuration.instance_shape_name,
|
97
85
|
instance_count=instance_count,
|
@@ -131,6 +119,7 @@ class AquaDeployment(DataClassSerializable):
|
|
131
119
|
region=region,
|
132
120
|
),
|
133
121
|
tags=freeform_tags,
|
122
|
+
environment_variables=environment_variables,
|
134
123
|
)
|
135
124
|
|
136
125
|
|
ads/aqua/ui.py
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
|
-
# -*- coding: utf-8 -*-
|
3
2
|
# Copyright (c) 2024 Oracle and/or its affiliates.
|
4
3
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
5
4
|
import concurrent.futures
|
6
|
-
from dataclasses import dataclass, field
|
5
|
+
from dataclasses import dataclass, field, fields
|
7
6
|
from datetime import datetime, timedelta
|
7
|
+
from enum import Enum
|
8
8
|
from threading import Lock
|
9
|
-
from typing import Dict, List
|
9
|
+
from typing import Dict, List, Optional
|
10
10
|
|
11
11
|
from cachetools import TTLCache
|
12
12
|
from oci.exceptions import ServiceError
|
@@ -14,6 +14,7 @@ from oci.identity.models import Compartment
|
|
14
14
|
|
15
15
|
from ads.aqua import logger
|
16
16
|
from ads.aqua.app import AquaApp
|
17
|
+
from ads.aqua.common.entities import ContainerSpec
|
17
18
|
from ads.aqua.common.enums import Tags
|
18
19
|
from ads.aqua.common.errors import AquaResourceAccessError, AquaValueError
|
19
20
|
from ads.aqua.common.utils import get_container_config, load_config, sanitize_response
|
@@ -31,14 +32,84 @@ from ads.config import (
|
|
31
32
|
from ads.telemetry import telemetry
|
32
33
|
|
33
34
|
|
35
|
+
class ModelFormat(Enum):
|
36
|
+
GGUF = "GGUF"
|
37
|
+
SAFETENSORS = "SAFETENSORS"
|
38
|
+
UNKNOWN = "UNKNOWN"
|
39
|
+
|
40
|
+
def to_dict(self):
|
41
|
+
return self.value
|
42
|
+
|
43
|
+
|
44
|
+
# todo: the container config spec information is shared across ui and deployment modules, move them
|
45
|
+
# within ads.aqua.common.entities. In that case, check for circular imports due to usage of get_container_config.
|
46
|
+
|
47
|
+
|
48
|
+
@dataclass(repr=False)
|
49
|
+
class AquaContainerEvaluationConfig(DataClassSerializable):
|
50
|
+
"""
|
51
|
+
Represents the evaluation configuration for the container.
|
52
|
+
"""
|
53
|
+
|
54
|
+
inference_max_threads: Optional[int] = None
|
55
|
+
inference_rps: Optional[int] = None
|
56
|
+
inference_timeout: Optional[int] = None
|
57
|
+
inference_retries: Optional[int] = None
|
58
|
+
inference_backoff_factor: Optional[int] = None
|
59
|
+
inference_delay: Optional[int] = None
|
60
|
+
|
61
|
+
@classmethod
|
62
|
+
def from_config(cls, config: dict) -> "AquaContainerEvaluationConfig":
|
63
|
+
return cls(
|
64
|
+
inference_max_threads=config.get("inference_max_threads"),
|
65
|
+
inference_rps=config.get("inference_rps"),
|
66
|
+
inference_timeout=config.get("inference_timeout"),
|
67
|
+
inference_retries=config.get("inference_retries"),
|
68
|
+
inference_backoff_factor=config.get("inference_backoff_factor"),
|
69
|
+
inference_delay=config.get("inference_delay"),
|
70
|
+
)
|
71
|
+
|
72
|
+
def to_filtered_dict(self):
|
73
|
+
return {
|
74
|
+
field.name: getattr(self, field.name)
|
75
|
+
for field in fields(self)
|
76
|
+
if getattr(self, field.name) is not None
|
77
|
+
}
|
78
|
+
|
79
|
+
|
80
|
+
@dataclass(repr=False)
|
81
|
+
class AquaContainerConfigSpec(DataClassSerializable):
|
82
|
+
cli_param: str = None
|
83
|
+
server_port: str = None
|
84
|
+
health_check_port: str = None
|
85
|
+
env_vars: List[dict] = None
|
86
|
+
restricted_params: List[str] = None
|
87
|
+
evaluation_configuration: AquaContainerEvaluationConfig = field(
|
88
|
+
default_factory=AquaContainerEvaluationConfig
|
89
|
+
)
|
90
|
+
|
91
|
+
|
34
92
|
@dataclass(repr=False)
|
35
93
|
class AquaContainerConfigItem(DataClassSerializable):
|
36
94
|
"""Represents an item of the AQUA container configuration."""
|
37
95
|
|
96
|
+
class Platform(Enum):
|
97
|
+
ARM_CPU = "ARM_CPU"
|
98
|
+
NVIDIA_GPU = "NVIDIA_GPU"
|
99
|
+
|
100
|
+
def to_dict(self):
|
101
|
+
return self.value
|
102
|
+
|
103
|
+
def __repr__(self):
|
104
|
+
return repr(self.value)
|
105
|
+
|
38
106
|
name: str = None
|
39
107
|
version: str = None
|
40
108
|
display_name: str = None
|
41
109
|
family: str = None
|
110
|
+
platforms: List[Platform] = None
|
111
|
+
model_formats: List[ModelFormat] = None
|
112
|
+
spec: AquaContainerConfigSpec = field(default_factory=AquaContainerConfigSpec)
|
42
113
|
|
43
114
|
|
44
115
|
@dataclass(repr=False)
|
@@ -47,12 +118,23 @@ class AquaContainerConfig(DataClassSerializable):
|
|
47
118
|
Represents a configuration with AQUA containers to be returned to the client.
|
48
119
|
"""
|
49
120
|
|
50
|
-
inference:
|
51
|
-
finetune:
|
52
|
-
evaluate:
|
121
|
+
inference: Dict[str, AquaContainerConfigItem] = field(default_factory=dict)
|
122
|
+
finetune: Dict[str, AquaContainerConfigItem] = field(default_factory=dict)
|
123
|
+
evaluate: Dict[str, AquaContainerConfigItem] = field(default_factory=dict)
|
124
|
+
|
125
|
+
def to_dict(self):
|
126
|
+
return {
|
127
|
+
"inference": list(self.inference.values()),
|
128
|
+
"finetune": list(self.finetune.values()),
|
129
|
+
"evaluate": list(self.evaluate.values()),
|
130
|
+
}
|
53
131
|
|
54
132
|
@classmethod
|
55
|
-
def from_container_index_json(
|
133
|
+
def from_container_index_json(
|
134
|
+
cls,
|
135
|
+
config: Optional[Dict] = None,
|
136
|
+
enable_spec: Optional[bool] = False,
|
137
|
+
) -> "AquaContainerConfig":
|
56
138
|
"""
|
57
139
|
Create an AquaContainerConfig instance from a container index JSON.
|
58
140
|
|
@@ -60,21 +142,39 @@ class AquaContainerConfig(DataClassSerializable):
|
|
60
142
|
----------
|
61
143
|
config : Dict
|
62
144
|
The container index JSON.
|
145
|
+
enable_spec: bool
|
146
|
+
flag to check if container specification details should be fetched.
|
63
147
|
|
64
148
|
Returns
|
65
149
|
-------
|
66
150
|
AquaContainerConfig
|
67
151
|
The container configuration instance.
|
68
152
|
"""
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
153
|
+
if not config:
|
154
|
+
config = get_container_config()
|
155
|
+
inference_items = {}
|
156
|
+
finetune_items = {}
|
157
|
+
evaluate_items = {}
|
73
158
|
|
74
159
|
# extract inference containers
|
75
160
|
for container_type, containers in config.items():
|
76
161
|
if isinstance(containers, list):
|
77
162
|
for container in containers:
|
163
|
+
platforms = [
|
164
|
+
AquaContainerConfigItem.Platform[platform]
|
165
|
+
for platform in container.get("platforms", [])
|
166
|
+
]
|
167
|
+
model_formats = [
|
168
|
+
ModelFormat[model_format]
|
169
|
+
for model_format in container.get("modelFormats", [])
|
170
|
+
]
|
171
|
+
container_spec = (
|
172
|
+
config.get(ContainerSpec.CONTAINER_SPEC, {}).get(
|
173
|
+
container_type, {}
|
174
|
+
)
|
175
|
+
if enable_spec
|
176
|
+
else None
|
177
|
+
)
|
78
178
|
container_item = AquaContainerConfigItem(
|
79
179
|
name=container.get("name", ""),
|
80
180
|
version=container.get("version", ""),
|
@@ -82,13 +182,35 @@ class AquaContainerConfig(DataClassSerializable):
|
|
82
182
|
"displayName", container.get("version", "")
|
83
183
|
),
|
84
184
|
family=container_type,
|
185
|
+
platforms=platforms,
|
186
|
+
model_formats=model_formats,
|
187
|
+
spec=AquaContainerConfigSpec(
|
188
|
+
cli_param=container_spec.get(ContainerSpec.CLI_PARM, ""),
|
189
|
+
server_port=container_spec.get(
|
190
|
+
ContainerSpec.SERVER_PORT, ""
|
191
|
+
),
|
192
|
+
health_check_port=container_spec.get(
|
193
|
+
ContainerSpec.HEALTH_CHECK_PORT, ""
|
194
|
+
),
|
195
|
+
env_vars=container_spec.get(ContainerSpec.ENV_VARS, []),
|
196
|
+
restricted_params=container_spec.get(
|
197
|
+
ContainerSpec.RESTRICTED_PARAMS, []
|
198
|
+
),
|
199
|
+
evaluation_configuration=AquaContainerEvaluationConfig.from_config(
|
200
|
+
container_spec.get(
|
201
|
+
ContainerSpec.EVALUATION_CONFIGURATION, {}
|
202
|
+
)
|
203
|
+
),
|
204
|
+
)
|
205
|
+
if container_spec
|
206
|
+
else None,
|
85
207
|
)
|
86
208
|
if container.get("type") == "inference":
|
87
|
-
inference_items
|
209
|
+
inference_items[container_type] = container_item
|
88
210
|
elif container_type == "odsc-llm-fine-tuning":
|
89
|
-
finetune_items
|
211
|
+
finetune_items[container_type] = container_item
|
90
212
|
elif container_type == "odsc-llm-evaluate":
|
91
|
-
evaluate_items
|
213
|
+
evaluate_items[container_type] = container_item
|
92
214
|
|
93
215
|
return AquaContainerConfig(
|
94
216
|
inference=inference_items, finetune=finetune_items, evaluate=evaluate_items
|
@@ -175,11 +297,11 @@ class AquaUIApp(AquaApp):
|
|
175
297
|
try:
|
176
298
|
if not TENANCY_OCID:
|
177
299
|
raise AquaValueError(
|
178
|
-
|
300
|
+
"TENANCY_OCID must be available in environment"
|
179
301
|
" variables to list the sub compartments."
|
180
302
|
)
|
181
303
|
|
182
|
-
if TENANCY_OCID in self._compartments_cache
|
304
|
+
if TENANCY_OCID in self._compartments_cache:
|
183
305
|
logger.info(
|
184
306
|
f"Returning compartments list in {TENANCY_OCID} from cache."
|
185
307
|
)
|
@@ -196,7 +318,7 @@ class AquaUIApp(AquaApp):
|
|
196
318
|
access_level="ANY",
|
197
319
|
)
|
198
320
|
)
|
199
|
-
except ServiceError
|
321
|
+
except ServiceError:
|
200
322
|
logger.error(
|
201
323
|
f"ERROR: Unable to list all sub compartment in tenancy {TENANCY_OCID}."
|
202
324
|
)
|
@@ -207,7 +329,7 @@ class AquaUIApp(AquaApp):
|
|
207
329
|
compartment_id=TENANCY_OCID,
|
208
330
|
)
|
209
331
|
)
|
210
|
-
except ServiceError
|
332
|
+
except ServiceError:
|
211
333
|
logger.error(
|
212
334
|
f"ERROR: Unable to list all child compartment in tenancy {TENANCY_OCID}."
|
213
335
|
)
|
@@ -216,7 +338,7 @@ class AquaUIApp(AquaApp):
|
|
216
338
|
TENANCY_OCID
|
217
339
|
).data
|
218
340
|
compartments.insert(0, root_compartment)
|
219
|
-
except ServiceError
|
341
|
+
except ServiceError:
|
220
342
|
logger.error(
|
221
343
|
f"ERROR: Unable to get details of the root compartment {TENANCY_OCID}."
|
222
344
|
)
|
@@ -248,7 +370,7 @@ class AquaUIApp(AquaApp):
|
|
248
370
|
"""
|
249
371
|
if not COMPARTMENT_OCID:
|
250
372
|
logger.error("No compartment id found from environment variables.")
|
251
|
-
return
|
373
|
+
return {"compartment_id": COMPARTMENT_OCID}
|
252
374
|
|
253
375
|
def clear_compartments_list_cache(self) -> dict:
|
254
376
|
"""Allows caller to clear compartments list cache
|
@@ -257,9 +379,9 @@ class AquaUIApp(AquaApp):
|
|
257
379
|
dict with the key used, and True if cache has the key that needs to be deleted.
|
258
380
|
"""
|
259
381
|
res = {}
|
260
|
-
logger.info(
|
382
|
+
logger.info("Clearing list_compartments cache")
|
261
383
|
with self._cache_lock:
|
262
|
-
if TENANCY_OCID in self._compartments_cache
|
384
|
+
if TENANCY_OCID in self._compartments_cache:
|
263
385
|
self._compartments_cache.pop(key=TENANCY_OCID)
|
264
386
|
res = {
|
265
387
|
"key": {
|
@@ -332,6 +454,7 @@ class AquaUIApp(AquaApp):
|
|
332
454
|
response = os_client.list_buckets(
|
333
455
|
namespace_name=namespace_name,
|
334
456
|
compartment_id=compartment_id,
|
457
|
+
limit=1000,
|
335
458
|
**kwargs,
|
336
459
|
).data
|
337
460
|
|
@@ -474,16 +597,16 @@ class AquaUIApp(AquaApp):
|
|
474
597
|
raise AquaResourceAccessError(
|
475
598
|
f"Could not check limits availability for the shape {instance_shape}. Make sure you have the necessary policy to check limits availability.",
|
476
599
|
service_payload=se.args[0] if se.args else None,
|
477
|
-
)
|
600
|
+
) from None
|
478
601
|
|
479
602
|
available = res.available
|
480
603
|
|
481
604
|
try:
|
482
605
|
cards = int(instance_shape.split(".")[-1])
|
483
|
-
except:
|
606
|
+
except Exception:
|
484
607
|
cards = 1
|
485
608
|
|
486
|
-
response =
|
609
|
+
response = {"available_count": available}
|
487
610
|
|
488
611
|
if available < cards:
|
489
612
|
raise AquaValueError(
|
@@ -516,7 +639,7 @@ class AquaUIApp(AquaApp):
|
|
516
639
|
is_versioned = False
|
517
640
|
message = f"Model artifact bucket {bucket_uri} is not versioned. Check if the path exists and enable versioning on the bucket to proceed with model creation."
|
518
641
|
|
519
|
-
return
|
642
|
+
return {"is_versioned": is_versioned, "message": message}
|
520
643
|
|
521
644
|
@telemetry(entry_point="plugin=ui&action=list_containers", name="aqua")
|
522
645
|
def list_containers(self) -> AquaContainerConfig:
|
@@ -526,8 +649,9 @@ class AquaUIApp(AquaApp):
|
|
526
649
|
Returns
|
527
650
|
-------
|
528
651
|
AquaContainerConfig
|
529
|
-
The AQUA containers
|
652
|
+
The AQUA containers configurations.
|
530
653
|
"""
|
531
654
|
return AquaContainerConfig.from_container_index_json(
|
532
|
-
config=get_container_config()
|
655
|
+
config=get_container_config(),
|
656
|
+
enable_spec=True,
|
533
657
|
)
|