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
@@ -1,5 +1,5 @@
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
  import base64
5
5
  import json
@@ -199,11 +199,11 @@ class AquaEvaluationApp(AquaApp):
199
199
  eval_inference_configuration = (
200
200
  container.spec.evaluation_configuration
201
201
  )
202
- except Exception:
202
+ except Exception as ex:
203
203
  logger.debug(
204
204
  f"Could not load inference config details for the evaluation source id: "
205
205
  f"{create_aqua_evaluation_details.evaluation_source_id}. Please check if the container"
206
- f" runtime has the correct SMC image information."
206
+ f" runtime has the correct SMC image information.\nError: {str(ex)}"
207
207
  )
208
208
  elif (
209
209
  DataScienceResource.MODEL
@@ -289,7 +289,7 @@ class AquaEvaluationApp(AquaApp):
289
289
  f"Invalid experiment name. Please provide an experiment with `{Tags.AQUA_EVALUATION}` in tags."
290
290
  )
291
291
  except Exception:
292
- logger.debug(
292
+ logger.info(
293
293
  f"Model version set {experiment_model_version_set_name} doesn't exist. "
294
294
  "Creating new model version set."
295
295
  )
@@ -711,21 +711,27 @@ class AquaEvaluationApp(AquaApp):
711
711
  try:
712
712
  log = utils.query_resource(log_id, return_all=False)
713
713
  log_name = log.display_name if log else ""
714
- except Exception:
714
+ except Exception as ex:
715
+ logger.debug(f"Failed to get associated log name. Error: {ex}")
715
716
  pass
716
717
 
717
718
  if loggroup_id:
718
719
  try:
719
720
  loggroup = utils.query_resource(loggroup_id, return_all=False)
720
721
  loggroup_name = loggroup.display_name if loggroup else ""
721
- except Exception:
722
+ except Exception as ex:
723
+ logger.debug(f"Failed to get associated loggroup name. Error: {ex}")
722
724
  pass
723
725
 
724
726
  try:
725
727
  introspection = json.loads(
726
728
  self._get_attribute_from_model_metadata(resource, "ArtifactTestResults")
727
729
  )
728
- except Exception:
730
+ except Exception as ex:
731
+ logger.debug(
732
+ f"There was an issue loading the model attribute as json object for evaluation {eval_id}. "
733
+ f"Setting introspection to empty.\n Error:{ex}"
734
+ )
729
735
  introspection = {}
730
736
 
731
737
  summary = AquaEvaluationDetail(
@@ -878,13 +884,13 @@ class AquaEvaluationApp(AquaApp):
878
884
  try:
879
885
  log_id = job_run_details.log_details.log_id
880
886
  except Exception as e:
881
- logger.debug(f"Failed to get associated log. {str(e)}")
887
+ logger.debug(f"Failed to get associated log.\nError: {str(e)}")
882
888
  log_id = ""
883
889
 
884
890
  try:
885
891
  loggroup_id = job_run_details.log_details.log_group_id
886
892
  except Exception as e:
887
- logger.debug(f"Failed to get associated log. {str(e)}")
893
+ logger.debug(f"Failed to get associated log.\nError: {str(e)}")
888
894
  loggroup_id = ""
889
895
 
890
896
  loggroup_url = get_log_links(region=self.region, log_group_id=loggroup_id)
@@ -958,7 +964,7 @@ class AquaEvaluationApp(AquaApp):
958
964
  )
959
965
  except Exception as e:
960
966
  logger.debug(
961
- "Failed to load `report.json` from evaluation artifact" f"{str(e)}"
967
+ f"Failed to load `report.json` from evaluation artifact.\nError: {str(e)}"
962
968
  )
963
969
  json_report = {}
964
970
 
@@ -1047,6 +1053,7 @@ class AquaEvaluationApp(AquaApp):
1047
1053
  return report
1048
1054
 
1049
1055
  with tempfile.TemporaryDirectory() as temp_dir:
1056
+ logger.info(f"Downloading evaluation artifact for {eval_id}.")
1050
1057
  DataScienceModel.from_id(eval_id).download_artifact(
1051
1058
  temp_dir,
1052
1059
  auth=self._auth,
@@ -1200,6 +1207,7 @@ class AquaEvaluationApp(AquaApp):
1200
1207
  def load_evaluation_config(self, container: Optional[str] = None) -> Dict:
1201
1208
  """Loads evaluation config."""
1202
1209
 
1210
+ logger.info("Loading evaluation container config.")
1203
1211
  # retrieve the evaluation config by container family name
1204
1212
  evaluation_config = get_evaluation_service_config(container)
1205
1213
 
@@ -1279,9 +1287,9 @@ class AquaEvaluationApp(AquaApp):
1279
1287
  raise AquaRuntimeError(
1280
1288
  f"Not supported source type: {resource_type}"
1281
1289
  )
1282
- except Exception:
1290
+ except Exception as ex:
1283
1291
  logger.debug(
1284
- f"Failed to retrieve source information for evaluation {evaluation.identifier}."
1292
+ f"Failed to retrieve source information for evaluation {evaluation.identifier}.\nError: {str(ex)}"
1285
1293
  )
1286
1294
  source_name = ""
1287
1295
 
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*--
3
2
 
4
- # Copyright (c) 2024 Oracle and/or its affiliates.
3
+ # Copyright (c) 2024, 2025 Oracle and/or its affiliates.
5
4
  # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
6
5
 
7
6
  import traceback
7
+ import uuid
8
8
  from abc import abstractmethod
9
9
  from http.client import responses
10
10
  from typing import List
@@ -34,7 +34,7 @@ class AquaWSMsgHandler:
34
34
  self.telemetry = TelemetryClient(
35
35
  bucket=AQUA_TELEMETRY_BUCKET, namespace=AQUA_TELEMETRY_BUCKET_NS
36
36
  )
37
- except:
37
+ except Exception:
38
38
  pass
39
39
 
40
40
  @staticmethod
@@ -66,16 +66,23 @@ class AquaWSMsgHandler:
66
66
  "message": message,
67
67
  "service_payload": service_payload,
68
68
  "reason": reason,
69
+ "request_id": str(uuid.uuid4()),
69
70
  }
70
71
  exc_info = kwargs.get("exc_info")
71
72
  if exc_info:
72
- logger.error("".join(traceback.format_exception(*exc_info)))
73
+ logger.error(
74
+ f"Error Request ID: {reply['request_id']}\n"
75
+ f"Error: {''.join(traceback.format_exception(*exc_info))}"
76
+ )
73
77
  e = exc_info[1]
74
78
  if isinstance(e, HTTPError):
75
79
  reply["message"] = e.log_message or message
76
80
  reply["reason"] = e.reason
77
- else:
78
- logger.warning(reply["message"])
81
+
82
+ logger.error(
83
+ f"Error Request ID: {reply['request_id']}\n"
84
+ f"Error: {reply['message']} {reply['reason']}"
85
+ )
79
86
  # telemetry may not be present if there is an error while initializing
80
87
  if hasattr(self, "telemetry"):
81
88
  aqua_api_details = kwargs.get("aqua_api_details", {})
@@ -83,7 +90,7 @@ class AquaWSMsgHandler:
83
90
  category="aqua/error",
84
91
  action=str(status_code),
85
92
  value=reason,
86
- **aqua_api_details
93
+ **aqua_api_details,
87
94
  )
