oracle-ads 2.13.6__py3-none-any.whl → 2.13.8__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/utils.py +12 -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 +278 -113
- 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/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/type_discovery/typed_feature.py +32 -34
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.8.dist-info}/METADATA +1 -1
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.8.dist-info}/RECORD +36 -37
- ads/aqua/config/config.py +0 -31
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.8.dist-info}/WHEEL +0 -0
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.8.dist-info}/entry_points.txt +0 -0
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.8.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,12 +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,
|
42
41
|
get_preferred_compatible_family,
|
43
42
|
list_os_files_with_extension,
|
44
43
|
load_config,
|
45
|
-
read_file,
|
46
44
|
upload_folder,
|
47
45
|
)
|
48
46
|
from ads.aqua.config.container_config import AquaContainerConfig, Usage
|
@@ -54,7 +52,7 @@ from ads.aqua.constants import (
|
|
54
52
|
AQUA_MODEL_TOKENIZER_CONFIG,
|
55
53
|
AQUA_MODEL_TYPE_CUSTOM,
|
56
54
|
HF_METADATA_FOLDER,
|
57
|
-
|
55
|
+
LICENSE,
|
58
56
|
MODEL_BY_REFERENCE_OSS_PATH_KEY,
|
59
57
|
README,
|
60
58
|
READY_TO_DEPLOY_STATUS,
|
@@ -66,6 +64,7 @@ from ads.aqua.constants import (
|
|
66
64
|
VALIDATION_METRICS_FINAL,
|
67
65
|
)
|
68
66
|
from ads.aqua.model.constants import (
|
67
|
+
AquaModelMetadataKeys,
|
69
68
|
FineTuningCustomMetadata,
|
70
69
|
FineTuningMetricCategories,
|
71
70
|
ModelCustomMetadataFields,
|
@@ -76,6 +75,7 @@ from ads.aqua.model.entities import (
|
|
76
75
|
AquaFineTuningMetric,
|
77
76
|
AquaModel,
|
78
77
|
AquaModelLicense,
|
78
|
+
AquaModelReadme,
|
79
79
|
AquaModelSummary,
|
80
80
|
ImportModelDetails,
|
81
81
|
ModelValidationResult,
|
@@ -83,16 +83,24 @@ from ads.aqua.model.entities import (
|
|
83
83
|
from ads.aqua.model.enums import MultiModelSupportedTaskType
|
84
84
|
from ads.common.auth import default_signer
|
85
85
|
from ads.common.oci_resource import SEARCH_TYPE, OCIResource
|
86
|
-
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
|
+
)
|
87
92
|
from ads.config import (
|
88
93
|
AQUA_DEPLOYMENT_CONTAINER_CMD_VAR_METADATA_NAME,
|
89
94
|
AQUA_DEPLOYMENT_CONTAINER_METADATA_NAME,
|
90
95
|
AQUA_DEPLOYMENT_CONTAINER_URI_METADATA_NAME,
|
91
96
|
AQUA_EVALUATION_CONTAINER_METADATA_NAME,
|
92
97
|
AQUA_FINETUNING_CONTAINER_METADATA_NAME,
|
98
|
+
AQUA_SERVICE_MODELS,
|
93
99
|
COMPARTMENT_OCID,
|
94
100
|
PROJECT_OCID,
|
101
|
+
SERVICE,
|
95
102
|
TENANCY_OCID,
|
103
|
+
USER,
|
96
104
|
)
|
97
105
|
from ads.model import DataScienceModel
|
98
106
|
from ads.model.common.utils import MetadataArtifactPathType
|
@@ -176,7 +184,8 @@ class AquaModelApp(AquaApp):
|
|
176
184
|
target_project = project_id or PROJECT_OCID
|
177
185
|
target_compartment = compartment_id or COMPARTMENT_OCID
|
178
186
|
|
179
|
-
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:
|
180
189
|
logger.info(
|
181
190
|
f"Aqua Model {model_id} already exists in the user's compartment."
|
182
191
|
"Skipped copying."
|
@@ -261,18 +270,15 @@ class AquaModelApp(AquaApp):
|
|
261
270
|
display_name_list = []
|
262
271
|
model_custom_metadata = ModelCustomMetadata()
|
263
272
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
service_inference_containers = AquaContainerConfig.from_container_index_json(
|
268
|
-
config=container_config
|
269
|
-
).inference.values()
|
273
|
+
service_inference_containers = (
|
274
|
+
self.get_container_config().to_dict().get("inference")
|
275
|
+
)
|
270
276
|
|
271
277
|
supported_container_families = [
|
272
278
|
container_config_item.family
|
273
279
|
for container_config_item in service_inference_containers
|
274
280
|
if any(
|
275
|
-
usage in container_config_item.usages
|
281
|
+
usage.upper() in container_config_item.usages
|
276
282
|
for usage in [Usage.MULTI_MODEL, Usage.OTHER]
|
277
283
|
)
|
278
284
|
]
|
@@ -298,14 +304,15 @@ class AquaModelApp(AquaApp):
|
|
298
304
|
# "Currently only service models are supported for multi model deployment."
|
299
305
|
# )
|
300
306
|
|
301
|
-
if
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
307
|
+
# TODO uncomment the section below if only the specific types of models should be allowed for multi-model deployment
|
308
|
+
# if (
|
309
|
+
# source_model.freeform_tags.get(Tags.TASK, UNKNOWN).lower()
|
310
|
+
# not in MultiModelSupportedTaskType
|
311
|
+
# ):
|
312
|
+
# raise AquaValueError(
|
313
|
+
# f"Invalid or missing {Tags.TASK} tag for selected model {display_name}. "
|
314
|
+
# f"Currently only `{MultiModelSupportedTaskType.values()}` models are supported for multi model deployment."
|
315
|
+
# )
|
309
316
|
|
310
317
|
display_name_list.append(display_name)
|
311
318
|
|
@@ -432,7 +439,7 @@ class AquaModelApp(AquaApp):
|
|
432
439
|
return custom_model
|
433
440
|
|
434
441
|
@telemetry(entry_point="plugin=model&action=get", name="aqua")
|
435
|
-
def get(self, model_id: str
|
442
|
+
def get(self, model_id: str) -> "AquaModel":
|
436
443
|
"""Gets the information of an Aqua model.
|
437
444
|
|
438
445
|
Parameters
|
@@ -455,6 +462,7 @@ class AquaModelApp(AquaApp):
|
|
455
462
|
|
456
463
|
logger.info(f"Fetching model details for model {model_id}.")
|
457
464
|
ds_model = DataScienceModel.from_id(model_id)
|
465
|
+
|
458
466
|
if not self._if_show(ds_model):
|
459
467
|
raise AquaRuntimeError(
|
460
468
|
f"Target model `{ds_model.id} `is not an Aqua model as it does not contain "
|
@@ -466,34 +474,6 @@ class AquaModelApp(AquaApp):
|
|
466
474
|
and ds_model.freeform_tags.get(Tags.AQUA_FINE_TUNED_MODEL_TAG)
|
467
475
|
)
|
468
476
|
|
469
|
-
# todo: consolidate this logic in utils for model and deployment use
|
470
|
-
is_verified_type = (
|
471
|
-
ds_model.freeform_tags.get(Tags.READY_TO_IMPORT, "false").upper()
|
472
|
-
== READY_TO_IMPORT_STATUS
|
473
|
-
)
|
474
|
-
|
475
|
-
model_card = ""
|
476
|
-
if load_model_card:
|
477
|
-
artifact_path = get_artifact_path(
|
478
|
-
ds_model.custom_metadata_list._to_oci_metadata()
|
479
|
-
)
|
480
|
-
if artifact_path != UNKNOWN:
|
481
|
-
model_card_path = (
|
482
|
-
f"{artifact_path.rstrip('/')}/config/{README}"
|
483
|
-
if is_verified_type
|
484
|
-
else f"{artifact_path.rstrip('/')}/{README}"
|
485
|
-
)
|
486
|
-
model_card = str(
|
487
|
-
read_file(
|
488
|
-
file_path=model_card_path,
|
489
|
-
auth=default_signer(),
|
490
|
-
)
|
491
|
-
)
|
492
|
-
if not model_card:
|
493
|
-
logger.warn(
|
494
|
-
f"Model card for {model_id} is empty or could not be loaded from {model_card_path}."
|
495
|
-
)
|
496
|
-
|
497
477
|
inference_container = ds_model.custom_metadata_list.get(
|
498
478
|
ModelCustomMetadataFields.DEPLOYMENT_CONTAINER,
|
499
479
|
ModelCustomMetadataItem(key=ModelCustomMetadataFields.DEPLOYMENT_CONTAINER),
|
@@ -520,7 +500,6 @@ class AquaModelApp(AquaApp):
|
|
520
500
|
aqua_model_attributes = dict(
|
521
501
|
**self._process_model(ds_model, self.region),
|
522
502
|
project_id=ds_model.project_id,
|
523
|
-
model_card=model_card,
|
524
503
|
inference_container=inference_container,
|
525
504
|
inference_container_uri=inference_container_uri,
|
526
505
|
finetuning_container=finetuning_container,
|
@@ -791,7 +770,9 @@ class AquaModelApp(AquaApp):
|
|
791
770
|
]
|
792
771
|
|
793
772
|
def get_hf_tokenizer_config(self, model_id):
|
794
|
-
"""
|
773
|
+
"""
|
774
|
+
Gets the default model tokenizer config for the given Aqua model.
|
775
|
+
Returns the content of tokenizer_config.json stored in model artifact.
|
795
776
|
|
796
777
|
Parameters
|
797
778
|
----------
|
@@ -800,14 +781,19 @@ class AquaModelApp(AquaApp):
|
|
800
781
|
|
801
782
|
Returns
|
802
783
|
-------
|
803
|
-
|
804
|
-
|
784
|
+
Dict:
|
785
|
+
Model tokenizer config.
|
805
786
|
"""
|
806
787
|
config = self.get_config(
|
807
788
|
model_id, AQUA_MODEL_TOKENIZER_CONFIG, ConfigFolder.ARTIFACT
|
808
789
|
).config
|
809
790
|
if not config:
|
810
|
-
logger.debug(
|
791
|
+
logger.debug(
|
792
|
+
f"{AQUA_MODEL_TOKENIZER_CONFIG} is not available for the model: {model_id}. "
|
793
|
+
f"Check if the custom metadata has the artifact path set."
|
794
|
+
)
|
795
|
+
return config
|
796
|
+
|
811
797
|
return config
|
812
798
|
|
813
799
|
@staticmethod
|
@@ -832,6 +818,7 @@ class AquaModelApp(AquaApp):
|
|
832
818
|
oci.resource_search.models.ResourceSummary,
|
833
819
|
],
|
834
820
|
region: str,
|
821
|
+
inference_containers: Optional[List[Any]] = None,
|
835
822
|
) -> dict:
|
836
823
|
"""Constructs required fields for AquaModelSummary."""
|
837
824
|
|
@@ -887,9 +874,10 @@ class AquaModelApp(AquaApp):
|
|
887
874
|
except Exception:
|
888
875
|
model_file = UNKNOWN
|
889
876
|
|
890
|
-
|
891
|
-
|
892
|
-
|
877
|
+
if not inference_containers:
|
878
|
+
inference_containers = (
|
879
|
+
AquaApp().get_container_config().to_dict().get("inference")
|
880
|
+
)
|
893
881
|
|
894
882
|
model_formats_str = freeform_tags.get(
|
895
883
|
Tags.MODEL_FORMAT, ModelFormat.SAFETENSORS
|
@@ -898,7 +886,7 @@ class AquaModelApp(AquaApp):
|
|
898
886
|
|
899
887
|
supported_platform: Set[str] = set()
|
900
888
|
|
901
|
-
for container in inference_containers
|
889
|
+
for container in inference_containers:
|
902
890
|
for model_format in model_formats:
|
903
891
|
if model_format in container.model_formats:
|
904
892
|
supported_platform.update(container.platforms)
|
@@ -932,12 +920,13 @@ class AquaModelApp(AquaApp):
|
|
932
920
|
def list(
|
933
921
|
self,
|
934
922
|
compartment_id: str = None,
|
923
|
+
category: str = None,
|
935
924
|
project_id: str = None,
|
936
925
|
model_type: str = None,
|
937
926
|
**kwargs,
|
938
927
|
) -> List["AquaModelSummary"]:
|
939
928
|
"""Lists all Aqua models within a specified compartment and/or project.
|
940
|
-
If `
|
929
|
+
If `category` is not specified, the method defaults to returning
|
941
930
|
the service models within the pre-configured default compartment. By default, the list
|
942
931
|
of models in the service compartment are cached. Use clear_model_list_cache() to invalidate
|
943
932
|
the cache.
|
@@ -946,6 +935,8 @@ class AquaModelApp(AquaApp):
|
|
946
935
|
----------
|
947
936
|
compartment_id: (str, optional). Defaults to `None`.
|
948
937
|
The compartment OCID.
|
938
|
+
category: (str,optional). Defaults to `SERVICE`
|
939
|
+
The category of the models to fetch. Can be either `USER` or `SERVICE`
|
949
940
|
project_id: (str, optional). Defaults to `None`.
|
950
941
|
The project OCID.
|
951
942
|
model_type: (str, optional). Defaults to `None`.
|
@@ -959,8 +950,9 @@ class AquaModelApp(AquaApp):
|
|
959
950
|
The list of the `ads.aqua.model.AquaModelSummary`.
|
960
951
|
"""
|
961
952
|
|
962
|
-
|
963
|
-
|
953
|
+
category = category or kwargs.pop("category", SERVICE)
|
954
|
+
compartment_id = compartment_id or COMPARTMENT_OCID
|
955
|
+
if category == USER:
|
964
956
|
# tracks number of times custom model listing was called
|
965
957
|
self.telemetry.record_event_async(
|
966
958
|
category="aqua/custom/model", action="list"
|
@@ -969,48 +961,47 @@ class AquaModelApp(AquaApp):
|
|
969
961
|
logger.info(f"Fetching custom models from compartment_id={compartment_id}.")
|
970
962
|
model_type = model_type.upper() if model_type else ModelType.FT
|
971
963
|
models = self._rqs(compartment_id, model_type=model_type)
|
964
|
+
logger.info(
|
965
|
+
f"Fetched {len(models)} models from {compartment_id or COMPARTMENT_OCID}."
|
966
|
+
)
|
972
967
|
else:
|
973
968
|
# tracks number of times service model listing was called
|
974
969
|
self.telemetry.record_event_async(
|
975
970
|
category="aqua/service/model", action="list"
|
976
971
|
)
|
977
972
|
|
978
|
-
if
|
979
|
-
logger.info(
|
980
|
-
|
981
|
-
)
|
982
|
-
return self._service_models_cache.get(ODSC_MODEL_COMPARTMENT_OCID)
|
983
|
-
logger.info(
|
984
|
-
f"Fetching service models from compartment_id={ODSC_MODEL_COMPARTMENT_OCID}"
|
985
|
-
)
|
973
|
+
if AQUA_SERVICE_MODELS in self._service_models_cache:
|
974
|
+
logger.info("Returning service models list from cache.")
|
975
|
+
return self._service_models_cache.get(AQUA_SERVICE_MODELS)
|
986
976
|
lifecycle_state = kwargs.pop(
|
987
977
|
"lifecycle_state", Model.LIFECYCLE_STATE_ACTIVE
|
988
978
|
)
|
989
979
|
|
990
980
|
models = self.list_resource(
|
991
981
|
self.ds_client.list_models,
|
992
|
-
compartment_id=
|
982
|
+
compartment_id=compartment_id,
|
993
983
|
lifecycle_state=lifecycle_state,
|
984
|
+
category=category,
|
994
985
|
**kwargs,
|
995
986
|
)
|
996
|
-
|
997
|
-
logger.info(
|
998
|
-
f"Fetched {len(models)} model in compartment_id={compartment_id or ODSC_MODEL_COMPARTMENT_OCID}."
|
999
|
-
)
|
987
|
+
logger.info(f"Fetched {len(models)} service models.")
|
1000
988
|
|
1001
989
|
aqua_models = []
|
1002
|
-
|
990
|
+
inference_containers = self.get_container_config().to_dict().get("inference")
|
1003
991
|
for model in models:
|
1004
992
|
aqua_models.append(
|
1005
993
|
AquaModelSummary(
|
1006
|
-
**self._process_model(
|
994
|
+
**self._process_model(
|
995
|
+
model=model,
|
996
|
+
region=self.region,
|
997
|
+
inference_containers=inference_containers,
|
998
|
+
),
|
1007
999
|
project_id=project_id or UNKNOWN,
|
1008
1000
|
)
|
1009
1001
|
)
|
1010
|
-
|
1011
|
-
if not compartment_id:
|
1002
|
+
if category == SERVICE:
|
1012
1003
|
self._service_models_cache.__setitem__(
|
1013
|
-
key=
|
1004
|
+
key=AQUA_SERVICE_MODELS, value=aqua_models
|
1014
1005
|
)
|
1015
1006
|
|
1016
1007
|
return aqua_models
|
@@ -1026,15 +1017,10 @@ class AquaModelApp(AquaApp):
|
|
1026
1017
|
"""
|
1027
1018
|
res = {}
|
1028
1019
|
with self._cache_lock:
|
1029
|
-
if
|
1030
|
-
self._service_models_cache.pop(key=
|
1031
|
-
logger.info(
|
1032
|
-
f"Cleared models cache for service compartment {ODSC_MODEL_COMPARTMENT_OCID}."
|
1033
|
-
)
|
1020
|
+
if AQUA_SERVICE_MODELS in self._service_models_cache:
|
1021
|
+
self._service_models_cache.pop(key=AQUA_SERVICE_MODELS)
|
1022
|
+
logger.info("Cleared models cache for service compartment.")
|
1034
1023
|
res = {
|
1035
|
-
"key": {
|
1036
|
-
"compartment_id": ODSC_MODEL_COMPARTMENT_OCID,
|
1037
|
-
},
|
1038
1024
|
"cache_deleted": True,
|
1039
1025
|
}
|
1040
1026
|
return res
|
@@ -1057,14 +1043,85 @@ class AquaModelApp(AquaApp):
|
|
1057
1043
|
|
1058
1044
|
@staticmethod
|
1059
1045
|
def list_valid_inference_containers():
|
1060
|
-
containers =
|
1061
|
-
AquaContainerConfig.from_container_index_json(
|
1062
|
-
config=get_container_config(), enable_spec=True
|
1063
|
-
).inference.values()
|
1064
|
-
)
|
1046
|
+
containers = AquaApp().get_container_config().to_dict().get("inference")
|
1065
1047
|
family_values = [item.family for item in containers]
|
1066
1048
|
return family_values
|
1067
1049
|
|
1050
|
+
@telemetry(
|
1051
|
+
entry_point="plugin=model&action=get_defined_metadata_artifact_content",
|
1052
|
+
name="aqua",
|
1053
|
+
)
|
1054
|
+
def get_defined_metadata_artifact_content(self, model_id: str, metadata_key: str):
|
1055
|
+
"""
|
1056
|
+
Gets the defined metadata artifact content for the given model
|
1057
|
+
|
1058
|
+
Args:
|
1059
|
+
model_id: str
|
1060
|
+
model ocid for which defined metadata artifact needs to be created
|
1061
|
+
metadata_key: str
|
1062
|
+
defined metadata key like Readme , License , DeploymentConfiguration , FinetuningConfiguration
|
1063
|
+
Returns:
|
1064
|
+
The model defined metadata artifact content. Can be either str or Dict
|
1065
|
+
|
1066
|
+
"""
|
1067
|
+
|
1068
|
+
content = self.get_config(model_id, metadata_key)
|
1069
|
+
if not content:
|
1070
|
+
logger.debug(
|
1071
|
+
f"Defined metadata artifact {metadata_key} for model: {model_id} is not available."
|
1072
|
+
)
|
1073
|
+
return content
|
1074
|
+
|
1075
|
+
@telemetry(
|
1076
|
+
entry_point="plugin=model&action=create_defined_metadata_artifact", name="aqua"
|
1077
|
+
)
|
1078
|
+
def create_defined_metadata_artifact(
|
1079
|
+
self,
|
1080
|
+
model_id: str,
|
1081
|
+
metadata_key: str,
|
1082
|
+
path_type: MetadataArtifactPathType,
|
1083
|
+
artifact_path_or_content: str,
|
1084
|
+
) -> None:
|
1085
|
+
"""
|
1086
|
+
Creates defined metadata artifact for the registered unverified model
|
1087
|
+
|
1088
|
+
Args:
|
1089
|
+
model_id: str
|
1090
|
+
model ocid for which defined metadata artifact needs to be created
|
1091
|
+
metadata_key: str
|
1092
|
+
defined metadata key like Readme , License , DeploymentConfiguration , FinetuningConfiguration
|
1093
|
+
path_type: str
|
1094
|
+
path type of the given defined metadata can be local , oss or the content itself
|
1095
|
+
artifact_path_or_content: str
|
1096
|
+
It can be local path or oss path or the actual content itself
|
1097
|
+
Returns:
|
1098
|
+
None
|
1099
|
+
"""
|
1100
|
+
|
1101
|
+
ds_model = DataScienceModel.from_id(model_id)
|
1102
|
+
oci_aqua = ds_model.freeform_tags.get(Tags.AQUA_TAG, None)
|
1103
|
+
if not oci_aqua:
|
1104
|
+
raise AquaRuntimeError(f"Target model {model_id} is not an Aqua model.")
|
1105
|
+
is_registered_model = ds_model.freeform_tags.get(Tags.BASE_MODEL_CUSTOM, None)
|
1106
|
+
is_verified_model = ds_model.freeform_tags.get(
|
1107
|
+
Tags.AQUA_SERVICE_MODEL_TAG, None
|
1108
|
+
)
|
1109
|
+
if is_registered_model and not is_verified_model:
|
1110
|
+
try:
|
1111
|
+
ds_model.create_defined_metadata_artifact(
|
1112
|
+
metadata_key_name=metadata_key,
|
1113
|
+
artifact_path_or_content=artifact_path_or_content,
|
1114
|
+
path_type=path_type,
|
1115
|
+
)
|
1116
|
+
except Exception as ex:
|
1117
|
+
raise AquaRuntimeError(
|
1118
|
+
f"Error occurred in creating defined metadata artifact for model {model_id}: {ex}"
|
1119
|
+
) from ex
|
1120
|
+
else:
|
1121
|
+
raise AquaRuntimeError(
|
1122
|
+
f"Cannot create defined metadata artifact for model {model_id}"
|
1123
|
+
)
|
1124
|
+
|
1068
1125
|
def _create_model_catalog_entry(
|
1069
1126
|
self,
|
1070
1127
|
os_path: str,
|
@@ -1121,7 +1178,9 @@ class AquaModelApp(AquaApp):
|
|
1121
1178
|
|
1122
1179
|
# Remove `ready_to_import` tag that might get copied from service model.
|
1123
1180
|
tags.pop(Tags.READY_TO_IMPORT, None)
|
1124
|
-
|
1181
|
+
defined_metadata_dict = {}
|
1182
|
+
readme_file_path = os_path.rstrip("/") + "/" + README
|
1183
|
+
license_file_path = os_path.rstrip("/") + "/" + LICENSE
|
1125
1184
|
if verified_model:
|
1126
1185
|
# 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.
|
1127
1186
|
# If set, then we copy all the model metadata.
|
@@ -1130,6 +1189,17 @@ class AquaModelApp(AquaApp):
|
|
1130
1189
|
model = model.with_model_file_description(
|
1131
1190
|
json_dict=verified_model.model_file_description
|
1132
1191
|
)
|
1192
|
+
defined_metadata_list = (
|
1193
|
+
verified_model.defined_metadata_list._to_oci_metadata()
|
1194
|
+
)
|
1195
|
+
for defined_metadata in defined_metadata_list:
|
1196
|
+
if defined_metadata.has_artifact:
|
1197
|
+
content = (
|
1198
|
+
self.ds_client.get_model_defined_metadatum_artifact_content(
|
1199
|
+
verified_model.id, defined_metadata.key
|
1200
|
+
).data.content
|
1201
|
+
)
|
1202
|
+
defined_metadata_dict[defined_metadata.key] = content
|
1133
1203
|
else:
|
1134
1204
|
metadata = ModelCustomMetadata()
|
1135
1205
|
if not inference_container:
|
@@ -1151,12 +1221,14 @@ class AquaModelApp(AquaApp):
|
|
1151
1221
|
category="Other",
|
1152
1222
|
)
|
1153
1223
|
|
1154
|
-
inference_containers =
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1224
|
+
inference_containers = (
|
1225
|
+
AquaContainerConfig.from_service_config(
|
1226
|
+
service_containers=self.list_service_containers()
|
1227
|
+
)
|
1228
|
+
.to_dict()
|
1229
|
+
.get("inference")
|
1230
|
+
)
|
1231
|
+
smc_container_set = {container.family for container in inference_containers}
|
1160
1232
|
# only add cmd vars if inference container is not an SMC
|
1161
1233
|
if (
|
1162
1234
|
inference_container not in smc_container_set
|
@@ -1225,6 +1297,33 @@ class AquaModelApp(AquaApp):
|
|
1225
1297
|
.with_defined_tags(**(defined_tags or {}))
|
1226
1298
|
).create(model_by_reference=True)
|
1227
1299
|
logger.debug(f"Created model catalog entry for the model:\n{model}")
|
1300
|
+
for key, value in defined_metadata_dict.items():
|
1301
|
+
model.create_defined_metadata_artifact(
|
1302
|
+
key, value, MetadataArtifactPathType.CONTENT
|
1303
|
+
)
|
1304
|
+
|
1305
|
+
if is_path_exists(readme_file_path):
|
1306
|
+
try:
|
1307
|
+
model.create_defined_metadata_artifact(
|
1308
|
+
AquaModelMetadataKeys.README,
|
1309
|
+
readme_file_path,
|
1310
|
+
MetadataArtifactPathType.OSS,
|
1311
|
+
)
|
1312
|
+
except Exception as ex:
|
1313
|
+
logger.error(
|
1314
|
+
f"Error Uploading Readme in defined metadata for model: {model.id} : {str(ex)}"
|
1315
|
+
)
|
1316
|
+
if not verified_model and is_path_exists(license_file_path):
|
1317
|
+
try:
|
1318
|
+
model.create_defined_metadata_artifact(
|
1319
|
+
AquaModelMetadataKeys.LICENSE,
|
1320
|
+
license_file_path,
|
1321
|
+
MetadataArtifactPathType.OSS,
|
1322
|
+
)
|
1323
|
+
except Exception as ex:
|
1324
|
+
logger.error(
|
1325
|
+
f"Error Uploading License in defined metadata for model: {model.id} : {str(ex)}"
|
1326
|
+
)
|
1228
1327
|
return model
|
1229
1328
|
|
1230
1329
|
@staticmethod
|
@@ -1739,6 +1838,7 @@ class AquaModelApp(AquaApp):
|
|
1739
1838
|
).rstrip("/")
|
1740
1839
|
else:
|
1741
1840
|
artifact_path = import_model_details.os_path.rstrip("/")
|
1841
|
+
|
1742
1842
|
# Create Model catalog entry with pass by reference
|
1743
1843
|
ds_model = self._create_model_catalog_entry(
|
1744
1844
|
os_path=artifact_path,
|
@@ -1777,12 +1877,6 @@ class AquaModelApp(AquaApp):
|
|
1777
1877
|
aqua_model_attributes = dict(
|
1778
1878
|
**self._process_model(ds_model, self.region),
|
1779
1879
|
project_id=ds_model.project_id,
|
1780
|
-
model_card=str(
|
1781
|
-
read_file(
|
1782
|
-
file_path=f"{artifact_path}/{README}",
|
1783
|
-
auth=default_signer(),
|
1784
|
-
)
|
1785
|
-
),
|
1786
1880
|
inference_container=inference_container,
|
1787
1881
|
inference_container_uri=inference_container_uri,
|
1788
1882
|
finetuning_container=finetuning_container,
|
@@ -1856,6 +1950,56 @@ class AquaModelApp(AquaApp):
|
|
1856
1950
|
separator = " " if description else ""
|
1857
1951
|
return f"{description}{separator}{tags_text}"
|
1858
1952
|
|
1953
|
+
@telemetry(entry_point="plugin=model&action=load_readme", name="aqua")
|
1954
|
+
def load_readme(self, model_id: str) -> AquaModelReadme:
|
1955
|
+
"""Loads the readme or the model card for the given model.
|
1956
|
+
|
1957
|
+
Parameters
|
1958
|
+
----------
|
1959
|
+
model_id: str
|
1960
|
+
The model id.
|
1961
|
+
|
1962
|
+
Returns
|
1963
|
+
-------
|
1964
|
+
AquaModelReadme:
|
1965
|
+
The instance of AquaModelReadme.
|
1966
|
+
"""
|
1967
|
+
oci_model = self.ds_client.get_model(model_id).data
|
1968
|
+
artifact_path = get_artifact_path(oci_model.custom_metadata_list)
|
1969
|
+
if not artifact_path:
|
1970
|
+
raise AquaRuntimeError(
|
1971
|
+
f"Readme could not be loaded. Failed to get artifact path from custom metadata for"
|
1972
|
+
f"the model {model_id}."
|
1973
|
+
)
|
1974
|
+
|
1975
|
+
content = ""
|
1976
|
+
try:
|
1977
|
+
content = self.ds_client.get_model_defined_metadatum_artifact_content(
|
1978
|
+
model_id, AquaModelMetadataKeys.README
|
1979
|
+
).data.content.decode("utf-8", errors="ignore")
|
1980
|
+
logger.info(f"Fetched {README} from defined metadata for model: {model_id}")
|
1981
|
+
except Exception as ex:
|
1982
|
+
logger.error(
|
1983
|
+
f"Readme could not be found for model: {model_id} in defined metadata : {str(ex)}"
|
1984
|
+
)
|
1985
|
+
artifact_path = get_artifact_path(oci_model.custom_metadata_list)
|
1986
|
+
readme_path = os.path.join(os.path.dirname(artifact_path), "artifact")
|
1987
|
+
if not is_path_exists(readme_path):
|
1988
|
+
readme_path = os.path.join(artifact_path.rstrip("/"), "artifact")
|
1989
|
+
if not is_path_exists(readme_path):
|
1990
|
+
readme_path = f"{artifact_path.rstrip('/')}/"
|
1991
|
+
|
1992
|
+
readme_file_path = os.path.join(readme_path, README)
|
1993
|
+
logger.info(f"Fetching {README} from {readme_file_path}")
|
1994
|
+
if is_path_exists(readme_file_path):
|
1995
|
+
try:
|
1996
|
+
content = str(read_file(readme_file_path, auth=default_signer()))
|
1997
|
+
except Exception as e:
|
1998
|
+
logger.debug(
|
1999
|
+
f"Error occurred while fetching config {README} at path {readme_file_path} : {str(e)}"
|
2000
|
+
)
|
2001
|
+
return AquaModelReadme(id=model_id, model_card=content)
|
2002
|
+
|
1859
2003
|
@telemetry(entry_point="plugin=model&action=load_license", name="aqua")
|
1860
2004
|
def load_license(self, model_id: str) -> AquaModelLicense:
|
1861
2005
|
"""Loads the license full text for the given model.
|
@@ -1878,13 +2022,34 @@ class AquaModelApp(AquaApp):
|
|
1878
2022
|
f"the model {model_id}."
|
1879
2023
|
)
|
1880
2024
|
|
1881
|
-
content =
|
1882
|
-
|
1883
|
-
|
1884
|
-
|
2025
|
+
content = ""
|
2026
|
+
try:
|
2027
|
+
content = self.ds_client.get_model_defined_metadatum_artifact_content(
|
2028
|
+
model_id, AquaModelMetadataKeys.LICENSE
|
2029
|
+
).data.content.decode("utf-8", errors="ignore")
|
2030
|
+
logger.info(
|
2031
|
+
f"Fetched {LICENSE} from defined metadata for model: {model_id}"
|
1885
2032
|
)
|
1886
|
-
|
1887
|
-
|
2033
|
+
except Exception as ex:
|
2034
|
+
logger.error(
|
2035
|
+
f"License could not be found for model: {model_id} in defined metadata : {str(ex)}"
|
2036
|
+
)
|
2037
|
+
artifact_path = get_artifact_path(oci_model.custom_metadata_list)
|
2038
|
+
license_path = os.path.join(os.path.dirname(artifact_path), "config")
|
2039
|
+
if not is_path_exists(license_path):
|
2040
|
+
license_path = os.path.join(artifact_path.rstrip("/"), "config")
|
2041
|
+
if not is_path_exists(license_path):
|
2042
|
+
license_path = f"{artifact_path.rstrip('/')}/"
|
2043
|
+
|
2044
|
+
license_file_path = os.path.join(license_path, LICENSE)
|
2045
|
+
logger.info(f"Fetching {LICENSE} from {license_file_path}")
|
2046
|
+
if is_path_exists(license_file_path):
|
2047
|
+
try:
|
2048
|
+
content = str(read_file(license_file_path, auth=default_signer()))
|
2049
|
+
except Exception as e:
|
2050
|
+
logger.debug(
|
2051
|
+
f"Error occurred while fetching config {LICENSE} at path {license_path} : {str(e)}"
|
2052
|
+
)
|
1888
2053
|
return AquaModelLicense(id=model_id, license=content)
|
1889
2054
|
|
1890
2055
|
def _find_matching_aqua_model(self, model_id: str) -> Optional[str]:
|