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/model/model.py
CHANGED
@@ -6,14 +6,14 @@ import os
|
|
6
6
|
import pathlib
|
7
7
|
from datetime import datetime, timedelta
|
8
8
|
from threading import Lock
|
9
|
-
from typing import Dict, List, Optional, Set, Union
|
9
|
+
from typing import Any, Dict, List, Optional, Set, Union
|
10
10
|
|
11
11
|
import oci
|
12
12
|
from cachetools import TTLCache
|
13
13
|
from huggingface_hub import snapshot_download
|
14
14
|
from oci.data_science.models import JobRun, Metadata, Model, UpdateModelDetails
|
15
15
|
|
16
|
-
from ads.aqua import
|
16
|
+
from ads.aqua import logger
|
17
17
|
from ads.aqua.app import AquaApp
|
18
18
|
from ads.aqua.common.entities import AquaMultiModelRef
|
19
19
|
from ads.aqua.common.enums import (
|
@@ -37,11 +37,10 @@ from ads.aqua.common.utils import (
|
|
37
37
|
create_word_icon,
|
38
38
|
generate_tei_cmd_var,
|
39
39
|
get_artifact_path,
|
40
|
-
get_container_config,
|
41
40
|
get_hf_model_info,
|
41
|
+
get_preferred_compatible_family,
|
42
42
|
list_os_files_with_extension,
|
43
43
|
load_config,
|
44
|
-
read_file,
|
45
44
|
upload_folder,
|
46
45
|
)
|
47
46
|
from ads.aqua.config.container_config import AquaContainerConfig, Usage
|
@@ -53,7 +52,7 @@ from ads.aqua.constants import (
|
|
53
52
|
AQUA_MODEL_TOKENIZER_CONFIG,
|
54
53
|
AQUA_MODEL_TYPE_CUSTOM,
|
55
54
|
HF_METADATA_FOLDER,
|
56
|
-
|
55
|
+
LICENSE,
|
57
56
|
MODEL_BY_REFERENCE_OSS_PATH_KEY,
|
58
57
|
README,
|
59
58
|
READY_TO_DEPLOY_STATUS,
|
@@ -65,6 +64,7 @@ from ads.aqua.constants import (
|
|
65
64
|
VALIDATION_METRICS_FINAL,
|
66
65
|
)
|
67
66
|
from ads.aqua.model.constants import (
|
67
|
+
AquaModelMetadataKeys,
|
68
68
|
FineTuningCustomMetadata,
|
69
69
|
FineTuningMetricCategories,
|
70
70
|
ModelCustomMetadataFields,
|
@@ -75,6 +75,7 @@ from ads.aqua.model.entities import (
|
|
75
75
|
AquaFineTuningMetric,
|
76
76
|
AquaModel,
|
77
77
|
AquaModelLicense,
|
78
|
+
AquaModelReadme,
|
78
79
|
AquaModelSummary,
|
79
80
|
ImportModelDetails,
|
80
81
|
ModelValidationResult,
|
@@ -82,16 +83,24 @@ from ads.aqua.model.entities import (
|
|
82
83
|
from ads.aqua.model.enums import MultiModelSupportedTaskType
|
83
84
|
from ads.common.auth import default_signer
|
84
85
|
from ads.common.oci_resource import SEARCH_TYPE, OCIResource
|
85
|
-
from ads.common.utils import
|
86
|
+
from ads.common.utils import (
|
87
|
+
UNKNOWN,
|
88
|
+
get_console_link,
|
89
|
+
is_path_exists,
|
90
|
+
read_file,
|
91
|
+
)
|
86
92
|
from ads.config import (
|
87
93
|
AQUA_DEPLOYMENT_CONTAINER_CMD_VAR_METADATA_NAME,
|
88
94
|
AQUA_DEPLOYMENT_CONTAINER_METADATA_NAME,
|
89
95
|
AQUA_DEPLOYMENT_CONTAINER_URI_METADATA_NAME,
|
90
96
|
AQUA_EVALUATION_CONTAINER_METADATA_NAME,
|
91
97
|
AQUA_FINETUNING_CONTAINER_METADATA_NAME,
|
98
|
+
AQUA_SERVICE_MODELS,
|
92
99
|
COMPARTMENT_OCID,
|
93
100
|
PROJECT_OCID,
|
101
|
+
SERVICE,
|
94
102
|
TENANCY_OCID,
|
103
|
+
USER,
|
95
104
|
)
|
96
105
|
from ads.model import DataScienceModel
|
97
106
|
from ads.model.common.utils import MetadataArtifactPathType
|
@@ -175,7 +184,8 @@ class AquaModelApp(AquaApp):
|
|
175
184
|
target_project = project_id or PROJECT_OCID
|
176
185
|
target_compartment = compartment_id or COMPARTMENT_OCID
|
177
186
|
|
178
|
-
if
|
187
|
+
# Skip model copying if it is registered model
|
188
|
+
if service_model.freeform_tags.get(Tags.BASE_MODEL_CUSTOM, None) is not None:
|
179
189
|
logger.info(
|
180
190
|
f"Aqua Model {model_id} already exists in the user's compartment."
|
181
191
|
"Skipped copying."
|
@@ -260,18 +270,15 @@ class AquaModelApp(AquaApp):
|
|
260
270
|
display_name_list = []
|
261
271
|
model_custom_metadata = ModelCustomMetadata()
|
262
272
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
service_inference_containers = AquaContainerConfig.from_container_index_json(
|
267
|
-
config=container_config
|
268
|
-
).inference.values()
|
273
|
+
service_inference_containers = (
|
274
|
+
self.get_container_config().to_dict().get("inference")
|
275
|
+
)
|
269
276
|
|
270
277
|
supported_container_families = [
|
271
278
|
container_config_item.family
|
272
279
|
for container_config_item in service_inference_containers
|
273
280
|
if any(
|
274
|
-
usage in container_config_item.usages
|
281
|
+
usage.upper() in container_config_item.usages
|
275
282
|
for usage in [Usage.MULTI_MODEL, Usage.OTHER]
|
276
283
|
)
|
277
284
|
]
|
@@ -337,15 +344,25 @@ class AquaModelApp(AquaApp):
|
|
337
344
|
|
338
345
|
selected_models_deployment_containers.add(deployment_container)
|
339
346
|
|
340
|
-
|
341
|
-
if len(selected_models_deployment_containers) > 1:
|
347
|
+
if not selected_models_deployment_containers:
|
342
348
|
raise AquaValueError(
|
343
|
-
"
|
344
|
-
|
345
|
-
"For multi-model deployment, all models in the group must share the same container family."
|
349
|
+
"None of the selected models are associated with a recognized container family. "
|
350
|
+
"Please review the selected models, or select a different group of models."
|
346
351
|
)
|
347
352
|
|
348
|
-
|
353
|
+
# Check if the all models in the group shares same container family
|
354
|
+
if len(selected_models_deployment_containers) > 1:
|
355
|
+
deployment_container = get_preferred_compatible_family(
|
356
|
+
selected_families=selected_models_deployment_containers
|
357
|
+
)
|
358
|
+
if not deployment_container:
|
359
|
+
raise AquaValueError(
|
360
|
+
"The selected models are associated with different container families: "
|
361
|
+
f"{list(selected_models_deployment_containers)}."
|
362
|
+
"For multi-model deployment, all models in the group must share the same container family."
|
363
|
+
)
|
364
|
+
else:
|
365
|
+
deployment_container = selected_models_deployment_containers.pop()
|
349
366
|
|
350
367
|
# Generate model group details
|
351
368
|
timestamp = datetime.now().strftime("%Y%m%d")
|
@@ -421,7 +438,7 @@ class AquaModelApp(AquaApp):
|
|
421
438
|
return custom_model
|
422
439
|
|
423
440
|
@telemetry(entry_point="plugin=model&action=get", name="aqua")
|
424
|
-
def get(self, model_id: str
|
441
|
+
def get(self, model_id: str) -> "AquaModel":
|
425
442
|
"""Gets the information of an Aqua model.
|
426
443
|
|
427
444
|
Parameters
|
@@ -444,6 +461,7 @@ class AquaModelApp(AquaApp):
|
|
444
461
|
|
445
462
|
logger.info(f"Fetching model details for model {model_id}.")
|
446
463
|
ds_model = DataScienceModel.from_id(model_id)
|
464
|
+
|
447
465
|
if not self._if_show(ds_model):
|
448
466
|
raise AquaRuntimeError(
|
449
467
|
f"Target model `{ds_model.id} `is not an Aqua model as it does not contain "
|
@@ -455,34 +473,6 @@ class AquaModelApp(AquaApp):
|
|
455
473
|
and ds_model.freeform_tags.get(Tags.AQUA_FINE_TUNED_MODEL_TAG)
|
456
474
|
)
|
457
475
|
|
458
|
-
# todo: consolidate this logic in utils for model and deployment use
|
459
|
-
is_verified_type = (
|
460
|
-
ds_model.freeform_tags.get(Tags.READY_TO_IMPORT, "false").upper()
|
461
|
-
== READY_TO_IMPORT_STATUS
|
462
|
-
)
|
463
|
-
|
464
|
-
model_card = ""
|
465
|
-
if load_model_card:
|
466
|
-
artifact_path = get_artifact_path(
|
467
|
-
ds_model.custom_metadata_list._to_oci_metadata()
|
468
|
-
)
|
469
|
-
if artifact_path != UNKNOWN:
|
470
|
-
model_card_path = (
|
471
|
-
f"{artifact_path.rstrip('/')}/config/{README}"
|
472
|
-
if is_verified_type
|
473
|
-
else f"{artifact_path.rstrip('/')}/{README}"
|
474
|
-
)
|
475
|
-
model_card = str(
|
476
|
-
read_file(
|
477
|
-
file_path=model_card_path,
|
478
|
-
auth=default_signer(),
|
479
|
-
)
|
480
|
-
)
|
481
|
-
if not model_card:
|
482
|
-
logger.warn(
|
483
|
-
f"Model card for {model_id} is empty or could not be loaded from {model_card_path}."
|
484
|
-
)
|
485
|
-
|
486
476
|
inference_container = ds_model.custom_metadata_list.get(
|
487
477
|
ModelCustomMetadataFields.DEPLOYMENT_CONTAINER,
|
488
478
|
ModelCustomMetadataItem(key=ModelCustomMetadataFields.DEPLOYMENT_CONTAINER),
|
@@ -509,7 +499,6 @@ class AquaModelApp(AquaApp):
|
|
509
499
|
aqua_model_attributes = dict(
|
510
500
|
**self._process_model(ds_model, self.region),
|
511
501
|
project_id=ds_model.project_id,
|
512
|
-
model_card=model_card,
|
513
502
|
inference_container=inference_container,
|
514
503
|
inference_container_uri=inference_container_uri,
|
515
504
|
finetuning_container=finetuning_container,
|
@@ -780,7 +769,9 @@ class AquaModelApp(AquaApp):
|
|
780
769
|
]
|
781
770
|
|
782
771
|
def get_hf_tokenizer_config(self, model_id):
|
783
|
-
"""
|
772
|
+
"""
|
773
|
+
Gets the default model tokenizer config for the given Aqua model.
|
774
|
+
Returns the content of tokenizer_config.json stored in model artifact.
|
784
775
|
|
785
776
|
Parameters
|
786
777
|
----------
|
@@ -789,14 +780,19 @@ class AquaModelApp(AquaApp):
|
|
789
780
|
|
790
781
|
Returns
|
791
782
|
-------
|
792
|
-
|
793
|
-
|
783
|
+
Dict:
|
784
|
+
Model tokenizer config.
|
794
785
|
"""
|
795
786
|
config = self.get_config(
|
796
787
|
model_id, AQUA_MODEL_TOKENIZER_CONFIG, ConfigFolder.ARTIFACT
|
797
788
|
).config
|
798
789
|
if not config:
|
799
|
-
logger.debug(
|
790
|
+
logger.debug(
|
791
|
+
f"{AQUA_MODEL_TOKENIZER_CONFIG} is not available for the model: {model_id}. "
|
792
|
+
f"Check if the custom metadata has the artifact path set."
|
793
|
+
)
|
794
|
+
return config
|
795
|
+
|
800
796
|
return config
|
801
797
|
|
802
798
|
@staticmethod
|
@@ -821,6 +817,7 @@ class AquaModelApp(AquaApp):
|
|
821
817
|
oci.resource_search.models.ResourceSummary,
|
822
818
|
],
|
823
819
|
region: str,
|
820
|
+
inference_containers: Optional[List[Any]] = None,
|
824
821
|
) -> dict:
|
825
822
|
"""Constructs required fields for AquaModelSummary."""
|
826
823
|
|
@@ -876,9 +873,10 @@ class AquaModelApp(AquaApp):
|
|
876
873
|
except Exception:
|
877
874
|
model_file = UNKNOWN
|
878
875
|
|
879
|
-
|
880
|
-
|
881
|
-
|
876
|
+
if not inference_containers:
|
877
|
+
inference_containers = (
|
878
|
+
AquaApp().get_container_config().to_dict().get("inference")
|
879
|
+
)
|
882
880
|
|
883
881
|
model_formats_str = freeform_tags.get(
|
884
882
|
Tags.MODEL_FORMAT, ModelFormat.SAFETENSORS
|
@@ -887,7 +885,7 @@ class AquaModelApp(AquaApp):
|
|
887
885
|
|
888
886
|
supported_platform: Set[str] = set()
|
889
887
|
|
890
|
-
for container in inference_containers
|
888
|
+
for container in inference_containers:
|
891
889
|
for model_format in model_formats:
|
892
890
|
if model_format in container.model_formats:
|
893
891
|
supported_platform.update(container.platforms)
|
@@ -921,12 +919,13 @@ class AquaModelApp(AquaApp):
|
|
921
919
|
def list(
|
922
920
|
self,
|
923
921
|
compartment_id: str = None,
|
922
|
+
category: str = None,
|
924
923
|
project_id: str = None,
|
925
924
|
model_type: str = None,
|
926
925
|
**kwargs,
|
927
926
|
) -> List["AquaModelSummary"]:
|
928
927
|
"""Lists all Aqua models within a specified compartment and/or project.
|
929
|
-
If `
|
928
|
+
If `category` is not specified, the method defaults to returning
|
930
929
|
the service models within the pre-configured default compartment. By default, the list
|
931
930
|
of models in the service compartment are cached. Use clear_model_list_cache() to invalidate
|
932
931
|
the cache.
|
@@ -935,6 +934,8 @@ class AquaModelApp(AquaApp):
|
|
935
934
|
----------
|
936
935
|
compartment_id: (str, optional). Defaults to `None`.
|
937
936
|
The compartment OCID.
|
937
|
+
category: (str,optional). Defaults to `SERVICE`
|
938
|
+
The category of the models to fetch. Can be either `USER` or `SERVICE`
|
938
939
|
project_id: (str, optional). Defaults to `None`.
|
939
940
|
The project OCID.
|
940
941
|
model_type: (str, optional). Defaults to `None`.
|
@@ -948,8 +949,9 @@ class AquaModelApp(AquaApp):
|
|
948
949
|
The list of the `ads.aqua.model.AquaModelSummary`.
|
949
950
|
"""
|
950
951
|
|
951
|
-
|
952
|
-
|
952
|
+
category = category or kwargs.pop("category", SERVICE)
|
953
|
+
compartment_id = compartment_id or COMPARTMENT_OCID
|
954
|
+
if category == USER:
|
953
955
|
# tracks number of times custom model listing was called
|
954
956
|
self.telemetry.record_event_async(
|
955
957
|
category="aqua/custom/model", action="list"
|
@@ -958,48 +960,47 @@ class AquaModelApp(AquaApp):
|
|
958
960
|
logger.info(f"Fetching custom models from compartment_id={compartment_id}.")
|
959
961
|
model_type = model_type.upper() if model_type else ModelType.FT
|
960
962
|
models = self._rqs(compartment_id, model_type=model_type)
|
963
|
+
logger.info(
|
964
|
+
f"Fetched {len(models)} models from {compartment_id or COMPARTMENT_OCID}."
|
965
|
+
)
|
961
966
|
else:
|
962
967
|
# tracks number of times service model listing was called
|
963
968
|
self.telemetry.record_event_async(
|
964
969
|
category="aqua/service/model", action="list"
|
965
970
|
)
|
966
971
|
|
967
|
-
if
|
968
|
-
logger.info(
|
969
|
-
|
970
|
-
)
|
971
|
-
return self._service_models_cache.get(ODSC_MODEL_COMPARTMENT_OCID)
|
972
|
-
logger.info(
|
973
|
-
f"Fetching service models from compartment_id={ODSC_MODEL_COMPARTMENT_OCID}"
|
974
|
-
)
|
972
|
+
if AQUA_SERVICE_MODELS in self._service_models_cache:
|
973
|
+
logger.info("Returning service models list from cache.")
|
974
|
+
return self._service_models_cache.get(AQUA_SERVICE_MODELS)
|
975
975
|
lifecycle_state = kwargs.pop(
|
976
976
|
"lifecycle_state", Model.LIFECYCLE_STATE_ACTIVE
|
977
977
|
)
|
978
978
|
|
979
979
|
models = self.list_resource(
|
980
980
|
self.ds_client.list_models,
|
981
|
-
compartment_id=
|
981
|
+
compartment_id=compartment_id,
|
982
982
|
lifecycle_state=lifecycle_state,
|
983
|
+
category=category,
|
983
984
|
**kwargs,
|
984
985
|
)
|
985
|
-
|
986
|
-
logger.info(
|
987
|
-
f"Fetched {len(models)} model in compartment_id={compartment_id or ODSC_MODEL_COMPARTMENT_OCID}."
|
988
|
-
)
|
986
|
+
logger.info(f"Fetched {len(models)} service models.")
|
989
987
|
|
990
988
|
aqua_models = []
|
991
|
-
|
989
|
+
inference_containers = self.get_container_config().to_dict().get("inference")
|
992
990
|
for model in models:
|
993
991
|
aqua_models.append(
|
994
992
|
AquaModelSummary(
|
995
|
-
**self._process_model(
|
993
|
+
**self._process_model(
|
994
|
+
model=model,
|
995
|
+
region=self.region,
|
996
|
+
inference_containers=inference_containers,
|
997
|
+
),
|
996
998
|
project_id=project_id or UNKNOWN,
|
997
999
|
)
|
998
1000
|
)
|
999
|
-
|
1000
|
-
if not compartment_id:
|
1001
|
+
if category == SERVICE:
|
1001
1002
|
self._service_models_cache.__setitem__(
|
1002
|
-
key=
|
1003
|
+
key=AQUA_SERVICE_MODELS, value=aqua_models
|
1003
1004
|
)
|
1004
1005
|
|
1005
1006
|
return aqua_models
|
@@ -1015,15 +1016,10 @@ class AquaModelApp(AquaApp):
|
|
1015
1016
|
"""
|
1016
1017
|
res = {}
|
1017
1018
|
with self._cache_lock:
|
1018
|
-
if
|
1019
|
-
self._service_models_cache.pop(key=
|
1020
|
-
logger.info(
|
1021
|
-
f"Cleared models cache for service compartment {ODSC_MODEL_COMPARTMENT_OCID}."
|
1022
|
-
)
|
1019
|
+
if AQUA_SERVICE_MODELS in self._service_models_cache:
|
1020
|
+
self._service_models_cache.pop(key=AQUA_SERVICE_MODELS)
|
1021
|
+
logger.info("Cleared models cache for service compartment.")
|
1023
1022
|
res = {
|
1024
|
-
"key": {
|
1025
|
-
"compartment_id": ODSC_MODEL_COMPARTMENT_OCID,
|
1026
|
-
},
|
1027
1023
|
"cache_deleted": True,
|
1028
1024
|
}
|
1029
1025
|
return res
|
@@ -1046,14 +1042,85 @@ class AquaModelApp(AquaApp):
|
|
1046
1042
|
|
1047
1043
|
@staticmethod
|
1048
1044
|
def list_valid_inference_containers():
|
1049
|
-
containers =
|
1050
|
-
AquaContainerConfig.from_container_index_json(
|
1051
|
-
config=get_container_config(), enable_spec=True
|
1052
|
-
).inference.values()
|
1053
|
-
)
|
1045
|
+
containers = AquaApp().get_container_config().to_dict().get("inference")
|
1054
1046
|
family_values = [item.family for item in containers]
|
1055
1047
|
return family_values
|
1056
1048
|
|
1049
|
+
@telemetry(
|
1050
|
+
entry_point="plugin=model&action=get_defined_metadata_artifact_content",
|
1051
|
+
name="aqua",
|
1052
|
+
)
|
1053
|
+
def get_defined_metadata_artifact_content(self, model_id: str, metadata_key: str):
|
1054
|
+
"""
|
1055
|
+
Gets the defined metadata artifact content for the given model
|
1056
|
+
|
1057
|
+
Args:
|
1058
|
+
model_id: str
|
1059
|
+
model ocid for which defined metadata artifact needs to be created
|
1060
|
+
metadata_key: str
|
1061
|
+
defined metadata key like Readme , License , DeploymentConfiguration , FinetuningConfiguration
|
1062
|
+
Returns:
|
1063
|
+
The model defined metadata artifact content. Can be either str or Dict
|
1064
|
+
|
1065
|
+
"""
|
1066
|
+
|
1067
|
+
content = self.get_config(model_id, metadata_key)
|
1068
|
+
if not content:
|
1069
|
+
logger.debug(
|
1070
|
+
f"Defined metadata artifact {metadata_key} for model: {model_id} is not available."
|
1071
|
+
)
|
1072
|
+
return content
|
1073
|
+
|
1074
|
+
@telemetry(
|
1075
|
+
entry_point="plugin=model&action=create_defined_metadata_artifact", name="aqua"
|
1076
|
+
)
|
1077
|
+
def create_defined_metadata_artifact(
|
1078
|
+
self,
|
1079
|
+
model_id: str,
|
1080
|
+
metadata_key: str,
|
1081
|
+
path_type: MetadataArtifactPathType,
|
1082
|
+
artifact_path_or_content: str,
|
1083
|
+
) -> None:
|
1084
|
+
"""
|
1085
|
+
Creates defined metadata artifact for the registered unverified model
|
1086
|
+
|
1087
|
+
Args:
|
1088
|
+
model_id: str
|
1089
|
+
model ocid for which defined metadata artifact needs to be created
|
1090
|
+
metadata_key: str
|
1091
|
+
defined metadata key like Readme , License , DeploymentConfiguration , FinetuningConfiguration
|
1092
|
+
path_type: str
|
1093
|
+
path type of the given defined metadata can be local , oss or the content itself
|
1094
|
+
artifact_path_or_content: str
|
1095
|
+
It can be local path or oss path or the actual content itself
|
1096
|
+
Returns:
|
1097
|
+
None
|
1098
|
+
"""
|
1099
|
+
|
1100
|
+
ds_model = DataScienceModel.from_id(model_id)
|
1101
|
+
oci_aqua = ds_model.freeform_tags.get(Tags.AQUA_TAG, None)
|
1102
|
+
if not oci_aqua:
|
1103
|
+
raise AquaRuntimeError(f"Target model {model_id} is not an Aqua model.")
|
1104
|
+
is_registered_model = ds_model.freeform_tags.get(Tags.BASE_MODEL_CUSTOM, None)
|
1105
|
+
is_verified_model = ds_model.freeform_tags.get(
|
1106
|
+
Tags.AQUA_SERVICE_MODEL_TAG, None
|
1107
|
+
)
|
1108
|
+
if is_registered_model and not is_verified_model:
|
1109
|
+
try:
|
1110
|
+
ds_model.create_defined_metadata_artifact(
|
1111
|
+
metadata_key_name=metadata_key,
|
1112
|
+
artifact_path_or_content=artifact_path_or_content,
|
1113
|
+
path_type=path_type,
|
1114
|
+
)
|
1115
|
+
except Exception as ex:
|
1116
|
+
raise AquaRuntimeError(
|
1117
|
+
f"Error occurred in creating defined metadata artifact for model {model_id}: {ex}"
|
1118
|
+
) from ex
|
1119
|
+
else:
|
1120
|
+
raise AquaRuntimeError(
|
1121
|
+
f"Cannot create defined metadata artifact for model {model_id}"
|
1122
|
+
)
|
1123
|
+
|
1057
1124
|
def _create_model_catalog_entry(
|
1058
1125
|
self,
|
1059
1126
|
os_path: str,
|
@@ -1110,7 +1177,9 @@ class AquaModelApp(AquaApp):
|
|
1110
1177
|
|
1111
1178
|
# Remove `ready_to_import` tag that might get copied from service model.
|
1112
1179
|
tags.pop(Tags.READY_TO_IMPORT, None)
|
1113
|
-
|
1180
|
+
defined_metadata_dict = {}
|
1181
|
+
readme_file_path = os_path.rstrip("/") + "/" + README
|
1182
|
+
license_file_path = os_path.rstrip("/") + "/" + LICENSE
|
1114
1183
|
if verified_model:
|
1115
1184
|
# Verified model is a model in the service catalog that either has no artifacts but contains all the necessary metadata for deploying and fine tuning.
|
1116
1185
|
# If set, then we copy all the model metadata.
|
@@ -1119,6 +1188,17 @@ class AquaModelApp(AquaApp):
|
|
1119
1188
|
model = model.with_model_file_description(
|
1120
1189
|
json_dict=verified_model.model_file_description
|
1121
1190
|
)
|
1191
|
+
defined_metadata_list = (
|
1192
|
+
verified_model.defined_metadata_list._to_oci_metadata()
|
1193
|
+
)
|
1194
|
+
for defined_metadata in defined_metadata_list:
|
1195
|
+
if defined_metadata.has_artifact:
|
1196
|
+
content = (
|
1197
|
+
self.ds_client.get_model_defined_metadatum_artifact_content(
|
1198
|
+
verified_model.id, defined_metadata.key
|
1199
|
+
).data.content
|
1200
|
+
)
|
1201
|
+
defined_metadata_dict[defined_metadata.key] = content
|
1122
1202
|
else:
|
1123
1203
|
metadata = ModelCustomMetadata()
|
1124
1204
|
if not inference_container:
|
@@ -1140,12 +1220,14 @@ class AquaModelApp(AquaApp):
|
|
1140
1220
|
category="Other",
|
1141
1221
|
)
|
1142
1222
|
|
1143
|
-
inference_containers =
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1223
|
+
inference_containers = (
|
1224
|
+
AquaContainerConfig.from_service_config(
|
1225
|
+
service_containers=self.list_service_containers()
|
1226
|
+
)
|
1227
|
+
.to_dict()
|
1228
|
+
.get("inference")
|
1229
|
+
)
|
1230
|
+
smc_container_set = {container.family for container in inference_containers}
|
1149
1231
|
# only add cmd vars if inference container is not an SMC
|
1150
1232
|
if (
|
1151
1233
|
inference_container not in smc_container_set
|
@@ -1214,6 +1296,33 @@ class AquaModelApp(AquaApp):
|
|
1214
1296
|
.with_defined_tags(**(defined_tags or {}))
|
1215
1297
|
).create(model_by_reference=True)
|
1216
1298
|
logger.debug(f"Created model catalog entry for the model:\n{model}")
|
1299
|
+
for key, value in defined_metadata_dict.items():
|
1300
|
+
model.create_defined_metadata_artifact(
|
1301
|
+
key, value, MetadataArtifactPathType.CONTENT
|
1302
|
+
)
|
1303
|
+
|
1304
|
+
if is_path_exists(readme_file_path):
|
1305
|
+
try:
|
1306
|
+
model.create_defined_metadata_artifact(
|
1307
|
+
AquaModelMetadataKeys.README,
|
1308
|
+
readme_file_path,
|
1309
|
+
MetadataArtifactPathType.OSS,
|
1310
|
+
)
|
1311
|
+
except Exception as ex:
|
1312
|
+
logger.error(
|
1313
|
+
f"Error Uploading Readme in defined metadata for model: {model.id} : {str(ex)}"
|
1314
|
+
)
|
1315
|
+
if not verified_model and is_path_exists(license_file_path):
|
1316
|
+
try:
|
1317
|
+
model.create_defined_metadata_artifact(
|
1318
|
+
AquaModelMetadataKeys.LICENSE,
|
1319
|
+
license_file_path,
|
1320
|
+
MetadataArtifactPathType.OSS,
|
1321
|
+
)
|
1322
|
+
except Exception as ex:
|
1323
|
+
logger.error(
|
1324
|
+
f"Error Uploading License in defined metadata for model: {model.id} : {str(ex)}"
|
1325
|
+
)
|
1217
1326
|
return model
|
1218
1327
|
|
1219
1328
|
@staticmethod
|
@@ -1728,6 +1837,7 @@ class AquaModelApp(AquaApp):
|
|
1728
1837
|
).rstrip("/")
|
1729
1838
|
else:
|
1730
1839
|
artifact_path = import_model_details.os_path.rstrip("/")
|
1840
|
+
|
1731
1841
|
# Create Model catalog entry with pass by reference
|
1732
1842
|
ds_model = self._create_model_catalog_entry(
|
1733
1843
|
os_path=artifact_path,
|
@@ -1766,12 +1876,6 @@ class AquaModelApp(AquaApp):
|
|
1766
1876
|
aqua_model_attributes = dict(
|
1767
1877
|
**self._process_model(ds_model, self.region),
|
1768
1878
|
project_id=ds_model.project_id,
|
1769
|
-
model_card=str(
|
1770
|
-
read_file(
|
1771
|
-
file_path=f"{artifact_path}/{README}",
|
1772
|
-
auth=default_signer(),
|
1773
|
-
)
|
1774
|
-
),
|
1775
1879
|
inference_container=inference_container,
|
1776
1880
|
inference_container_uri=inference_container_uri,
|
1777
1881
|
finetuning_container=finetuning_container,
|
@@ -1845,6 +1949,56 @@ class AquaModelApp(AquaApp):
|
|
1845
1949
|
separator = " " if description else ""
|
1846
1950
|
return f"{description}{separator}{tags_text}"
|
1847
1951
|
|
1952
|
+
@telemetry(entry_point="plugin=model&action=load_readme", name="aqua")
|
1953
|
+
def load_readme(self, model_id: str) -> AquaModelReadme:
|
1954
|
+
"""Loads the readme or the model card for the given model.
|
1955
|
+
|
1956
|
+
Parameters
|
1957
|
+
----------
|
1958
|
+
model_id: str
|
1959
|
+
The model id.
|
1960
|
+
|
1961
|
+
Returns
|
1962
|
+
-------
|
1963
|
+
AquaModelReadme:
|
1964
|
+
The instance of AquaModelReadme.
|
1965
|
+
"""
|
1966
|
+
oci_model = self.ds_client.get_model(model_id).data
|
1967
|
+
artifact_path = get_artifact_path(oci_model.custom_metadata_list)
|
1968
|
+
if not artifact_path:
|
1969
|
+
raise AquaRuntimeError(
|
1970
|
+
f"Readme could not be loaded. Failed to get artifact path from custom metadata for"
|
1971
|
+
f"the model {model_id}."
|
1972
|
+
)
|
1973
|
+
|
1974
|
+
content = ""
|
1975
|
+
try:
|
1976
|
+
content = self.ds_client.get_model_defined_metadatum_artifact_content(
|
1977
|
+
model_id, AquaModelMetadataKeys.README
|
1978
|
+
).data.content.decode("utf-8", errors="ignore")
|
1979
|
+
logger.info(f"Fetched {README} from defined metadata for model: {model_id}")
|
1980
|
+
except Exception as ex:
|
1981
|
+
logger.error(
|
1982
|
+
f"Readme could not be found for model: {model_id} in defined metadata : {str(ex)}"
|
1983
|
+
)
|
1984
|
+
artifact_path = get_artifact_path(oci_model.custom_metadata_list)
|
1985
|
+
readme_path = os.path.join(os.path.dirname(artifact_path), "artifact")
|
1986
|
+
if not is_path_exists(readme_path):
|
1987
|
+
readme_path = os.path.join(artifact_path.rstrip("/"), "artifact")
|
1988
|
+
if not is_path_exists(readme_path):
|
1989
|
+
readme_path = f"{artifact_path.rstrip('/')}/"
|
1990
|
+
|
1991
|
+
readme_file_path = os.path.join(readme_path, README)
|
1992
|
+
logger.info(f"Fetching {README} from {readme_file_path}")
|
1993
|
+
if is_path_exists(readme_file_path):
|
1994
|
+
try:
|
1995
|
+
content = str(read_file(readme_file_path, auth=default_signer()))
|
1996
|
+
except Exception as e:
|
1997
|
+
logger.debug(
|
1998
|
+
f"Error occurred while fetching config {README} at path {readme_file_path} : {str(e)}"
|
1999
|
+
)
|
2000
|
+
return AquaModelReadme(id=model_id, model_card=content)
|
2001
|
+
|
1848
2002
|
@telemetry(entry_point="plugin=model&action=load_license", name="aqua")
|
1849
2003
|
def load_license(self, model_id: str) -> AquaModelLicense:
|
1850
2004
|
"""Loads the license full text for the given model.
|
@@ -1867,13 +2021,34 @@ class AquaModelApp(AquaApp):
|
|
1867
2021
|
f"the model {model_id}."
|
1868
2022
|
)
|
1869
2023
|
|
1870
|
-
content =
|
1871
|
-
|
1872
|
-
|
1873
|
-
|
2024
|
+
content = ""
|
2025
|
+
try:
|
2026
|
+
content = self.ds_client.get_model_defined_metadatum_artifact_content(
|
2027
|
+
model_id, AquaModelMetadataKeys.LICENSE
|
2028
|
+
).data.content.decode("utf-8", errors="ignore")
|
2029
|
+
logger.info(
|
2030
|
+
f"Fetched {LICENSE} from defined metadata for model: {model_id}"
|
1874
2031
|
)
|
1875
|
-
|
1876
|
-
|
2032
|
+
except Exception as ex:
|
2033
|
+
logger.error(
|
2034
|
+
f"License could not be found for model: {model_id} in defined metadata : {str(ex)}"
|
2035
|
+
)
|
2036
|
+
artifact_path = get_artifact_path(oci_model.custom_metadata_list)
|
2037
|
+
license_path = os.path.join(os.path.dirname(artifact_path), "config")
|
2038
|
+
if not is_path_exists(license_path):
|
2039
|
+
license_path = os.path.join(artifact_path.rstrip("/"), "config")
|
2040
|
+
if not is_path_exists(license_path):
|
2041
|
+
license_path = f"{artifact_path.rstrip('/')}/"
|
2042
|
+
|
2043
|
+
license_file_path = os.path.join(license_path, LICENSE)
|
2044
|
+
logger.info(f"Fetching {LICENSE} from {license_file_path}")
|
2045
|
+
if is_path_exists(license_file_path):
|
2046
|
+
try:
|
2047
|
+
content = str(read_file(license_file_path, auth=default_signer()))
|
2048
|
+
except Exception as e:
|
2049
|
+
logger.debug(
|
2050
|
+
f"Error occurred while fetching config {LICENSE} at path {license_path} : {str(e)}"
|
2051
|
+
)
|
1877
2052
|
return AquaModelLicense(id=model_id, license=content)
|
1878
2053
|
|
1879
2054
|
def _find_matching_aqua_model(self, model_id: str) -> Optional[str]:
|