88
95
  response = AquaWsError(
89
96
  status=status_code,
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
- # Copyright (c) 2024 Oracle and/or its affiliates.
2
+ # Copyright (c) 2024, 2025 Oracle and/or its affiliates.
4
3
  # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
5
4
 
6
5
 
@@ -35,7 +34,7 @@ class AquaAPIhandler(APIHandler):
35
34
  self.telemetry = TelemetryClient(
36
35
  bucket=AQUA_TELEMETRY_BUCKET, namespace=AQUA_TELEMETRY_BUCKET_NS
37
36
  )
38
- except:
37
+ except Exception:
39
38
  pass
40
39
 
41
40
  @staticmethod
@@ -82,19 +81,23 @@ class AquaAPIhandler(APIHandler):
82
81
  "message": message,
83
82
  "service_payload": service_payload,
84
83
  "reason": reason,
84
+ "request_id": str(uuid.uuid4()),
85
85
  }
86
86
  exc_info = kwargs.get("exc_info")
87
87
  if exc_info:
88
- logger.error("".join(traceback.format_exception(*exc_info)))
88
+ logger.error(
89
+ f"Error Request ID: {reply['request_id']}\n"
90
+ f"Error: {''.join(traceback.format_exception(*exc_info))}"
91
+ )
89
92
  e = exc_info[1]
