oracle-ads 2.13.4__py3-none-any.whl → 2.13.5__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.
@@ -1,60 +1,123 @@
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
- from dataclasses import dataclass, field
6
- from typing import List, Optional, Union
5
+ from typing import Any, Dict, List, Optional, Union
7
6
 
8
- from oci.data_science.models import (
9
- ModelDeployment,
10
- ModelDeploymentSummary,
11
- )
7
+ from oci.data_science.models import ModelDeployment, ModelDeploymentSummary
8
+ from pydantic import BaseModel, Field, model_validator
12
9
 
10
+ from ads.aqua import logger
11
+ from ads.aqua.common.entities import AquaMultiModelRef
13
12
  from ads.aqua.common.enums import Tags
13
+ from ads.aqua.config.utils.serializer import Serializable
14
14
  from ads.aqua.constants import UNKNOWN_DICT
15
15
  from ads.aqua.data import AquaResourceIdentifier
16
16
  from ads.common.serializer import DataClassSerializable
17
17
  from ads.common.utils import UNKNOWN, get_console_link
18
18
 
19
19
 
20
- @dataclass
21
- class ModelParams:
22
- max_tokens: int = None
23
- temperature: float = None
24
- top_k: float = None
25
- top_p: float = None
26
- model: str = None
20
+ class ConfigValidationError(Exception):
21
+ """Exception raised for config validation."""
27
22
 
23
+ def __init__(
24
+ self,
25
+ message: str = (
26
+ "Validation failed: The provided model group configuration is incompatible "
27
+ "with the selected instance shape. Please verify the GPU count per model and ensure "
28
+ "multi-model deployment is supported for the chosen instance shape."
29
+ ),
30
+ ):
31
+ super().__init__(message)
28
32
 
29
- @dataclass
30
- class ShapeInfo:
31
- instance_shape: str = None
32
- instance_count: int = None
33
- ocpus: float = None
34
- memory_in_gbs: float = None
35
33
 
34
+ class ShapeInfo(Serializable):
35
+ """
36
+ Represents the configuration details for a compute instance shape.
37
+ """
36
38
 
37
- @dataclass(repr=False)
38
- class AquaDeployment(DataClassSerializable):
39
+ instance_shape: Optional[str] = Field(
40
+ default=None,
41
+ description="The identifier of the compute instance shape (e.g., VM.Standard2.1)",
42
+ )
43
+ instance_count: Optional[int] = Field(
44
+ default=None, description="The number of instances for the given shape."
45
+ )
46
+ ocpus: Optional[float] = Field(
47
+ default=None,
48
+ description="The number of Oracle CPUs allocated for the instance.",
49
+ )
50
+ memory_in_gbs: Optional[float] = Field(
51
+ default=None,
52
+ description="The total memory allocated for the instance, in gigabytes.",
53
+ )
54
+
55
+
56
+ class ModelParams(Serializable):
57
+ max_tokens: Optional[int] = None
58
+ temperature: Optional[float] = None
59
+ top_k: Optional[float] = None
60
+ top_p: Optional[float] = None
61
+ model: Optional[str] = None
62
+
63
+ class Config:
64
+ extra = "allow"
65
+ protected_namespaces = ()
66
+
67
+
68
+ class AquaDeployment(Serializable):
39
69
  """Represents an Aqua Model Deployment"""
40
70
 
