oracle-ads 2.11.15__py3-none-any.whl → 2.11.16__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 (41) hide show
  1. ads/aqua/common/entities.py +17 -0
  2. ads/aqua/common/enums.py +5 -1
  3. ads/aqua/common/utils.py +32 -2
  4. ads/aqua/config/config.py +1 -1
  5. ads/aqua/config/deployment_config_defaults.json +29 -1
  6. ads/aqua/config/resource_limit_names.json +1 -0
  7. ads/aqua/constants.py +5 -1
  8. ads/aqua/evaluation/entities.py +0 -1
  9. ads/aqua/evaluation/evaluation.py +47 -14
  10. ads/aqua/extension/common_ws_msg_handler.py +57 -0
  11. ads/aqua/extension/deployment_handler.py +14 -13
  12. ads/aqua/extension/deployment_ws_msg_handler.py +54 -0
  13. ads/aqua/extension/errors.py +1 -1
  14. ads/aqua/extension/evaluation_ws_msg_handler.py +28 -6
  15. ads/aqua/extension/model_handler.py +31 -6
  16. ads/aqua/extension/models/ws_models.py +78 -3
  17. ads/aqua/extension/models_ws_msg_handler.py +49 -0
  18. ads/aqua/extension/ui_websocket_handler.py +7 -1
  19. ads/aqua/model/entities.py +11 -1
  20. ads/aqua/model/model.py +260 -90
  21. ads/aqua/modeldeployment/deployment.py +52 -7
  22. ads/aqua/modeldeployment/entities.py +9 -20
  23. ads/aqua/ui.py +152 -28
  24. ads/common/object_storage_details.py +2 -5
  25. ads/common/serializer.py +2 -3
  26. ads/jobs/builders/infrastructure/dsc_job.py +29 -3
  27. ads/jobs/builders/infrastructure/dsc_job_runtime.py +74 -27
  28. ads/jobs/builders/runtimes/container_runtime.py +83 -4
  29. ads/opctl/operator/lowcode/anomaly/const.py +1 -0
  30. ads/opctl/operator/lowcode/anomaly/model/base_model.py +23 -7
  31. ads/opctl/operator/lowcode/anomaly/operator_config.py +1 -0
  32. ads/opctl/operator/lowcode/anomaly/schema.yaml +4 -0
  33. ads/opctl/operator/lowcode/common/errors.py +6 -0
  34. ads/opctl/operator/lowcode/forecast/model/base_model.py +21 -13
  35. ads/opctl/operator/lowcode/forecast/model_evaluator.py +11 -2
  36. ads/pipeline/ads_pipeline_run.py +13 -2
  37. {oracle_ads-2.11.15.dist-info → oracle_ads-2.11.16.dist-info}/METADATA +1 -1
  38. {oracle_ads-2.11.15.dist-info → oracle_ads-2.11.16.dist-info}/RECORD +41 -37
  39. {oracle_ads-2.11.15.dist-info → oracle_ads-2.11.16.dist-info}/LICENSE.txt +0 -0
  40. {oracle_ads-2.11.15.dist-info → oracle_ads-2.11.16.dist-info}/WHEEL +0 -0
  41. {oracle_ads-2.11.15.dist-info → oracle_ads-2.11.16.dist-info}/entry_points.txt +0 -0
ads/aqua/model/model.py CHANGED
@@ -1,27 +1,31 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
2
  # Copyright (c) 2024 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
  import os
6
5
  from datetime import datetime, timedelta
7
6
  from threading import Lock
8
- from typing import List, Optional, Union
7
+ from typing import Dict, Optional, Set, Union
9
8
 
10
9
  from cachetools import TTLCache
11
- from oci.data_science.models import JobRun, Model
12
10
 
13
11
  from ads.aqua import ODSC_MODEL_COMPARTMENT_OCID
14
12
  from ads.aqua.app import AquaApp
15
13
  from ads.aqua.common.enums import Tags
16
- from ads.aqua.common.errors import AquaRuntimeError
14
+ from ads.aqua.common.errors import AquaRuntimeError, AquaValueError
17
15
  from ads.aqua.common.utils import (
16
+ copy_model_config,
18
17
  create_word_icon,
19
18
  get_artifact_path,
20
- read_file,
21
- copy_model_config,
19
+ list_os_files_with_extension,
22
20
  load_config,
21
+ read_file,
23
22
  )