90
93
  if isinstance(e, HTTPError):
91
94
  reply["message"] = e.log_message or message
92
95
  reply["reason"] = e.reason if e.reason else reply["reason"]
93
- reply["request_id"] = str(uuid.uuid4())
94
- else:
95
- reply["request_id"] = str(uuid.uuid4())
96
96
 
97
- logger.warning(reply["message"])
97
+ logger.error(
98
+ f"Error Request ID: {reply['request_id']}\n"
99
+ f"Error: {reply['message']} {reply['reason']}"
100
+ )
98
101
 
99
102
  # telemetry may not be present if there is an error while initializing
100
103
  if hasattr(self, "telemetry"):
@@ -103,7 +106,7 @@ class AquaAPIhandler(APIHandler):
103
106
  category="aqua/error",
104
107
  action=str(status_code),
105
108
  value=reason,
106
- **aqua_api_details
109
+ **aqua_api_details,
107
110
  )
108
111
 
109
112
  self.finish(json.dumps(reply))
@@ -133,13 +133,17 @@ class AquaModelHandler(AquaAPIhandler):
133
133
  )
134
134
  local_dir = input_data.get("local_dir")
135
135
  cleanup_model_cache = (
136
- str(input_data.get("cleanup_model_cache", "true")).lower() == "true"
136
+ str(input_data.get("cleanup_model_cache", "false")).lower() == "true"
137
137
  )
138
138
  inference_container_uri = input_data.get("inference_container_uri")
139
139
  allow_patterns = input_data.get("allow_patterns")
140
140
  ignore_patterns = input_data.get("ignore_patterns")
141
141
  freeform_tags = input_data.get("freeform_tags")
142
142
  defined_tags = input_data.get("defined_tags")
143
+ ignore_model_artifact_check = (
144
+ str(input_data.get("ignore_model_artifact_check", "false")).lower()
145
+ == "true"
146
+ )
143
147
 
144
148
  return self.finish(
145
149
  AquaModelApp().register(
@@ -158,6 +162,7 @@ class AquaModelHandler(AquaAPIhandler):
158
162
  ignore_patterns=ignore_patterns,
159
163
  freeform_tags=freeform_tags,
160
164
  defined_tags=defined_tags,
165
+ ignore_model_artifact_check=ignore_model_artifact_check,
161
166
  )
162
167
  )
163
168
 
@@ -122,6 +122,8 @@ class CreateFineTuningDetails(Serializable):
122
122
  The log group id for fine tuning job infrastructure.
123
123
  log_id: (str, optional). Defaults to `None`.
124
124
  The log id for fine tuning job infrastructure.
125
+ watch_logs: (bool, optional). Defaults to `False`.
126
+ The flag to watch the job run logs when a fine-tuning job is created.
125
127
  force_overwrite: (bool, optional). Defaults to `False`.
126
128
  Whether to force overwrite the existing file in object storage.
127
129
  freeform_tags: (dict, optional)
@@ -148,6 +150,7 @@ class CreateFineTuningDetails(Serializable):
148
150
  subnet_id: Optional[str] = None
149
151
  log_id: Optional[str] = None
150
152
  log_group_id: Optional[str] = None
153
+ watch_logs: Optional[bool] = False
151
154
  force_overwrite: Optional[bool] = False
152
155
  freeform_tags: Optional[dict] = None
153
156
  defined_tags: Optional[dict] = None
