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.
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 +269 -105
  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.7.dist-info}/METADATA +1 -1
  33. {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.7.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.7.dist-info}/WHEEL +0 -0
  36. {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.7.dist-info}/entry_points.txt +0 -0
  37. {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.7.dist-info}/licenses/LICENSE.txt +0 -0
ads/aqua/constants.py CHANGED
@@ -6,9 +6,10 @@
6
6
  UNKNOWN_VALUE = ""
7
7
  READY_TO_IMPORT_STATUS = "TRUE"
8
8
  UNKNOWN_DICT = {}
9
- README = "README.md"
10
- LICENSE_TXT = "config/LICENSE.txt"
11
9
  DEPLOYMENT_CONFIG = "deployment_config.json"
10
+ FINE_TUNING_CONFIG = "ft_config.json"
11
+ README = "README.md"
12
+ LICENSE = "LICENSE.txt"
12
13
  AQUA_MODEL_TOKENIZER_CONFIG = "tokenizer_config.json"
13
14
  COMPARTMENT_MAPPING_KEY = "service-model-compartment"
14
15
  CONTAINER_INDEX = "container_index.json"
@@ -16,6 +17,7 @@ EVALUATION_REPORT_JSON = "report.json"
16
17
  EVALUATION_REPORT_MD = "report.md"
17
18
  EVALUATION_REPORT = "report.html"
18
19
  UNKNOWN_JSON_STR = "{}"
20
+ UNKNOWN_JSON_LIST = "[]"
19
21
  FINE_TUNING_RUNTIME_CONTAINER = "iad.ocir.io/ociodscdev/aqua_ft_cuda121:0.3.17.20"
20
22
  DEFAULT_FT_BLOCK_STORAGE_SIZE = 750
21
23
  DEFAULT_FT_REPLICA = 1