24
23
  from ads.aqua.constants import (
24
+ AQUA_MODEL_ARTIFACT_CONFIG,
25
+ AQUA_MODEL_ARTIFACT_CONFIG_MODEL_NAME,
26
+ AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE,
27
+ AQUA_MODEL_ARTIFACT_FILE,
28
+ AQUA_MODEL_TYPE_CUSTOM,
25
29
  LICENSE_TXT,
26
30
  MODEL_BY_REFERENCE_OSS_PATH_KEY,
27
31
  README,
@@ -33,13 +37,10 @@ from ads.aqua.constants import (
33
37
  UNKNOWN,
34
38
  VALIDATION_METRICS,
35
39
  VALIDATION_METRICS_FINAL,
36
- AQUA_MODEL_ARTIFACT_CONFIG,
37
- AQUA_MODEL_ARTIFACT_CONFIG_MODEL_NAME,
38
- AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE,
39
- AQUA_MODEL_TYPE_CUSTOM,
40
40
  )
41
41
  from ads.aqua.model.constants import *
42
42
  from ads.aqua.model.entities import *
43
+ from ads.aqua.ui import AquaContainerConfig, AquaContainerConfigItem
43
44
  from ads.common.auth import default_signer
44
45
  from ads.common.oci_resource import SEARCH_TYPE, OCIResource
45
46
  from ads.common.utils import get_console_link
@@ -54,6 +55,7 @@ from ads.config import (
54
55
  from ads.model import DataScienceModel
55
56
  from ads.model.model_metadata import ModelCustomMetadata, ModelCustomMetadataItem
56
57
  from ads.telemetry import telemetry
58
+ from oci.data_science.models import JobRun, Model
57
59
 
58
60
 
59
61
  class AquaModelApp(AquaApp):
@@ -236,7 +238,7 @@ class AquaModelApp(AquaApp):
236
238
  try:
237
239
  jobrun_ocid = ds_model.provenance_metadata.training_id
238
240
  jobrun = self.ds_client.get_job_run(jobrun_ocid).data
239
- except Exception as e:
241
+ except Exception:
240
242
  logger.debug(
241
243
  f"Missing jobrun information in the provenance metadata of the given model {model_id}."
242
244
  )
@@ -268,8 +270,7 @@ class AquaModelApp(AquaApp):
268
270
 
269
271
  job_run_status = (
270
272
  jobrun.lifecycle_state
271
- if jobrun
272
- and not jobrun.lifecycle_state == JobRun.LIFECYCLE_STATE_DELETED
273
+ if jobrun and jobrun.lifecycle_state != JobRun.LIFECYCLE_STATE_DELETED
273
274
  else (
274
275
  JobRun.LIFECYCLE_STATE_SUCCEEDED
275
276
  if self.if_artifact_exist(ds_model.id)
@@ -363,8 +364,21 @@ class AquaModelApp(AquaApp):
363
364
  training_final,
364
365
  ]
365
366
 
367
+ @staticmethod
368
+ def to_aqua_model(
369
+ model: Union[
370
+ DataScienceModel,
371
+ oci.data_science.models.model.Model,
372
+ oci.data_science.models.ModelSummary,
373
+ oci.resource_search.models.ResourceSummary,
374
+ ],
375
+ region: str,
376
+ ) -> AquaModel:
377
+ """Converts a model to an Aqua model."""
378
+ return AquaModel(**AquaModelApp._process_model(model, region))
379
+
380
+ @staticmethod
366
381
  def _process_model(
367
- self,
368
382
  model: Union[
369
383
  DataScienceModel,
370
384
  oci.data_science.models.model.Model,
@@ -389,12 +403,10 @@ class AquaModelApp(AquaApp):
389
403
  else model.id
390
404
  )
391
405
 
392
- console_link = (
393
- get_console_link(
394
- resource="models",
395
- ocid=model_id,
396
- region=region,
397
- ),
406
+ console_link = get_console_link(
407
+ resource="models",
408
+ ocid=model_id,
409
+ region=region,
398
410
  )
399
411
 
400
412
  description = ""
@@ -406,7 +418,7 @@ class AquaModelApp(AquaApp):
406
418
  description = model.additional_details.get("description")
407
419
 
408
420
  search_text = (
409
- self._build_search_text(tags=tags, description=description)
421
+ AquaModelApp._build_search_text(tags=tags, description=description)
410
422
  if tags
411
423
  else UNKNOWN
412
424
  )
@@ -416,6 +428,7 @@ class AquaModelApp(AquaApp):
416
428
  ready_to_deploy = (
417
429
  freeform_tags.get(Tags.AQUA_TAG, "").upper() == READY_TO_DEPLOY_STATUS
418
430
  )
431
+
419
432
  ready_to_finetune = (
420
433
  freeform_tags.get(Tags.READY_TO_FINE_TUNE, "").upper()
421
434
  == READY_TO_FINE_TUNE_STATUS
@@ -425,6 +438,24 @@ class AquaModelApp(AquaApp):
425
438
  == READY_TO_IMPORT_STATUS
426
439
  )
427
440
 
441
+ inference_containers = AquaContainerConfig.from_container_index_json().inference
442
+
443
+ model_format = ModelFormat[
444
+ freeform_tags.get(Tags.MODEL_FORMAT, ModelFormat.SAFETENSORS.value).upper()
445
+ ]
446
+ supported_platform: Set[AquaContainerConfigItem.Platform] = set()
447
+
448
+ for container in inference_containers.values():
449
+ if model_format in container.model_formats:
450
+ supported_platform.update(container.platforms)
451
+
452
+ nvidia_gpu_supported = (
453
+ AquaContainerConfigItem.Platform.NVIDIA_GPU in supported_platform
454
+ )
455
+ arm_cpu_supported = (
456
+ AquaContainerConfigItem.Platform.ARM_CPU in supported_platform
457
+ )
458
+
428
459
  return dict(
429
460
  compartment_id=model.compartment_id,
430
461
  icon=icon or UNKNOWN,
@@ -433,7 +464,7 @@ class AquaModelApp(AquaApp):
433
464
  name=model.display_name,
434
465
  organization=freeform_tags.get(Tags.ORGANIZATION, UNKNOWN),
435
466
  task=freeform_tags.get(Tags.TASK, UNKNOWN),
436
- time_created=model.time_created,
467
+ time_created=str(model.time_created),
437
468
  is_fine_tuned_model=is_fine_tuned_model,
438
469
  tags=tags,
439
470
  console_link=console_link,
@@ -441,6 +472,9 @@ class AquaModelApp(AquaApp):
441
472
  ready_to_deploy=ready_to_deploy,
442
473
  ready_to_finetune=ready_to_finetune,
443
474
  ready_to_import=ready_to_import,
475
+ nvidia_gpu_supported=nvidia_gpu_supported,
476
+ arm_cpu_supported=arm_cpu_supported,
477
+ model_format=model_format,
444
478
  )
445
479
 
446
480
  @telemetry(entry_point="plugin=model&action=list", name="aqua")
@@ -540,7 +574,7 @@ class AquaModelApp(AquaApp):
540
574
  dict with the key used, and True if cache has the key that needs to be deleted.
541
575
  """
542
576
  res = {}
543
- logger.info(f"Clearing _service_models_cache")
577
+ logger.info("Clearing _service_models_cache")
544
578
  with self._cache_lock:
545
579
  if ODSC_MODEL_COMPARTMENT_OCID in self._service_models_cache.keys():
546
580
  self._service_models_cache.pop(key=ODSC_MODEL_COMPARTMENT_OCID)
@@ -559,8 +593,10 @@ class AquaModelApp(AquaApp):
559
593
  inference_container: str,
560
594
  finetuning_container: str,
561
595
  verified_model: DataScienceModel,
596
+ model_format: ModelFormat,
562
597
  compartment_id: Optional[str],
563
598
  project_id: Optional[str],
599
+ model_file: Optional[str],
564
600
  ) -> DataScienceModel:
565
601
  """Create model by reference from the object storage path
566
602
 
@@ -577,15 +613,19 @@ class AquaModelApp(AquaApp):
577
613
  DataScienceModel: Returns Datascience model instance.
578
614
  """
579
615
  model = DataScienceModel()
580
- tags = (
616
+ tags: Dict[str, str] = (
581
617
  {
582
618
  **verified_model.freeform_tags,
583
619
  Tags.AQUA_SERVICE_MODEL_TAG: verified_model.id,
584
620
  }
585
621
  if verified_model
586
- else {Tags.AQUA_TAG: "active", Tags.BASE_MODEL_CUSTOM: "true"}
622
+ else {
623
+ Tags.AQUA_TAG: "active",
624
+ Tags.BASE_MODEL_CUSTOM: "true",
625
+ }
587
626
  )
588
627
  tags.update({Tags.BASE_MODEL_CUSTOM: "true"})
628
+ tags.update({Tags.MODEL_FORMAT: model_format.value})
589
629
 
590
630
  # Remove `ready_to_import` tag that might get copied from service model.
591
631
  tags.pop(Tags.READY_TO_IMPORT, None)
@@ -615,8 +655,15 @@ class AquaModelApp(AquaApp):
615
655
  )
616
656
  else:
617
657
  logger.warn(
618
- f"Proceeding with model registration without the fine-tuning container information. "
619
- f"This model will not be available for fine tuning."
658
+ "Proceeding with model registration without the fine-tuning container information. "
659
+ "This model will not be available for fine tuning."
660
+ )
661
+ if model_file:
662
+ metadata.add(
663
+ key=AQUA_MODEL_ARTIFACT_FILE,
664
+ value=model_file,
665
+ description=f"The model file for {model_name}",
666
+ category="Other",
620
667
  )
621
668
 
622
669
  metadata.add(
@@ -673,6 +720,174 @@ class AquaModelApp(AquaApp):
673
720
  logger.debug(model)
674
721
  return model
675
722
 
723
+ @staticmethod
724
+ def get_model_files(os_path: str, model_format: ModelFormat) -> [str]:
725
+ """
726
+ Get a list of model files based on the given OS path and model format.
727
+
728
+ Args:
729
+ os_path (str): The OS path where the model files are located.
730
+ model_format (ModelFormat): The format of the model files.
731
+
732
+ Returns:
733
+ List[str]: A list of model file names.
734
+
735
+ """
736
+ model_files: List[str] = []
737
+ if model_format == ModelFormat.SAFETENSORS:
738
+ try:
739
+ load_config(
740
+ file_path=os_path,
741
+ config_file_name=AQUA_MODEL_ARTIFACT_CONFIG,
742
+ )
743
+ except AquaValueError:
744
+ pass
745
+ else:
746
+ model_files.append(AQUA_MODEL_ARTIFACT_CONFIG)
747
+
748
+ if model_format == ModelFormat.GGUF:
749
+ model_files.extend(
750
+ list_os_files_with_extension(oss_path=os_path, extension=".gguf")
751
+ )
752
+ return model_files
753
+
754
+ def validate_model_config(
755
+ self,
756
+ import_model_details: ImportModelDetails,
757
+ verified_model: Optional[DataScienceModel],
758
+ ) -> ModelValidationResult:
759
+ """
760
+ Validates the model configuration and returns the model format telemetry model name.
761
+
762
+ Args:
763
+ import_model_details (ImportModelDetails): The details of the imported model.
764
+ verified_model (Optional[DataScienceModel]): The verified model.
765
+
766
+ Returns:
767
+ ModelValidationResult: The result of the model validation.
768
+
769
+ Raises:
770
+ AquaRuntimeError: If there is an error while loading the config file or if the model path is incorrect.
771
+ AquaValueError: If the model format is not supported by AQUA."""
772
+ inference_containers_config = (
773
+ AquaContainerConfig.from_container_index_json().inference
774
+ )
775
+ inference_container = import_model_details.inference_container
776
+ model_format: ModelFormat
777
+ validation_result: ModelValidationResult = ModelValidationResult()
778
+ if verified_model:
779
+ aqua_model = self.to_aqua_model(verified_model, self.region)
780
+ model_format = aqua_model.model_format
781
+ else:
782
+ # Todo: Revisit this logic once a container supports multiple formats
783
+ try:
784
+ model_format = inference_containers_config[
785
+ inference_container
786
+ ].model_formats[0]
787
+ except (KeyError, IndexError):
788
+ logger.warn(
789
+ "Unable to fetch model format for the model automatically defaulting to safetensors"
790
+ )
791
+ model_format = ModelFormat.SAFETENSORS
792
+ pass
793
+ validation_result.model_format = model_format
794
+ if model_format == ModelFormat.SAFETENSORS:
795
+ try:
796
+ model_config = load_config(
797
+ file_path=import_model_details.os_path,
798
+ config_file_name=AQUA_MODEL_ARTIFACT_CONFIG,
799
+ )
800
+ except Exception as ex:
801
+ logger.error(
802
+ f"Exception occurred while loading config file from {import_model_details.os_path}"
803
+ f"Exception message: {ex}"
804
+ )
805
+ raise AquaRuntimeError(
806
+ f"The model path {import_model_details.os_path} does not contain the file config.json. "
807
+ f"Please check if the path is correct or the model artifacts are available at this location."
808
+ )
809
+ else:
810
+ try:
811
+ metadata_model_type = verified_model.custom_metadata_list.get(
812
+ AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE
813
+ ).value
814
+ if metadata_model_type:
815
+ if AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE in model_config:
816
+ if (
817
+ model_config[AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE]
818
+ != metadata_model_type
819
+ ):
820
+ raise AquaRuntimeError(
821
+ f"The {AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE} attribute in {AQUA_MODEL_ARTIFACT_CONFIG}"
822
+ f" at {import_model_details.os_path} is invalid, expected {metadata_model_type} for "
823
+ f"the model {import_model_details.model}. Please check if the path is correct or "
824
+ f"the correct model artifacts are available at this location."
825
+ f""
826
+ )
827
+ else:
828
+ logger.debug(
829
+ f"Could not find {AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE} attribute in "
830
+ f"{AQUA_MODEL_ARTIFACT_CONFIG}. Proceeding with model registration."
831
+ )
832
+ except:
833
+ pass
834
+ if verified_model:
835
+ validation_result.telemetry_model_name = verified_model.display_name
836
+ elif (
837
+ model_config is not None
838
+ and AQUA_MODEL_ARTIFACT_CONFIG_MODEL_NAME in model_config
839
+ ):
840
+ validation_result.telemetry_model_name = f"{AQUA_MODEL_TYPE_CUSTOM}_{model_config[AQUA_MODEL_ARTIFACT_CONFIG_MODEL_NAME]}"
841
+ elif (
842
+ model_config is not None
843
+ and AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE in model_config
844
+ ):
845
+ validation_result.telemetry_model_name = f"{AQUA_MODEL_TYPE_CUSTOM}_{model_config[AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE]}"
846
+ else:
847
+ validation_result.telemetry_model_name = AQUA_MODEL_TYPE_CUSTOM
848
+
849
+ elif model_format == ModelFormat.GGUF:
850
+ if import_model_details.finetuning_container:
851
+ raise AquaValueError(
852
+ "Finetuning is currently not supported with GGUF model format"
853
+ )
854
+ if verified_model:
855
+ model_file = verified_model.custom_metadata_list.get(
856
+ AQUA_MODEL_ARTIFACT_FILE, None
857
+ )
858
+ else:
859
+ model_file = import_model_details.model_file
860
+ model_files = self.get_model_files(
861
+ import_model_details.os_path, model_format
862
+ )
863
+ if model_file:
864
+ if model_file not in model_files:
865
+ raise AquaRuntimeError(
866
+ f"The model path {import_model_details.os_path} does not contain the file {model_file}. "
867
+ f"Please check if the path is correct or the model artifacts are available at this location."
868
+ )
869
+ else:
870
+ validation_result.model_file = model_file
871
+ elif len(model_files) == 0:
872
+ raise AquaRuntimeError(
873
+ f"The model path {import_model_details.os_path} does not contain any GGUF format files. "
874
+ f"Please check if the path is correct or the model artifacts are available at this location."
875
+ )
876
+ elif len(model_files) > 1:
877
+ raise AquaRuntimeError(
878
+ f"The model path {import_model_details.os_path} contains multiple GGUF format files. Please specify the file that needs to be deployed."
879
+ )
880
+ else:
881
+ validation_result.model_file = model_files[0]
882
+
883
+ if verified_model:
884
+ validation_result.telemetry_model_name = verified_model.display_name
885
+ else:
886
+ validation_result.telemetry_model_name = AQUA_MODEL_TYPE_CUSTOM
887
+ else:
888
+ raise AquaValueError("This model format is currently not supported by AQUA")
889
+ return validation_result
890
+
676
891
  def register(
677
892
  self, import_model_details: ImportModelDetails = None, **kwargs
678
893
  ) -> AquaModel:
@@ -692,72 +907,34 @@ class AquaModelApp(AquaApp):
692
907
  AquaModel:
693
908
  The registered model as a AquaModel object.
694
909
  """
695
- verified_model_details: DataScienceModel = None
696
-
697
910
  if not import_model_details:
698
911
  import_model_details = ImportModelDetails(**kwargs)
699
912
 
700
- try:
701
- model_config = load_config(
702
- file_path=import_model_details.os_path,
703
- config_file_name=AQUA_MODEL_ARTIFACT_CONFIG,
704
- )
705
- except Exception as ex:
706
- logger.error(
707
- f"Exception occurred while loading config file from {import_model_details.os_path}"
708
- f"Exception message: {ex}"
709
- )
710
- raise AquaRuntimeError(
711
- f"The model path {import_model_details.os_path} does not contain the file config.json. "
712
- f"Please check if the path is correct or the model artifacts are available at this location."
713
- )
714
-
715
- model_service_id = None
716
913
  # If OCID of a model is passed, we need to copy the defaults for Tags and metadata from the service model.
914
+ verified_model: Optional[DataScienceModel] = None
717
915
  if (
718
916
  import_model_details.model.startswith("ocid")
719
917
  and "datasciencemodel" in import_model_details.model
720
918
  ):
721
- model_service_id = import_model_details.model
919
+ verified_model = DataScienceModel.from_id(import_model_details.model)
722
920
  else:
723
921
  # 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
724
922
  model_service_id = self._find_matching_aqua_model(
725
923
  import_model_details.model
726
924
  )
727
- logger.info(
728
- f"Found service model for {import_model_details.model}: {model_service_id}"
729
- )
730
- if model_service_id:
731
- verified_model_details = DataScienceModel.from_id(model_service_id)
732
- try:
733
- metadata_model_type = verified_model_details.custom_metadata_list.get(
734
- AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE
735
- ).value
736
- if metadata_model_type:
737
- if AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE in model_config:
738
- if (
739
- model_config[AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE]
740
- != metadata_model_type
741
- ):
742
- raise AquaRuntimeError(
743
- f"The {AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE} attribute in {AQUA_MODEL_ARTIFACT_CONFIG}"
744
- f" at {import_model_details.os_path} is invalid, expected {metadata_model_type} for "
745
- f"the model {import_model_details.model}. Please check if the path is correct or "
746
- f"the correct model artifacts are available at this location."
747
- f""
748
- )
749
- else:
750
- logger.debug(
751
- f"Could not find {AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE} attribute in "
752
- f"{AQUA_MODEL_ARTIFACT_CONFIG}. Proceeding with model registration."
753
- )
754
- except:
755
- pass
925
+ if model_service_id:
926
+ logger.info(
927
+ f"Found service model for {import_model_details.model}: {model_service_id}"
928
+ )
929
+ verified_model = DataScienceModel.from_id(model_service_id)
756
930
 
931
+ validation_result = self.validate_model_config(
932
+ import_model_details, verified_model
933
+ )
757
934
  # Copy the model name from the service model if `model` is ocid
758
935
  model_name = (
759
- verified_model_details.display_name
760
- if verified_model_details
936
+ verified_model.display_name
937
+ if verified_model
761
938
  else import_model_details.model
762
939
  )
763
940
 
@@ -767,9 +944,11 @@ class AquaModelApp(AquaApp):
767
944
  model_name=model_name,
768
945
  inference_container=import_model_details.inference_container,
769
946
  finetuning_container=import_model_details.finetuning_container,
770
- verified_model=verified_model_details,
947
+ verified_model=verified_model,
771
948
  compartment_id=import_model_details.compartment_id,
772
949
  project_id=import_model_details.project_id,
950
+ model_file=validation_result.model_file,
951
+ model_format=validation_result.model_format,
773
952
  )
774
953
  # registered model will always have inference and evaluation container, but
775
954
  # fine-tuning container may be not set
@@ -800,20 +979,10 @@ class AquaModelApp(AquaApp):
800
979
  evaluation_container=evaluation_container,
801
980
  )
802
981
 
803
- if verified_model_details:
804
- telemetry_model_name = model_name
805
- else:
806
- if AQUA_MODEL_ARTIFACT_CONFIG_MODEL_NAME in model_config:
807
- telemetry_model_name = f"{AQUA_MODEL_TYPE_CUSTOM}_{model_config[AQUA_MODEL_ARTIFACT_CONFIG_MODEL_NAME]}"
808
- elif AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE in model_config:
809
- telemetry_model_name = f"{AQUA_MODEL_TYPE_CUSTOM}_{model_config[AQUA_MODEL_ARTIFACT_CONFIG_MODEL_TYPE]}"
810
- else:
811
- telemetry_model_name = AQUA_MODEL_TYPE_CUSTOM
812
-
813
982
  self.telemetry.record_event_async(
814
983
  category="aqua/model",
815
984
  action="register",
816
- detail=telemetry_model_name,
985
+ detail=validation_result.telemetry_model_name,
817
986
  )
818
987
 
819
988
  return AquaModel(**aqua_model_attributes)
@@ -856,7 +1025,8 @@ class AquaModelApp(AquaApp):
856
1025
  query, type=SEARCH_TYPE.STRUCTURED, tenant_id=TENANCY_OCID, **kwargs
857
1026
  )
858
1027
 
859
- def _build_search_text(self, tags: dict, description: str = None) -> str:
1028
+ @staticmethod
1029
+ def _build_search_text(tags: dict, description: str = None) -> str:
860
1030
  """Constructs search_text field in response."""
861
1031
  description = description or ""
862
1032
  tags_text = (
@@ -3,9 +3,10 @@
3
3
  # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
4
4
 
5
5
  import logging
6
- from typing import Dict, List, Union
6
+ from typing import Dict, List, Optional, Union
7
7
 
8
8
  from ads.aqua.app import AquaApp, logger
9
+ from ads.aqua.common.entities import ContainerSpec
9
10
  from ads.aqua.common.enums import (
10
11
  InferenceContainerTypeFamily,
11
12
  Tags,
@@ -25,6 +26,7 @@ from ads.aqua.common.utils import (
25
26
  load_config,
26
27
  )
27
28
  from ads.aqua.constants import (
29
+ AQUA_MODEL_ARTIFACT_FILE,
28
30
  AQUA_MODEL_TYPE_CUSTOM,
29
31
  AQUA_MODEL_TYPE_SERVICE,
30
32
  MODEL_BY_REFERENCE_OSS_PATH_KEY,
@@ -37,8 +39,8 @@ from ads.aqua.model import AquaModelApp
37
39
  from ads.aqua.modeldeployment.entities import (
38
40
  AquaDeployment,
39
41
  AquaDeploymentDetail,
40
- ContainerSpec,
41
42
  )
43
+ from ads.aqua.ui import ModelFormat
42
44
  from ads.common.object_storage_details import ObjectStorageDetails
43
45
  from ads.common.utils import get_log_links
44
46
  from ads.config import (
@@ -102,6 +104,8 @@ class AquaDeploymentApp(AquaApp):
102
104
  health_check_port: int = None,
103
105
  env_var: Dict = None,
104
106
  container_family: str = None,
107
+ memory_in_gbs: Optional[float] = None,
108
+ ocpus: Optional[float] = None,
105
109
  ) -> "AquaDeployment":
106
110
  """
107
111
  Creates a new Aqua deployment
@@ -142,6 +146,10 @@ class AquaDeploymentApp(AquaApp):
142
146
  Environment variable for the deployment, by default None.
143
147
  container_family: str
144
148
  The image family of model deployment container runtime. Required for unverified Aqua models.
149
+ memory_in_gbs: float
150
+ The memory in gbs for the shape selected.
151
+ ocpus: float
152
+ The ocpu count for the shape selected.
145
153
  Returns
146
154
  -------
147
155
  AquaDeployment
@@ -204,6 +212,21 @@ class AquaDeploymentApp(AquaApp):
204
212
 
205
213
  env_var.update({"BASE_MODEL": f"{model_path_prefix}"})
206
214
 
215
+ model_format = aqua_model.freeform_tags.get(
216
+ Tags.MODEL_FORMAT, ModelFormat.SAFETENSORS.value
217
+ ).upper()
218
+ if model_format == ModelFormat.GGUF.value:
219
+ try:
220
+ model_file = aqua_model.custom_metadata_list.get(
221
+ AQUA_MODEL_ARTIFACT_FILE
222
+ ).value
223
+ except ValueError as err:
224
+ raise AquaValueError(
225
+ f"{AQUA_MODEL_ARTIFACT_FILE} key is not available in the custom metadata field "
226
+ f"for model {aqua_model.id}."
227
+ ) from err
228
+ env_var.update({"BASE_MODEL_FILE": f"{model_file}"})
229
+
207
230
  if is_fine_tuned_model:
208
231
  _, fine_tune_output_path = get_model_by_reference_paths(
209
232
  aqua_model.model_file_description
@@ -258,8 +281,10 @@ class AquaDeploymentApp(AquaApp):
258
281
  f"Aqua Image used for deploying {aqua_model.id} : {container_image}"
259
282
  )
260
283
 
284
+ # todo: use AquaContainerConfig.from_container_index_json instead.
261
285
  # Fetch the startup cli command for the container
262
- # container_index.json will have "containerSpec" section which will provide the cli params for a given container family
286
+ # container_index.json will have "containerSpec" section which will provide the cli params for
287
+ # a given container family
263
288
  container_config = get_container_config()
264
289
  container_spec = container_config.get(ContainerSpec.CONTAINER_SPEC, {}).get(
265
290
  container_type_key, {}
@@ -285,6 +310,18 @@ class AquaDeploymentApp(AquaApp):
285
310
  # validate user provided params
286
311
  user_params = env_var.get("PARAMS", UNKNOWN)
287
312
  if user_params:
313
+ # todo: remove this check in the future version, logic to be moved to container_index
314
+ if (
315
+ container_type_key.lower()
316
+ == InferenceContainerTypeFamily.AQUA_LLAMA_CPP_CONTAINER_FAMILY
317
+ ):
318
+ # AQUA_LLAMA_CPP_CONTAINER_FAMILY container uses uvicorn that required model/server params
319
+ # to be set as env vars
320
+ raise AquaValueError(
321
+ f"Currently, parameters cannot be overridden for the container: {container_image}. Please proceed "
322
+ f"with deployment without parameter overrides."
323
+ )
324
+
288
325
  restricted_params = self._find_restricted_params(
289
326
  params, user_params, container_type_key
290
327
  )
@@ -296,13 +333,15 @@ class AquaDeploymentApp(AquaApp):
296
333
 
297
334
  deployment_params = get_combined_params(config_params, user_params)
298
335
 
299
- if deployment_params:
300
- params = f"{params} {deployment_params}"
336
+ params = f"{params} {deployment_params}".strip()
337
+ if params:
338
+ env_var.update({"PARAMS": params})
301
339
 
302
- env_var.update({"PARAMS": params})
303
340
  for env in container_spec.get(ContainerSpec.ENV_VARS, []):
304
341
  if isinstance(env, dict):
305
- env_var.update(env)
342
+ for key, _items in env.items():
343
+ if key not in env_var:
344
+ env_var.update(env)
306
345
 
307
346
  logging.info(f"Env vars used for deploying {aqua_model.id} :{env_var}")
308
347
 
@@ -325,6 +364,11 @@ class AquaDeploymentApp(AquaApp):
325
364
  log_id=predict_log_id,
326
365
  )
327
366
  )
367
+ if memory_in_gbs and ocpus and infrastructure.shape_name.endswith("Flex"):
368
+ infrastructure.with_shape_config_details(
369
+ ocpus=ocpus,
370
+ memory_in_gbs=memory_in_gbs,
371
+ )
328
372
  # configure model deployment runtime
329
373
  container_runtime = (
330
374
  ModelDeploymentContainerRuntime()
@@ -338,6 +382,7 @@ class AquaDeploymentApp(AquaApp):
338
382
  .with_overwrite_existing_artifact(True)
339
383
  .with_remove_existing_artifact(True)
340
384
  )
385
+
341
386
  # configure model deployment and deploy model on container runtime
342
387
  deployment = (
343
388
  ModelDeployment()