@@ -4,6 +4,8 @@
4
4
 
5
5
  import json
6
6
  import os
7
+ import time
8
+ import traceback
7
9
  from typing import Dict
8
10
 
9
11
  from oci.data_science.models import (
@@ -149,6 +151,15 @@ class AquaFineTuningApp(AquaApp):
149
151
  f"Logging is required for fine tuning if replica is larger than {DEFAULT_FT_REPLICA}."
150
152
  )
151
153
 
154
+ if create_fine_tuning_details.watch_logs and not (
155
+ create_fine_tuning_details.log_id
156
+ and create_fine_tuning_details.log_group_id
157
+ ):
158
+ raise AquaValueError(
159
+ "Logging is required for fine tuning if watch_logs is set to True. "
160
+ "Please provide log_id and log_group_id with the request parameters."
161
+ )
162
+
152
163
  ft_parameters = self._get_finetuning_params(
153
164
  create_fine_tuning_details.ft_parameters
154
165
  )
@@ -382,6 +393,9 @@ class AquaFineTuningApp(AquaApp):
382
393
  defined_tags=model_defined_tags,
383
394
  ),
384
395
  )
396
+ logger.debug(
397
+ f"Successfully updated model custom metadata list and freeform tags for the model {ft_model.id}."
398
+ )
385
399
 
386
400
  self.update_model_provenance(
387
401
  model_id=ft_model.id,
@@ -389,6 +403,9 @@ class AquaFineTuningApp(AquaApp):
389
403
  training_id=ft_job_run.id
390
404
  ),
391
405
  )
406
+ logger.debug(
407
+ f"Successfully updated model provenance for the model {ft_model.id}."
408
+ )
392
409
 
393
410
  # tracks the shape and replica used for fine-tuning the service models
394
411
  telemetry_kwargs = (
@@ -416,6 +433,20 @@ class AquaFineTuningApp(AquaApp):
416
433
  value=source.display_name,
417
434
  )
418
435
 
436
+ if create_fine_tuning_details.watch_logs:
437
+ logger.info(
438
+ f"Watching fine-tuning job run logs for {ft_job_run.id}. Press Ctrl+C to stop watching logs.\n"
439
+ )
440
+ try:
441
+ ft_job_run.watch()
442
+ except KeyboardInterrupt:
443
+ logger.info(f"\nStopped watching logs for {ft_job_run.id}.\n")
444
+ time.sleep(1)
445
+ except Exception:
446
+ logger.debug(
447
+ f"Something unexpected occurred while watching logs.\n{traceback.format_exc()}"
448
+ )
449
+
419
450
  return AquaFineTuningSummary(
420
451
  id=ft_model.id,
421
452
  name=ft_model.display_name,
@@ -564,7 +595,7 @@ class AquaFineTuningApp(AquaApp):
564
595
  config = self.get_config(model_id, AQUA_MODEL_FINETUNING_CONFIG)
565
596
  if not config:
566
597
  logger.debug(
567
- f"Fine-tuning config for custom model: {model_id} is not available."
598
+ f"Fine-tuning config for custom model: {model_id} is not available. Use defaults."
568
599
  )
569
600
  return config
570
601
 
@@ -283,7 +283,7 @@ class ImportModelDetails(CLIBuilderMixin):
283
283
  os_path: str
284
284
  download_from_hf: Optional[bool] = True
285
285
  local_dir: Optional[str] = None
286
- cleanup_model_cache: Optional[bool] = True
286
+ cleanup_model_cache: Optional[bool] = False
287
287
  inference_container: Optional[str] = None
288
288
  finetuning_container: Optional[str] = None
289
289
  compartment_id: Optional[str] = None
@@ -294,6 +294,7 @@ class ImportModelDetails(CLIBuilderMixin):
294
294
  ignore_patterns: Optional[List[str]] = None
295
295
  freeform_tags: Optional[dict] = None
296
296
  defined_tags: Optional[dict] = None
297
+ ignore_model_artifact_check: Optional[bool] = None
297
298
 
298
299
  def __post_init__(self):
299
300
  self._command = "model register"