41
- id: str = None
42
- display_name: str = None
43
- aqua_service_model: bool = None
44
- model_id: str = None
45
- aqua_model_name: str = None
46
- state: str = None
47
- description: str = None
48
- created_on: str = None
49
- created_by: str = None
50
- endpoint: str = None
51
- private_endpoint_id: str = None
52
- console_link: str = None
53
- lifecycle_details: str = None
54
- shape_info: Optional[ShapeInfo] = None
55
- tags: dict = None
56
- environment_variables: dict = None
57
- cmd: List[str] = None
71
+ id: Optional[str] = Field(None, description="The model deployment OCID.")
72
+ display_name: Optional[str] = Field(
73
+ None, description="The name of the model deployment."
74
+ )
75
+ aqua_service_model: Optional[bool] = Field(
76
+ False, description="The bool value to indicate if it's aqua service model."
77
+ )
78
+ model_id: str = Field(..., description="The model OCID to deploy.")
79
+ models: Optional[List[AquaMultiModelRef]] = Field(
80
+ default_factory=list, description="List of models for multi model deployment."
81
+ )
82
+ aqua_model_name: Optional[str] = Field(
83
+ None, description="The name of the aqua model."
84
+ )
85
+ state: Optional[str] = Field(None, description="The state of the model deployment.")
86
+ description: Optional[str] = Field(
87
+ None, description="The description of the model deployment."
88
+ )
89
+ created_on: Optional[str] = Field(
90
+ None, description="The creation time of the model deployment."
91
+ )
92
+ created_by: Optional[str] = Field(
93
+ None, description="The OCID that creates the model deployment."
94
+ )
95
+ endpoint: Optional[str] = Field(
96
+ None, description="The endpoint of the model deployment."
97
+ )
98
+ private_endpoint_id: Optional[str] = Field(
99
+ None, description="The private endpoint id of the model deployment."
100
+ )
101
+ console_link: Optional[str] = Field(
102
+ None, description="The console link of the model deployment."
103
+ )
104
+ lifecycle_details: Optional[str] = Field(
105
+ None, description="The lifecycle details of the model deployment."
106
+ )
107
+ shape_info: Optional[ShapeInfo] = Field(
108
+ default_factory=ShapeInfo,
109
+ description="The shape information of the model deployment.",
110
+ )
111
+ tags: Optional[dict] = Field(
112
+ default_factory=dict, description="The tags of the model deployment."
113
+ )
114
+ environment_variables: Optional[dict] = Field(
115
+ default_factory=dict,
116
+ description="The environment variables of the model deployment.",
117
+ )
118
+ cmd: Optional[List[str]] = Field(
119
+ default_factory=list, description="The cmd of the model deployment."
120
+ )
58
121
 
59
122
  @classmethod
60
123
  def from_oci_model_deployment(
@@ -135,10 +198,456 @@ class AquaDeployment(DataClassSerializable):
135
198
  cmd=cmd,
136
199
  )
137
200
 
201
+ class Config:
202
+ extra = "ignore"
203
+ protected_namespaces = ()
204
+
138
205
 
139
- @dataclass(repr=False)
140
206
  class AquaDeploymentDetail(AquaDeployment, DataClassSerializable):
141
207
  """Represents a details of Aqua deployment."""
142
208
 
