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.
- ads/aqua/__init__.py +2 -1
- ads/aqua/app.py +30 -16
- ads/aqua/client/__init__.py +3 -0
- ads/aqua/client/client.py +799 -0
- ads/aqua/evaluation/evaluation.py +20 -12
- ads/aqua/extension/aqua_ws_msg_handler.py +14 -7
- ads/aqua/extension/base_handler.py +12 -9
- ads/aqua/extension/model_handler.py +6 -1
- ads/aqua/finetuning/entities.py +3 -0
- ads/aqua/finetuning/finetuning.py +32 -1
- ads/aqua/model/entities.py +2 -1
- ads/aqua/model/model.py +136 -76
- ads/aqua/modeldeployment/deployment.py +22 -10
- ads/cli.py +16 -8
- ads/opctl/operator/lowcode/common/transformations.py +38 -3
- ads/opctl/operator/lowcode/common/utils.py +11 -1
- ads/opctl/operator/lowcode/forecast/__main__.py +10 -0
- ads/opctl/operator/lowcode/forecast/model/forecast_datasets.py +1 -1
- ads/opctl/operator/lowcode/forecast/operator_config.py +31 -0
- ads/opctl/operator/lowcode/forecast/schema.yaml +63 -0
- ads/opctl/operator/lowcode/forecast/whatifserve/__init__.py +7 -0
- ads/opctl/operator/lowcode/forecast/whatifserve/deployment_manager.py +233 -0
- ads/opctl/operator/lowcode/forecast/whatifserve/score.py +238 -0
- {oracle_ads-2.12.10rc0.dist-info → oracle_ads-2.12.11.dist-info}/METADATA +3 -1
- {oracle_ads-2.12.10rc0.dist-info → oracle_ads-2.12.11.dist-info}/RECORD +28 -23
- {oracle_ads-2.12.10rc0.dist-info → oracle_ads-2.12.11.dist-info}/LICENSE.txt +0 -0
- {oracle_ads-2.12.10rc0.dist-info → oracle_ads-2.12.11.dist-info}/WHEEL +0 -0
- {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.
|
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
|
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
|
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
|
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(
|
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
|
-
|
78
|
-
|
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
|
-
#
|
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(
|
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.
|
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", "
|
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
|
|
ads/aqua/finetuning/entities.py
CHANGED
@@ -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
|
|
ads/aqua/model/entities.py
CHANGED
@@ -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] =
|
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"
|