oracle-ads 2.12.8__py3-none-any.whl → 2.12.10__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 +4 -3
- ads/aqua/app.py +40 -18
- ads/aqua/client/__init__.py +3 -0
- ads/aqua/client/client.py +799 -0
- ads/aqua/common/enums.py +3 -0
- ads/aqua/common/utils.py +62 -2
- ads/aqua/data.py +2 -19
- ads/aqua/evaluation/entities.py +6 -0
- ads/aqua/evaluation/evaluation.py +45 -15
- ads/aqua/extension/aqua_ws_msg_handler.py +14 -7
- ads/aqua/extension/base_handler.py +12 -9
- ads/aqua/extension/deployment_handler.py +8 -4
- ads/aqua/extension/finetune_handler.py +8 -14
- ads/aqua/extension/model_handler.py +30 -6
- ads/aqua/extension/ui_handler.py +13 -1
- ads/aqua/finetuning/constants.py +5 -2
- ads/aqua/finetuning/entities.py +73 -17
- ads/aqua/finetuning/finetuning.py +110 -82
- ads/aqua/model/entities.py +5 -1
- ads/aqua/model/model.py +230 -104
- ads/aqua/modeldeployment/deployment.py +35 -11
- ads/aqua/modeldeployment/entities.py +7 -4
- ads/aqua/ui.py +24 -2
- ads/cli.py +16 -8
- ads/common/auth.py +9 -9
- ads/llm/autogen/__init__.py +2 -0
- ads/llm/autogen/constants.py +15 -0
- ads/llm/autogen/reports/__init__.py +2 -0
- ads/llm/autogen/reports/base.py +67 -0
- ads/llm/autogen/reports/data.py +103 -0
- ads/llm/autogen/reports/session.py +526 -0
- ads/llm/autogen/reports/templates/chat_box.html +13 -0
- ads/llm/autogen/reports/templates/chat_box_lt.html +5 -0
- ads/llm/autogen/reports/templates/chat_box_rt.html +6 -0
- ads/llm/autogen/reports/utils.py +56 -0
- ads/llm/autogen/v02/__init__.py +4 -0
- ads/llm/autogen/{client_v02.py → v02/client.py} +23 -10
- ads/llm/autogen/v02/log_handlers/__init__.py +2 -0
- ads/llm/autogen/v02/log_handlers/oci_file_handler.py +83 -0
- ads/llm/autogen/v02/loggers/__init__.py +6 -0
- ads/llm/autogen/v02/loggers/metric_logger.py +320 -0
- ads/llm/autogen/v02/loggers/session_logger.py +580 -0
- ads/llm/autogen/v02/loggers/utils.py +86 -0
- ads/llm/autogen/v02/runtime_logging.py +163 -0
- ads/llm/guardrails/base.py +6 -5
- ads/llm/langchain/plugins/chat_models/oci_data_science.py +46 -20
- ads/llm/langchain/plugins/llms/oci_data_science_model_deployment_endpoint.py +38 -11
- ads/model/__init__.py +11 -13
- ads/model/artifact.py +47 -8
- ads/model/extractor/embedding_onnx_extractor.py +80 -0
- ads/model/framework/embedding_onnx_model.py +438 -0
- ads/model/generic_model.py +26 -24
- ads/model/model_metadata.py +8 -7
- ads/opctl/config/merger.py +13 -14
- ads/opctl/operator/common/operator_config.py +4 -4
- ads/opctl/operator/lowcode/common/transformations.py +50 -8
- ads/opctl/operator/lowcode/common/utils.py +22 -6
- ads/opctl/operator/lowcode/forecast/__main__.py +10 -0
- ads/opctl/operator/lowcode/forecast/const.py +3 -0
- ads/opctl/operator/lowcode/forecast/model/arima.py +19 -13
- ads/opctl/operator/lowcode/forecast/model/automlx.py +129 -36
- ads/opctl/operator/lowcode/forecast/model/autots.py +1 -0
- ads/opctl/operator/lowcode/forecast/model/base_model.py +58 -17
- ads/opctl/operator/lowcode/forecast/model/forecast_datasets.py +1 -1
- ads/opctl/operator/lowcode/forecast/model/neuralprophet.py +10 -3
- ads/opctl/operator/lowcode/forecast/model/prophet.py +25 -18
- ads/opctl/operator/lowcode/forecast/model_evaluator.py +3 -2
- ads/opctl/operator/lowcode/forecast/operator_config.py +31 -0
- ads/opctl/operator/lowcode/forecast/schema.yaml +76 -0
- ads/opctl/operator/lowcode/forecast/utils.py +8 -6
- 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
- ads/telemetry/base.py +18 -11
- ads/telemetry/client.py +33 -13
- ads/templates/schemas/openapi.json +1740 -0
- ads/templates/score_embedding_onnx.jinja2 +202 -0
- {oracle_ads-2.12.8.dist-info → oracle_ads-2.12.10.dist-info}/METADATA +11 -10
- {oracle_ads-2.12.8.dist-info → oracle_ads-2.12.10.dist-info}/RECORD +82 -56
- {oracle_ads-2.12.8.dist-info → oracle_ads-2.12.10.dist-info}/LICENSE.txt +0 -0
- {oracle_ads-2.12.8.dist-info → oracle_ads-2.12.10.dist-info}/WHEEL +0 -0
- {oracle_ads-2.12.8.dist-info → oracle_ads-2.12.10.dist-info}/entry_points.txt +0 -0
ads/aqua/model/model.py
CHANGED
@@ -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 os
|
5
5
|
import pathlib
|
@@ -15,15 +15,20 @@ from oci.data_science.models import JobRun, Metadata, Model, UpdateModelDetails
|
|
15
15
|
from ads.aqua import ODSC_MODEL_COMPARTMENT_OCID, logger
|
16
16
|
from ads.aqua.app import AquaApp
|
17
17
|
from ads.aqua.common.enums import (
|
18
|
+
CustomInferenceContainerTypeFamily,
|
18
19
|
FineTuningContainerTypeFamily,
|
19
20
|
InferenceContainerTypeFamily,
|
20
21
|
Tags,
|
21
22
|
)
|
22
|
-
from ads.aqua.common.errors import
|
23
|
+
from ads.aqua.common.errors import (
|
24
|
+
AquaFileNotFoundError,
|
25
|
+
AquaRuntimeError,
|
26
|
+
AquaValueError,
|
27
|
+
)
|
23
28
|
from ads.aqua.common.utils import (
|
24
29
|
LifecycleStatus,
|
25
30
|
_build_resource_identifier,
|
26
|
-
|
31
|
+
cleanup_local_hf_model_artifact,
|
27
32
|
create_word_icon,
|
28
33
|
generate_tei_cmd_var,
|
29
34
|
get_artifact_path,
|
@@ -127,7 +132,13 @@ class AquaModelApp(AquaApp):
|
|
127
132
|
|
128
133
|
@telemetry(entry_point="plugin=model&action=create", name="aqua")
|
129
134
|
def create(
|
130
|
-
self,
|
135
|
+
self,
|
136
|
+
model_id: str,
|
137
|
+
project_id: str,
|
138
|
+
compartment_id: str = None,
|
139
|
+
freeform_tags: Optional[dict] = None,
|
140
|
+
defined_tags: Optional[dict] = None,
|
141
|
+
**kwargs,
|
131
142
|
) -> DataScienceModel:
|
132
143
|
"""Creates custom aqua model from service model.
|
133
144
|
|
@@ -140,7 +151,10 @@ class AquaModelApp(AquaApp):
|
|
140
151
|
compartment_id: str
|
141
152
|
The compartment id for custom model. Defaults to None.
|
142
153
|
If not provided, compartment id will be fetched from environment variables.
|
143
|
-
|
154
|
+
freeform_tags: dict
|
155
|
+
Freeform tags for the model
|
156
|
+
defined_tags: dict
|
157
|
+
Defined tags for the model
|
144
158
|
Returns
|
145
159
|
-------
|
146
160
|
DataScienceModel:
|
@@ -151,12 +165,22 @@ class AquaModelApp(AquaApp):
|
|
151
165
|
target_compartment = compartment_id or COMPARTMENT_OCID
|
152
166
|
|
153
167
|
if service_model.compartment_id != ODSC_MODEL_COMPARTMENT_OCID:
|
154
|
-
logger.
|
168
|
+
logger.info(
|
155
169
|
f"Aqua Model {model_id} already exists in user's compartment."
|
156
170
|
"Skipped copying."
|
157
171
|
)
|
158
172
|
return service_model
|
159
173
|
|
174
|
+
# combine tags
|
175
|
+
combined_freeform_tags = {
|
176
|
+
**(service_model.freeform_tags or {}),
|
177
|
+
**(freeform_tags or {}),
|
178
|
+
}
|
179
|
+
combined_defined_tags = {
|
180
|
+
**(service_model.defined_tags or {}),
|
181
|
+
**(defined_tags or {}),
|
182
|
+
}
|
183
|
+
|
160
184
|
custom_model = (
|
161
185
|
DataScienceModel()
|
162
186
|
.with_compartment_id(target_compartment)
|
@@ -164,16 +188,16 @@ class AquaModelApp(AquaApp):
|
|
164
188
|
.with_model_file_description(json_dict=service_model.model_file_description)
|
165
189
|
.with_display_name(service_model.display_name)
|
166
190
|
.with_description(service_model.description)
|
167
|
-
.with_freeform_tags(**
|
168
|
-
.with_defined_tags(**
|
191
|
+
.with_freeform_tags(**combined_freeform_tags)
|
192
|
+
.with_defined_tags(**combined_defined_tags)
|
169
193
|
.with_custom_metadata_list(service_model.custom_metadata_list)
|
170
194
|
.with_defined_metadata_list(service_model.defined_metadata_list)
|
171
195
|
.with_provenance_metadata(service_model.provenance_metadata)
|
172
196
|
# TODO: decide what kwargs will be needed.
|
173
197
|
.create(model_by_reference=True, **kwargs)
|
174
198
|
)
|
175
|
-
logger.
|
176
|
-
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}."
|
177
201
|
)
|
178
202
|
|
179
203
|
# tracks unique models that were created in the user compartment
|
@@ -204,11 +228,16 @@ class AquaModelApp(AquaApp):
|
|
204
228
|
|
205
229
|
cached_item = self._service_model_details_cache.get(model_id)
|
206
230
|
if cached_item:
|
231
|
+
logger.info(f"Fetching model details for model {model_id} from cache.")
|
207
232
|
return cached_item
|
208
233
|
|
234
|
+
logger.info(f"Fetching model details for model {model_id}.")
|
209
235
|
ds_model = DataScienceModel.from_id(model_id)
|
210
236
|
if not self._if_show(ds_model):
|
211
|
-
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
|
+
)
|
212
241
|
|
213
242
|
is_fine_tuned_model = bool(
|
214
243
|
ds_model.freeform_tags
|
@@ -227,16 +256,21 @@ class AquaModelApp(AquaApp):
|
|
227
256
|
ds_model.custom_metadata_list._to_oci_metadata()
|
228
257
|
)
|
229
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
|
+
)
|
230
264
|
model_card = str(
|
231
265
|
read_file(
|
232
|
-
file_path=
|
233
|
-
f"{artifact_path.rstrip('/')}/config/{README}"
|
234
|
-
if is_verified_type
|
235
|
-
else f"{artifact_path.rstrip('/')}/{README}"
|
236
|
-
),
|
266
|
+
file_path=model_card_path,
|
237
267
|
auth=default_signer(),
|
238
268
|
)
|
239
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
|
+
)
|
240
274
|
|
241
275
|
inference_container = ds_model.custom_metadata_list.get(
|
242
276
|
ModelCustomMetadataFields.DEPLOYMENT_CONTAINER,
|
@@ -282,9 +316,10 @@ class AquaModelApp(AquaApp):
|
|
282
316
|
try:
|
283
317
|
jobrun_ocid = ds_model.provenance_metadata.training_id
|
284
318
|
jobrun = self.ds_client.get_job_run(jobrun_ocid).data
|
285
|
-
except Exception:
|
319
|
+
except Exception as e:
|
286
320
|
logger.debug(
|
287
321
|
f"Missing jobrun information in the provenance metadata of the given model {model_id}."
|
322
|
+
f"\nError: {str(e)}"
|
288
323
|
)
|
289
324
|
jobrun = None
|
290
325
|
|
@@ -293,7 +328,10 @@ class AquaModelApp(AquaApp):
|
|
293
328
|
FineTuningCustomMetadata.FT_SOURCE
|
294
329
|
).value
|
295
330
|
except ValueError as e:
|
296
|
-
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
|
+
)
|
297
335
|
source_id = UNKNOWN
|
298
336
|
|
299
337
|
try:
|
@@ -301,7 +339,10 @@ class AquaModelApp(AquaApp):
|
|
301
339
|
FineTuningCustomMetadata.FT_SOURCE_NAME
|
302
340
|
).value
|
303
341
|
except ValueError as e:
|
304
|
-
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
|
+
)
|
305
346
|
source_name = UNKNOWN
|
306
347
|
|
307
348
|
source_identifier = _build_resource_identifier(
|
@@ -351,14 +392,17 @@ class AquaModelApp(AquaApp):
|
|
351
392
|
Tags.AQUA_FINE_TUNED_MODEL_TAG, None
|
352
393
|
)
|
353
394
|
if is_registered_model or is_fine_tuned_model:
|
395
|
+
logger.info(f"Deleting model {model_id}.")
|
354
396
|
return ds_model.delete()
|
355
397
|
else:
|
356
398
|
raise AquaRuntimeError(
|
357
399
|
f"Failed to delete model:{model_id}. Only registered models or finetuned model can be deleted."
|
358
400
|
)
|
359
401
|
|
360
|
-
@telemetry(entry_point="plugin=model&action=
|
361
|
-
def edit_registered_model(
|
402
|
+
@telemetry(entry_point="plugin=model&action=edit", name="aqua")
|
403
|
+
def edit_registered_model(
|
404
|
+
self, id, inference_container, inference_container_uri, enable_finetuning, task
|
405
|
+
):
|
362
406
|
"""Edits the default config of unverified registered model.
|
363
407
|
|
364
408
|
Parameters
|
@@ -367,6 +411,8 @@ class AquaModelApp(AquaApp):
|
|
367
411
|
The model OCID.
|
368
412
|
inference_container: str.
|
369
413
|
The inference container family name
|
414
|
+
inference_container_uri: str
|
415
|
+
The inference container uri for embedding models
|
370
416
|
enable_finetuning: str
|
371
417
|
Flag to enable or disable finetuning over the model. Defaults to None
|
372
418
|
task:
|
@@ -382,19 +428,44 @@ class AquaModelApp(AquaApp):
|
|
382
428
|
if ds_model.freeform_tags.get(Tags.BASE_MODEL_CUSTOM, None):
|
383
429
|
if ds_model.freeform_tags.get(Tags.AQUA_SERVICE_MODEL_TAG, None):
|
384
430
|
raise AquaRuntimeError(
|
385
|
-
|
431
|
+
"Only registered unverified models can be edited."
|
386
432
|
)
|
387
433
|
else:
|
388
434
|
custom_metadata_list = ds_model.custom_metadata_list
|
389
435
|
freeform_tags = ds_model.freeform_tags
|
390
436
|
if inference_container:
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
437
|
+
if (
|
438
|
+
inference_container in CustomInferenceContainerTypeFamily
|
439
|
+
and inference_container_uri is None
|
440
|
+
):
|
441
|
+
raise AquaRuntimeError(
|
442
|
+
"Inference container URI must be provided."
|
443
|
+
)
|
444
|
+
else:
|
445
|
+
custom_metadata_list.add(
|
446
|
+
key=ModelCustomMetadataFields.DEPLOYMENT_CONTAINER,
|
447
|
+
value=inference_container,
|
448
|
+
category=MetadataCustomCategory.OTHER,
|
449
|
+
description="Deployment container mapping for SMC",
|
450
|
+
replace=True,
|
451
|
+
)
|
452
|
+
if inference_container_uri:
|
453
|
+
if (
|
454
|
+
inference_container in CustomInferenceContainerTypeFamily
|
455
|
+
or inference_container is None
|
456
|
+
):
|
457
|
+
custom_metadata_list.add(
|
458
|
+
key=ModelCustomMetadataFields.DEPLOYMENT_CONTAINER_URI,
|
459
|
+
value=inference_container_uri,
|
460
|
+
category=MetadataCustomCategory.OTHER,
|
461
|
+
description=f"Inference container URI for {ds_model.display_name}",
|
462
|
+
replace=True,
|
463
|
+
)
|
464
|
+
else:
|
465
|
+
raise AquaRuntimeError(
|
466
|
+
f"Inference container URI can be edited only with container values: {CustomInferenceContainerTypeFamily.values()}"
|
467
|
+
)
|
468
|
+
|
398
469
|
if enable_finetuning is not None:
|
399
470
|
if enable_finetuning.lower() == "true":
|
400
471
|
custom_metadata_list.add(
|
@@ -414,7 +485,7 @@ class AquaModelApp(AquaApp):
|
|
414
485
|
except Exception as ex:
|
415
486
|
raise AquaRuntimeError(
|
416
487
|
f"The given model already doesn't support finetuning: {ex}"
|
417
|
-
)
|
488
|
+
) from ex
|
418
489
|
|
419
490
|
custom_metadata_list.remove("modelDescription")
|
420
491
|
if task:
|
@@ -428,10 +499,9 @@ class AquaModelApp(AquaApp):
|
|
428
499
|
freeform_tags=freeform_tags,
|
429
500
|
)
|
430
501
|
AquaApp().update_model(id, update_model_details)
|
502
|
+
logger.info(f"Updated model details for the model {id}.")
|
431
503
|
else:
|
432
|
-
raise AquaRuntimeError(
|
433
|
-
f"Failed to edit model:{id}. Only registered unverified models can be edited."
|
434
|
-
)
|
504
|
+
raise AquaRuntimeError("Only registered unverified models can be edited.")
|
435
505
|
|
436
506
|
def _fetch_metric_from_metadata(
|
437
507
|
self,
|
@@ -687,7 +757,7 @@ class AquaModelApp(AquaApp):
|
|
687
757
|
)
|
688
758
|
|
689
759
|
logger.info(
|
690
|
-
f"
|
760
|
+
f"Fetched {len(models)} model in compartment_id={compartment_id or ODSC_MODEL_COMPARTMENT_OCID}."
|
691
761
|
)
|
692
762
|
|
693
763
|
aqua_models = []
|
@@ -717,10 +787,12 @@ class AquaModelApp(AquaApp):
|
|
717
787
|
dict with the key used, and True if cache has the key that needs to be deleted.
|
718
788
|
"""
|
719
789
|
res = {}
|
720
|
-
logger.info("Clearing _service_models_cache")
|
721
790
|
with self._cache_lock:
|
722
791
|
if ODSC_MODEL_COMPARTMENT_OCID in self._service_models_cache:
|
723
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
|
+
)
|
724
796
|
res = {
|
725
797
|
"key": {
|
726
798
|
"compartment_id": ODSC_MODEL_COMPARTMENT_OCID,
|
@@ -737,10 +809,10 @@ class AquaModelApp(AquaApp):
|
|
737
809
|
dict with the key used, and True if cache has the key that needs to be deleted.
|
738
810
|
"""
|
739
811
|
res = {}
|
740
|
-
logger.info(f"Clearing _service_model_details_cache for {model_id}")
|
741
812
|
with self._cache_lock:
|
742
813
|
if model_id in self._service_model_details_cache:
|
743
814
|
self._service_model_details_cache.pop(key=model_id)
|
815
|
+
logger.info(f"Clearing model details cache for model {model_id}.")
|
744
816
|
res = {"key": {"model_id": model_id}, "cache_deleted": True}
|
745
817
|
|
746
818
|
return res
|
@@ -766,6 +838,8 @@ class AquaModelApp(AquaApp):
|
|
766
838
|
compartment_id: Optional[str],
|
767
839
|
project_id: Optional[str],
|
768
840
|
inference_container_uri: Optional[str],
|
841
|
+
freeform_tags: Optional[dict] = None,
|
842
|
+
defined_tags: Optional[dict] = None,
|
769
843
|
) -> DataScienceModel:
|
770
844
|
"""Create model by reference from the object storage path
|
771
845
|
|
@@ -778,6 +852,8 @@ class AquaModelApp(AquaApp):
|
|
778
852
|
compartment_id (Optional[str]): Compartment Id of the compartment where the model has to be created
|
779
853
|
project_id (Optional[str]): Project id of the project where the model has to be created
|
780
854
|
inference_container_uri (Optional[str]): Inference container uri for BYOC
|
855
|
+
freeform_tags (dict): Freeform tags for the model
|
856
|
+
defined_tags (dict): Defined tags for the model
|
781
857
|
|
782
858
|
Returns:
|
783
859
|
DataScienceModel: Returns Datascience model instance.
|
@@ -821,7 +897,8 @@ class AquaModelApp(AquaApp):
|
|
821
897
|
metadata = ModelCustomMetadata()
|
822
898
|
if not inference_container:
|
823
899
|
raise AquaRuntimeError(
|
824
|
-
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."
|
825
902
|
)
|
826
903
|
metadata.add(
|
827
904
|
key=AQUA_DEPLOYMENT_CONTAINER_METADATA_NAME,
|
@@ -846,8 +923,7 @@ class AquaModelApp(AquaApp):
|
|
846
923
|
# only add cmd vars if inference container is not an SMC
|
847
924
|
if (
|
848
925
|
inference_container not in smc_container_set
|
849
|
-
and inference_container
|
850
|
-
== InferenceContainerTypeFamily.AQUA_TEI_CONTAINER_FAMILY
|
926
|
+
and inference_container in CustomInferenceContainerTypeFamily.values()
|
851
927
|
):
|
852
928
|
cmd_vars = generate_tei_cmd_var(os_path)
|
853
929
|
metadata.add(
|
@@ -892,24 +968,6 @@ class AquaModelApp(AquaApp):
|
|
892
968
|
)
|
893
969
|
tags[Tags.LICENSE] = validation_result.tags.get(Tags.LICENSE, UNKNOWN)
|
894
970
|
|
895
|
-
try:
|
896
|
-
# If verified model already has a artifact json, use that.
|
897
|
-
artifact_path = metadata.get(MODEL_BY_REFERENCE_OSS_PATH_KEY).value
|
898
|
-
logger.info(
|
899
|
-
f"Found model artifact in the service bucket. "
|
900
|
-
f"Using artifact from service bucket instead of {os_path}"
|
901
|
-
)
|
902
|
-
|
903
|
-
# todo: implement generic copy_folder method
|
904
|
-
# copy model config from artifact path to user bucket
|
905
|
-
copy_model_config(
|
906
|
-
artifact_path=artifact_path, os_path=os_path, auth=default_signer()
|
907
|
-
)
|
908
|
-
except Exception:
|
909
|
-
logger.debug(
|
910
|
-
f"Proceeding with model registration without copying model config files at {os_path}. "
|
911
|
-
f"Default configuration will be used for deployment and fine-tuning."
|
912
|
-
)
|
913
971
|
# Set artifact location to user bucket, and replace existing key if present.
|
914
972
|
metadata.add(
|
915
973
|
key=MODEL_BY_REFERENCE_OSS_PATH_KEY,
|
@@ -918,6 +976,8 @@ class AquaModelApp(AquaApp):
|
|
918
976
|
category="Other",
|
919
977
|
replace=True,
|
920
978
|
)
|
979
|
+
# override tags with freeform tags if set
|
980
|
+
tags = {**tags, **(freeform_tags or {})}
|
921
981
|
model = (
|
922
982
|
model.with_custom_metadata_list(metadata)
|
923
983
|
.with_compartment_id(compartment_id or COMPARTMENT_OCID)
|
@@ -925,8 +985,9 @@ class AquaModelApp(AquaApp):
|
|
925
985
|
.with_artifact(os_path)
|
926
986
|
.with_display_name(model_name)
|
927
987
|
.with_freeform_tags(**tags)
|
988
|
+
.with_defined_tags(**(defined_tags or {}))
|
928
989
|
).create(model_by_reference=True)
|
929
|
-
logger.debug(model)
|
990
|
+
logger.debug(f"Created model catalog entry for the model:\n{model}")
|
930
991
|
return model
|
931
992
|
|
932
993
|
@staticmethod
|
@@ -946,13 +1007,23 @@ class AquaModelApp(AquaApp):
|
|
946
1007
|
# todo: revisit this logic to account for .bin files. In the current state, .bin and .safetensor models
|
947
1008
|
# are grouped in one category and validation checks for config.json files only.
|
948
1009
|
if model_format == ModelFormat.SAFETENSORS:
|
1010
|
+
model_files.extend(
|
1011
|
+
list_os_files_with_extension(oss_path=os_path, extension=".safetensors")
|
1012
|
+
)
|
949
1013
|
try:
|
950
1014
|
load_config(
|
951
1015
|
file_path=os_path,
|
952
1016
|
config_file_name=AQUA_MODEL_ARTIFACT_CONFIG,
|
953
1017
|
)
|
954
|
-
except Exception:
|
955
|
-
|
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
|
+
)
|
956
1027
|
else:
|
957
1028
|
model_files.append(AQUA_MODEL_ARTIFACT_CONFIG)
|
958
1029
|
|
@@ -960,6 +1031,9 @@ class AquaModelApp(AquaApp):
|
|
960
1031
|
model_files.extend(
|
961
1032
|
list_os_files_with_extension(oss_path=os_path, extension=".gguf")
|
962
1033
|
)
|
1034
|
+
logger.debug(
|
1035
|
+
f"Fetched {len(model_files)} model files from {os_path} for model format {model_format}."
|
1036
|
+
)
|
963
1037
|
return model_files
|
964
1038
|
|
965
1039
|
@staticmethod
|
@@ -996,12 +1070,17 @@ class AquaModelApp(AquaApp):
|
|
996
1070
|
|
997
1071
|
for model_sibling in model_siblings:
|
998
1072
|
extension = pathlib.Path(model_sibling.rfilename).suffix[1:].upper()
|
999
|
-
if
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
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:
|
1003
1079
|
model_files.append(model_sibling.rfilename)
|
1004
1080
|
|
1081
|
+
logger.debug(
|
1082
|
+
f"Fetched {len(model_files)} model files for the model {model_name} for model format {model_format}."
|
1083
|
+
)
|
1005
1084
|
return model_files
|
1006
1085
|
|
1007
1086
|
def _validate_model(
|
@@ -1035,7 +1114,10 @@ class AquaModelApp(AquaApp):
|
|
1035
1114
|
safetensors_model_files = self.get_hf_model_files(
|
1036
1115
|
model_name, ModelFormat.SAFETENSORS
|
1037
1116
|
)
|
1038
|
-
if
|
1117
|
+
if (
|
1118
|
+
safetensors_model_files
|
1119
|
+
and AQUA_MODEL_ARTIFACT_CONFIG in safetensors_model_files
|
1120
|
+
):
|
1039
1121
|
hf_download_config_present = True
|
1040
1122
|
gguf_model_files = self.get_hf_model_files(model_name, ModelFormat.GGUF)
|
1041
1123
|
else:
|
@@ -1091,8 +1173,11 @@ class AquaModelApp(AquaApp):
|
|
1091
1173
|
Tags.LICENSE: license_value,
|
1092
1174
|
}
|
1093
1175
|
validation_result.tags = hf_tags
|
1094
|
-
except Exception:
|
1095
|
-
|
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
|
+
)
|
1096
1181
|
|
1097
1182
|
validation_result.model_formats = model_formats
|
1098
1183
|
|
@@ -1147,40 +1232,55 @@ class AquaModelApp(AquaApp):
|
|
1147
1232
|
model_name: str = None,
|
1148
1233
|
):
|
1149
1234
|
if import_model_details.download_from_hf:
|
1150
|
-
# validates config.json exists for safetensors model from
|
1151
|
-
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
|
+
):
|
1152
1240
|
raise AquaRuntimeError(
|
1153
1241
|
f"The model {model_name} does not contain {AQUA_MODEL_ARTIFACT_CONFIG} file as required "
|
1154
1242
|
f"by {ModelFormat.SAFETENSORS.value} format model."
|
1155
1243
|
f" Please check if the model name is correct in Hugging Face repository."
|
1156
1244
|
)
|
1245
|
+
validation_result.telemetry_model_name = model_name
|
1157
1246
|
else:
|
1247
|
+
# validate if config.json is available from object storage, and get model name for telemetry
|
1248
|
+
model_config = None
|
1158
1249
|
try:
|
1159
1250
|
model_config = load_config(
|
1160
1251
|
file_path=import_model_details.os_path,
|
1161
1252
|
config_file_name=AQUA_MODEL_ARTIFACT_CONFIG,
|
1162
1253
|
)
|
1163
1254
|
except Exception as ex:
|
1164
|
-
|
1165
|
-
f"Exception occurred while loading config file from {import_model_details.os_path}"
|
1166
|
-
f"Exception message: {ex}"
|
1167
|
-
)
|
1168
|
-
raise AquaRuntimeError(
|
1255
|
+
message = (
|
1169
1256
|
f"The model path {import_model_details.os_path} does not contain the file config.json. "
|
1170
1257
|
f"Please check if the path is correct or the model artifacts are available at this location."
|
1171
|
-
)
|
1172
|
-
|
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.
|
1173
1273
|
try:
|
1174
1274
|
metadata_model_type = verified_model.custom_metadata_list.get(
|
1175
1275
|
AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE
|
1176
1276
|
).value
|
1177
|
-
if metadata_model_type:
|
1277
|
+
if metadata_model_type and model_config is not None:
|
1178
1278
|
if AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE in model_config:
|
1179
1279
|
if (
|
1180
1280
|
model_config[AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE]
|
1181
1281
|
!= metadata_model_type
|
1182
1282
|
):
|
1183
|
-
|
1283
|
+
logger.debug(
|
1184
1284
|
f"The {AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE} attribute in {AQUA_MODEL_ARTIFACT_CONFIG}"
|
1185
1285
|
f" at {import_model_details.os_path} is invalid, expected {metadata_model_type} for "
|
1186
1286
|
f"the model {model_name}. Please check if the path is correct or "
|
@@ -1192,22 +1292,26 @@ class AquaModelApp(AquaApp):
|
|
1192
1292
|
f"Could not find {AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE} attribute in "
|
1193
1293
|
f"{AQUA_MODEL_ARTIFACT_CONFIG}. Proceeding with model registration."
|
1194
1294
|
)
|
1195
|
-
except Exception:
|
1196
|
-
pass
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
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
|
1211
1315
|
|
1212
1316
|
@staticmethod
|
1213
1317
|
def _validate_gguf_format(
|
@@ -1296,25 +1400,29 @@ class AquaModelApp(AquaApp):
|
|
1296
1400
|
Returns
|
1297
1401
|
-------
|
1298
1402
|
model_artifact_path (str): Location where the model artifacts are downloaded.
|
1299
|
-
|
1300
1403
|
"""
|
1301
1404
|
# Download the model from hub
|
1302
|
-
if
|
1303
|
-
local_dir = os.path.join(
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1405
|
+
if local_dir:
|
1406
|
+
local_dir = os.path.join(local_dir, model_name)
|
1407
|
+
os.makedirs(local_dir, exist_ok=True)
|
1408
|
+
|
1409
|
+
# if local_dir is not set, the return value points to the cached data folder
|
1410
|
+
local_dir = snapshot_download(
|
1307
1411
|
repo_id=model_name,
|
1308
1412
|
local_dir=local_dir,
|
1309
1413
|
allow_patterns=allow_patterns,
|
1310
1414
|
ignore_patterns=ignore_patterns,
|
1311
1415
|
)
|
1312
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
|
+
)
|
1420
|
+
# Upload to object storage
|
1313
1421
|
model_artifact_path = upload_folder(
|
1314
1422
|
os_path=os_path,
|
1315
1423
|
local_dir=local_dir,
|
1316
1424
|
model_name=model_name,
|
1317
|
-
exclude_pattern=f"{HF_METADATA_FOLDER}*"
|
1425
|
+
exclude_pattern=f"{HF_METADATA_FOLDER}*",
|
1318
1426
|
)
|
1319
1427
|
|
1320
1428
|
return model_artifact_path
|
@@ -1339,6 +1447,8 @@ class AquaModelApp(AquaApp):
|
|
1339
1447
|
ignore_patterns (list): Model files matching any of the patterns are not downloaded.
|
1340
1448
|
Example: ["*.json"] will ignore all .json files. ["folder/*"] will ignore all files under `folder`.
|
1341
1449
|
Patterns are Standard Wildcards (globbing patterns) and rules can be found here: https://docs.python.org/3/library/fnmatch.html
|
1450
|
+
cleanup_model_cache (bool): Deletes downloaded files from local machine after model is successfully
|
1451
|
+
registered. Set to True by default.
|
1342
1452
|
|
1343
1453
|
Returns:
|
1344
1454
|
AquaModel:
|
@@ -1353,6 +1463,7 @@ class AquaModelApp(AquaApp):
|
|
1353
1463
|
import_model_details.model.startswith("ocid")
|
1354
1464
|
and "datasciencemodel" in import_model_details.model
|
1355
1465
|
):
|
1466
|
+
logger.info(f"Fetching details for model {import_model_details.model}.")
|
1356
1467
|
verified_model = DataScienceModel.from_id(import_model_details.model)
|
1357
1468
|
else:
|
1358
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
|
@@ -1390,7 +1501,6 @@ class AquaModelApp(AquaApp):
|
|
1390
1501
|
).rstrip("/")
|
1391
1502
|
else:
|
1392
1503
|
artifact_path = import_model_details.os_path.rstrip("/")
|
1393
|
-
|
1394
1504
|
# Create Model catalog entry with pass by reference
|
1395
1505
|
ds_model = self._create_model_catalog_entry(
|
1396
1506
|
os_path=artifact_path,
|
@@ -1402,6 +1512,8 @@ class AquaModelApp(AquaApp):
|
|
1402
1512
|
compartment_id=import_model_details.compartment_id,
|
1403
1513
|
project_id=import_model_details.project_id,
|
1404
1514
|
inference_container_uri=import_model_details.inference_container_uri,
|
1515
|
+
freeform_tags=import_model_details.freeform_tags,
|
1516
|
+
defined_tags=import_model_details.defined_tags,
|
1405
1517
|
)
|
1406
1518
|
# registered model will always have inference and evaluation container, but
|
1407
1519
|
# fine-tuning container may be not set
|
@@ -1446,6 +1558,14 @@ class AquaModelApp(AquaApp):
|
|
1446
1558
|
detail=validation_result.telemetry_model_name,
|
1447
1559
|
)
|
1448
1560
|
|
1561
|
+
if (
|
1562
|
+
import_model_details.download_from_hf
|
1563
|
+
and import_model_details.cleanup_model_cache
|
1564
|
+
):
|
1565
|
+
cleanup_local_hf_model_artifact(
|
1566
|
+
model_name=model_name, local_dir=import_model_details.local_dir
|
1567
|
+
)
|
1568
|
+
|
1449
1569
|
return AquaModel(**aqua_model_attributes)
|
1450
1570
|
|
1451
1571
|
def _if_show(self, model: DataScienceModel) -> bool:
|
@@ -1473,7 +1593,7 @@ class AquaModelApp(AquaApp):
|
|
1473
1593
|
elif model_type == ModelType.BASE:
|
1474
1594
|
filter_tag = Tags.BASE_MODEL_CUSTOM
|
1475
1595
|
else:
|
1476
|
-
raise
|
1596
|
+
raise AquaValueError(
|
1477
1597
|
f"Model of type {model_type} is unknown. The values should be in {ModelType.values()}"
|
1478
1598
|
)
|
1479
1599
|
|
@@ -1513,7 +1633,10 @@ class AquaModelApp(AquaApp):
|
|
1513
1633
|
oci_model = self.ds_client.get_model(model_id).data
|
1514
1634
|
artifact_path = get_artifact_path(oci_model.custom_metadata_list)
|
1515
1635
|
if not artifact_path:
|
1516
|
-
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
|
+
)
|
1517
1640
|
|
1518
1641
|
content = str(
|
1519
1642
|
read_file(
|
@@ -1544,6 +1667,9 @@ class AquaModelApp(AquaApp):
|
|
1544
1667
|
|
1545
1668
|
for aqua_model_summary in aqua_model_list:
|
1546
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
|
+
)
|
1547
1673
|
return aqua_model_summary.id
|
1548
1674
|
|
1549
1675
|
return None
|