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
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
|
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.
|
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.
|
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(
|
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(
|
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(
|
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"
|
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
|
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
|
-
|
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
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
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
|
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
|
-
|
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
|
1205
|
-
if not
|
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
|
-
|
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
|
-
)
|
1226
|
-
|
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
|
-
|
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
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
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
|
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(
|
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
|
-
|
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
|
-
|
284
|
+
logger.info(f"CMD used for deploying {aqua_model.id} :{cmd_var}")
|
286
285
|
except ValueError:
|
287
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
#
|
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
|
-
|
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
|
-
|
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
|
-
|
126
|
-
logger.
|
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}")
|