oracle-ads 2.13.5__py3-none-any.whl → 2.13.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.
- ads/aqua/__init__.py +0 -5
- ads/aqua/app.py +133 -20
- ads/aqua/cli.py +2 -15
- ads/aqua/common/enums.py +14 -0
- ads/aqua/common/utils.py +50 -83
- ads/aqua/config/container_config.py +105 -69
- ads/aqua/config/evaluation/evaluation_service_config.py +40 -0
- ads/aqua/constants.py +22 -20
- ads/aqua/evaluation/evaluation.py +98 -32
- ads/aqua/extension/common_handler.py +3 -12
- ads/aqua/extension/common_ws_msg_handler.py +3 -24
- ads/aqua/extension/model_handler.py +59 -6
- ads/aqua/extension/models/ws_models.py +2 -0
- ads/aqua/extension/models_ws_msg_handler.py +1 -0
- ads/aqua/extension/utils.py +11 -24
- ads/aqua/finetuning/entities.py +23 -1
- ads/aqua/finetuning/finetuning.py +26 -10
- ads/aqua/model/constants.py +8 -0
- ads/aqua/model/entities.py +8 -1
- ads/aqua/model/model.py +286 -111
- ads/aqua/modeldeployment/deployment.py +51 -47
- ads/aqua/modeldeployment/utils.py +23 -5
- ads/aqua/ui.py +3 -4
- ads/config.py +2 -2
- ads/dataset/recommendation.py +11 -20
- ads/model/datascience_model.py +29 -0
- ads/model/service/oci_datascience_model.py +1 -1
- ads/opctl/operator/lowcode/anomaly/model/anomaly_dataset.py +8 -6
- ads/opctl/operator/lowcode/anomaly/model/base_model.py +1 -1
- ads/opctl/operator/lowcode/anomaly/operator_config.py +5 -3
- ads/opctl/operator/lowcode/common/transformations.py +2 -0
- ads/opctl/operator/lowcode/forecast/model/automlx.py +29 -0
- ads/opctl/operator/lowcode/pii/model/report.py +9 -16
- ads/opctl/utils.py +1 -1
- ads/type_discovery/typed_feature.py +32 -34
- {oracle_ads-2.13.5.dist-info → oracle_ads-2.13.7.dist-info}/METADATA +1 -1
- {oracle_ads-2.13.5.dist-info → oracle_ads-2.13.7.dist-info}/RECORD +40 -41
- ads/aqua/config/config.py +0 -31
- {oracle_ads-2.13.5.dist-info → oracle_ads-2.13.7.dist-info}/WHEEL +0 -0
- {oracle_ads-2.13.5.dist-info → oracle_ads-2.13.7.dist-info}/entry_points.txt +0 -0
- {oracle_ads-2.13.5.dist-info → oracle_ads-2.13.7.dist-info}/licenses/LICENSE.txt +0 -0
ads/aqua/__init__.py
CHANGED
@@ -14,7 +14,6 @@ from ads.aqua.client.client import (
|
|
14
14
|
get_async_httpx_client,
|
15
15
|
get_httpx_client,
|
16
16
|
)
|
17
|
-
from ads.aqua.common.utils import fetch_service_compartment
|
18
17
|
from ads.config import OCI_RESOURCE_PRINCIPAL_VERSION
|
19
18
|
|
20
19
|
ENV_VAR_LOG_LEVEL = "ADS_AQUA_LOG_LEVEL"
|
@@ -39,7 +38,3 @@ def set_log_level(log_level: str):
|
|
39
38
|
|
40
39
|
if OCI_RESOURCE_PRINCIPAL_VERSION:
|
41
40
|
set_auth("resource_principal")
|
42
|
-
|
43
|
-
ODSC_MODEL_COMPARTMENT_OCID = (
|
44
|
-
os.environ.get("ODSC_MODEL_COMPARTMENT_OCID") or fetch_service_compartment()
|
45
|
-
)
|
ads/aqua/app.py
CHANGED
@@ -7,11 +7,16 @@ import os
|
|
7
7
|
import traceback
|
8
8
|
from dataclasses import fields
|
9
9
|
from datetime import datetime, timedelta
|
10
|
-
from
|
10
|
+
from itertools import chain
|
11
|
+
from typing import Any, Dict, List, Optional, Union
|
11
12
|
|
12
13
|
import oci
|
13
14
|
from cachetools import TTLCache, cached
|
14
|
-
from oci.data_science.models import
|
15
|
+
from oci.data_science.models import (
|
16
|
+
ContainerSummary,
|
17
|
+
UpdateModelDetails,
|
18
|
+
UpdateModelProvenanceDetails,
|
19
|
+
)
|
15
20
|
|
16
21
|
from ads import set_auth
|
17
22
|
from ads.aqua import logger
|
@@ -24,6 +29,11 @@ from ads.aqua.common.utils import (
|
|
24
29
|
is_valid_ocid,
|
25
30
|
load_config,
|
26
31
|
)
|
32
|
+
from ads.aqua.config.container_config import (
|
33
|
+
AquaContainerConfig,
|
34
|
+
AquaContainerConfigItem,
|
35
|
+
)
|
36
|
+
from ads.aqua.constants import SERVICE_MANAGED_CONTAINER_URI_SCHEME
|
27
37
|
from ads.common import oci_client as oc
|
28
38
|
from ads.common.auth import default_signer
|
29
39
|
from ads.common.utils import UNKNOWN, extract_region, is_path_exists
|
@@ -240,7 +250,9 @@ class AquaApp:
|
|
240
250
|
.with_custom_metadata_list(model_custom_metadata)
|
241
251
|
.with_defined_metadata_list(model_taxonomy_metadata)
|
242
252
|
.with_provenance_metadata(ModelProvenanceMetadata(training_id=UNKNOWN))
|
243
|
-
.with_defined_tags(
|
253
|
+
.with_defined_tags(
|
254
|
+
**(defined_tags or {})
|
255
|
+
) # Create defined tags when a model is created.
|
244
256
|
.create(
|
245
257
|
**kwargs,
|
246
258
|
)
|
@@ -271,6 +283,43 @@ class AquaApp:
|
|
271
283
|
logger.info(f"Artifact not found in model {model_id}.")
|
272
284
|
return False
|
273
285
|
|
286
|
+
def get_config_from_metadata(
|
287
|
+
self, model_id: str, metadata_key: str
|
288
|
+
) -> ModelConfigResult:
|
289
|
+
"""Gets the config for the given Aqua model from model catalog metadata content.
|
290
|
+
|
291
|
+
Parameters
|
292
|
+
----------
|
293
|
+
model_id: str
|
294
|
+
The OCID of the Aqua model.
|
295
|
+
metadata_key: str
|
296
|
+
The metadata key name where artifact content is stored
|
297
|
+
Returns
|
298
|
+
-------
|
299
|
+
ModelConfigResult
|
300
|
+
A Pydantic model containing the model_details (extracted from OCI) and the config dictionary.
|
301
|
+
"""
|
302
|
+
config = {}
|
303
|
+
oci_model = self.ds_client.get_model(model_id).data
|
304
|
+
try:
|
305
|
+
config = self.ds_client.get_model_defined_metadatum_artifact_content(
|
306
|
+
model_id, metadata_key
|
307
|
+
).data.content.decode("utf-8")
|
308
|
+
return ModelConfigResult(config=json.loads(config), model_details=oci_model)
|
309
|
+
except UnicodeDecodeError as ex:
|
310
|
+
logger.error(
|
311
|
+
f"Failed to decode content for '{metadata_key}' in defined metadata for model '{model_id}' : {ex}"
|
312
|
+
)
|
313
|
+
except json.JSONDecodeError as ex:
|
314
|
+
logger.error(
|
315
|
+
f"Invalid JSON format for '{metadata_key}' in defined metadata for model '{model_id}' : {ex}"
|
316
|
+
)
|
317
|
+
except Exception as ex:
|
318
|
+
logger.error(
|
319
|
+
f"Failed to retrieve defined metadata key '{metadata_key}' for model '{model_id}': {ex}"
|
320
|
+
)
|
321
|
+
return ModelConfigResult(config=config, model_details=oci_model)
|
322
|
+
|
274
323
|
@cached(cache=TTLCache(maxsize=1, ttl=timedelta(minutes=1), timer=datetime.now))
|
275
324
|
def get_config(
|
276
325
|
self,
|
@@ -310,22 +359,7 @@ class AquaApp:
|
|
310
359
|
raise AquaRuntimeError(f"Target model {oci_model.id} is not an Aqua model.")
|
311
360
|
|
312
361
|
config: Dict[str, Any] = {}
|
313
|
-
|
314
|
-
# if the current model has a service model tag, then
|
315
|
-
if Tags.AQUA_SERVICE_MODEL_TAG in oci_model.freeform_tags:
|
316
|
-
base_model_ocid = oci_model.freeform_tags[Tags.AQUA_SERVICE_MODEL_TAG]
|
317
|
-
logger.info(
|
318
|
-
f"Base model found for the model: {oci_model.id}. "
|
319
|
-
f"Loading {config_file_name} for base model {base_model_ocid}."
|
320
|
-
)
|
321
|
-
if config_folder == ConfigFolder.ARTIFACT:
|
322
|
-
artifact_path = get_artifact_path(oci_model.custom_metadata_list)
|
323
|
-
else:
|
324
|
-
base_model = self.ds_client.get_model(base_model_ocid).data
|
325
|
-
artifact_path = get_artifact_path(base_model.custom_metadata_list)
|
326
|
-
else:
|
327
|
-
logger.info(f"Loading {config_file_name} for model {oci_model.id}...")
|
328
|
-
artifact_path = get_artifact_path(oci_model.custom_metadata_list)
|
362
|
+
artifact_path = get_artifact_path(oci_model.custom_metadata_list)
|
329
363
|
if not artifact_path:
|
330
364
|
logger.debug(
|
331
365
|
f"Failed to get artifact path from custom metadata for the model: {model_id}"
|
@@ -340,7 +374,7 @@ class AquaApp:
|
|
340
374
|
config_file_path = os.path.join(config_path, config_file_name)
|
341
375
|
if is_path_exists(config_file_path):
|
342
376
|
try:
|
343
|
-
logger.
|
377
|
+
logger.info(
|
344
378
|
f"Loading config: `{config_file_name}` from `{config_path}`"
|
345
379
|
)
|
346
380
|
config = load_config(
|
@@ -361,6 +395,85 @@ class AquaApp:
|
|
361
395
|
|
362
396
|
return ModelConfigResult(config=config, model_details=oci_model)
|
363
397
|
|
398
|
+
def get_container_image(self, container_type: str = None) -> str:
|
399
|
+
"""
|
400
|
+
Gets the latest smc container complete image name from the given container type.
|
401
|
+
|
402
|
+
Parameters
|
403
|
+
----------
|
404
|
+
container_type: str
|
405
|
+
type of container, can be either odsc-vllm-serving, odsc-llm-fine-tuning, odsc-llm-evaluate
|
406
|
+
|
407
|
+
Returns
|
408
|
+
-------
|
409
|
+
str:
|
410
|
+
A complete container name along with version. ex: dsmc://odsc-vllm-serving:0.7.4.1
|
411
|
+
"""
|
412
|
+
|
413
|
+
containers = self.list_service_containers()
|
414
|
+
container = next(
|
415
|
+
(c for c in containers if c.is_latest and c.family_name == container_type),
|
416
|
+
None,
|
417
|
+
)
|
418
|
+
if not container:
|
419
|
+
raise AquaValueError(f"Invalid container type : {container_type}")
|
420
|
+
container_image = (
|
421
|
+
SERVICE_MANAGED_CONTAINER_URI_SCHEME
|
422
|
+
+ container.container_name
|
423
|
+
+ ":"
|
424
|
+
+ container.tag
|
425
|
+
)
|
426
|
+
return container_image
|
427
|
+
|
428
|
+
@cached(cache=TTLCache(maxsize=20, ttl=timedelta(minutes=30), timer=datetime.now))
|
429
|
+
def list_service_containers(self) -> List[ContainerSummary]:
|
430
|
+
"""
|
431
|
+
List containers from containers.conf in OCI Datascience control plane
|
432
|
+
"""
|
433
|
+
containers = self.ds_client.list_containers().data
|
434
|
+
return containers
|
435
|
+
|
436
|
+
def get_container_config(self) -> AquaContainerConfig:
|
437
|
+
"""
|
438
|
+
Fetches latest containers from containers.conf in OCI Datascience control plane
|
439
|
+
|
440
|
+
Returns
|
441
|
+
-------
|
442
|
+
AquaContainerConfig
|
443
|
+
An Object that contains latest container info for the given container family
|
444
|
+
|
445
|
+
"""
|
446
|
+
return AquaContainerConfig.from_service_config(
|
447
|
+
service_containers=self.list_service_containers()
|
448
|
+
)
|
449
|
+
|
450
|
+
def get_container_config_item(
|
451
|
+
self, container_family: str
|
452
|
+
) -> AquaContainerConfigItem:
|
453
|
+
"""
|
454
|
+
Fetches latest container for given container_family_name from containers.conf in OCI Datascience control plane
|
455
|
+
|
456
|
+
Returns
|
457
|
+
-------
|
458
|
+
AquaContainerConfigItem
|
459
|
+
An Object that contains latest container info for the given container family
|
460
|
+
|
461
|
+
"""
|
462
|
+
|
463
|
+
aqua_container_config = self.get_container_config()
|
464
|
+
inference_config = aqua_container_config.inference.values()
|
465
|
+
ft_config = aqua_container_config.finetune.values()
|
466
|
+
eval_config = aqua_container_config.evaluate.values()
|
467
|
+
container = next(
|
468
|
+
(
|
469
|
+
container
|
470
|
+
for container in chain(inference_config, ft_config, eval_config)
|
471
|
+
if container.family.lower() == container_family.lower()
|
472
|
+
),
|
473
|
+
None,
|
474
|
+
)
|
475
|
+
return container
|
476
|
+
|
364
477
|
@property
|
365
478
|
def telemetry(self):
|
366
479
|
if not self._telemetry:
|
ads/aqua/cli.py
CHANGED
@@ -1,23 +1,20 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
|
-
# -*- coding: utf-8 -*--
|
3
2
|
|
4
|
-
# Copyright (c) 2024 Oracle and/or its affiliates.
|
3
|
+
# Copyright (c) 2024, 2025 Oracle and/or its affiliates.
|
5
4
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
6
5
|
import os
|
7
6
|
|
8
7
|
from ads.aqua import (
|
9
8
|
ENV_VAR_LOG_LEVEL,
|
10
|
-
ODSC_MODEL_COMPARTMENT_OCID,
|
11
9
|
logger,
|
12
10
|
set_log_level,
|
13
11
|
)
|
14
|
-
from ads.aqua.common.errors import AquaCLIError
|
12
|
+
from ads.aqua.common.errors import AquaCLIError
|
15
13
|
from ads.aqua.evaluation import AquaEvaluationApp
|
16
14
|
from ads.aqua.finetuning import AquaFineTuningApp
|
17
15
|
from ads.aqua.model import AquaModelApp
|
18
16
|
from ads.aqua.modeldeployment import AquaDeploymentApp
|
19
17
|
from ads.common.utils import LOG_LEVELS
|
20
|
-
from ads.config import NB_SESSION_OCID
|
21
18
|
|
22
19
|
|
23
20
|
class AquaCommand:
|
@@ -82,16 +79,6 @@ class AquaCommand:
|
|
82
79
|
|
83
80
|
set_log_level(aqua_log_level)
|
84
81
|
|
85
|
-
if not ODSC_MODEL_COMPARTMENT_OCID:
|
86
|
-
if NB_SESSION_OCID:
|
87
|
-
raise AquaConfigError(
|
88
|
-
f"Aqua is not available for the notebook session {NB_SESSION_OCID}. For more information, "
|
89
|
-
f"please refer to the documentation."
|
90
|
-
)
|
91
|
-
raise AquaConfigError(
|
92
|
-
"ODSC_MODEL_COMPARTMENT_OCID environment variable is not set for Aqua."
|
93
|
-
)
|
94
|
-
|
95
82
|
@staticmethod
|
96
83
|
def _validate_value(flag, value):
|
97
84
|
"""Check if the given value for bool flag is valid.
|
ads/aqua/common/enums.py
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
# Copyright (c) 2024, 2025 Oracle and/or its affiliates.
|
3
3
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
4
4
|
|
5
|
+
from typing import Dict, List
|
6
|
+
|
5
7
|
from ads.common.extended_enum import ExtendedEnum
|
6
8
|
|
7
9
|
|
@@ -106,3 +108,15 @@ class ModelFormat(ExtendedEnum):
|
|
106
108
|
class Platform(ExtendedEnum):
|
107
109
|
ARM_CPU = "ARM_CPU"
|
108
110
|
NVIDIA_GPU = "NVIDIA_GPU"
|
111
|
+
|
112
|
+
|
113
|
+
# This dictionary defines compatibility groups for container families.
|
114
|
+
# The structure is:
|
115
|
+
# - Key: The preferred container family to use when multiple compatible families are selected.
|
116
|
+
# - Value: A list of all compatible families (including the preferred one).
|
117
|
+
CONTAINER_FAMILY_COMPATIBILITY: Dict[str, List[str]] = {
|
118
|
+
InferenceContainerTypeFamily.AQUA_VLLM_V1_CONTAINER_FAMILY: [
|
119
|
+
InferenceContainerTypeFamily.AQUA_VLLM_V1_CONTAINER_FAMILY,
|
120
|
+
InferenceContainerTypeFamily.AQUA_VLLM_CONTAINER_FAMILY,
|
121
|
+
],
|
122
|
+
}
|
ads/aqua/common/utils.py
CHANGED
@@ -37,6 +37,7 @@ from pydantic import BaseModel, ValidationError
|
|
37
37
|
|
38
38
|
from ads.aqua.common.entities import GPUShapesIndex
|
39
39
|
from ads.aqua.common.enums import (
|
40
|
+
CONTAINER_FAMILY_COMPATIBILITY,
|
40
41
|
InferenceContainerParamType,
|
41
42
|
InferenceContainerType,
|
42
43
|
RqsAdditionalDetails,
|
@@ -49,12 +50,14 @@ from ads.aqua.common.errors import (
|
|
49
50
|
)
|
50
51
|
from ads.aqua.constants import (
|
51
52
|
AQUA_GA_LIST,
|
52
|
-
COMPARTMENT_MAPPING_KEY,
|
53
53
|
CONSOLE_LINK_RESOURCE_TYPE_MAPPING,
|
54
|
-
|
54
|
+
DEPLOYMENT_CONFIG,
|
55
|
+
FINE_TUNING_CONFIG,
|
55
56
|
HF_LOGIN_DEFAULT_TIMEOUT,
|
57
|
+
LICENSE,
|
56
58
|
MAXIMUM_ALLOWED_DATASET_IN_BYTE,
|
57
59
|
MODEL_BY_REFERENCE_OSS_PATH_KEY,
|
60
|
+
README,
|
58
61
|
SERVICE_MANAGED_CONTAINER_URI_SCHEME,
|
59
62
|
SUPPORTED_FILE_FORMATS,
|
60
63
|
TEI_CONTAINER_DEFAULT_HOST,
|
@@ -88,6 +91,14 @@ from ads.model import DataScienceModel, ModelVersionSet
|
|
88
91
|
logger = logging.getLogger("ads.aqua")
|
89
92
|
|
90
93
|
|
94
|
+
DEFINED_METADATA_TO_FILE_MAP = {
|
95
|
+
"readme": README,
|
96
|
+
"license": LICENSE,
|
97
|
+
"finetuneconfiguration": FINE_TUNING_CONFIG,
|
98
|
+
"deploymentconfiguration": DEPLOYMENT_CONFIG,
|
99
|
+
}
|
100
|
+
|
101
|
+
|
91
102
|
class LifecycleStatus(ExtendedEnum):
|
92
103
|
UNKNOWN = ""
|
93
104
|
|
@@ -548,87 +559,6 @@ def _build_job_identifier(
|
|
548
559
|
return AquaResourceIdentifier()
|
549
560
|
|
550
561
|
|
551
|
-
def service_config_path():
|
552
|
-
return f"oci://{AQUA_SERVICE_MODELS_BUCKET}@{CONDA_BUCKET_NS}/service_models/config"
|
553
|
-
|
554
|
-
|
555
|
-
@cached(cache=TTLCache(maxsize=1, ttl=timedelta(minutes=10), timer=datetime.now))
|
556
|
-
def get_container_config():
|
557
|
-
config = load_config(
|
558
|
-
file_path=service_config_path(),
|
559
|
-
config_file_name=CONTAINER_INDEX,
|
560
|
-
)
|
561
|
-
|
562
|
-
return config
|
563
|
-
|
564
|
-
|
565
|
-
def get_container_image(
|
566
|
-
config_file_name: str = None, container_type: str = None
|
567
|
-
) -> str:
|
568
|
-
"""Gets the image name from the given model and container type.
|
569
|
-
Parameters
|
570
|
-
----------
|
571
|
-
config_file_name: str
|
572
|
-
name of the config file
|
573
|
-
container_type: str
|
574
|
-
type of container, can be either deployment-container, finetune-container, evaluation-container
|
575
|
-
|
576
|
-
Returns
|
577
|
-
-------
|
578
|
-
Dict:
|
579
|
-
A dict of allowed configs.
|
580
|
-
"""
|
581
|
-
|
582
|
-
container_image = UNKNOWN
|
583
|
-
config = config_file_name or get_container_config()
|
584
|
-
config_file_name = service_config_path()
|
585
|
-
|
586
|
-
if container_type not in config:
|
587
|
-
return UNKNOWN
|
588
|
-
|
589
|
-
mapping = config[container_type]
|
590
|
-
versions = [obj["version"] for obj in mapping]
|
591
|
-
# assumes numbered versions, update if `latest` is used
|
592
|
-
latest = get_max_version(versions)
|
593
|
-
for obj in mapping:
|
594
|
-
if obj["version"] == str(latest):
|
595
|
-
container_image = f"{obj['name']}:{obj['version']}"
|
596
|
-
break
|
597
|
-
|
598
|
-
if not container_image:
|
599
|
-
raise AquaValueError(
|
600
|
-
f"{config_file_name} is missing name and/or version details."
|
601
|
-
)
|
602
|
-
|
603
|
-
return container_image
|
604
|
-
|
605
|
-
|
606
|
-
def fetch_service_compartment() -> Union[str, None]:
|
607
|
-
"""
|
608
|
-
Loads the compartment mapping json from service bucket.
|
609
|
-
This json file has a service-model-compartment key which contains a dictionary of namespaces
|
610
|
-
and the compartment OCID of the service models in that namespace.
|
611
|
-
"""
|
612
|
-
config_file_name = (
|
613
|
-
f"oci://{AQUA_SERVICE_MODELS_BUCKET}@{CONDA_BUCKET_NS}/service_models/config"
|
614
|
-
)
|
615
|
-
|
616
|
-
try:
|
617
|
-
config = load_config(
|
618
|
-
file_path=config_file_name,
|
619
|
-
config_file_name=CONTAINER_INDEX,
|
620
|
-
)
|
621
|
-
except Exception as e:
|
622
|
-
logger.debug(
|
623
|
-
f"Config file {config_file_name}/{CONTAINER_INDEX} to fetch service compartment OCID "
|
624
|
-
f"could not be found. \n{str(e)}."
|
625
|
-
)
|
626
|
-
return
|
627
|
-
compartment_mapping = config.get(COMPARTMENT_MAPPING_KEY)
|
628
|
-
if compartment_mapping:
|
629
|
-
return compartment_mapping.get(CONDA_BUCKET_NS)
|
630
|
-
|
631
|
-
|
632
562
|
def get_max_version(versions):
|
633
563
|
"""Takes in a list of versions and returns the higher version."""
|
634
564
|
if not versions:
|
@@ -1316,3 +1246,40 @@ def load_gpu_shapes_index(
|
|
1316
1246
|
)
|
1317
1247
|
|
1318
1248
|
return GPUShapesIndex(**data)
|
1249
|
+
|
1250
|
+
|
1251
|
+
def get_preferred_compatible_family(selected_families: set[str]) -> str:
|
1252
|
+
"""
|
1253
|
+
Determines the preferred container family from a given set of container families.
|
1254
|
+
|
1255
|
+
This method is used in the context of multi-model deployment to handle cases
|
1256
|
+
where models selected for deployment use different, but compatible, container families.
|
1257
|
+
|
1258
|
+
It checks the input `families` set against the `CONTAINER_FAMILY_COMPATIBILITY` map.
|
1259
|
+
If a compatibility group exists that fully includes all the families in the input,
|
1260
|
+
the corresponding key (i.e., the preferred family) is returned.
|
1261
|
+
|
1262
|
+
Parameters
|
1263
|
+
----------
|
1264
|
+
families : set[str]
|
1265
|
+
A set of container family identifiers.
|
1266
|
+
|
1267
|
+
Returns
|
1268
|
+
-------
|
1269
|
+
Optional[str]
|
1270
|
+
The preferred container family if all families are compatible within one group;
|
1271
|
+
otherwise, returns `None` indicating that no compatible family group was found.
|
1272
|
+
|
1273
|
+
Example
|
1274
|
+
-------
|
1275
|
+
>>> get_preferred_compatible_family({"odsc-vllm-serving", "odsc-vllm-serving-v1"})
|
1276
|
+
'odsc-vllm-serving-v1'
|
1277
|
+
|
1278
|
+
>>> get_preferred_compatible_family({"odsc-vllm-serving", "odsc-tgi-serving"})
|
1279
|
+
None # Incompatible families
|
1280
|
+
"""
|
1281
|
+
for preferred, compatible_list in CONTAINER_FAMILY_COMPATIBILITY.items():
|
1282
|
+
if selected_families.issubset(set(compatible_list)):
|
1283
|
+
return preferred
|
1284
|
+
|
1285
|
+
return None
|
@@ -1,14 +1,20 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
2
|
# Copyright (c) 2025 Oracle and/or its affiliates.
|
3
3
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
4
|
-
|
4
|
+
import json
|
5
5
|
from typing import Dict, List, Optional
|
6
6
|
|
7
|
+
from oci.data_science.models import ContainerSummary
|
7
8
|
from pydantic import Field
|
8
9
|
|
9
|
-
from ads.aqua.common.entities import ContainerSpec
|
10
10
|
from ads.aqua.config.utils.serializer import Serializable
|
11
|
+
from ads.aqua.constants import (
|
12
|
+
SERVICE_MANAGED_CONTAINER_URI_SCHEME,
|
13
|
+
UNKNOWN_JSON_LIST,
|
14
|
+
UNKNOWN_JSON_STR,
|
15
|
+
)
|
11
16
|
from ads.common.extended_enum import ExtendedEnum
|
17
|
+
from ads.common.utils import UNKNOWN
|
12
18
|
|
13
19
|
|
14
20
|
class Usage(ExtendedEnum):
|
@@ -46,6 +52,9 @@ class AquaContainerConfigSpec(Serializable):
|
|
46
52
|
restricted_params: Optional[List[str]] = Field(
|
47
53
|
default_factory=list, description="List of restricted parameters."
|
48
54
|
)
|
55
|
+
evaluation_configuration: Optional[Dict] = Field(
|
56
|
+
default_factory=dict, description="Dict of evaluation configuration."
|
57
|
+
)
|
49
58
|
|
50
59
|
class Config:
|
51
60
|
extra = "allow"
|
@@ -126,87 +135,114 @@ class AquaContainerConfig(Serializable):
|
|
126
135
|
}
|
127
136
|
|
128
137
|
@classmethod
|
129
|
-
def
|
130
|
-
cls,
|
131
|
-
config: Dict,
|
132
|
-
enable_spec: Optional[bool] = False,
|
138
|
+
def from_service_config(
|
139
|
+
cls, service_containers: List[ContainerSummary]
|
133
140
|
) -> "AquaContainerConfig":
|
134
141
|
"""
|
135
|
-
Creates an AquaContainerConfig instance from a
|
142
|
+
Creates an AquaContainerConfig instance from a service containers.conf.
|
136
143
|
|
137
144
|
Parameters
|
138
145
|
----------
|
139
|
-
|
140
|
-
enable_spec (Optional[bool]): If True, fetch container specification details.
|
141
|
-
|
146
|
+
service_containers (List[Any]): List of containers specified in containers.conf
|
142
147
|
Returns
|
143
148
|
-------
|
144
149
|
AquaContainerConfig: The constructed container configuration.
|
145
150
|
"""
|
146
|
-
# TODO: Return this logic back if necessary in the next iteraion.
|
147
|
-
# if not config:
|
148
|
-
# config = get_container_config()
|
149
151
|
|
150
152
|
inference_items: Dict[str, AquaContainerConfigItem] = {}
|
151
153
|
finetune_items: Dict[str, AquaContainerConfigItem] = {}
|
152
154
|
evaluate_items: Dict[str, AquaContainerConfigItem] = {}
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
155
|
+
for container in service_containers:
|
156
|
+
if not container.is_latest:
|
157
|
+
continue
|
158
|
+
container_item = AquaContainerConfigItem(
|
159
|
+
name=SERVICE_MANAGED_CONTAINER_URI_SCHEME + container.container_name,
|
160
|
+
version=container.tag,
|
161
|
+
display_name=container.display_name,
|
162
|
+
family=container.family_name,
|
163
|
+
usages=container.usages,
|
164
|
+
platforms=[],
|
165
|
+
model_formats=[],
|
166
|
+
spec=None,
|
167
|
+
)
|
168
|
+
container_type = container.family_name
|
169
|
+
usages = [x.upper() for x in container.usages]
|
170
|
+
if "INFERENCE" in usages or "MULTI_MODEL" in usages:
|
171
|
+
container_item.platforms.append(
|
172
|
+
container.workload_configuration_details_list[
|
173
|
+
0
|
174
|
+
].additional_configurations.get("platforms")
|
175
|
+
)
|
176
|
+
container_item.model_formats.append(
|
177
|
+
container.workload_configuration_details_list[
|
178
|
+
0
|
179
|
+
].additional_configurations.get("modelFormats")
|
180
|
+
)
|
181
|
+
env_vars = [
|
182
|
+
{
|
183
|
+
"MODEL_DEPLOY_PREDICT_ENDPOINT": container.workload_configuration_details_list[
|
184
|
+
0
|
185
|
+
].additional_configurations.get(
|
186
|
+
"MODEL_DEPLOY_PREDICT_ENDPOINT", UNKNOWN
|
163
187
|
)
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
188
|
+
},
|
189
|
+
{
|
190
|
+
"MODEL_DEPLOY_HEALTH_ENDPOINT": container.workload_configuration_details_list[
|
191
|
+
0
|
192
|
+
].additional_configurations.get(
|
193
|
+
"MODEL_DEPLOY_HEALTH_ENDPOINT", UNKNOWN
|
194
|
+
)
|
195
|
+
},
|
196
|
+
{
|
197
|
+
"MODEL_DEPLOY_ENABLE_STREAMING": container.workload_configuration_details_list[
|
198
|
+
0
|
199
|
+
].additional_configurations.get(
|
200
|
+
"MODEL_DEPLOY_ENABLE_STREAMING", UNKNOWN
|
201
|
+
)
|
202
|
+
},
|
203
|
+
{
|
204
|
+
"PORT": container.workload_configuration_details_list[
|
205
|
+
0
|
206
|
+
].additional_configurations.get("PORT", "")
|
207
|
+
},
|
208
|
+
{
|
209
|
+
"HEALTH_CHECK_PORT": container.workload_configuration_details_list[
|
210
|
+
0
|
211
|
+
].additional_configurations.get("HEALTH_CHECK_PORT", UNKNOWN),
|
212
|
+
},
|
213
|
+
]
|
214
|
+
container_spec = AquaContainerConfigSpec(
|
215
|
+
cli_param=container.workload_configuration_details_list[0].cmd,
|
216
|
+
server_port=str(
|
217
|
+
container.workload_configuration_details_list[0].server_port
|
218
|
+
),
|
219
|
+
health_check_port=str(
|
220
|
+
container.workload_configuration_details_list[
|
221
|
+
0
|
222
|
+
].health_check_port
|
223
|
+
),
|
224
|
+
env_vars=env_vars,
|
225
|
+
restricted_params=json.loads(
|
226
|
+
container.workload_configuration_details_list[
|
227
|
+
0
|
228
|
+
].additional_configurations.get("restrictedParams")
|
229
|
+
or UNKNOWN_JSON_LIST
|
230
|
+
),
|
231
|
+
evaluation_configuration=json.loads(
|
232
|
+
container.workload_configuration_details_list[
|
233
|
+
0
|
234
|
+
].additional_configurations.get(
|
235
|
+
"evaluationConfiguration", UNKNOWN_JSON_STR
|
236
|
+
)
|
237
|
+
),
|
238
|
+
)
|
239
|
+
container_item.spec = container_spec
|
240
|
+
if "INFERENCE" in usages or "MULTI_MODEL" in usages:
|
241
|
+
inference_items[container_type] = container_item
|
242
|
+
if "FINE_TUNE" in usages:
|
243
|
+
finetune_items[container_type] = container_item
|
244
|
+
if "EVALUATION" in usages:
|
245
|
+
evaluate_items[container_type] = container_item
|
210
246
|
return cls(
|
211
247
|
inference=inference_items, finetune=finetune_items, evaluate=evaluate_items
|
212
248
|
)
|