143
- log_group: AquaResourceIdentifier = field(default_factory=AquaResourceIdentifier)
144
- log: AquaResourceIdentifier = field(default_factory=AquaResourceIdentifier)
209
+ log_group: AquaResourceIdentifier = Field(default_factory=AquaResourceIdentifier)
210
+ log: AquaResourceIdentifier = Field(default_factory=AquaResourceIdentifier)
211
+
212
+ class Config:
213
+ extra = "allow"
214
+
215
+
216
+ class ShapeInfoConfig(Serializable):
217
+ """Describes how many memory and cpu to this model for specific shape.
218
+
219
+ Attributes:
220
+ memory_in_gbs (float, optional): The number of memory in gbs to this model of the shape.
221
+ ocpu (float, optional): The number of ocpus to this model of the shape.
222
+ """
223
+
224
+ memory_in_gbs: Optional[float] = Field(
225
+ None,
226
+ description="The number of memory in gbs to this model of the shape.",
227
+ )
228
+ ocpu: Optional[float] = Field(
229
+ None,
230
+ description="The number of ocpus to this model of the shape.",
231
+ )
232
+
233
+ class Config:
234
+ extra = "allow"
235
+
236
+
237
+ class DeploymentShapeInfo(Serializable):
238
+ """Describes the shape information to this model for specific shape.
239
+
240
+ Attributes:
241
+ configs (List[ShapeInfoConfig], optional): A list of memory and cpu number details to this model of the shape.
242
+ type (str, optional): The type of the shape.
243
+ """
244
+
245
+ configs: Optional[List[ShapeInfoConfig]] = Field(
246
+ default_factory=list,
247
+ description="A list of memory and cpu number details to this model of the shape.",
248
+ )
249
+ type: Optional[str] = Field(
250
+ default_factory=str, description="The type of the shape."
251
+ )
252
+
253
+ class Config:
254
+ extra = "allow"
255
+
256
+
257
+ class MultiModelConfig(Serializable):
258
+ """Describes how many GPUs and the parameters of specific shape for multi model deployment.
259
+
260
+ Attributes:
261
+ gpu_count (int, optional): Number of GPUs count to this model of this shape.
262
+ parameters (Dict[str, str], optional): A dictionary of parameters (e.g., VLLM_PARAMS) to
263
+ configure the behavior of a particular GPU shape.
264
+ """
265
+
266
+ gpu_count: Optional[int] = Field(
267
+ default_factory=int, description="The number of GPUs allocated to the model."
268
+ )
269
+ parameters: Optional[Dict[str, str]] = Field(
270
+ default_factory=dict,
271
+ description="Key-value pairs for GPU shape parameters (e.g., VLLM_PARAMS).",
272
+ )
273
+
274
+ class Config:
275
+ extra = "allow"
276
+
277
+
278
+ class ConfigurationItem(Serializable):
279
+ """Holds key-value parameter pairs for a specific GPU or CPU shape.
280
+
281
+ Attributes:
282
+ parameters (Dict[str, str], optional): A dictionary of parameters (e.g., VLLM_PARAMS) to
283
+ configure the behavior of a particular GPU shape.
284
+ multi_model_deployment (List[MultiModelConfig], optional): A list of multi model configuration details.
285
+ shape_info (DeploymentShapeInfo, optional): The shape information to this model for specific CPU shape.
286
+ """
287
+
288
+ parameters: Optional[Dict[str, str]] = Field(
289
+ default_factory=dict,
290
+ description="Key-value pairs for shape parameters.",
291
+ )
292
+ multi_model_deployment: Optional[List[MultiModelConfig]] = Field(
293
+ default_factory=list, description="A list of multi model configuration details."
294
+ )
295
+ shape_info: Optional[DeploymentShapeInfo] = Field(
296
+ default_factory=DeploymentShapeInfo,
297
+ description="The shape information to this model for specific shape",
298
+ )
299
+
300
+ class Config:
301
+ extra = "allow"
302
+
303
+
304
+ class AquaDeploymentConfig(Serializable):
305
+ """Represents multi model's shape list and detailed configuration.
306
+
307
+ Attributes:
308
+ shape (List[str], optional): A list of shape names (e.g., BM.GPU.A10.4).
309
+ configuration (Dict[str, ConfigurationItem], optional): Maps each shape to its configuration details.
310
+ """
311
+
312
+ shape: Optional[List[str]] = Field(
313
+ default_factory=list, description="List of supported shapes for the model."
314
+ )
315
+ configuration: Optional[Dict[str, ConfigurationItem]] = Field(
316
+ default_factory=dict, description="Configuration details keyed by shape."
317
+ )
318
+
319
+ class Config:
320
+ extra = "allow"
321
+
322
+
323
+ class GPUModelAllocation(Serializable):
324
+ """Describes how many GPUs are allocated to a particular model.
325
+
326
+ Attributes:
327
+ ocid (str, optional): The unique identifier of the model.
328
+ gpu_count (int, optional): Number of GPUs allocated to this model.
329
+ """
330
+
331
+ ocid: Optional[str] = Field(
332
+ default_factory=str, description="The unique model OCID."
333
+ )
334
+ gpu_count: Optional[int] = Field(
335
+ default_factory=int, description="The number of GPUs allocated to the model."
336
+ )
337
+
338
+ class Config:
339
+ extra = "allow"
340
+
341
+
342
+ class GPUShapeAllocation(Serializable):
343
+ """
344
+ Allocation details for a specific GPU shape.
345
+
346
+ Attributes:
347
+ models (List[GPUModelAllocation], optional): List of model GPU allocations for this shape.
348
+ total_gpus_available (int, optional): The total number of GPUs available for this shape.
349
+ """
350
+
351
+ models: Optional[List[GPUModelAllocation]] = Field(
352
+ default_factory=list, description="List of model allocations for this shape."
353
+ )
354
+ total_gpus_available: Optional[int] = Field(
355
+ default_factory=int, description="Total GPUs available for this shape."
356
+ )
357
+
358
+ class Config:
359
+ extra = "allow"
360
+
361
+
362
+ class ModelDeploymentConfigSummary(Serializable):
363
+ """Top-level configuration model for OCI-based deployments.
364
+
365
+ Attributes:
366
+ deployment_config (Dict[str, AquaDeploymentConfig], optional): Deployment configurations
367
+ keyed by model OCID.
368
+ gpu_allocation (Dict[str, GPUShapeAllocation], optional): GPU allocations keyed by GPU shape.
369
+ error_message (str, optional): Error message if GPU allocation is not possible.
370
+ """
371
+
372
+ deployment_config: Optional[Dict[str, AquaDeploymentConfig]] = Field(
373
+ default_factory=dict,
374
+ description=(
375
+ "Deployment configuration details for each model, including supported shapes "
376
+ "and shape-specific parameters."
377
+ ),
378
+ )
379
+ gpu_allocation: Optional[Dict[str, GPUShapeAllocation]] = Field(
380
+ default_factory=dict,
381
+ description=(
382
+ "Details on how GPUs are allocated per shape, including the total "
383
+ "GPUs available for each shape."
384
+ ),
385
+ )
386
+ error_message: Optional[str] = Field(
387
+ default=None, description="Error message if GPU allocation is not possible."
388
+ )
389
+
390
+ class Config:
391
+ extra = "allow"
392
+
393
+
394
+ class CreateModelDeploymentDetails(BaseModel):
395
+ """Class for creating Aqua model deployments."""
396
+
397
+ instance_shape: str = Field(
398
+ ..., description="The instance shape used for deployment."
399
+ )
400
+ display_name: str = Field(..., description="The name of the model deployment.")
401
+ compartment_id: Optional[str] = Field(None, description="The compartment OCID.")
402
+ project_id: Optional[str] = Field(None, description="The project OCID.")
403
+ description: Optional[str] = Field(
404
+ None, description="The description of the deployment."
405
+ )
406
+ model_id: Optional[str] = Field(None, description="The model OCID to deploy.")
407
+ models: Optional[List[AquaMultiModelRef]] = Field(
408
+ None, description="List of models for multimodel deployment."
409
+ )
410
+ instance_count: int = Field(
411
+ None, description="Number of instances used for deployment."
412
+ )
413
+ log_group_id: Optional[str] = Field(
414
+ None, description="OCI logging group ID for logs."
415
+ )
416
+ access_log_id: Optional[str] = Field(
417
+ None,
418
+ description="OCID for access logs. "
419
+ "https://docs.oracle.com/en-us/iaas/data-science/using/model_dep_using_logging.htm",
420
+ )
421
+ predict_log_id: Optional[str] = Field(
422
+ None,
423
+ description="OCID for prediction logs."
424
+ "https://docs.oracle.com/en-us/iaas/data-science/using/model_dep_using_logging.htm",
425
+ )
426
+ bandwidth_mbps: Optional[int] = Field(
427
+ None, description="Bandwidth limit on the load balancer in Mbps."
428
+ )
429
+ web_concurrency: Optional[int] = Field(
430
+ None, description="Number of worker processes/threads for handling requests."
431
+ )
432
+ server_port: Optional[int] = Field(
433
+ None, description="Server port for the Docker container image."
434
+ )
435
+ health_check_port: Optional[int] = Field(
436
+ None, description="Health check port for the Docker container image."
437
+ )
438
+ env_var: Optional[Dict[str, str]] = Field(
439
+ default_factory=dict, description="Environment variables for deployment."
440
+ )
441
+ container_family: Optional[str] = Field(
442
+ None, description="Image family of the model deployment container runtime."
443
+ )
444
+ memory_in_gbs: Optional[float] = Field(
445
+ None, description="Memory (in GB) for the selected shape."
446
+ )
447
+ ocpus: Optional[float] = Field(
448
+ None, description="OCPU count for the selected shape."
449
+ )
450
+ model_file: Optional[str] = Field(
451
+ None, description="File used for model deployment."
452
+ )
453
+ private_endpoint_id: Optional[str] = Field(
454
+ None, description="Private endpoint ID for model deployment."
455
+ )
456
+ container_image_uri: Optional[str] = Field(
457
+ None,
458
+ description="Image URI for model deployment container runtime "
459
+ "(ignored for service-managed containers). "
460
+ "Required parameter for BYOC based deployments if this parameter was not set during "
461
+ "model registration.",
462
+ )
463
+ cmd_var: Optional[List[str]] = Field(
464
+ None, description="Command variables for the container runtime."
465
+ )
466
+ freeform_tags: Optional[Dict] = Field(
467
+ None, description="Freeform tags for model deployment."
468
+ )
469
+ defined_tags: Optional[Dict] = Field(
470
+ None, description="Defined tags for model deployment."
471
+ )
472
+
473
+ @model_validator(mode="before")
474
+ @classmethod
475
+ def validate(cls, values: Any) -> Any:
476
+ """Ensures exactly one of `model_id` or `models` is provided."""
477
+ model_id = values.get("model_id")
478
+ models = values.get("models")
479
+ if bool(model_id) == bool(models): # Both set or both unset
480
+ raise ValueError(
481
+ "Exactly one of `model_id` or `models` must be provided to create a model deployment."
482
+ )
483
+ return values
484
+
485
+ def validate_multimodel_deployment_feasibility(
486
+ self, models_config_summary: ModelDeploymentConfigSummary
487
+ ) -> None:
488
+ """
489
+ Validates whether the selected model group is feasible for a multi-model deployment
490
+ on the chosen instance shape.
491
+
492
+ Validation Criteria:
493
+ - Ensures that the model group is not empty.
494
+ - Verifies that the selected instance shape is supported by the GPU allocation.
495
+ - Confirms that each model in the group has a corresponding deployment configuration.
496
+ - Ensures that each model's user-specified GPU allocation is allowed by its deployment configuration.
497
+ - Checks that the total GPUs requested by the model group does not exceed the available GPU capacity
498
+ for the selected instance shape.
499
+
500
+ Parameters
501
+ ----------
502
+ models_config_summary : ModelDeploymentConfigSummary
503
+ Contains GPU allocations and deployment configuration for models.
504
+
505
+ Raises
506
+ ------
507
+ ConfigValidationError:
508
+ - If the model group is empty.
509
+ - If the selected instance shape is not supported.
510
+ - If any model is missing from the deployment configuration.
511
+ - If a model's GPU allocation does not match any valid configuration.
512
+ - If the total requested GPUs exceed the instance shape’s capacity.
513
+ """
514
+ # Ensure that at least one model is provided.
515
+ if not self.models:
516
+ logger.error("No models provided in the model group.")
517
+ raise ConfigValidationError(
518
+ "Multi-model deployment requires at least one model. Please provide one or more models."
519
+ )
520
+
521
+ selected_shape = self.instance_shape
522
+
523
+ if models_config_summary.error_message:
524
+ logger.error(models_config_summary.error_message)
525
+ raise ConfigValidationError(models_config_summary.error_message)
526
+
527
+ # Verify that the selected shape is supported by the GPU allocation.
528
+ if selected_shape not in models_config_summary.gpu_allocation:
529
+ supported_shapes = list(models_config_summary.gpu_allocation.keys())
530
+ error_message = (
531
+ f"The model group is not compatible with the selected instance shape `{selected_shape}`. "
532
+ f"Supported shapes: {supported_shapes}."
533
+ )
534
+ logger.error(error_message)
535
+ raise ConfigValidationError(error_message)
536
+
537
+ total_available_gpus: int = models_config_summary.gpu_allocation[
538
+ selected_shape
539
+ ].total_gpus_available
540
+ model_deployment_config = models_config_summary.deployment_config
541
+
542
+ # Verify that every model in the group has a corresponding deployment configuration.
543
+ required_model_ids = {model.model_id for model in self.models}
544
+ missing_model_ids = required_model_ids - set(model_deployment_config.keys())
545
+ if missing_model_ids:
546
+ error_message = (
547
+ f"Missing deployment configuration for models: {list(missing_model_ids)}. "
548
+ "Ensure all selected models are properly configured. If you are deploying custom "
549
+ "models that lack AQUA service configuration, refer to the deployment guidelines here: "
550
+ "https://github.com/oracle-samples/oci-data-science-ai-samples/blob/main/ai-quick-actions/multimodel-deployment-tips.md#custom_models"
551
+ )
552
+ logger.error(error_message)
553
+ raise ConfigValidationError(error_message)
554
+
555
+ sum_model_gpus = 0
556
+ is_single_model = len(self.models) == 1
557
+
558
+ # Validate each model's GPU allocation against its deployment configuration.
559
+ for model in self.models:
560
+ sum_model_gpus += model.gpu_count
561
+ aqua_deployment_config = model_deployment_config[model.model_id]
562
+
563
+ # Skip validation for models without deployment configuration details.
564
+ if not aqua_deployment_config.configuration:
565
+ error_message = (
566
+ f"Missing deployment configuration for model `{model.model_id}`. "
567
+ "Please verify that the model is correctly configured. If you are deploying custom models without AQUA service configuration, "
568
+ "refer to the guidelines at: "
569
+ "https://github.com/oracle-samples/oci-data-science-ai-samples/blob/main/ai-quick-actions/multimodel-deployment-tips.md#custom_models"
570
+ )
571
+
572
+ logger.error(error_message)
573
+ raise ConfigValidationError(error_message)
574
+
575
+ allowed_shapes = (
576
+ list(
577
+ set(aqua_deployment_config.configuration.keys()).union(
578
+ set(aqua_deployment_config.shape or [])
579
+ )
580
+ )
581
+ if is_single_model
582
+ else list(aqua_deployment_config.configuration.keys())
583
+ )
584
+
585
+ if selected_shape not in allowed_shapes:
586
+ error_message = (
587
+ f"Model `{model.model_id}` is not compatible with the selected instance shape `{selected_shape}`. "
588
+ f"Select a different instance shape from allowed shapes {allowed_shapes}."
589
+ )
590
+ logger.error(error_message)
591
+ raise ConfigValidationError(error_message)
592
+
593
+ # Retrieve valid GPU counts for the selected shape.
594
+ multi_model_configs = aqua_deployment_config.configuration.get(
595
+ selected_shape, ConfigurationItem()
596
+ ).multi_model_deployment
597
+
598
+ valid_gpu_configurations = [cfg.gpu_count for cfg in multi_model_configs]
599
+
600
+ if model.gpu_count not in valid_gpu_configurations:
601
+ valid_gpu_str = valid_gpu_configurations or []
602
+
603
+ if is_single_model:
604
+ # If total GPU allocation is not supported by selected model
605
+ if selected_shape not in aqua_deployment_config.shape:
606
+ error_message = (
607
+ f"Model `{model.model_id}` is configured with {model.gpu_count} GPU(s), "
608
+ f"which is invalid. The allowed GPU configurations are: {valid_gpu_str}."
609
+ )
610
+ logger.error(error_message)
611
+ raise ConfigValidationError(error_message)
612
+
613
+ if model.gpu_count != total_available_gpus:
614
+ error_message = (
615
+ f"Model '{model.model_id}' is configured to use {model.gpu_count} GPU(s), "
616
+ f"which not fully utilize the selected instance shape with {total_available_gpus} available GPU(s). "
617
+ "Consider adjusting the GPU allocation to better utilize the available resources and maximize performance."
618
+ )
619
+ logger.error(error_message)
620
+ raise ConfigValidationError(error_message)
621
+
622
+ else:
623
+ error_message = (
624
+ f"Model `{model.model_id}` is configured with {model.gpu_count} GPU(s), which is invalid. "
625
+ f"Valid GPU configurations are: {valid_gpu_str}. Please adjust the GPU allocation "
626
+ f"or choose an instance shape that supports a higher GPU count."
627
+ )
628
+ logger.error(error_message)
629
+ raise ConfigValidationError(error_message)
630
+
631
+ if sum_model_gpus < total_available_gpus:
632
+ error_message = (
633
+ f"Selected models are configured to use {sum_model_gpus} GPU(s), "
634
+ f"which not fully utilize the selected instance shape with {total_available_gpus} available GPU(s). "
635
+ "This configuration may lead to suboptimal performance for a multi-model deployment. "
636
+ "Consider adjusting the GPU allocation to better utilize the available resources and maximize performance."
637
+ )
638
+ logger.warning(error_message)
639
+ # raise ConfigValidationError(error_message)
640
+
641
+ # Check that the total GPU count for the model group does not exceed the instance capacity.
642
+ if sum_model_gpus > total_available_gpus:
643
+ error_message = (
644
+ f"The selected instance shape `{selected_shape}` provides `{total_available_gpus}` GPU(s), "
645
+ f"but the total GPU allocation required by the model group is `{sum_model_gpus}` GPU(s). "
646
+ "Please adjust the GPU allocation per model or choose an instance shape with greater GPU capacity."
647
+ )
648
+ logger.error(error_message)
649
+ raise ConfigValidationError(error_message)
650
+
651
+ class Config:
652
+ extra = "allow"
653
+ protected_namespaces = ()
@@ -1,15 +1,14 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*--
3
2
 
4
- # Copyright (c) 2024 Oracle and/or its affiliates.
3
+ # Copyright (c) 2024, 2025 Oracle and/or its affiliates.
5
4
  # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
6
5
 
7
6
  import json
8
- from dataclasses import asdict, dataclass, field
7
+ from dataclasses import dataclass, field
9
8
 
10
9
  import requests
11
10
 
12
- from ads.aqua.app import AquaApp, logger
11
+ from ads.aqua.app import AquaApp
13
12
  from ads.aqua.modeldeployment.entities import ModelParams
14
13
  from ads.common.auth import default_signer
15
14
  from ads.telemetry import telemetry
@@ -63,7 +62,7 @@ class MDInferenceResponse(AquaApp):
63
62
  model_response_content
64
63
  """
65
64
 
66
- params_dict = asdict(self.model_params)
65
+ params_dict = self.model_params.to_dict()
67
66
  params_dict = {
68
67
  key: value for key, value in params_dict.items() if value is not None
69
68
  }