@@ -88,25 +90,25 @@ LLAMA_CPP_INFERENCE_RESTRICTED_PARAMS = {
88
90
  TEI_CONTAINER_DEFAULT_HOST = "8080"
89
91
 
90
92
  OCI_OPERATION_FAILURES = {
91
- "list_model_deployments": "Unable to list model deployments. See tips for troubleshooting: ",
92
- "list_models": "Unable to list models. See tips for troubleshooting: ",
93
- "get_namespace": "Unable to access specified Object Storage Bucket. See tips for troubleshooting: ",
94
- "list_log_groups":"Unable to access logs. See tips for troubleshooting: " ,
95
- "list_buckets": "Unable to list Object Storage Bucket. See tips for troubleshooting: ",
96
- "put_object": "Unable to access or find Object Storage Bucket. See tips for troubleshooting: ",
97
- "list_model_version_sets": "Unable to create or fetch model version set. See tips for troubleshooting:",
98
- "update_model": "Unable to update model. See tips for troubleshooting: ",
99
- "list_data_science_private_endpoints": "Unable to access private endpoint. See tips for troubleshooting: ",
100
- "create_model" : "Unable to register model. See tips for troubleshooting: ",
101
- "create_deployment": "Unable to create deployment. See tips for troubleshooting: ",
102
- "create_model_version_sets" : "Unable to create model version set. See tips for troubleshooting: ",
103
- "create_job": "Unable to create job. See tips for troubleshooting: ",
104
- "create_job_run": "Unable to create job run. See tips for troubleshooting: ",
93
+ "list_model_deployments": "Unable to list model deployments. See tips for troubleshooting: ",
94
+ "list_models": "Unable to list models. See tips for troubleshooting: ",
95
+ "get_namespace": "Unable to access specified Object Storage Bucket. See tips for troubleshooting: ",
96
+ "list_log_groups": "Unable to access logs. See tips for troubleshooting: ",
97
+ "list_buckets": "Unable to list Object Storage Bucket. See tips for troubleshooting: ",
98
+ "put_object": "Unable to access or find Object Storage Bucket. See tips for troubleshooting: ",
99
+ "list_model_version_sets": "Unable to create or fetch model version set. See tips for troubleshooting:",
100
+ "update_model": "Unable to update model. See tips for troubleshooting: ",
101
+ "list_data_science_private_endpoints": "Unable to access private endpoint. See tips for troubleshooting: ",
102
+ "create_model": "Unable to register model. See tips for troubleshooting: ",
103
+ "create_deployment": "Unable to create deployment. See tips for troubleshooting: ",
104
+ "create_model_version_sets": "Unable to create model version set. See tips for troubleshooting: ",
105
+ "create_job": "Unable to create job. See tips for troubleshooting: ",
106
+ "create_job_run": "Unable to create job run. See tips for troubleshooting: ",
105
107
  }
106
108
 
107
109
  STATUS_CODE_MESSAGES = {
108
- "400": "Could not process your request due to invalid input.",
109
- "403": "We're having trouble processing your request with the information provided.",
110
- "404": "Authorization Failed: The resource you're looking for isn't accessible.",
111
- "408": "Server is taking too long to respond, please try again.",
110
+ "400": "Could not process your request due to invalid input.",
111
+ "403": "We're having trouble processing your request with the information provided.",
112
+ "404": "Authorization Failed: The resource you're looking for isn't accessible.",
113
+ "408": "Server is taking too long to respond, please try again.",
112
114
  }
@@ -41,13 +41,14 @@ from ads.aqua.common.errors import (
41
41
  from ads.aqua.common.utils import (
42
42
  extract_id_and_name_from_tag,
43
43
  fire_and_forget,
44
- get_container_config,
45
- get_container_image,
46
44
  is_valid_ocid,
47
45
  upload_local_to_os,
48
46
  )
49
- from ads.aqua.config.config import get_evaluation_service_config
50
- from ads.aqua.config.container_config import AquaContainerConfig
47
+ from ads.aqua.config.evaluation.evaluation_service_config import (
48
+ DEFAULT_EVALUATION_CONTAINER,
49
+ EvaluationServiceConfig,
50
+ MetricConfig,
51
+ )
51
52
  from ads.aqua.constants import (
52
53
  CONSOLE_LINK_RESOURCE_TYPE_MAPPING,
53
54
  EVALUATION_REPORT,
@@ -80,7 +81,13 @@ from ads.aqua.evaluation.errors import EVALUATION_JOB_EXIT_CODE_MESSAGE
80
81
  from ads.aqua.model.constants import ModelCustomMetadataFields
81
82
  from ads.common.auth import default_signer
82
83
  from ads.common.object_storage_details import ObjectStorageDetails
83
- from ads.common.utils import UNKNOWN, get_console_link, get_files, get_log_links
84
+ from ads.common.utils import (
85
+ UNKNOWN,
86
+ get_console_link,
87
+ get_files,
88
+ get_log_links,
89
+ read_file,
90
+ )
84
91
  from ads.config import (
85
92
  AQUA_JOB_SUBNET_ID,
86
93
  COMPARTMENT_OCID,
@@ -260,10 +267,10 @@ class AquaEvaluationApp(AquaApp):
260
267
  runtime = ModelDeploymentContainerRuntime.from_dict(
261
268
  evaluation_source.runtime.to_dict()
262
269
  )
263
- inference_config = AquaContainerConfig.from_container_index_json(
264
- config=get_container_config(), enable_spec=True
265
- ).inference
266
- for container in inference_config.values():
270
+ inference_config = (
271
+ self.get_container_config().to_dict().get("inference")
272
+ )
273
+ for container in inference_config:
267
274
  if container.name == runtime.image[: runtime.image.rfind(":")]:
268
275
  eval_inference_configuration = (
269
276
  container.spec.evaluation_configuration
@@ -801,14 +808,13 @@ class AquaEvaluationApp(AquaApp):
801
808
 
802
809
  return source.display_name
803
810
 
804
- @staticmethod
805
- def _get_evaluation_container(source_id: str) -> str:
811
+ def _get_evaluation_container(self, source_id: str) -> str:
806
812
  # todo: use the source, identify if it is a model or a deployment. If latter, then fetch the base model id
807
813
  # from the deployment object, and call ds_client.get_model() to get model details. Use custom metadata to
808
814
  # get the container_type_key. Pass this key as container_type to get_container_image method.
809
815
 
810
816
  # fetch image name from config
811
- container_image = get_container_image(
817
+ container_image = self.get_container_image(
812
818
  container_type="odsc-llm-evaluate",
813
819
  )
814
820
  logger.info(f"Aqua Image used for evaluating {source_id} :{container_image}")
@@ -1102,11 +1108,18 @@ class AquaEvaluationApp(AquaApp):
1102
1108
  "loggroup_url": loggroup_url,
1103
1109
  }
1104
1110
 
1105
- def get_supported_metrics(self) -> dict:
1111
+ def get_supported_metrics(self) -> List[MetricConfig]:
1106
1112
  """Gets a list of supported metrics for evaluation."""
1107
- return [
1108
- item.to_dict() for item in get_evaluation_service_config().ui_config.metrics
1109
- ]
1113
+ containers = self.list_service_containers()
1114
+ container_item = next(
1115
+ c
1116
+ for c in containers
1117
+ if c.is_latest and c.family_name == DEFAULT_EVALUATION_CONTAINER
1118
+ )
1119
+ evaluation_service_config = EvaluationServiceConfig.from_oci_container_config(
1120
+ container_item
1121
+ )
1122
+ return evaluation_service_config.ui_config.metrics
1110
1123
 
1111
1124
  @telemetry(entry_point="plugin=evaluation&action=load_metrics", name="aqua")
1112
1125
  def load_metrics(self, eval_id: str) -> AquaEvalMetrics:
@@ -1130,17 +1143,31 @@ class AquaEvaluationApp(AquaApp):
1130
1143
 
1131
1144
  with tempfile.TemporaryDirectory() as temp_dir:
1132
1145
  logger.info(f"Downloading evaluation artifact: {eval_id}.")
1133
- DataScienceModel.from_id(eval_id).download_artifact(
1134
- temp_dir,
1135
- auth=self._auth,
1136
- )
1146
+
1147
+ dsc_model = DataScienceModel.from_id(eval_id)
1148
+ if dsc_model.if_model_custom_metadata_artifact_exist(
1149
+ EVALUATION_REPORT_MD
1150
+ ) and dsc_model.if_model_custom_metadata_artifact_exist(
1151
+ EVALUATION_REPORT_JSON
1152
+ ):
1153
+ logger.info(
1154
+ f"Fetching {EVALUATION_REPORT_MD} and {EVALUATION_REPORT_JSON} from custom metadata..."
1155
+ )
1156
+ dsc_model.get_custom_metadata_artifact(EVALUATION_REPORT_MD, temp_dir)
1157
+ dsc_model.get_custom_metadata_artifact(EVALUATION_REPORT_JSON, temp_dir)
1158
+ else:
1159
+ logger.info("Fetching Evaluation Reports from OSS bucket...")
1160
+ dsc_model.download_artifact(
1161
+ temp_dir,
1162
+ auth=self._auth,
1163
+ )
1137
1164
 
1138
1165
  files_in_artifact = get_files(temp_dir)
1139
1166
  md_report_content = self._read_from_artifact(
1140
1167
  temp_dir, files_in_artifact, EVALUATION_REPORT_MD
1141
1168
  )
1142
1169
 
1143
- # json report not availiable for failed evaluation
1170
+ # json report not available for failed evaluation
1144
1171
  try:
1145
1172
  json_report = json.loads(
1146
1173
  self._read_from_artifact(
@@ -1239,14 +1266,46 @@ class AquaEvaluationApp(AquaApp):
1239
1266
 
1240
1267
  with tempfile.TemporaryDirectory() as temp_dir:
1241
1268
  logger.info(f"Downloading evaluation artifact for {eval_id}.")
1242
- DataScienceModel.from_id(eval_id).download_artifact(
1243
- temp_dir,
1244
- auth=self._auth,
1269
+ dsc_model = DataScienceModel.from_id(eval_id)
1270
+ if_custom_metadata_exists = (
1271
+ dsc_model.if_model_custom_metadata_artifact_exist(EVALUATION_REPORT)
1245
1272
  )
1246
- content = self._read_from_artifact(
1247
- temp_dir, get_files(temp_dir), EVALUATION_REPORT
1248
- )
1249
-
1273
+ if if_custom_metadata_exists:
1274
+ logger.info(f"Fetching {EVALUATION_REPORT} from custom metadata.")
1275
+ dsc_model.get_custom_metadata_artifact(EVALUATION_REPORT, temp_dir)
1276
+ else:
1277
+ logger.info(f"Fetching {EVALUATION_REPORT} from Model artifact.")
1278
+ dsc_model.download_artifact(
1279
+ temp_dir,
1280
+ auth=self._auth,
1281
+ )
1282
+ files_in_artifact = get_files(temp_dir)
1283
+ if not len(files_in_artifact):
1284
+ try:
1285
+ evaluation_output_path = dsc_model.custom_metadata_list.get(
1286
+ EvaluationCustomMetadata.EVALUATION_OUTPUT_PATH
1287
+ ).value
1288
+ report_path = (
1289
+ evaluation_output_path.rstrip("/")
1290
+ + "/"
1291
+ + eval_id
1292
+ + "/"
1293
+ + EVALUATION_REPORT
1294
+ )
1295
+ logger.info(
1296
+ f"Fetching {EVALUATION_REPORT} from {report_path} for evaluation {eval_id}"
1297
+ )
1298
+ content = read_file(
1299
+ file_path=report_path, auth=default_signer()
1300
+ ).encode()
1301
+ except ValueError as err:
1302
+ raise AquaValueError(
1303
+ f"{EvaluationCustomMetadata.EVALUATION_OUTPUT_PATH} is missing from custom metadata for the model {eval_id}"
1304
+ ) from err
1305
+ else:
1306
+ content = self._read_from_artifact(
1307
+ temp_dir, files_in_artifact, EVALUATION_REPORT
1308
+ )
1250
1309
  report = AquaEvalReport(
1251
1310
  evaluation_id=eval_id, content=base64.b64encode(content).decode()
1252
1311
  )
@@ -1376,11 +1435,10 @@ class AquaEvaluationApp(AquaApp):
1376
1435
 
1377
1436
  @staticmethod
1378
1437
  @fire_and_forget
1379
- def _delete_job_and_model(job, model):
1438
+ def _delete_job_and_model(job: DataScienceJob, model: DataScienceModel):
1380
1439
  try:
1381
1440
  job.dsc_job.delete(force_delete=True)
1382
1441
  logger.info(f"Deleting Job: {job.job_id} for evaluation {model.id}")
1383
-
1384
1442
  model.delete()
1385
1443
  logger.info(f"Deleting evaluation: {model.id}")
1386
1444
  except oci.exceptions.ServiceError as ex:
@@ -1389,12 +1447,20 @@ class AquaEvaluationApp(AquaApp):
1389
1447
  f"Exception message: {ex}"
1390
1448
  )
1391
1449
 
1392
- def load_evaluation_config(self, container: Optional[str] = None) -> Dict:
1450
+ def load_evaluation_config(
1451
+ self, container: Optional[str] = DEFAULT_EVALUATION_CONTAINER
1452
+ ) -> Dict:
1393
1453
  """Loads evaluation config."""
1394
1454
 
1395
1455
  logger.info("Loading evaluation container config.")
1396
1456
  # retrieve the evaluation config by container family name
1397
- evaluation_config = get_evaluation_service_config(container)
1457
+ containers = self.list_service_containers()
1458
+ container_item = next(
1459
+ c for c in containers if c.is_latest and c.family_name == container
1460
+ )
1461
+ evaluation_config = EvaluationServiceConfig.from_oci_container_config(
1462
+ container_item
1463
+ )
1398
1464
 
1399
1465
  # convert the new config representation to the old one
1400
1466
  return {
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python
2
- # Copyright (c) 2024 Oracle and/or its affiliates.
2
+ # Copyright (c) 2025 Oracle and/or its affiliates.
3
3
  # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
4
4
 
5
5
 
@@ -12,14 +12,12 @@ from huggingface_hub.utils import LocalTokenNotFoundError
12
12
  from tornado.web import HTTPError
13
13
 
14
14
  from ads.aqua.common.decorator import handle_exceptions
15
- from ads.aqua.common.errors import AquaResourceAccessError, AquaRuntimeError
15
+ from ads.aqua.common.errors import AquaRuntimeError
16
16
  from ads.aqua.common.utils import (
17
17
  get_huggingface_login_timeout,
18
- known_realm,
19
18
  )
20
19
  from ads.aqua.extension.base_handler import AquaAPIhandler
21
20
  from ads.aqua.extension.errors import Errors
22
- from ads.aqua.extension.utils import ui_compatability_check
23
21
 
24
22
 
25
23
  class ADSVersionHandler(AquaAPIhandler):
@@ -50,14 +48,7 @@ class CompatibilityCheckHandler(AquaAPIhandler):
50
48
  AquaResourceAccessError: raised when aqua is not accessible in the given session/region.
51
49
 
52
50
  """
53
- if ui_compatability_check():
54
- return self.finish({"status": "ok"})
55
- elif known_realm():
56
- return self.finish({"status": "compatible"})
57
- else:
58
- raise AquaResourceAccessError(
59
- "The AI Quick actions extension is not compatible in the given region."
60
- )
51
+ return self.finish({"status": "ok"})
61
52
 
62
53
 
63
54
  class NetworkStatusHandler(AquaAPIhandler):
@@ -1,22 +1,18 @@
1
1
  #!/usr/bin/env python
2
2
 
3
- # Copyright (c) 2024 Oracle and/or its affiliates.
3
+ # Copyright (c) 2024, 2025 Oracle and/or its affiliates.
4
4
  # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
5
5
 
6
6
  import json
7
7
  from importlib import metadata
8
- from typing import List, Union
8
+ from typing import List, Optional, Union
9
9
 
10
10
  from ads.aqua.common.decorator import handle_exceptions
11
- from ads.aqua.common.errors import AquaResourceAccessError
12
- from ads.aqua.common.utils import known_realm
13
11
  from ads.aqua.extension.aqua_ws_msg_handler import AquaWSMsgHandler
14
12
  from ads.aqua.extension.models.ws_models import (
15
13
  AdsVersionResponse,
16
- CompatibilityCheckResponse,
17
14
  RequestResponseType,
18
15
  )
19
- from ads.aqua.extension.utils import ui_compatability_check
20
16
 
21
17
 
22
18
  class AquaCommonWsMsgHandler(AquaWSMsgHandler):
@@ -28,7 +24,7 @@ class AquaCommonWsMsgHandler(AquaWSMsgHandler):
28
24
  super().__init__(message)
29
25
 
30
26
  @handle_exceptions
31
- def process(self) -> Union[AdsVersionResponse, CompatibilityCheckResponse]:
27
+ def process(self) -> Optional[AdsVersionResponse]:
32
28
  request = json.loads(self.message)
33
29
  if request.get("kind") == "AdsVersion":
34
30
  version = metadata.version("oracle_ads")
@@ -38,20 +34,3 @@ class AquaCommonWsMsgHandler(AquaWSMsgHandler):
38
34
  data=version,
39
35
  )
40
36
  return response
41
- if request.get("kind") == "CompatibilityCheck":
42
- if ui_compatability_check():
43
- return CompatibilityCheckResponse(
44
- message_id=request.get("message_id"),
45
- kind=RequestResponseType.CompatibilityCheck,
46
- data={"status": "ok"},
47
- )
48
- elif known_realm():
49
- return CompatibilityCheckResponse(
50
- message_id=request.get("message_id"),
51
- kind=RequestResponseType.CompatibilityCheck,
52
- data={"status": "compatible"},
53
- )
54
- else:
55
- raise AquaResourceAccessError(
56
- "The AI Quick actions extension is not compatible in the given region."
57
- )
@@ -9,12 +9,14 @@ from tornado.web import HTTPError
9
9
 
10
10
  from ads.aqua.common.decorator import handle_exceptions
11
11
  from ads.aqua.common.enums import CustomInferenceContainerTypeFamily
12
- from ads.aqua.common.errors import AquaRuntimeError, AquaValueError
12
+ from ads.aqua.common.errors import AquaRuntimeError
13
13
  from ads.aqua.common.utils import get_hf_model_info, is_valid_ocid, list_hf_models
14
14
  from ads.aqua.extension.base_handler import AquaAPIhandler
15
15
  from ads.aqua.extension.errors import Errors
16
16
  from ads.aqua.model import AquaModelApp
17
17
  from ads.aqua.model.entities import AquaModelSummary, HFModelSummary
18
+ from ads.config import SERVICE
19
+ from ads.model.common.utils import MetadataArtifactPathType
18
20
 
19
21
 
20
22
  class AquaModelHandler(AquaAPIhandler):
@@ -37,13 +39,11 @@ class AquaModelHandler(AquaAPIhandler):
37
39
  raise HTTPError(
38
40
  400, Errors.MISSING_REQUIRED_PARAMETER.format("model_format")
39
41
  )
40
-
42
+
41
43
  model_format = model_format.upper()
42
-
44
+
43
45
  if os_path:
44
- return self.finish(
45
- AquaModelApp.get_model_files(os_path, model_format)
46
- )
46
+ return self.finish(AquaModelApp.get_model_files(os_path, model_format))
47
47
  elif model_name:
48
48
  return self.finish(
49
49
  AquaModelApp.get_hf_model_files(model_name, model_format)
@@ -82,11 +82,13 @@ class AquaModelHandler(AquaAPIhandler):
82
82
  # project_id is no needed.
83
83
  project_id = self.get_argument("project_id", default=None)
84
84
  model_type = self.get_argument("model_type", default=None)
85
+ category = self.get_argument("category", default=SERVICE)
85
86
  return self.finish(
86
87
  AquaModelApp().list(
87
88
  compartment_id=compartment_id,
88
89
  project_id=project_id,
89
90
  model_type=model_type,
91
+ category=category,
90
92
  )
91
93
  )
92
94
 
@@ -206,6 +208,16 @@ class AquaModelLicenseHandler(AquaAPIhandler):
206
208
  return self.finish(AquaModelApp().load_license(model_id))
207
209
 
208
210
 
211
+ class AquaModelReadmeHandler(AquaAPIhandler):
212
+ """
213
+ Handler for fetching model card for AQUA models
214
+ """
215
+
216
+ def get(self, model_id):
217
+ model_id = model_id.split("/")[0]
218
+ return self.finish(AquaModelApp().load_readme(model_id).model_dump())
219
+
220
+
209
221
  class AquaHuggingFaceHandler(AquaAPIhandler):
210
222
  """Handler for Aqua Hugging Face REST APIs."""
211
223
 
@@ -329,9 +341,50 @@ class AquaModelTokenizerConfigHandler(AquaAPIhandler):
329
341
  raise HTTPError(400, f"The request {self.request.path} is invalid.")
330
342
 
331
343
 
344
+ class AquaModelDefinedMetadataArtifactHandler(AquaAPIhandler):
345
+ """
346
+ Handler for Model Defined metadata artifact content
347
+
348
+ Raises
349
+ ------
350
+ HTTPError
351
+ Raises HTTPError if inputs are missing or are invalid.
352
+ """
353
+
354
+ @handle_exceptions
355
+ def get(self, model_id: str, metadata_key: str):
356
+ """
357
+ model_id: ocid of the model
358
+ metadata_key: the metadata key for which artifact content needs to be downloaded.
359
+ Can be any of Readme, License , FinetuneConfiguration , DeploymentConfiguration
360
+ """
361
+
362
+ return self.finish(
363
+ AquaModelApp().get_defined_metadata_artifact_content(model_id, metadata_key)
364
+ )
365
+
366
+ @handle_exceptions
367
+ def post(self, model_id: str, metadata_key: str):
368
+ input_body = self.get_json_body()
369
+ path_type = input_body.get("path_type")
370
+ artifact_path_or_content = input_body.get("artifact_path_or_content")
371
+ if path_type not in MetadataArtifactPathType.values():
372
+ raise HTTPError(400, f"Invalid value of path_type: {path_type}")
373
+ return self.finish(
374
+ AquaModelApp().create_defined_metadata_artifact(
375
+ model_id, metadata_key, path_type, artifact_path_or_content
376
+ )
377
+ )
378
+
379
+
332
380
  __handlers__ = [
333
381
  ("model/?([^/]*)", AquaModelHandler),
334
382
  ("model/?([^/]*)/license", AquaModelLicenseHandler),
383
+ ("model/?([^/]*)/readme", AquaModelReadmeHandler),
335
384
  ("model/?([^/]*)/tokenizer", AquaModelTokenizerConfigHandler),
336
385
  ("model/hf/search/?([^/]*)", AquaHuggingFaceHandler),
386
+ (
387
+ "model/?([^/]*)/definedMetadata/?([^/]*)",
388
+ AquaModelDefinedMetadataArtifactHandler,
389
+ ),
337
390
  ]
@@ -6,6 +6,7 @@
6
6
  from dataclasses import dataclass
7
7
  from typing import List, Optional
8
8
 
9
+ import ads.config
9
10
  from ads.aqua.evaluation.entities import AquaEvaluationDetail, AquaEvaluationSummary
10
11
  from ads.aqua.model.entities import AquaModel, AquaModelSummary
11
12
  from ads.aqua.modeldeployment.entities import AquaDeployment, AquaDeploymentDetail
@@ -57,6 +58,7 @@ class ListModelsRequest(BaseRequest):
57
58
  compartment_id: Optional[str] = None
58
59
  project_id: Optional[str] = None
59
60
  model_type: Optional[str] = None
61
+ category: str = ads.config.USER
60
62
  kind = RequestResponseType.ListDeployments
61
63
 
62
64
 
@@ -32,6 +32,7 @@ class AquaModelWSMsgHandler(AquaWSMsgHandler):
32
32
  compartment_id=request.get("compartment_id"),
33
33
  project_id=request.get("project_id"),
34
34
  model_type=request.get("model_type"),
35
+ category=request.get("category"),
35
36
  )
36
37
  response = ListModelsResponse(
37
38
  message_id=request.get("message_id"),
@@ -1,20 +1,17 @@
1
1
  #!/usr/bin/env python
2
- # Copyright (c) 2024 Oracle and/or its affiliates.
2
+ # Copyright (c) 2024, 2025 Oracle and/or its affiliates.
3
3
  # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
4
4
 
5
5
  import re
6
6
  import traceback
7
7
  import uuid
8
8
  from dataclasses import fields
9
- from datetime import datetime, timedelta
10
9
  from http.client import responses
11
10
  from typing import Dict, Optional
12
11
 
13
- from cachetools import TTLCache, cached
14
12
  from tornado.web import HTTPError
15
13
 
16
- from ads.aqua import ODSC_MODEL_COMPARTMENT_OCID, logger
17
- from ads.aqua.common.utils import fetch_service_compartment
14
+ from ads.aqua import logger
18
15
  from ads.aqua.constants import (
19
16
  AQUA_TROUBLESHOOTING_LINK,
20
17
  OCI_OPERATION_FAILURES,
@@ -36,19 +33,11 @@ def validate_function_parameters(data_class, input_data: Dict):
36
33
  )
37
34
 
38
35
 
39
- @cached(cache=TTLCache(maxsize=1, ttl=timedelta(minutes=1), timer=datetime.now))
40
- def ui_compatability_check():
41
- """This method caches the service compartment OCID details that is set by either the environment variable or if
42
- fetched from the configuration. The cached result is returned when multiple calls are made in quick succession
43
- from the UI to avoid multiple config file loads."""
44
- return ODSC_MODEL_COMPARTMENT_OCID or fetch_service_compartment()
45
-
46
-
47
36
  def get_default_error_messages(
48
37
  service_payload: dict,
49
38
  status_code: str,
50
39
  default_msg: str = "Unknown HTTP Error.",
51
- )-> str:
40
+ ) -> str:
52
41
  """Method that maps the error messages based on the operation performed or the status codes encountered."""
53
42
 
54
43
  if service_payload and "operation_name" in service_payload:
@@ -66,14 +55,13 @@ def get_documentation_link(key: str) -> str:
66
55
  return f"{AQUA_TROUBLESHOOTING_LINK}#{github_header}"
67
56
 
68
57
 
69
- def get_troubleshooting_tips(service_payload: dict,
70
- status_code: str) -> str:
58
+ def get_troubleshooting_tips(service_payload: dict, status_code: str) -> str:
71
59
  """Maps authorization errors to potential solutions on Troubleshooting Page per Aqua Documentation on oci-data-science-ai-samples"""
72
60
 
73
61
  tip = f"For general tips on troubleshooting: {AQUA_TROUBLESHOOTING_LINK}"
74
62
 
75
63
  if status_code in (404, 400):
76
- failed_operation = service_payload.get('operation_name')
64
+ failed_operation = service_payload.get("operation_name")
77
65
 
78
66
  if failed_operation in OCI_OPERATION_FAILURES:
79
67
  link = get_documentation_link(failed_operation)
@@ -118,14 +106,13 @@ def construct_error(status_code: int, **kwargs) -> ReplyDetails:
118
106
 
119
107
  tips = get_troubleshooting_tips(service_payload, status_code)
120
108
 
121
-
122
109
  reply = ReplyDetails(
123
- status = status_code,
124
- troubleshooting_tips = tips,
125
- message = message,
126
- service_payload = service_payload,
127
- reason = reason,
128
- request_id = str(uuid.uuid4()),
110
+ status=status_code,
111
+ troubleshooting_tips=tips,
112
+ message=message,
113
+ service_payload=service_payload,
114
+ reason=reason,
115
+ request_id=str(uuid.uuid4()),
129
116
  )
130
117
 
131
118
  exc_info = kwargs.get("exc_info")
@@ -3,7 +3,7 @@
3
3
  # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
4
4
 
5
5
  import json
6
- from typing import List, Literal, Optional, Union
6
+ from typing import Any, Dict, List, Literal, Optional, Union
7
7
 
8
8
  from pydantic import Field, model_validator
9
9
 
@@ -55,6 +55,28 @@ class AquaFineTuningParams(Serializable):
55
55
  return data
56
56
 
57
57
 
58
+ class AquaFineTuningConfig(Serializable):
59
+ """Represents model's shape list and detailed configuration for fine-tuning.
60
+
61
+ Attributes:
62
+ shape (List[str], optional): A list of shape names (e.g., BM.GPU.A10.4).
63
+ configuration (Dict[str, Any], optional): Configuration details of fine-tuning.
64
+ """
65
+
66
+ shape: Optional[Dict[str, Any]] = Field(
67
+ default_factory=dict, description="List of supported shapes for the model."
68
+ )
69
+ finetuning_params: Optional[str] = Field(
70
+ default_factory=str, description="Fine tuning parameters."
71
+ )
72
+ configuration: Optional[Dict[str, Any]] = Field(
73
+ default_factory=dict, description="Configuration details keyed by shape."
74
+ )
75
+
76
+ class Config:
77
+ extra = "allow"
78
+
79
+
58
80
  class AquaFineTuningSummary(Serializable):
59
81
  """Represents a summary of Aqua Finetuning job."""
60
82