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.
Files changed (37) hide show
  1. ads/aqua/__init__.py +0 -5
  2. ads/aqua/app.py +133 -20
  3. ads/aqua/cli.py +2 -15
  4. ads/aqua/common/utils.py +12 -83
  5. ads/aqua/config/container_config.py +105 -69
  6. ads/aqua/config/evaluation/evaluation_service_config.py +40 -0
  7. ads/aqua/constants.py +22 -20
  8. ads/aqua/evaluation/evaluation.py +98 -32
  9. ads/aqua/extension/common_handler.py +3 -12
  10. ads/aqua/extension/common_ws_msg_handler.py +3 -24
  11. ads/aqua/extension/model_handler.py +59 -6
  12. ads/aqua/extension/models/ws_models.py +2 -0
  13. ads/aqua/extension/models_ws_msg_handler.py +1 -0
  14. ads/aqua/extension/utils.py +11 -24
  15. ads/aqua/finetuning/entities.py +23 -1
  16. ads/aqua/finetuning/finetuning.py +26 -10
  17. ads/aqua/model/constants.py +8 -0
  18. ads/aqua/model/entities.py +8 -1
  19. ads/aqua/model/model.py +278 -113
  20. ads/aqua/modeldeployment/deployment.py +51 -47
  21. ads/aqua/modeldeployment/utils.py +23 -5
  22. ads/aqua/ui.py +3 -4
  23. ads/config.py +2 -2
  24. ads/model/datascience_model.py +29 -0
  25. ads/model/service/oci_datascience_model.py +1 -1
  26. ads/opctl/operator/lowcode/anomaly/model/anomaly_dataset.py +8 -6
  27. ads/opctl/operator/lowcode/anomaly/model/base_model.py +1 -1
  28. ads/opctl/operator/lowcode/anomaly/operator_config.py +5 -3
  29. ads/opctl/operator/lowcode/common/transformations.py +2 -0
  30. ads/opctl/operator/lowcode/forecast/model/automlx.py +29 -0
  31. ads/type_discovery/typed_feature.py +32 -34
  32. {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.8.dist-info}/METADATA +1 -1
  33. {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.8.dist-info}/RECORD +36 -37
  34. ads/aqua/config/config.py +0 -31
  35. {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.8.dist-info}/WHEEL +0 -0
  36. {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.8.dist-info}/entry_points.txt +0 -0
  37. {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 ODSC_MODEL_COMPARTMENT_OCID, logger
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
- LICENSE_TXT,
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 UNKNOWN, get_console_link
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 service_model.compartment_id != ODSC_MODEL_COMPARTMENT_OCID:
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
- # Get container config
265
- container_config = get_container_config()
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
- source_model.freeform_tags.get(Tags.TASK, UNKNOWN).lower()
303
- not in MultiModelSupportedTaskType
304
- ):
305
- raise AquaValueError(
306
- f"Invalid or missing {Tags.TASK} tag for selected model {display_name}. "
307
- f"Currently only `{MultiModelSupportedTaskType.values()}` models are supported for multi model deployment."
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, load_model_card: Optional[bool] = True) -> "AquaModel":
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
- """Gets the default chat template for the given Aqua model.
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
- str:
804
- Chat template string.
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(f"Tokenizer config for model: {model_id} is not available.")
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
- inference_containers = AquaContainerConfig.from_container_index_json(
891
- config=get_container_config()
892
- ).inference
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.values():
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 `compartment_id` is not specified, the method defaults to returning
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
- models = []
963
- if compartment_id:
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 ODSC_MODEL_COMPARTMENT_OCID in self._service_models_cache:
979
- logger.info(
980
- f"Returning service models list in {ODSC_MODEL_COMPARTMENT_OCID} from cache."
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=ODSC_MODEL_COMPARTMENT_OCID,
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(model=model, region=self.region),
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=ODSC_MODEL_COMPARTMENT_OCID, value=aqua_models
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 ODSC_MODEL_COMPARTMENT_OCID in self._service_models_cache:
1030
- self._service_models_cache.pop(key=ODSC_MODEL_COMPARTMENT_OCID)
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 = list(
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 = AquaContainerConfig.from_container_index_json(
1155
- config=get_container_config()
1156
- ).inference
1157
- smc_container_set = {
1158
- container.family for container in inference_containers.values()
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 = str(
1882
- read_file(
1883
- file_path=f"{os.path.dirname(artifact_path)}/{LICENSE_TXT}",
1884
- auth=default_signer(),
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]: