oracle-ads 2.12.10rc0__py3-none-any.whl → 2.12.11__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 (28) hide show
  1. ads/aqua/__init__.py +2 -1
  2. ads/aqua/app.py +30 -16
  3. ads/aqua/client/__init__.py +3 -0
  4. ads/aqua/client/client.py +799 -0
  5. ads/aqua/evaluation/evaluation.py +20 -12
  6. ads/aqua/extension/aqua_ws_msg_handler.py +14 -7
  7. ads/aqua/extension/base_handler.py +12 -9
  8. ads/aqua/extension/model_handler.py +6 -1
  9. ads/aqua/finetuning/entities.py +3 -0
  10. ads/aqua/finetuning/finetuning.py +32 -1
  11. ads/aqua/model/entities.py +2 -1
  12. ads/aqua/model/model.py +136 -76
  13. ads/aqua/modeldeployment/deployment.py +22 -10
  14. ads/cli.py +16 -8
  15. ads/opctl/operator/lowcode/common/transformations.py +38 -3
  16. ads/opctl/operator/lowcode/common/utils.py +11 -1
  17. ads/opctl/operator/lowcode/forecast/__main__.py +10 -0
  18. ads/opctl/operator/lowcode/forecast/model/forecast_datasets.py +1 -1
  19. ads/opctl/operator/lowcode/forecast/operator_config.py +31 -0
  20. ads/opctl/operator/lowcode/forecast/schema.yaml +63 -0
  21. ads/opctl/operator/lowcode/forecast/whatifserve/__init__.py +7 -0
  22. ads/opctl/operator/lowcode/forecast/whatifserve/deployment_manager.py +233 -0
  23. ads/opctl/operator/lowcode/forecast/whatifserve/score.py +238 -0
  24. {oracle_ads-2.12.10rc0.dist-info → oracle_ads-2.12.11.dist-info}/METADATA +3 -1
  25. {oracle_ads-2.12.10rc0.dist-info → oracle_ads-2.12.11.dist-info}/RECORD +28 -23
  26. {oracle_ads-2.12.10rc0.dist-info → oracle_ads-2.12.11.dist-info}/LICENSE.txt +0 -0
  27. {oracle_ads-2.12.10rc0.dist-info → oracle_ads-2.12.11.dist-info}/WHEEL +0 -0
  28. {oracle_ads-2.12.10rc0.dist-info → oracle_ads-2.12.11.dist-info}/entry_points.txt +0 -0
ads/aqua/model/model.py CHANGED
@@ -20,12 +20,15 @@ from ads.aqua.common.enums import (
20
20
  InferenceContainerTypeFamily,
21
21
  Tags,
22
22
  )
23
- from ads.aqua.common.errors import AquaRuntimeError, AquaValueError
23
+ from ads.aqua.common.errors import (
24
+ AquaFileNotFoundError,
25
+ AquaRuntimeError,
26
+ AquaValueError,
27
+ )
24
28
  from ads.aqua.common.utils import (
25
29
  LifecycleStatus,
26
30
  _build_resource_identifier,
27
31
  cleanup_local_hf_model_artifact,
28
- copy_model_config,
29
32
  create_word_icon,
30
33
  generate_tei_cmd_var,
31
34
  get_artifact_path,
@@ -162,7 +165,7 @@ class AquaModelApp(AquaApp):
162
165
  target_compartment = compartment_id or COMPARTMENT_OCID
163
166
 
164
167
  if service_model.compartment_id != ODSC_MODEL_COMPARTMENT_OCID:
165
- logger.debug(
168
+ logger.info(
166
169
  f"Aqua Model {model_id} already exists in user's compartment."
167
170
  "Skipped copying."
168
171
  )
@@ -193,8 +196,8 @@ class AquaModelApp(AquaApp):
193
196
  # TODO: decide what kwargs will be needed.
194
197
  .create(model_by_reference=True, **kwargs)
195
198
  )
196
- logger.debug(
197
- f"Aqua Model {custom_model.id} created with the service model {model_id}"
199
+ logger.info(
200
+ f"Aqua Model {custom_model.id} created with the service model {model_id}."
198
201
  )
199
202
 
200
203
  # tracks unique models that were created in the user compartment
@@ -225,11 +228,16 @@ class AquaModelApp(AquaApp):
225
228
 
226
229
  cached_item = self._service_model_details_cache.get(model_id)
227
230
  if cached_item:
231
+ logger.info(f"Fetching model details for model {model_id} from cache.")
228
232
  return cached_item
229
233
 
234
+ logger.info(f"Fetching model details for model {model_id}.")
230
235
  ds_model = DataScienceModel.from_id(model_id)
231
236
  if not self._if_show(ds_model):
232
- raise AquaRuntimeError(f"Target model `{ds_model.id} `is not Aqua model.")
237
+ raise AquaRuntimeError(
238
+ f"Target model `{ds_model.id} `is not an Aqua model as it does not contain "
239
+ f"{Tags.AQUA_TAG} tag."
240
+ )
233
241
 
234
242
  is_fine_tuned_model = bool(
235
243
  ds_model.freeform_tags
@@ -248,16 +256,21 @@ class AquaModelApp(AquaApp):
248
256
  ds_model.custom_metadata_list._to_oci_metadata()
249
257
  )
250
258
  if artifact_path != UNKNOWN:
259
+ model_card_path = (
260
+ f"{artifact_path.rstrip('/')}/config/{README}"
261
+ if is_verified_type
262
+ else f"{artifact_path.rstrip('/')}/{README}"
263
+ )
251
264
  model_card = str(
252
265
  read_file(
253
- file_path=(
254
- f"{artifact_path.rstrip('/')}/config/{README}"
255
- if is_verified_type
256
- else f"{artifact_path.rstrip('/')}/{README}"
257
- ),
266
+ file_path=model_card_path,
258
267
  auth=default_signer(),
259
268
  )
260
269
  )
270
+ if not model_card:
271
+ logger.warn(
272
+ f"Model card for {model_id} is empty or could not be loaded from {model_card_path}."
273
+ )
261
274
 
262
275
  inference_container = ds_model.custom_metadata_list.get(
263
276
  ModelCustomMetadataFields.DEPLOYMENT_CONTAINER,
@@ -303,9 +316,10 @@ class AquaModelApp(AquaApp):
303
316
  try:
304
317
  jobrun_ocid = ds_model.provenance_metadata.training_id
305
318
  jobrun = self.ds_client.get_job_run(jobrun_ocid).data
306
- except Exception:
319
+ except Exception as e:
307
320
  logger.debug(
308
321
  f"Missing jobrun information in the provenance metadata of the given model {model_id}."
322
+ f"\nError: {str(e)}"
309
323
  )
310
324
  jobrun = None
311
325
 
@@ -314,7 +328,10 @@ class AquaModelApp(AquaApp):
314
328
  FineTuningCustomMetadata.FT_SOURCE
315
329
  ).value
316
330
  except ValueError as e:
317
- logger.debug(str(e))
331
+ logger.debug(
332
+ f"Custom metadata is missing {FineTuningCustomMetadata.FT_SOURCE} key for "
333
+ f"model {model_id}.\nError: {str(e)}"
334
+ )
318
335
  source_id = UNKNOWN
319
336
 
320
337
  try:
@@ -322,7 +339,10 @@ class AquaModelApp(AquaApp):
322
339
  FineTuningCustomMetadata.FT_SOURCE_NAME
323
340
  ).value
324
341
  except ValueError as e:
325
- logger.debug(str(e))
342
+ logger.debug(
343
+ f"Custom metadata is missing {FineTuningCustomMetadata.FT_SOURCE_NAME} key for "
344
+ f"model {model_id}.\nError: {str(e)}"
345
+ )
326
346
  source_name = UNKNOWN
327
347
 
328
348
  source_identifier = _build_resource_identifier(
@@ -372,6 +392,7 @@ class AquaModelApp(AquaApp):
372
392
  Tags.AQUA_FINE_TUNED_MODEL_TAG, None
373
393
  )
374
394
  if is_registered_model or is_fine_tuned_model:
395
+ logger.info(f"Deleting model {model_id}.")
375
396
  return ds_model.delete()
376
397
  else:
377
398
  raise AquaRuntimeError(
@@ -478,6 +499,7 @@ class AquaModelApp(AquaApp):
478
499
  freeform_tags=freeform_tags,
479
500
  )
480
501
  AquaApp().update_model(id, update_model_details)
502
+ logger.info(f"Updated model details for the model {id}.")
481
503
  else:
482
504
  raise AquaRuntimeError("Only registered unverified models can be edited.")
483
505
 
@@ -735,7 +757,7 @@ class AquaModelApp(AquaApp):
735
757
  )
736
758
 
737
759
  logger.info(
738
- f"Fetch {len(models)} model in compartment_id={compartment_id or ODSC_MODEL_COMPARTMENT_OCID}."
760
+ f"Fetched {len(models)} model in compartment_id={compartment_id or ODSC_MODEL_COMPARTMENT_OCID}."
739
761
  )
740
762
 
741
763
  aqua_models = []
@@ -765,10 +787,12 @@ class AquaModelApp(AquaApp):
765
787
  dict with the key used, and True if cache has the key that needs to be deleted.
766
788
  """
767
789
  res = {}
768
- logger.info("Clearing _service_models_cache")
769
790
  with self._cache_lock:
770
791
  if ODSC_MODEL_COMPARTMENT_OCID in self._service_models_cache:
771
792
  self._service_models_cache.pop(key=ODSC_MODEL_COMPARTMENT_OCID)
793
+ logger.info(
794
+ f"Cleared models cache for service compartment {ODSC_MODEL_COMPARTMENT_OCID}."
795
+ )
772
796
  res = {
773
797
  "key": {
774
798
  "compartment_id": ODSC_MODEL_COMPARTMENT_OCID,
@@ -785,10 +809,10 @@ class AquaModelApp(AquaApp):
785
809
  dict with the key used, and True if cache has the key that needs to be deleted.
786
810
  """
787
811
  res = {}
788
- logger.info(f"Clearing _service_model_details_cache for {model_id}")
789
812
  with self._cache_lock:
790
813
  if model_id in self._service_model_details_cache:
791
814
  self._service_model_details_cache.pop(key=model_id)
815
+ logger.info(f"Clearing model details cache for model {model_id}.")
792
816
  res = {"key": {"model_id": model_id}, "cache_deleted": True}
793
817
 
794
818
  return res
@@ -873,7 +897,8 @@ class AquaModelApp(AquaApp):
873
897
  metadata = ModelCustomMetadata()
874
898
  if not inference_container:
875
899
  raise AquaRuntimeError(
876
- f"Require Inference container information. Model: {model_name} does not have associated inference container defaults. Check docs for more information on how to pass inference container."
900
+ f"Require Inference container information. Model: {model_name} does not have associated inference "
901
+ f"container defaults. Check docs for more information on how to pass inference container."
877
902
  )
878
903
  metadata.add(
879
904
  key=AQUA_DEPLOYMENT_CONTAINER_METADATA_NAME,
@@ -943,24 +968,6 @@ class AquaModelApp(AquaApp):
943
968
  )
944
969
  tags[Tags.LICENSE] = validation_result.tags.get(Tags.LICENSE, UNKNOWN)
945
970
 
946
- try:
947
- # If verified model already has a artifact json, use that.
948
- artifact_path = metadata.get(MODEL_BY_REFERENCE_OSS_PATH_KEY).value
949
- logger.info(
950
- f"Found model artifact in the service bucket. "
951
- f"Using artifact from service bucket instead of {os_path}"
952
- )
953
-
954
- # todo: implement generic copy_folder method
955
- # copy model config from artifact path to user bucket
956
- copy_model_config(
957
- artifact_path=artifact_path, os_path=os_path, auth=default_signer()
958
- )
959
- except Exception:
960
- logger.debug(
961
- f"Proceeding with model registration without copying model config files at {os_path}. "
962
- f"Default configuration will be used for deployment and fine-tuning."
963
- )
964
971
  # Set artifact location to user bucket, and replace existing key if present.
965
972
  metadata.add(
966
973
  key=MODEL_BY_REFERENCE_OSS_PATH_KEY,
@@ -980,7 +987,7 @@ class AquaModelApp(AquaApp):
980
987
  .with_freeform_tags(**tags)
981
988
  .with_defined_tags(**(defined_tags or {}))
982
989
  ).create(model_by_reference=True)
983
- logger.debug(model)
990
+ logger.debug(f"Created model catalog entry for the model:\n{model}")
984
991
  return model
985
992
 
986
993
  @staticmethod
@@ -1000,13 +1007,23 @@ class AquaModelApp(AquaApp):
1000
1007
  # todo: revisit this logic to account for .bin files. In the current state, .bin and .safetensor models
1001
1008
  # are grouped in one category and validation checks for config.json files only.
1002
1009
  if model_format == ModelFormat.SAFETENSORS:
1010
+ model_files.extend(
1011
+ list_os_files_with_extension(oss_path=os_path, extension=".safetensors")
1012
+ )
1003
1013
  try:
1004
1014
  load_config(
1005
1015
  file_path=os_path,
1006
1016
  config_file_name=AQUA_MODEL_ARTIFACT_CONFIG,
1007
1017
  )
1008
- except Exception:
1009
- pass
1018
+ except Exception as ex:
1019
+ message = (
1020
+ f"The model path {os_path} does not contain the file config.json. "
1021
+ f"Please check if the path is correct or the model artifacts are available at this location."
1022
+ )
1023
+ logger.warning(
1024
+ f"{message}\n"
1025
+ f"Details: {ex.reason if isinstance(ex, AquaFileNotFoundError) else str(ex)}\n"
1026
+ )
1010
1027
  else:
1011
1028
  model_files.append(AQUA_MODEL_ARTIFACT_CONFIG)
1012
1029
 
@@ -1014,6 +1031,9 @@ class AquaModelApp(AquaApp):
1014
1031
  model_files.extend(
1015
1032
  list_os_files_with_extension(oss_path=os_path, extension=".gguf")
1016
1033
  )
1034
+ logger.debug(
1035
+ f"Fetched {len(model_files)} model files from {os_path} for model format {model_format}."
1036
+ )
1017
1037
  return model_files
1018
1038
 
1019
1039
  @staticmethod
@@ -1050,12 +1070,17 @@ class AquaModelApp(AquaApp):
1050
1070
 
1051
1071
  for model_sibling in model_siblings:
1052
1072
  extension = pathlib.Path(model_sibling.rfilename).suffix[1:].upper()
1053
- if model_format == ModelFormat.SAFETENSORS:
1054
- if model_sibling.rfilename == AQUA_MODEL_ARTIFACT_CONFIG:
1055
- model_files.append(model_sibling.rfilename)
1056
- elif extension == model_format.value:
1073
+ if (
1074
+ model_format == ModelFormat.SAFETENSORS
1075
+ and model_sibling.rfilename == AQUA_MODEL_ARTIFACT_CONFIG
1076
+ ):
1077
+ model_files.append(model_sibling.rfilename)
1078
+ if extension == model_format.value:
1057
1079
  model_files.append(model_sibling.rfilename)
1058
1080
 
1081
+ logger.debug(
1082
+ f"Fetched {len(model_files)} model files for the model {model_name} for model format {model_format}."
1083
+ )
1059
1084
  return model_files
1060
1085
 
1061
1086
  def _validate_model(
@@ -1089,7 +1114,10 @@ class AquaModelApp(AquaApp):
1089
1114
  safetensors_model_files = self.get_hf_model_files(
1090
1115
  model_name, ModelFormat.SAFETENSORS
1091
1116
  )
1092
- if safetensors_model_files:
1117
+ if (
1118
+ safetensors_model_files
1119
+ and AQUA_MODEL_ARTIFACT_CONFIG in safetensors_model_files
1120
+ ):
1093
1121
  hf_download_config_present = True
1094
1122
  gguf_model_files = self.get_hf_model_files(model_name, ModelFormat.GGUF)
1095
1123
  else:
@@ -1145,8 +1173,11 @@ class AquaModelApp(AquaApp):
1145
1173
  Tags.LICENSE: license_value,
1146
1174
  }
1147
1175
  validation_result.tags = hf_tags
1148
- except Exception:
1149
- pass
1176
+ except Exception as ex:
1177
+ logger.debug(
1178
+ f"An error occurred while getting tag information for model {model_name}. "
1179
+ f"Error: {str(ex)}"
1180
+ )
1150
1181
 
1151
1182
  validation_result.model_formats = model_formats
1152
1183
 
@@ -1201,40 +1232,55 @@ class AquaModelApp(AquaApp):
1201
1232
  model_name: str = None,
1202
1233
  ):
1203
1234
  if import_model_details.download_from_hf:
1204
- # validates config.json exists for safetensors model from hugginface
1205
- if not hf_download_config_present:
1235
+ # validates config.json exists for safetensors model from huggingface
1236
+ if not (
1237
+ hf_download_config_present
1238
+ or import_model_details.ignore_model_artifact_check
1239
+ ):
1206
1240
  raise AquaRuntimeError(
1207
1241
  f"The model {model_name} does not contain {AQUA_MODEL_ARTIFACT_CONFIG} file as required "
1208
1242
  f"by {ModelFormat.SAFETENSORS.value} format model."
1209
1243
  f" Please check if the model name is correct in Hugging Face repository."
1210
1244
  )
1245
+ validation_result.telemetry_model_name = model_name
1211
1246
  else:
1247
+ # validate if config.json is available from object storage, and get model name for telemetry
1248
+ model_config = None
1212
1249
  try:
1213
1250
  model_config = load_config(
1214
1251
  file_path=import_model_details.os_path,
1215
1252
  config_file_name=AQUA_MODEL_ARTIFACT_CONFIG,
1216
1253
  )
1217
1254
  except Exception as ex:
1218
- logger.error(
1219
- f"Exception occurred while loading config file from {import_model_details.os_path}"
1220
- f"Exception message: {ex}"
1221
- )
1222
- raise AquaRuntimeError(
1255
+ message = (
1223
1256
  f"The model path {import_model_details.os_path} does not contain the file config.json. "
1224
1257
  f"Please check if the path is correct or the model artifacts are available at this location."
1225
- ) from ex
1226
- else:
1258
+ )
1259
+ if not import_model_details.ignore_model_artifact_check:
1260
+ logger.error(
1261
+ f"{message}\n"
1262
+ f"Details: {ex.reason if isinstance(ex, AquaFileNotFoundError) else str(ex)}"
1263
+ )
1264
+ raise AquaRuntimeError(message) from ex
1265
+ else:
1266
+ logger.warning(
1267
+ f"{message}\n"
1268
+ f"Proceeding with model registration as ignore_model_artifact_check field is set."
1269
+ )
1270
+
1271
+ if verified_model:
1272
+ # model_type validation, log message if metadata field doesn't match.
1227
1273
  try:
1228
1274
  metadata_model_type = verified_model.custom_metadata_list.get(
1229
1275
  AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE
1230
1276
  ).value
1231
- if metadata_model_type:
1277
+ if metadata_model_type and model_config is not None:
1232
1278
  if AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE in model_config:
1233
1279
  if (
1234
1280
  model_config[AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE]
1235
1281
  != metadata_model_type
1236
1282
  ):
1237
- raise AquaRuntimeError(
1283
+ logger.debug(
1238
1284
  f"The {AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE} attribute in {AQUA_MODEL_ARTIFACT_CONFIG}"
1239
1285
  f" at {import_model_details.os_path} is invalid, expected {metadata_model_type} for "
1240
1286
  f"the model {model_name}. Please check if the path is correct or "
@@ -1246,22 +1292,26 @@ class AquaModelApp(AquaApp):
1246
1292
  f"Could not find {AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE} attribute in "
1247
1293
  f"{AQUA_MODEL_ARTIFACT_CONFIG}. Proceeding with model registration."
1248
1294
  )
1249
- except Exception:
1250
- pass
1251
- if verified_model:
1252
- validation_result.telemetry_model_name = verified_model.display_name
1253
- elif (
1254
- model_config is not None
1255
- and AQUA_MODEL_ARTIFACT_CONFIG_MODEL_NAME in model_config
1256
- ):
1257
- validation_result.telemetry_model_name = f"{AQUA_MODEL_TYPE_CUSTOM}_{model_config[AQUA_MODEL_ARTIFACT_CONFIG_MODEL_NAME]}"
1258
- elif (
1259
- model_config is not None
1260
- and AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE in model_config
1261
- ):
1262
- validation_result.telemetry_model_name = f"{AQUA_MODEL_TYPE_CUSTOM}_{model_config[AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE]}"
1263
- else:
1264
- validation_result.telemetry_model_name = AQUA_MODEL_TYPE_CUSTOM
1295
+ except Exception as ex:
1296
+ # todo: raise exception if model_type doesn't match. Currently log message and pass since service
1297
+ # models do not have this metadata.
1298
+ logger.debug(
1299
+ f"Error occurred while processing metadata for model {model_name}. "
1300
+ f"Exception: {str(ex)}"
1301
+ )
1302
+ validation_result.telemetry_model_name = verified_model.display_name
1303
+ elif (
1304
+ model_config is not None
1305
+ and AQUA_MODEL_ARTIFACT_CONFIG_MODEL_NAME in model_config
1306
+ ):
1307
+ validation_result.telemetry_model_name = f"{AQUA_MODEL_TYPE_CUSTOM}_{model_config[AQUA_MODEL_ARTIFACT_CONFIG_MODEL_NAME]}"
1308
+ elif (
1309
+ model_config is not None
1310
+ and AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE in model_config
1311
+ ):
1312
+ validation_result.telemetry_model_name = f"{AQUA_MODEL_TYPE_CUSTOM}_{model_config[AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE]}"
1313
+ else:
1314
+ validation_result.telemetry_model_name = AQUA_MODEL_TYPE_CUSTOM
1265
1315
 
1266
1316
  @staticmethod
1267
1317
  def _validate_gguf_format(
@@ -1363,6 +1413,10 @@ class AquaModelApp(AquaApp):
1363
1413
  allow_patterns=allow_patterns,
1364
1414
  ignore_patterns=ignore_patterns,
1365
1415
  )
1416
+ # Upload to object storage and skip .cache/huggingface/ folder
1417
+ logger.debug(
1418
+ f"Uploading local artifacts from local directory {local_dir} to {os_path}."
1419
+ )
1366
1420
  # Upload to object storage
1367
1421
  model_artifact_path = upload_folder(
1368
1422
  os_path=os_path,
@@ -1409,6 +1463,7 @@ class AquaModelApp(AquaApp):
1409
1463
  import_model_details.model.startswith("ocid")
1410
1464
  and "datasciencemodel" in import_model_details.model
1411
1465
  ):
1466
+ logger.info(f"Fetching details for model {import_model_details.model}.")
1412
1467
  verified_model = DataScienceModel.from_id(import_model_details.model)
1413
1468
  else:
1414
1469
  # If users passes model name, check if there is model with the same name in the service model catalog. If it is there, then use that model
@@ -1446,7 +1501,6 @@ class AquaModelApp(AquaApp):
1446
1501
  ).rstrip("/")
1447
1502
  else:
1448
1503
  artifact_path = import_model_details.os_path.rstrip("/")
1449
-
1450
1504
  # Create Model catalog entry with pass by reference
1451
1505
  ds_model = self._create_model_catalog_entry(
1452
1506
  os_path=artifact_path,
@@ -1539,7 +1593,7 @@ class AquaModelApp(AquaApp):
1539
1593
  elif model_type == ModelType.BASE:
1540
1594
  filter_tag = Tags.BASE_MODEL_CUSTOM
1541
1595
  else:
1542
- raise ValueError(
1596
+ raise AquaValueError(
1543
1597
  f"Model of type {model_type} is unknown. The values should be in {ModelType.values()}"
1544
1598
  )
1545
1599
 
@@ -1579,7 +1633,10 @@ class AquaModelApp(AquaApp):
1579
1633
  oci_model = self.ds_client.get_model(model_id).data
1580
1634
  artifact_path = get_artifact_path(oci_model.custom_metadata_list)
1581
1635
  if not artifact_path:
1582
- raise AquaRuntimeError("Failed to get artifact path from custom metadata.")
1636
+ raise AquaRuntimeError(
1637
+ f"License could not be loaded. Failed to get artifact path from custom metadata for"
1638
+ f"the model {model_id}."
1639
+ )
1583
1640
 
1584
1641
  content = str(
1585
1642
  read_file(
@@ -1610,6 +1667,9 @@ class AquaModelApp(AquaApp):
1610
1667
 
1611
1668
  for aqua_model_summary in aqua_model_list:
1612
1669
  if aqua_model_summary.name.lower() == model_id_lower:
1670
+ logger.info(
1671
+ f"Found matching verified model id {aqua_model_summary.id} for the model {model_id}"
1672
+ )
1613
1673
  return aqua_model_summary.id
1614
1674
 
1615
1675
  return None
@@ -1,8 +1,7 @@
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
- import logging
6
5
  import shlex
7
6
  from typing import Dict, List, Optional, Union
8
7
 
@@ -271,7 +270,7 @@ class AquaDeploymentApp(AquaApp):
271
270
  f"field. Either re-register the model with custom container URI, or set container_image_uri "
272
271
  f"parameter when creating this deployment."
273
272
  ) from err
274
- logging.info(
273
+ logger.info(
275
274
  f"Aqua Image used for deploying {aqua_model.id} : {container_image_uri}"
276
275
  )
277
276
 
@@ -282,14 +281,14 @@ class AquaDeploymentApp(AquaApp):
282
281
  default_cmd_var = shlex.split(cmd_var_string)
283
282
  if default_cmd_var:
284
283
  cmd_var = validate_cmd_var(default_cmd_var, cmd_var)
285
- logging.info(f"CMD used for deploying {aqua_model.id} :{cmd_var}")
284
+ logger.info(f"CMD used for deploying {aqua_model.id} :{cmd_var}")
286
285
  except ValueError:
287
- logging.debug(
286
+ logger.debug(
288
287
  f"CMD will be ignored for this deployment as {AQUA_DEPLOYMENT_CONTAINER_CMD_VAR_METADATA_NAME} "
289
288
  f"key is not available in the custom metadata field for this model."
290
289
  )
291
290
  except Exception as e:
292
- logging.error(
291
+ logger.error(
293
292
  f"There was an issue processing CMD arguments. Error: {str(e)}"
294
293
  )
295
294
 
@@ -385,7 +384,7 @@ class AquaDeploymentApp(AquaApp):
385
384
  if key not in env_var:
386
385
  env_var.update(env)
387
386
 
388
- logging.info(f"Env vars used for deploying {aqua_model.id} :{env_var}")
387
+ logger.info(f"Env vars used for deploying {aqua_model.id} :{env_var}")
389
388
 
390
389
  # Start model deployment
391
390
  # configure model deployment infrastructure
@@ -440,10 +439,14 @@ class AquaDeploymentApp(AquaApp):
440
439
  .with_runtime(container_runtime)
441
440
  ).deploy(wait_for_completion=False)
442
441
 
442
+ deployment_id = deployment.dsc_model_deployment.id
443
+ logger.info(
444
+ f"Aqua model deployment {deployment_id} created for model {aqua_model.id}."
445
+ )
443
446
  model_type = (
444
447
  AQUA_MODEL_TYPE_CUSTOM if is_fine_tuned_model else AQUA_MODEL_TYPE_SERVICE
445
448
  )
446
- deployment_id = deployment.dsc_model_deployment.id
449
+
447
450
  # we arbitrarily choose last 8 characters of OCID to identify MD in telemetry
448
451
  telemetry_kwargs = {"ocid": get_ocid_substring(deployment_id, key_len=8)}
449
452
 
@@ -539,6 +542,9 @@ class AquaDeploymentApp(AquaApp):
539
542
  value=state,
540
543
  )
541
544
 
545
+ logger.info(
546
+ f"Fetched {len(results)} model deployments from compartment_id={compartment_id}."
547
+ )
542
548
  # tracks number of times deployment listing was called
543
549
  self.telemetry.record_event_async(category="aqua/deployment", action="list")
544
550
 
@@ -546,18 +552,21 @@ class AquaDeploymentApp(AquaApp):
546
552
 
547
553
  @telemetry(entry_point="plugin=deployment&action=delete", name="aqua")
548
554
  def delete(self, model_deployment_id: str):
555
+ logger.info(f"Deleting model deployment {model_deployment_id}.")
549
556
  return self.ds_client.delete_model_deployment(
550
557
  model_deployment_id=model_deployment_id
551
558
  ).data
552
559
 
553
560
  @telemetry(entry_point="plugin=deployment&action=deactivate", name="aqua")
554
561
  def deactivate(self, model_deployment_id: str):
562
+ logger.info(f"Deactivating model deployment {model_deployment_id}.")
555
563
  return self.ds_client.deactivate_model_deployment(
556
564
  model_deployment_id=model_deployment_id
557
565
  ).data
558
566
 
559
567
  @telemetry(entry_point="plugin=deployment&action=activate", name="aqua")
560
568
  def activate(self, model_deployment_id: str):
569
+ logger.info(f"Activating model deployment {model_deployment_id}.")
561
570
  return self.ds_client.activate_model_deployment(
562
571
  model_deployment_id=model_deployment_id
563
572
  ).data
@@ -579,6 +588,8 @@ class AquaDeploymentApp(AquaApp):
579
588
  AquaDeploymentDetail:
580
589
  The instance of the Aqua model deployment details.
581
590
  """
591
+ logger.info(f"Fetching model deployment details for {model_deployment_id}.")
592
+
582
593
  model_deployment = self.ds_client.get_model_deployment(
583
594
  model_deployment_id=model_deployment_id, **kwargs
584
595
  ).data
@@ -594,7 +605,8 @@ class AquaDeploymentApp(AquaApp):
594
605
 
595
606
  if not oci_aqua:
596
607
  raise AquaRuntimeError(
597
- f"Target deployment {model_deployment_id} is not Aqua deployment."
608
+ f"Target deployment {model_deployment_id} is not Aqua deployment as it does not contain "
609
+ f"{Tags.AQUA_TAG} tag."
598
610
  )
599
611
 
600
612
  log_id = ""
@@ -652,7 +664,7 @@ class AquaDeploymentApp(AquaApp):
652
664
  config = self.get_config(model_id, AQUA_MODEL_DEPLOYMENT_CONFIG)
653
665
  if not config:
654
666
  logger.debug(
655
- f"Deployment config for custom model: {model_id} is not available."
667
+ f"Deployment config for custom model: {model_id} is not available. Use defaults."
656
668
  )
657
669
  return config
658
670
 
ads/cli.py CHANGED
@@ -1,14 +1,15 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*--
3
-
4
- # Copyright (c) 2021, 2024 Oracle and/or its affiliates.
2
+ # Copyright (c) 2021, 2025 Oracle and/or its affiliates.
5
3
  # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
6
4
 
5
+ import json
6
+ import logging
7
7
  import sys
8
8
  import traceback
9
- from dataclasses import is_dataclass
9
+ import uuid
10
10
 
11
11
  import fire
12
+ from pydantic import BaseModel
12
13
 
13
14
  from ads.common import logger
14
15
 
@@ -27,7 +28,7 @@ except Exception as ex:
27
28
  )
28
29
  logger.debug(ex)
29
30
  logger.debug(traceback.format_exc())
30
- exit()
31
+ sys.exit()
31
32
 
32
33
  # https://packaging.python.org/en/latest/guides/single-sourcing-package-version/#single-sourcing-the-package-version
33
34
  if sys.version_info >= (3, 8):
@@ -84,7 +85,13 @@ def serialize(data):
84
85
  The string representation of each dataclass object.
85
86
  """
86
87
  if isinstance(data, list):
87
- [print(str(item)) for item in data]
88
+ for item in data:
89
+ if isinstance(item, BaseModel):
90
+ print(json.dumps(item.dict(), indent=4))
91
+ else:
92
+ print(str(item))
93
+ elif isinstance(data, BaseModel):
94
+ print(json.dumps(data.dict(), indent=4))
88
95
  else:
89
96
  print(str(data))
90
97
 
@@ -122,8 +129,9 @@ def exit_program(ex: Exception, logger: "logging.Logger") -> None:
122
129
  ... exit_program(e, logger)
123
130
  """
124
131
 
125
- logger.debug(traceback.format_exc())
126
- logger.error(str(ex))
132
+ request_id = str(uuid.uuid4())
133
+ logger.debug(f"Error Request ID: {request_id}\nError: {traceback.format_exc()}")
134
+ logger.error(f"Error Request ID: {request_id}\n" f"Error: {str(ex)}")
127
135
 
128
136
  exit_code = getattr(ex, "exit_code", 1)
129
137
  logger.error(f"Exit code: {exit_code}")