oracle-ads 2.13.6__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/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 +269 -105
- 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.7.dist-info}/METADATA +1 -1
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.7.dist-info}/RECORD +36 -37
- ads/aqua/config/config.py +0 -31
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.7.dist-info}/WHEEL +0 -0
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.7.dist-info}/entry_points.txt +0 -0
- {oracle_ads-2.13.6.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,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
|
]
|
@@ -432,7 +438,7 @@ class AquaModelApp(AquaApp):
|
|
432
438
|
return custom_model
|
433
439
|
|
434
440
|
@telemetry(entry_point="plugin=model&action=get", name="aqua")
|
435
|
-
def get(self, model_id: str
|
441
|
+
def get(self, model_id: str) -> "AquaModel":
|
436
442
|
"""Gets the information of an Aqua model.
|
437
443
|
|
438
444
|
Parameters
|
@@ -455,6 +461,7 @@ class AquaModelApp(AquaApp):
|
|
455
461
|
|
456
462
|
logger.info(f"Fetching model details for model {model_id}.")
|
457
463
|
ds_model = DataScienceModel.from_id(model_id)
|
464
|
+
|
458
465
|
if not self._if_show(ds_model):
|
459
466
|
raise AquaRuntimeError(
|
460
467
|
f"Target model `{ds_model.id} `is not an Aqua model as it does not contain "
|
@@ -466,34 +473,6 @@ class AquaModelApp(AquaApp):
|
|
466
473
|
and ds_model.freeform_tags.get(Tags.AQUA_FINE_TUNED_MODEL_TAG)
|
467
474
|
)
|
468
475
|
|
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
476
|
inference_container = ds_model.custom_metadata_list.get(
|
498
477
|
ModelCustomMetadataFields.DEPLOYMENT_CONTAINER,
|
499
478
|
ModelCustomMetadataItem(key=ModelCustomMetadataFields.DEPLOYMENT_CONTAINER),
|
@@ -520,7 +499,6 @@ class AquaModelApp(AquaApp):
|
|
520
499
|
aqua_model_attributes = dict(
|
521
500
|
**self._process_model(ds_model, self.region),
|
522
501
|
project_id=ds_model.project_id,
|
523
|
-
model_card=model_card,
|
524
502
|
inference_container=inference_container,
|
525
503
|
inference_container_uri=inference_container_uri,
|
526
504
|
finetuning_container=finetuning_container,
|
@@ -791,7 +769,9 @@ class AquaModelApp(AquaApp):
|
|
791
769
|
]
|
792
770
|
|
793
771
|
def get_hf_tokenizer_config(self, model_id):
|
794
|
-
"""
|
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.
|
795
775
|
|
796
776
|
Parameters
|
797
777
|
----------
|
@@ -800,14 +780,19 @@ class AquaModelApp(AquaApp):
|
|
800
780
|
|
801
781
|
Returns
|
802
782
|
-------
|
803
|
-
|
804
|
-
|
783
|
+
Dict:
|
784
|
+
Model tokenizer config.
|
805
785
|
"""
|
806
786
|
config = self.get_config(
|
807
787
|
model_id, AQUA_MODEL_TOKENIZER_CONFIG, ConfigFolder.ARTIFACT
|
808
788
|
).config
|
809
789
|
if not config:
|
810
|
-
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
|
+
|
811
796
|
return config
|
812
797
|
|
813
798
|
@staticmethod
|
@@ -832,6 +817,7 @@ class AquaModelApp(AquaApp):
|
|
832
817
|
oci.resource_search.models.ResourceSummary,
|
833
818
|
],
|
834
819
|
region: str,
|
820
|
+
inference_containers: Optional[List[Any]] = None,
|
835
821
|
) -> dict:
|
836
822
|
"""Constructs required fields for AquaModelSummary."""
|
837
823
|
|
@@ -887,9 +873,10 @@ class AquaModelApp(AquaApp):
|
|
887
873
|
except Exception:
|
888
874
|
model_file = UNKNOWN
|
889
875
|
|
890
|
-
|
891
|
-
|
892
|
-
|
876
|
+
if not inference_containers:
|
877
|
+
inference_containers = (
|
878
|
+
AquaApp().get_container_config().to_dict().get("inference")
|
879
|
+
)
|
893
880
|
|
894
881
|
model_formats_str = freeform_tags.get(
|
895
882
|
Tags.MODEL_FORMAT, ModelFormat.SAFETENSORS
|
@@ -898,7 +885,7 @@ class AquaModelApp(AquaApp):
|
|
898
885
|
|
899
886
|
supported_platform: Set[str] = set()
|
900
887
|
|
901
|
-
for container in inference_containers
|
888
|
+
for container in inference_containers:
|
902
889
|
for model_format in model_formats:
|
903
890
|
if model_format in container.model_formats:
|
904
891
|
supported_platform.update(container.platforms)
|
@@ -932,12 +919,13 @@ class AquaModelApp(AquaApp):
|
|
932
919
|
def list(
|
933
920
|
self,
|
934
921
|
compartment_id: str = None,
|
922
|
+
category: str = None,
|
935
923
|
project_id: str = None,
|
936
924
|
model_type: str = None,
|
937
925
|
**kwargs,
|
938
926
|
) -> List["AquaModelSummary"]:
|
939
927
|
"""Lists all Aqua models within a specified compartment and/or project.
|
940
|
-
If `
|
928
|
+
If `category` is not specified, the method defaults to returning
|
941
929
|
the service models within the pre-configured default compartment. By default, the list
|
942
930
|
of models in the service compartment are cached. Use clear_model_list_cache() to invalidate
|
943
931
|
the cache.
|
@@ -946,6 +934,8 @@ class AquaModelApp(AquaApp):
|
|
946
934
|
----------
|
947
935
|
compartment_id: (str, optional). Defaults to `None`.
|
948
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`
|
949
939
|
project_id: (str, optional). Defaults to `None`.
|
950
940
|
The project OCID.
|
951
941
|
model_type: (str, optional). Defaults to `None`.
|
@@ -959,8 +949,9 @@ class AquaModelApp(AquaApp):
|
|
959
949
|
The list of the `ads.aqua.model.AquaModelSummary`.
|
960
950
|
"""
|
961
951
|
|
962
|
-
|
963
|
-
|
952
|
+
category = category or kwargs.pop("category", SERVICE)
|
953
|
+
compartment_id = compartment_id or COMPARTMENT_OCID
|
954
|
+
if category == USER:
|
964
955
|
# tracks number of times custom model listing was called
|
965
956
|
self.telemetry.record_event_async(
|
966
957
|
category="aqua/custom/model", action="list"
|
@@ -969,48 +960,47 @@ class AquaModelApp(AquaApp):
|
|
969
960
|
logger.info(f"Fetching custom models from compartment_id={compartment_id}.")
|
970
961
|
model_type = model_type.upper() if model_type else ModelType.FT
|
971
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
|
+
)
|
972
966
|
else:
|
973
967
|
# tracks number of times service model listing was called
|
974
968
|
self.telemetry.record_event_async(
|
975
969
|
category="aqua/service/model", action="list"
|
976
970
|
)
|
977
971
|
|
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
|
-
)
|
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)
|
986
975
|
lifecycle_state = kwargs.pop(
|
987
976
|
"lifecycle_state", Model.LIFECYCLE_STATE_ACTIVE
|
988
977
|
)
|
989
978
|
|
990
979
|
models = self.list_resource(
|
991
980
|
self.ds_client.list_models,
|
992
|
-
compartment_id=
|
981
|
+
compartment_id=compartment_id,
|
993
982
|
lifecycle_state=lifecycle_state,
|
983
|
+
category=category,
|
994
984
|
**kwargs,
|
995
985
|
)
|
996
|
-
|
997
|
-
logger.info(
|
998
|
-
f"Fetched {len(models)} model in compartment_id={compartment_id or ODSC_MODEL_COMPARTMENT_OCID}."
|
999
|
-
)
|
986
|
+
logger.info(f"Fetched {len(models)} service models.")
|
1000
987
|
|
1001
988
|
aqua_models = []
|
1002
|
-
|
989
|
+
inference_containers = self.get_container_config().to_dict().get("inference")
|
1003
990
|
for model in models:
|
1004
991
|
aqua_models.append(
|
1005
992
|
AquaModelSummary(
|
1006
|
-
**self._process_model(
|
993
|
+
**self._process_model(
|
994
|
+
model=model,
|
995
|
+
region=self.region,
|
996
|
+
inference_containers=inference_containers,
|
997
|
+
),
|
1007
998
|
project_id=project_id or UNKNOWN,
|
1008
999
|
)
|
1009
1000
|
)
|
1010
|
-
|
1011
|
-
if not compartment_id:
|
1001
|
+
if category == SERVICE:
|
1012
1002
|
self._service_models_cache.__setitem__(
|
1013
|
-
key=
|
1003
|
+
key=AQUA_SERVICE_MODELS, value=aqua_models
|
1014
1004
|
)
|
1015
1005
|
|
1016
1006
|
return aqua_models
|
@@ -1026,15 +1016,10 @@ class AquaModelApp(AquaApp):
|
|
1026
1016
|
"""
|
1027
1017
|
res = {}
|
1028
1018
|
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
|
-
)
|
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.")
|
1034
1022
|
res = {
|
1035
|
-
"key": {
|
1036
|
-
"compartment_id": ODSC_MODEL_COMPARTMENT_OCID,
|
1037
|
-
},
|
1038
1023
|
"cache_deleted": True,
|
1039
1024
|
}
|
1040
1025
|
return res
|
@@ -1057,14 +1042,85 @@ class AquaModelApp(AquaApp):
|
|
1057
1042
|
|
1058
1043
|
@staticmethod
|
1059
1044
|
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
|
-
)
|
1045
|
+
containers = AquaApp().get_container_config().to_dict().get("inference")
|
1065
1046
|
family_values = [item.family for item in containers]
|
1066
1047
|
return family_values
|
1067
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
|
+
|
1068
1124
|
def _create_model_catalog_entry(
|
1069
1125
|
self,
|
1070
1126
|
os_path: str,
|
@@ -1121,7 +1177,9 @@ class AquaModelApp(AquaApp):
|
|
1121
1177
|
|
1122
1178
|
# Remove `ready_to_import` tag that might get copied from service model.
|
1123
1179
|
tags.pop(Tags.READY_TO_IMPORT, None)
|
1124
|
-
|
1180
|
+
defined_metadata_dict = {}
|
1181
|
+
readme_file_path = os_path.rstrip("/") + "/" + README
|
1182
|
+
license_file_path = os_path.rstrip("/") + "/" + LICENSE
|
1125
1183
|
if verified_model:
|
1126
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.
|
1127
1185
|
# If set, then we copy all the model metadata.
|
@@ -1130,6 +1188,17 @@ class AquaModelApp(AquaApp):
|
|
1130
1188
|
model = model.with_model_file_description(
|
1131
1189
|
json_dict=verified_model.model_file_description
|
1132
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
|
1133
1202
|
else:
|
1134
1203
|
metadata = ModelCustomMetadata()
|
1135
1204
|
if not inference_container:
|
@@ -1151,12 +1220,14 @@ class AquaModelApp(AquaApp):
|
|
1151
1220
|
category="Other",
|
1152
1221
|
)
|
1153
1222
|
|
1154
|
-
inference_containers =
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
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}
|
1160
1231
|
# only add cmd vars if inference container is not an SMC
|
1161
1232
|
if (
|
1162
1233
|
inference_container not in smc_container_set
|
@@ -1225,6 +1296,33 @@ class AquaModelApp(AquaApp):
|
|
1225
1296
|
.with_defined_tags(**(defined_tags or {}))
|
1226
1297
|
).create(model_by_reference=True)
|
1227
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
|
+
)
|
1228
1326
|
return model
|
1229
1327
|
|
1230
1328
|
@staticmethod
|
@@ -1739,6 +1837,7 @@ class AquaModelApp(AquaApp):
|
|
1739
1837
|
).rstrip("/")
|
1740
1838
|
else:
|
1741
1839
|
artifact_path = import_model_details.os_path.rstrip("/")
|
1840
|
+
|
1742
1841
|
# Create Model catalog entry with pass by reference
|
1743
1842
|
ds_model = self._create_model_catalog_entry(
|
1744
1843
|
os_path=artifact_path,
|
@@ -1777,12 +1876,6 @@ class AquaModelApp(AquaApp):
|
|
1777
1876
|
aqua_model_attributes = dict(
|
1778
1877
|
**self._process_model(ds_model, self.region),
|
1779
1878
|
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
1879
|
inference_container=inference_container,
|
1787
1880
|
inference_container_uri=inference_container_uri,
|
1788
1881
|
finetuning_container=finetuning_container,
|
@@ -1856,6 +1949,56 @@ class AquaModelApp(AquaApp):
|
|
1856
1949
|
separator = " " if description else ""
|
1857
1950
|
return f"{description}{separator}{tags_text}"
|
1858
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
|
+
|
1859
2002
|
@telemetry(entry_point="plugin=model&action=load_license", name="aqua")
|
1860
2003
|
def load_license(self, model_id: str) -> AquaModelLicense:
|
1861
2004
|
"""Loads the license full text for the given model.
|
@@ -1878,13 +2021,34 @@ class AquaModelApp(AquaApp):
|
|
1878
2021
|
f"the model {model_id}."
|
1879
2022
|
)
|
1880
2023
|
|
1881
|
-
content =
|
1882
|
-
|
1883
|
-
|
1884
|
-
|
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}"
|
1885
2031
|
)
|
1886
|
-
|
1887
|
-
|
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
|
+
)
|
1888
2052
|
return AquaModelLicense(id=model_id, license=content)
|
1889
2053
|
|
1890
2054
|
def _find_matching_aqua_model(self, model_id: str) -> Optional[str]:
|