oracle-ads 2.13.9rc1__py3-none-any.whl → 2.13.10rc0__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/app.py CHANGED
@@ -64,6 +64,7 @@ class AquaApp:
64
64
  set_auth("resource_principal")
65
65
  self._auth = default_signer({"service_endpoint": OCI_ODSC_SERVICE_ENDPOINT})
66
66
  self.ds_client = oc.OCIClientFactory(**self._auth).data_science
67
+ self.compute_client = oc.OCIClientFactory(**default_signer()).compute
67
68
  self.logging_client = oc.OCIClientFactory(**default_signer()).logging_management
68
69
  self.identity_client = oc.OCIClientFactory(**default_signer()).identity
69
70
  self.region = extract_region(self._auth)
@@ -157,6 +157,8 @@ class AquaMultiModelRef(Serializable):
157
157
  Optional environment variables to override during deployment.
158
158
  artifact_location : Optional[str]
159
159
  Artifact path of model in the multimodel group.
160
+ fine_tune_weights_location : Optional[str]
161
+ For fine tuned models, the artifact path of the modified model weights
160
162
  """
161
163
 
162
164
  model_id: str = Field(..., description="The model OCID to deploy.")
@@ -171,6 +173,9 @@ class AquaMultiModelRef(Serializable):
171
173
  artifact_location: Optional[str] = Field(
172
174
  None, description="Artifact path of model in the multimodel group."
173
175
  )
176
+ fine_tune_weights_location: Optional[str] = Field(
177
+ None, description="For fine tuned models, the artifact path of the modified model weights"
178
+ )
174
179
 
175
180
  class Config:
176
181
  extra = "ignore"
ads/aqua/common/enums.py CHANGED
@@ -20,6 +20,12 @@ class Resource(ExtendedEnum):
20
20
  MODEL_VERSION_SET = "model-version-sets"
21
21
 
22
22
 
23
+ class PredictEndpoints(ExtendedEnum):
24
+ CHAT_COMPLETIONS_ENDPOINT = "/v1/chat/completions"
25
+ TEXT_COMPLETIONS_ENDPOINT = "/v1/completions"
26
+ EMBEDDING_ENDPOINT = "/v1/embedding"
27
+
28
+
23
29
  class Tags(ExtendedEnum):
24
30
  TASK = "task"
25
31
  LICENSE = "license"
@@ -49,6 +55,7 @@ class InferenceContainerType(ExtendedEnum):
49
55
  class InferenceContainerTypeFamily(ExtendedEnum):
50
56
  AQUA_VLLM_CONTAINER_FAMILY = "odsc-vllm-serving"
51
57
  AQUA_VLLM_V1_CONTAINER_FAMILY = "odsc-vllm-serving-v1"
58
+ AQUA_VLLM_LLAMA4_CONTAINER_FAMILY = "odsc-vllm-serving-llama4"
52
59
  AQUA_TGI_CONTAINER_FAMILY = "odsc-tgi-serving"
53
60
  AQUA_LLAMA_CPP_CONTAINER_FAMILY = "odsc-llama-cpp-serving"
54
61
 
@@ -119,4 +126,9 @@ CONTAINER_FAMILY_COMPATIBILITY: Dict[str, List[str]] = {
119
126
  InferenceContainerTypeFamily.AQUA_VLLM_V1_CONTAINER_FAMILY,
120
127
  InferenceContainerTypeFamily.AQUA_VLLM_CONTAINER_FAMILY,
121
128
  ],
129
+ InferenceContainerTypeFamily.AQUA_VLLM_LLAMA4_CONTAINER_FAMILY: [
130
+ InferenceContainerTypeFamily.AQUA_VLLM_LLAMA4_CONTAINER_FAMILY,
131
+ InferenceContainerTypeFamily.AQUA_VLLM_V1_CONTAINER_FAMILY,
132
+ InferenceContainerTypeFamily.AQUA_VLLM_CONTAINER_FAMILY,
133
+ ],
122
134
  }
ads/aqua/common/utils.py CHANGED
@@ -832,7 +832,9 @@ def get_params_dict(params: Union[str, List[str]]) -> dict:
832
832
  """
833
833
  params_list = get_params_list(params) if isinstance(params, str) else params
834
834
  return {
835
- split_result[0]: split_result[1] if len(split_result) > 1 else UNKNOWN
835
+ split_result[0]: " ".join(split_result[1:])
836
+ if len(split_result) > 1
837
+ else UNKNOWN
836
838
  for split_result in (x.split() for x in params_list)
837
839
  }
838
840
 
@@ -881,7 +883,9 @@ def build_params_string(params: dict) -> str:
881
883
  A params string.
882
884
  """
883
885
  return (
884
- " ".join(f"{name} {value}" for name, value in params.items()).strip()
886
+ " ".join(
887
+ f"{name} {value}" if value else f"{name}" for name, value in params.items()
888
+ ).strip()
885
889
  if params
886
890
  else UNKNOWN
887
891
  )
@@ -1158,9 +1162,11 @@ def validate_cmd_var(cmd_var: List[str], overrides: List[str]) -> List[str]:
1158
1162
 
1159
1163
 
1160
1164
  def build_pydantic_error_message(ex: ValidationError):
1161
- """Added to handle error messages from pydantic model validator.
1165
+ """
1166
+ Added to handle error messages from pydantic model validator.
1162
1167
  Combine both loc and msg for errors where loc (field) is present in error details, else only build error
1163
- message using msg field."""
1168
+ message using msg field.
1169
+ """
1164
1170
 
1165
1171
  return {
1166
1172
  ".".join(map(str, e["loc"])): e["msg"]
@@ -1185,67 +1191,71 @@ def is_pydantic_model(obj: object) -> bool:
1185
1191
 
1186
1192
  @cached(cache=TTLCache(maxsize=1, ttl=timedelta(minutes=5), timer=datetime.now))
1187
1193
  def load_gpu_shapes_index(
1188
- auth: Optional[Dict] = None,
1194
+ auth: Optional[Dict[str, Any]] = None,
1189
1195
  ) -> GPUShapesIndex:
1190
1196
  """
1191
- Loads the GPU shapes index from Object Storage or a local resource folder.
1197
+ Load the GPU shapes index, preferring the OS bucket copy over the local one.
1192
1198
 
1193
- The function first attempts to load the file from an Object Storage bucket using fsspec.
1194
- If the loading fails (due to connection issues, missing file, etc.), it falls back to
1195
- loading the index from a local file.
1199
+ Attempts to read `gpu_shapes_index.json` from OCI Object Storage first;
1200
+ if that succeeds, those entries will override the local defaults.
1196
1201
 
1197
1202
  Parameters
1198
1203
  ----------
1199
- auth: (Dict, optional). Defaults to None.
1200
- The default authentication is set using `ads.set_auth` API. If you need to override the
1201
- default, use the `ads.common.auth.api_keys` or `ads.common.auth.resource_principal` to create appropriate
1202
- authentication signer and kwargs required to instantiate IdentityClient object.
1204
+ auth
1205
+ Optional auth dict (as returned by `ads.common.auth.default_signer()`)
1206
+ to pass through to `fsspec.open()`.
1203
1207
 
1204
1208
  Returns
1205
1209
  -------
1206
- GPUShapesIndex: The parsed GPU shapes index.
1210
+ GPUShapesIndex
1211
+ Merged index where any shape present remotely supersedes the local entry.
1207
1212
 
1208
1213
  Raises
1209
1214
  ------
1210
- FileNotFoundError: If the GPU shapes index cannot be found in either Object Storage or locally.
1211
- json.JSONDecodeError: If the JSON is malformed.
1215
+ json.JSONDecodeError
1216
+ If any of the JSON is malformed.
1212
1217
  """
1213
1218
  file_name = "gpu_shapes_index.json"
1214
- data: Dict[str, Any] = {}
1215
1219
 
1216
- # Check if the CONDA_BUCKET_NS environment variable is set.
1220
+ # Try remote load
1221
+ remote_data: Dict[str, Any] = {}
1217
1222
  if CONDA_BUCKET_NS:
1218
1223
  try:
1219
1224
  auth = auth or authutil.default_signer()
1220
- # Construct the object storage path. Adjust bucket name and path as needed.
1221
1225
  storage_path = (
1222
1226
  f"oci://{CONDA_BUCKET_NAME}@{CONDA_BUCKET_NS}/service_pack/{file_name}"
1223
1227
  )
1224
- logger.debug("Loading GPU shapes index from Object Storage")
1225
- with fsspec.open(storage_path, mode="r", **auth) as file_obj:
1226
- data = json.load(file_obj)
1227
- logger.debug("Successfully loaded GPU shapes index.")
1228
- except Exception as ex:
1229
1228
  logger.debug(
1230
- f"Failed to load GPU shapes index from Object Storage. Details: {ex}"
1231
- )
1232
-
1233
- # If loading from Object Storage failed, load from the local resource folder.
1234
- if not data:
1235
- try:
1236
- local_path = os.path.join(
1237
- os.path.dirname(__file__), "../resources", file_name
1229
+ "Loading GPU shapes index from Object Storage: %s", storage_path
1238
1230
  )
1239
- logger.debug(f"Loading GPU shapes index from {local_path}.")
1240
- with open(local_path) as file_obj:
1241
- data = json.load(file_obj)
1242
- logger.debug("Successfully loaded GPU shapes index.")
1243
- except Exception as e:
1231
+ with fsspec.open(storage_path, mode="r", **auth) as f:
1232
+ remote_data = json.load(f)
1244
1233
  logger.debug(
1245
- f"Failed to load GPU shapes index from {local_path}. Details: {e}"
1234
+ "Loaded %d shapes from Object Storage",
1235
+ len(remote_data.get("shapes", {})),
1246
1236
  )
1237
+ except Exception as ex:
1238
+ logger.debug("Remote load failed (%s); falling back to local", ex)
1239
+
1240
+ # Load local copy
1241
+ local_data: Dict[str, Any] = {}
1242
+ local_path = os.path.join(os.path.dirname(__file__), "../resources", file_name)
1243
+ try:
1244
+ logger.debug("Loading GPU shapes index from local file: %s", local_path)
1245
+ with open(local_path) as f:
1246
+ local_data = json.load(f)
1247
+ logger.debug(
1248
+ "Loaded %d shapes from local file", len(local_data.get("shapes", {}))
1249
+ )
1250
+ except Exception as ex:
1251
+ logger.debug("Local load GPU shapes index failed (%s)", ex)
1252
+
1253
+ # Merge: remote shapes override local
1254
+ local_shapes = local_data.get("shapes", {})
1255
+ remote_shapes = remote_data.get("shapes", {})
1256
+ merged_shapes = {**local_shapes, **remote_shapes}
1247
1257
 
1248
- return GPUShapesIndex(**data)
1258
+ return GPUShapesIndex(shapes=merged_shapes)
1249
1259
 
1250
1260
 
1251
1261
  def get_preferred_compatible_family(selected_families: set[str]) -> str:
@@ -7,6 +7,7 @@ from typing import Dict, List, Optional
7
7
  from oci.data_science.models import ContainerSummary
8
8
  from pydantic import Field
9
9
 
10
+ from ads.aqua import logger
10
11
  from ads.aqua.config.utils.serializer import Serializable
11
12
  from ads.aqua.constants import (
12
13
  SERVICE_MANAGED_CONTAINER_URI_SCHEME,
@@ -168,50 +169,47 @@ class AquaContainerConfig(Serializable):
168
169
  container_type = container.family_name
169
170
  usages = [x.upper() for x in container.usages]
170
171
  if "INFERENCE" in usages or "MULTI_MODEL" in usages:
172
+ # Extract additional configurations
173
+ additional_configurations = {}
174
+ try:
175
+ additional_configurations = (
176
+ container.workload_configuration_details_list[
177
+ 0
178
+ ].additional_configurations
179
+ )
180
+ except (AttributeError, IndexError) as ex:
181
+ logger.debug(
182
+ "Failed to extract `additional_configurations` for container '%s': %s",
183
+ getattr(container, "container_name", "<unknown>"),
184
+ ex,
185
+ )
186
+
171
187
  container_item.platforms.append(
172
- container.workload_configuration_details_list[
173
- 0
174
- ].additional_configurations.get("platforms")
188
+ additional_configurations.get("platforms")
175
189
  )
176
190
  container_item.model_formats.append(
177
- container.workload_configuration_details_list[
178
- 0
179
- ].additional_configurations.get("modelFormats")
191
+ additional_configurations.get("modelFormats")
180
192
  )
193
+
194
+ # Parse environment variables from `additional_configurations`.
195
+ # Only keys present in the configuration will be added to the result.
196
+ config_keys = {
197
+ "MODEL_DEPLOY_PREDICT_ENDPOINT": UNKNOWN,
198
+ "MODEL_DEPLOY_HEALTH_ENDPOINT": UNKNOWN,
199
+ "MODEL_DEPLOY_ENABLE_STREAMING": UNKNOWN,
200
+ "PORT": UNKNOWN,
201
+ "HEALTH_CHECK_PORT": UNKNOWN,
202
+ "VLLM_USE_V1": UNKNOWN,
203
+ }
204
+
181
205
  env_vars = [
182
- {
183
- "MODEL_DEPLOY_PREDICT_ENDPOINT": container.workload_configuration_details_list[
184
- 0
185
- ].additional_configurations.get(
186
- "MODEL_DEPLOY_PREDICT_ENDPOINT", UNKNOWN
187
- )
188
- },
189
- {
190
- "MODEL_DEPLOY_HEALTH_ENDPOINT": container.workload_configuration_details_list[
191
- 0
192
- ].additional_configurations.get(
193
- "MODEL_DEPLOY_HEALTH_ENDPOINT", UNKNOWN
194
- )
195
- },
196
- {
197
- "MODEL_DEPLOY_ENABLE_STREAMING": container.workload_configuration_details_list[
198
- 0
199
- ].additional_configurations.get(
200
- "MODEL_DEPLOY_ENABLE_STREAMING", UNKNOWN
201
- )
202
- },
203
- {
204
- "PORT": container.workload_configuration_details_list[
205
- 0
206
- ].additional_configurations.get("PORT", "")
207
- },
208
- {
209
- "HEALTH_CHECK_PORT": container.workload_configuration_details_list[
210
- 0
211
- ].additional_configurations.get("HEALTH_CHECK_PORT", UNKNOWN),
212
- },
206
+ {key: additional_configurations.get(key, default)}
207
+ for key, default in config_keys.items()
208
+ if key in additional_configurations
213
209
  ]
214
- container_spec = AquaContainerConfigSpec(
210
+
211
+ # Build container spec
212
+ container_item.spec = AquaContainerConfigSpec(
215
213
  cli_param=container.workload_configuration_details_list[0].cmd,
216
214
  server_port=str(
217
215
  container.workload_configuration_details_list[0].server_port
@@ -236,13 +234,14 @@ class AquaContainerConfig(Serializable):
236
234
  )
237
235
  ),
238
236
  )
239
- container_item.spec = container_spec
237
+
240
238
  if "INFERENCE" in usages or "MULTI_MODEL" in usages:
241
239
  inference_items[container_type] = container_item
242
240
  if "FINE_TUNE" in usages:
243
241
  finetune_items[container_type] = container_item
244
242
  if "EVALUATION" in usages:
245
243
  evaluate_items[container_type] = container_item
244
+
246
245
  return cls(
247
246
  inference=inference_items, finetune=finetune_items, evaluate=evaluate_items
248
247
  )
@@ -2,16 +2,18 @@
2
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 typing import List, Union
5
+ from typing import List, Optional, Union
6
6
  from urllib.parse import urlparse
7
7
 
8
8
  from tornado.web import HTTPError
9
9
 
10
+ from ads.aqua.app import logger
11
+ from ads.aqua.client.client import Client, ExtendedRequestError
10
12
  from ads.aqua.common.decorator import handle_exceptions
13
+ from ads.aqua.common.enums import PredictEndpoints
11
14
  from ads.aqua.extension.base_handler import AquaAPIhandler
12
15
  from ads.aqua.extension.errors import Errors
13
- from ads.aqua.modeldeployment import AquaDeploymentApp, MDInferenceResponse
14
- from ads.aqua.modeldeployment.entities import ModelParams
16
+ from ads.aqua.modeldeployment import AquaDeploymentApp
15
17
  from ads.config import COMPARTMENT_OCID
16
18
 
17
19
 
@@ -175,23 +177,107 @@ class AquaDeploymentHandler(AquaAPIhandler):
175
177
  )
176
178
 
177
179
 
178
- class AquaDeploymentInferenceHandler(AquaAPIhandler):
179
- @staticmethod
180
- def validate_predict_url(endpoint):
181
- try:
182
- url = urlparse(endpoint)
183
- if url.scheme != "https":
184
- return False
185
- if not url.netloc:
186
- return False
187
- return url.path.endswith("/predict")
188
- except Exception:
189
- return False
180
+ class AquaDeploymentStreamingInferenceHandler(AquaAPIhandler):
181
+ def _get_model_deployment_response(
182
+ self,
183
+ model_deployment_id: str,
184
+ payload: dict,
185
+ route_override_header: Optional[str],
186
+ ):
187
+ """
188
+ Returns the model deployment inference response in a streaming fashion.
189
+
190
+ This method connects to the specified model deployment endpoint and
191
+ streams the inference output back to the caller, handling both text
192
+ and chat completion endpoints depending on the route override.
193
+
194
+ Parameters
195
+ ----------
196
+ model_deployment_id : str
197
+ The OCID of the model deployment to invoke.
198
+ Example: 'ocid1.datasciencemodeldeployment.iad.oc1.xxxyz'
199
+
200
+ payload : dict
201
+ Dictionary containing the model inference parameters.
202
+ Same example for text completions:
203
+ {
204
+ "max_tokens": 1024,
205
+ "temperature": 0.5,
206
+ "prompt": "what are some good skills deep learning expert. Give us some tips on how to structure interview with some coding example?",
207
+ "top_p": 0.4,
208
+ "top_k": 100,
209
+ "model": "odsc-llm",
210
+ "frequency_penalty": 1,
211
+ "presence_penalty": 1,
212
+ "stream": true
213
+ }
214
+
215
+ route_override_header : Optional[str]
216
+ Optional override for the inference route, used for routing between
217
+ different endpoint types (e.g., chat vs. text completions).
218
+ Example: '/v1/chat/completions'
219
+
220
+ Returns
221
+ -------
222
+ Generator[str]
223
+ A generator that yields strings of the model's output as they are received.
224
+
225
+ Raises
226
+ ------
227
+ HTTPError
228
+ If the request to the model deployment fails or if streaming cannot be established.
229
+ """
230
+
231
+ model_deployment = AquaDeploymentApp().get(model_deployment_id)
232
+ endpoint = model_deployment.endpoint + "/predictWithResponseStream"
233
+ endpoint_type = model_deployment.environment_variables.get(
234
+ "MODEL_DEPLOY_PREDICT_ENDPOINT", PredictEndpoints.TEXT_COMPLETIONS_ENDPOINT
235
+ )
236
+ aqua_client = Client(endpoint=endpoint)
237
+
238
+ if PredictEndpoints.CHAT_COMPLETIONS_ENDPOINT in (
239
+ endpoint_type,
240
+ route_override_header,
241
+ ):
242
+ try:
243
+ for chunk in aqua_client.chat(
244
+ messages=payload.pop("messages"),
245
+ payload=payload,
246
+ stream=True,
247
+ ):
248
+ try:
249
+ yield chunk["choices"][0]["delta"]["content"]
250
+ except Exception as e:
251
+ logger.debug(
252
+ f"Exception occurred while parsing streaming response: {e}"
253
+ )
254
+ except ExtendedRequestError as ex:
255
+ raise HTTPError(400, str(ex))
256
+ except Exception as ex:
257
+ raise HTTPError(500, str(ex))
258
+
259
+ elif endpoint_type == PredictEndpoints.TEXT_COMPLETIONS_ENDPOINT:
260
+ try:
261
+ for chunk in aqua_client.generate(
262
+ prompt=payload.pop("prompt"),
263
+ payload=payload,
264
+ stream=True,
265
+ ):
266
+ try:
267
+ yield chunk["choices"][0]["text"]
268
+ except Exception as e:
269
+ logger.debug(
270
+ f"Exception occurred while parsing streaming response: {e}"
271
+ )
272
+ except ExtendedRequestError as ex:
273
+ raise HTTPError(400, str(ex))
274
+ except Exception as ex:
275
+ raise HTTPError(500, str(ex))
190
276
 
191
277
  @handle_exceptions
192
- def post(self, *args, **kwargs): # noqa: ARG002
278
+ def post(self, model_deployment_id):
193
279
  """
194
- Handles inference request for the Active Model Deployments
280
+ Handles streaming inference request for the Active Model Deployments
195
281
  Raises
196
282
  ------
197
283
  HTTPError
@@ -205,32 +291,29 @@ class AquaDeploymentInferenceHandler(AquaAPIhandler):
205
291
  if not input_data:
206
292
  raise HTTPError(400, Errors.NO_INPUT_DATA)
207
293
 
208
- endpoint = input_data.get("endpoint")
209
- if not endpoint:
210
- raise HTTPError(400, Errors.MISSING_REQUIRED_PARAMETER.format("endpoint"))
211
-
212
- if not self.validate_predict_url(endpoint):
213
- raise HTTPError(400, Errors.INVALID_INPUT_DATA_FORMAT.format("endpoint"))
214
-
215
294
  prompt = input_data.get("prompt")
216
- if not prompt:
217
- raise HTTPError(400, Errors.MISSING_REQUIRED_PARAMETER.format("prompt"))
295
+ messages = input_data.get("messages")
218
296
 
219
- model_params = (
220
- input_data.get("model_params") if input_data.get("model_params") else {}
221
- )
222
- try:
223
- model_params_obj = ModelParams(**model_params)
224
- except Exception as ex:
297
+ if not prompt and not messages:
225
298
  raise HTTPError(
226
- 400, Errors.INVALID_INPUT_DATA_FORMAT.format("model_params")
227
- ) from ex
228
-
229
- return self.finish(
230
- MDInferenceResponse(prompt, model_params_obj).get_model_deployment_response(
231
- endpoint
299
+ 400, Errors.MISSING_REQUIRED_PARAMETER.format("prompt/messages")
232
300
  )
301
+ if not input_data.get("model"):
302
+ raise HTTPError(400, Errors.MISSING_REQUIRED_PARAMETER.format("model"))
303
+ route_override_header = self.request.headers.get("route", None)
304
+ self.set_header("Content-Type", "text/event-stream")
305
+ response_gen = self._get_model_deployment_response(
306
+ model_deployment_id, input_data, route_override_header
233
307
  )
308
+ try:
309
+ for chunk in response_gen:
310
+ self.write(chunk)
311
+ self.flush()
312
+ self.finish()
313
+ except Exception as ex:
314
+ self.set_status(ex.status_code)
315
+ self.write({"message": "Error occurred", "reason": str(ex)})
316
+ self.finish()
234
317
 
235
318
 
236
319
  class AquaDeploymentParamsHandler(AquaAPIhandler):
@@ -294,5 +377,5 @@ __handlers__ = [
294
377
  ("deployments/?([^/]*)", AquaDeploymentHandler),
295
378
  ("deployments/?([^/]*)/activate", AquaDeploymentHandler),
296
379
  ("deployments/?([^/]*)/deactivate", AquaDeploymentHandler),
297
- ("inference", AquaDeploymentInferenceHandler),
380
+ ("inference/stream/?([^/]*)", AquaDeploymentStreamingInferenceHandler),
298
381
  ]
@@ -15,7 +15,7 @@ from ads.aqua.extension.errors import Errors
15
15
  from ads.aqua.extension.utils import validate_function_parameters
16
16
  from ads.aqua.model.entities import ImportModelDetails
17
17
  from ads.aqua.ui import AquaUIApp
18
- from ads.config import COMPARTMENT_OCID
18
+ from ads.config import COMPARTMENT_OCID, IS_BYOR_ENABLED
19
19
 
20
20
 
21
21
  @dataclass
@@ -82,6 +82,10 @@ class AquaUIHandler(AquaAPIhandler):
82
82
  return self.is_bucket_versioned()
83
83
  elif paths.startswith("aqua/containers"):
84
84
  return self.list_containers()
85
+ elif paths.startswith("aqua/capacityreservations/enabled"):
86
+ return self.is_capacity_reservations_enabled()
87
+ elif paths.startswith("aqua/capacityreservations"):
88
+ return self.list_capacity_reservations()
85
89
  else:
86
90
  raise HTTPError(400, f"The request {self.request.path} is invalid.")
87
91
 
@@ -103,6 +107,19 @@ class AquaUIHandler(AquaAPIhandler):
103
107
  AquaUIApp().list_log_groups(compartment_id=compartment_id, **kwargs)
104
108
  )
105
109
 
110
+ def is_capacity_reservations_enabled(self):
111
+ """Checks if the tenant is whitelisted for BYOR (Bring your own reservation) feature."""
112
+ return self.finish({"status": str(IS_BYOR_ENABLED).strip().lower() == "true"})
113
+
114
+ def list_capacity_reservations(self, **kwargs):
115
+ """Lists users compute reservations in a specified compartment."""
116
+ compartment_id = self.get_argument("compartment_id", default=COMPARTMENT_OCID)
117
+ return self.finish(
118
+ AquaUIApp().list_capacity_reservations(
119
+ compartment_id=compartment_id, **kwargs
120
+ )
121
+ )
122
+
106
123
  def list_logs(self, log_group_id: str, **kwargs):
107
124
  """Lists the specified log group's log objects."""
108
125
  return self.finish(AquaUIApp().list_logs(log_group_id=log_group_id, **kwargs))
@@ -279,4 +296,5 @@ __handlers__ = [
279
296
  ("bucket/versioning/?([^/]*)", AquaUIHandler),
280
297
  ("containers/?([^/]*)", AquaUIHandler),
281
298
  ("cli/?([^/]*)", AquaCLIHandler),
299
+ ("capacityreservations/?([^/]*)", AquaUIHandler),
282
300
  ]
ads/aqua/model/model.py CHANGED
@@ -83,6 +83,10 @@ from ads.aqua.model.entities import (
83
83
  ModelValidationResult,
84
84
  )
85
85
  from ads.aqua.model.enums import MultiModelSupportedTaskType
86
+ from ads.aqua.model.utils import (
87
+ extract_base_model_from_ft,
88
+ extract_fine_tune_artifacts_path,
89
+ )
86
90
  from ads.common.auth import default_signer
87
91
  from ads.common.oci_resource import SEARCH_TYPE, OCIResource
88
92
  from ads.common.utils import (
@@ -311,12 +315,27 @@ class AquaModelApp(AquaApp):
311
315
  # "Currently only service models are supported for multi model deployment."
312
316
  # )
313
317
 
318
+ # check if model is a fine-tuned model and if so, add the fine tuned weights path to the fine_tune_weights_location pydantic field
319
+ is_fine_tuned_model = (
320
+ Tags.AQUA_FINE_TUNED_MODEL_TAG in source_model.freeform_tags
321
+ )
322
+
323
+ if is_fine_tuned_model:
324
+ model.model_id, model.model_name = extract_base_model_from_ft(
325
+ source_model
326
+ )
327
+ model_artifact_path, model.fine_tune_weights_location = (
328
+ extract_fine_tune_artifacts_path(source_model)
329
+ )
330
+
331
+ else:
332
+ # Retrieve model artifact for base models
333
+ model_artifact_path = source_model.artifact
334
+
314
335
  display_name_list.append(display_name)
315
336
 
316
337
  self._extract_model_task(model, source_model)
317
338
 
318
- # Retrieve model artifact
319
- model_artifact_path = source_model.artifact
320
339
  if not model_artifact_path:
321
340
  raise AquaValueError(
322
341
  f"Model '{display_name}' (ID: {model.model_id}) has no artifacts. "
@@ -367,7 +386,8 @@ class AquaModelApp(AquaApp):
367
386
  raise AquaValueError(
368
387
  "The selected models are associated with different container families: "
369
388
  f"{list(selected_models_deployment_containers)}."
370
- "For multi-model deployment, all models in the group must share the same container family."
389
+ "For multi-model deployment, all models in the group must belong to the same container "
390
+ "family or to compatible container families."
371
391
  )
372
392
  else:
373
393
  deployment_container = selected_models_deployment_containers.pop()
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env python
2
+ # Copyright (c) 2025 Oracle and/or its affiliates.
3
+ # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
4
+ """AQUA model utils"""
5
+
6
+ from typing import Dict, Optional, Tuple
7
+
8
+ from ads.aqua.common.entities import AquaMultiModelRef
9
+ from ads.aqua.common.errors import AquaValueError
10
+ from ads.aqua.common.utils import get_model_by_reference_paths
11
+ from ads.aqua.finetuning.constants import FineTuneCustomMetadata
12
+ from ads.common.object_storage_details import ObjectStorageDetails
13
+ from ads.model.datascience_model import DataScienceModel
14
+
15
+
16
+ def extract_base_model_from_ft(aqua_model: DataScienceModel) -> Tuple[str, str]:
17
+ """Extracts the model_name and base model OCID (config_source_id) OCID for a fine-tuned model"""
18
+
19
+ config_source_id = aqua_model.custom_metadata_list.get(
20
+ FineTuneCustomMetadata.FINE_TUNE_SOURCE
21
+ ).value
22
+ model_name = aqua_model.custom_metadata_list.get(
23
+ FineTuneCustomMetadata.FINE_TUNE_SOURCE_NAME
24
+ ).value
25
+
26
+ if not config_source_id or not model_name:
27
+ raise AquaValueError(
28
+ f"Either {FineTuneCustomMetadata.FINE_TUNE_SOURCE} or {FineTuneCustomMetadata.FINE_TUNE_SOURCE_NAME} is missing "
29
+ f"from custom metadata for the model {config_source_id}"
30
+ )
31
+
32
+ return config_source_id, model_name
33
+
34
+
35
+ def extract_fine_tune_artifacts_path(aqua_model: DataScienceModel) -> Tuple[str, str]:
36
+ """Extracts the fine tuning source (fine_tune_output_path) and base model path from the DataScienceModel Object"""
37
+
38
+ base_model_path, fine_tune_output_path = get_model_by_reference_paths(
39
+ aqua_model.model_file_description
40
+ )
41
+
42
+ if not fine_tune_output_path or not ObjectStorageDetails.is_oci_path(
43
+ fine_tune_output_path
44
+ ):
45
+ raise AquaValueError(
46
+ "Fine tuned output path is not available in the model artifact."
47
+ )
48
+
49
+ os_path = ObjectStorageDetails.from_path(fine_tune_output_path)
50
+ fine_tune_output_path = os_path.filepath.rstrip("/")
51
+
52
+ return base_model_path, fine_tune_output_path
@@ -1,8 +1,6 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
- # Copyright (c) 2024 Oracle and/or its affiliates.
2
+ # Copyright (c) 2025 Oracle and/or its affiliates.
4
3
  # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
5
4
  from ads.aqua.modeldeployment.deployment import AquaDeploymentApp
6
- from ads.aqua.modeldeployment.inference import MDInferenceResponse
7
5
 
8
- __all__ = ["AquaDeploymentApp", "MDInferenceResponse"]
6
+ __all__ = ["AquaDeploymentApp"]
@@ -17,7 +17,11 @@ from ads.aqua.common.entities import (
17
17
  ComputeShapeSummary,
18
18
  ContainerPath,
19
19
  )
20
- from ads.aqua.common.enums import InferenceContainerTypeFamily, ModelFormat, Tags
20
+ from ads.aqua.common.enums import (
21
+ InferenceContainerTypeFamily,
22
+ ModelFormat,
23
+ Tags,
24
+ )
21
25
  from ads.aqua.common.errors import AquaRuntimeError, AquaValueError
22
26
  from ads.aqua.common.utils import (
23
27
  DEFINED_METADATA_TO_FILE_MAP,
@@ -25,7 +29,6 @@ from ads.aqua.common.utils import (
25
29
  build_pydantic_error_message,
26
30
  get_combined_params,
27
31
  get_container_params_type,
28
- get_model_by_reference_paths,
29
32
  get_ocid_substring,
30
33
  get_params_dict,
31
34
  get_params_list,
@@ -46,9 +49,12 @@ from ads.aqua.constants import (
46
49
  UNKNOWN_DICT,
47
50
  )
48
51
  from ads.aqua.data import AquaResourceIdentifier
49
- from ads.aqua.finetuning.finetuning import FineTuneCustomMetadata
50
52
  from ads.aqua.model import AquaModelApp
51
53
  from ads.aqua.model.constants import AquaModelMetadataKeys, ModelCustomMetadataFields
54
+ from ads.aqua.model.utils import (
55
+ extract_base_model_from_ft,
56
+ extract_fine_tune_artifacts_path,
57
+ )
52
58
  from ads.aqua.modeldeployment.entities import (
53
59
  AquaDeployment,
54
60
  AquaDeploymentConfig,
@@ -211,6 +217,7 @@ class AquaDeploymentApp(AquaApp):
211
217
  )
212
218
  else:
213
219
  model_ids = [model.model_id for model in create_deployment_details.models]
220
+
214
221
  try:
215
222
  model_config_summary = self.get_multimodel_deployment_config(
216
223
  model_ids=model_ids, compartment_id=compartment_id
@@ -343,22 +350,6 @@ class AquaDeploymentApp(AquaApp):
343
350
  config_source_id = create_deployment_details.model_id
344
351
  model_name = aqua_model.display_name
345
352
 
346
- is_fine_tuned_model = Tags.AQUA_FINE_TUNED_MODEL_TAG in aqua_model.freeform_tags
347
-
348
- if is_fine_tuned_model:
349
- try:
350
- config_source_id = aqua_model.custom_metadata_list.get(
351
- FineTuneCustomMetadata.FINE_TUNE_SOURCE
352
- ).value
353
- model_name = aqua_model.custom_metadata_list.get(
354
- FineTuneCustomMetadata.FINE_TUNE_SOURCE_NAME
355
- ).value
356
- except ValueError as err:
357
- raise AquaValueError(
358
- f"Either {FineTuneCustomMetadata.FINE_TUNE_SOURCE} or {FineTuneCustomMetadata.FINE_TUNE_SOURCE_NAME} is missing "
359
- f"from custom metadata for the model {config_source_id}"
360
- ) from err
361
-
362
353
  # set up env and cmd var
363
354
  env_var = create_deployment_details.env_var or {}
364
355
  cmd_var = create_deployment_details.cmd_var or []
@@ -378,19 +369,11 @@ class AquaDeploymentApp(AquaApp):
378
369
 
379
370
  env_var.update({"BASE_MODEL": f"{model_path_prefix}"})
380
371
 
381
- if is_fine_tuned_model:
382
- _, fine_tune_output_path = get_model_by_reference_paths(
383
- aqua_model.model_file_description
384
- )
385
-
386
- if not fine_tune_output_path:
387
- raise AquaValueError(
388
- "Fine tuned output path is not available in the model artifact."
389
- )
390
-
391
- os_path = ObjectStorageDetails.from_path(fine_tune_output_path)
392
- fine_tune_output_path = os_path.filepath.rstrip("/")
372
+ is_fine_tuned_model = Tags.AQUA_FINE_TUNED_MODEL_TAG in aqua_model.freeform_tags
393
373
 
374
+ if is_fine_tuned_model:
375
+ config_source_id, model_name = extract_base_model_from_ft(aqua_model)
376
+ _, fine_tune_output_path = extract_fine_tune_artifacts_path(aqua_model)
394
377
  env_var.update({"FT_MODEL": f"{fine_tune_output_path}"})
395
378
 
396
379
  container_type_key = self._get_container_type_key(
@@ -647,6 +630,12 @@ class AquaDeploymentApp(AquaApp):
647
630
  config_data = {"params": params, "model_path": artifact_path_prefix}
648
631
  if model.model_task:
649
632
  config_data["model_task"] = model.model_task
633
+
634
+ if model.fine_tune_weights_location:
635
+ config_data["fine_tune_weights_location"] = (
636
+ model.fine_tune_weights_location
637
+ )
638
+
650
639
  model_config.append(config_data)
651
640
  model_name_list.append(model.model_name)
652
641
 
@@ -805,6 +794,9 @@ class AquaDeploymentApp(AquaApp):
805
794
  # we arbitrarily choose last 8 characters of OCID to identify MD in telemetry
806
795
  telemetry_kwargs = {"ocid": get_ocid_substring(deployment_id, key_len=8)}
807
796
 
797
+ if Tags.BASE_MODEL_CUSTOM in tags:
798
+ telemetry_kwargs["custom_base_model"] = True
799
+
808
800
  # tracks unique deployments that were created in the user compartment
809
801
  self.telemetry.record_event_async(
810
802
  category=f"aqua/{model_type}/deployment",
@@ -948,7 +940,6 @@ class AquaDeploymentApp(AquaApp):
948
940
  model_deployment = self.ds_client.get_model_deployment(
949
941
  model_deployment_id=model_deployment_id, **kwargs
950
942
  ).data
951
-
952
943
  oci_aqua = (
953
944
  (
954
945
  Tags.AQUA_TAG in model_deployment.freeform_tags
@@ -993,7 +984,6 @@ class AquaDeploymentApp(AquaApp):
993
984
  aqua_deployment = AquaDeployment.from_oci_model_deployment(
994
985
  model_deployment, self.region
995
986
  )
996
-
997
987
  if Tags.MULTIMODEL_TYPE_TAG in model_deployment.freeform_tags:
998
988
  aqua_model_id = model_deployment.freeform_tags.get(
999
989
  Tags.AQUA_MODEL_ID_TAG, UNKNOWN
@@ -1024,7 +1014,6 @@ class AquaDeploymentApp(AquaApp):
1024
1014
  aqua_deployment.models = [
1025
1015
  AquaMultiModelRef(**metadata) for metadata in multi_model_metadata
1026
1016
  ]
1027
-
1028
1017
  return AquaDeploymentDetail(
1029
1018
  **vars(aqua_deployment),
1030
1019
  log_group=AquaResourceIdentifier(
ads/aqua/ui.py CHANGED
@@ -90,6 +90,26 @@ class AquaUIApp(AquaApp):
90
90
  res = self.logging_client.list_logs(log_group_id=log_group_id, **kwargs).data
91
91
  return sanitize_response(oci_client=self.logging_client, response=res)
92
92
 
93
+ @telemetry(entry_point="plugin=ui&action=list_capacity_reservations", name="aqua")
94
+ def list_capacity_reservations(self, **kwargs) -> list:
95
+ """
96
+ Lists users compute reservations in a specified compartment
97
+
98
+ Returns
99
+ -------
100
+ json representation of `oci.core.models.ComputeCapacityReservationSummary`.
101
+
102
+ """
103
+ compartment_id = kwargs.pop("compartment_id", COMPARTMENT_OCID)
104
+ logger.info(f"Loading Capacity reservations from compartment: {compartment_id}")
105
+
106
+ reservations = self.compute_client.list_compute_capacity_reservations(
107
+ compartment_id=compartment_id, **kwargs
108
+ )
109
+ return sanitize_response(
110
+ oci_client=self.compute_client, response=reservations.data
111
+ )
112
+
93
113
  @telemetry(entry_point="plugin=ui&action=list_compartments", name="aqua")
94
114
  def list_compartments(self) -> str:
95
115
  """Lists the compartments in a tenancy specified by TENANCY_OCID env variable. This is a pass through the OCI list_compartments
ads/common/oci_client.py CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8; -*-
3
2
 
4
- # Copyright (c) 2021, 2024 Oracle and/or its affiliates.
3
+ # Copyright (c) 2021, 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 logging
@@ -9,20 +8,20 @@ import logging
9
8
  import oci.artifacts
10
9
  from oci.ai_language import AIServiceLanguageClient
11
10
  from oci.artifacts import ArtifactsClient
11
+ from oci.core import ComputeClient, VirtualNetworkClient
12
12
  from oci.data_catalog import DataCatalogClient
13
13
  from oci.data_flow import DataFlowClient
14
14
  from oci.data_labeling_service import DataLabelingManagementClient
15
15
  from oci.data_labeling_service_dataplane import DataLabelingClient
16
16
  from oci.data_science import DataScienceClient
17
17
  from oci.identity import IdentityClient
18
+ from oci.limits import LimitsClient
19
+ from oci.logging import LoggingManagementClient
18
20
  from oci.marketplace import MarketplaceClient
19
21
  from oci.object_storage import ObjectStorageClient
20
22
  from oci.resource_search import ResourceSearchClient
21
23
  from oci.secrets import SecretsClient
22
24
  from oci.vault import VaultsClient
23
- from oci.logging import LoggingManagementClient
24
- from oci.core import VirtualNetworkClient
25
- from oci.limits import LimitsClient
26
25
 
27
26
  logger = logging.getLogger(__name__)
28
27
 
@@ -69,6 +68,7 @@ class OCIClientFactory:
69
68
  "secret": SecretsClient,
70
69
  "vault": VaultsClient,
71
70
  "identity": IdentityClient,
71
+ "compute": ComputeClient,
72
72
  "ai_language": AIServiceLanguageClient,
73
73
  "data_labeling_dp": DataLabelingClient,
74
74
  "data_labeling_cp": DataLabelingManagementClient,
@@ -114,6 +114,10 @@ class OCIClientFactory:
114
114
  def object_storage(self):
115
115
  return self.create_client("object_storage")
116
116
 
117
+ @property
118
+ def compute(self):
119
+ return self.create_client("compute")
120
+
117
121
  @property
118
122
  def identity(self):
119
123
  return self.create_client("identity")
ads/config.py CHANGED
@@ -14,6 +14,7 @@ OCI_ODSC_SERVICE_ENDPOINT = os.environ.get("OCI_ODSC_SERVICE_ENDPOINT")
14
14
  OCI_IDENTITY_SERVICE_ENDPOINT = os.environ.get("OCI_IDENTITY_SERVICE_ENDPOINT")
15
15
  NB_SESSION_COMPARTMENT_OCID = os.environ.get("NB_SESSION_COMPARTMENT_OCID")
16
16
  PROJECT_OCID = os.environ.get("PROJECT_OCID") or os.environ.get("PIPELINE_PROJECT_OCID")
17
+ IS_BYOR_ENABLED = os.environ.get("ALLOWLISTED_FOR_BYOR", False)
17
18
  NB_SESSION_OCID = os.environ.get("NB_SESSION_OCID")
18
19
  USER_OCID = os.environ.get("USER_OCID")
19
20
  OCI_RESOURCE_PRINCIPAL_VERSION = os.environ.get("OCI_RESOURCE_PRINCIPAL_VERSION")
@@ -43,22 +43,27 @@ def _fit_model(data, params, additional_regressors):
43
43
  from prophet import Prophet
44
44
 
45
45
  monthly_seasonality = params.pop("monthly_seasonality", False)
46
- data_floor = params.pop("min", None)
47
- data_cap = params.pop("max", None)
48
- if data_cap or data_floor:
46
+
47
+ has_min = "min" in params
48
+ has_max = "max" in params
49
+ if has_min or has_max:
49
50
  params["growth"] = "logistic"
51
+ data_floor = params.pop("min", None)
52
+ data_cap = params.pop("max", None)
53
+
50
54
  model = Prophet(**params)
51
55
  if monthly_seasonality:
52
56
  model.add_seasonality(name="monthly", period=30.5, fourier_order=5)
53
57
  params["monthly_seasonality"] = monthly_seasonality
54
58
  for add_reg in additional_regressors:
55
59
  model.add_regressor(add_reg)
56
- if data_floor:
60
+
61
+ if has_min:
57
62
  data["floor"] = float(data_floor)
58
- params["floor"] = data_floor
59
- if data_cap:
63
+ params["min"] = data_floor
64
+ if has_max:
60
65
  data["cap"] = float(data_cap)
61
- params["cap"] = data_cap
66
+ params["max"] = data_cap
62
67
 
63
68
  model.fit(data)
64
69
  return model
@@ -304,7 +309,7 @@ class ProphetOperatorModel(ForecastOperatorBaseModel):
304
309
  # Global Expl
305
310
  g_expl = self.drop_horizon(expl_df).mean()
306
311
  g_expl.name = s_id
307
- global_expl.append(g_expl)
312
+ global_expl.append(np.abs(g_expl))
308
313
  self.global_explanation = pd.concat(global_expl, axis=1)
309
314
  self.formatted_global_explanation = (
310
315
  self.global_explanation / self.global_explanation.sum(axis=0) * 100
ads/telemetry/client.py CHANGED
@@ -8,6 +8,7 @@ import threading
8
8
  import traceback
9
9
  import urllib.parse
10
10
  from typing import Optional
11
+ import concurrent.futures
11
12
 
12
13
  import oci
13
14
 
@@ -16,7 +17,8 @@ from ads.config import DEBUG_TELEMETRY
16
17
  from .base import TelemetryBase
17
18
 
18
19
  logger = logging.getLogger(__name__)
19
-
20
+ THREAD_POOL_SIZE = 16
21
+ thread_pool = concurrent.futures.ThreadPoolExecutor(max_workers=THREAD_POOL_SIZE)
20
22
 
21
23
  class TelemetryClient(TelemetryBase):
22
24
  """Represents a telemetry python client providing functions to record an event.
@@ -102,7 +104,7 @@ class TelemetryClient(TelemetryBase):
102
104
 
103
105
  def record_event_async(
104
106
  self, category: str = None, action: str = None, detail: str = None, **kwargs
105
- ):
107
+ )-> None:
106
108
  """Send a head request to generate an event record.
107
109
 
108
110
  Parameters
@@ -117,9 +119,4 @@ class TelemetryClient(TelemetryBase):
117
119
  Thread
118
120
  A started thread to send a head request to generate an event record.
119
121
  """
120
- thread = threading.Thread(
121
- target=self.record_event, args=(category, action, detail), kwargs=kwargs
122
- )
123
- thread.daemon = True
124
- thread.start()
125
- return thread
122
+ thread_pool.submit(self.record_event, args=(category, action, detail), kwargs=kwargs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oracle_ads
3
- Version: 2.13.9rc1
3
+ Version: 2.13.10rc0
4
4
  Summary: Oracle Accelerated Data Science SDK
5
5
  Keywords: Oracle Cloud Infrastructure,OCI,Machine Learning,ML,Artificial Intelligence,AI,Data Science,Cloud,Oracle,GenAI,Generative AI,Forecast,Anomaly,Document Understanding
6
6
  Author: Oracle Data Science
@@ -15,7 +15,7 @@ Classifier: Programming Language :: Python :: 3.10
15
15
  Classifier: Programming Language :: Python :: 3.11
16
16
  Classifier: Programming Language :: Python :: 3.12
17
17
  License-File: LICENSE.txt
18
- Requires-Dist: PyYAML>=6
18
+ Requires-Dist: PyYAML>=6.0.1
19
19
  Requires-Dist: asteval>=0.9.25
20
20
  Requires-Dist: cerberus>=1.3.4
21
21
  Requires-Dist: cloudpickle>=1.6.0
@@ -99,13 +99,14 @@ Requires-Dist: ipython>=7.23.1, <8.0 ; extra == "notebook"
99
99
  Requires-Dist: ipywidgets~=7.6.3 ; extra == "notebook"
100
100
  Requires-Dist: lightgbm ; extra == "onnx"
101
101
  Requires-Dist: onnx>=1.12.0,<=1.15.0 ; extra == "onnx" and ( python_version < '3.12')
102
- Requires-Dist: onnx>=1.12.0 ; extra == "onnx" and ( python_version >= '3.12')
103
- Requires-Dist: onnxmltools>=1.10.0 ; extra == "onnx"
102
+ Requires-Dist: onnx~=1.17.0 ; extra == "onnx" and ( python_version >= '3.12')
103
+ Requires-Dist: onnxmltools~=1.13.0 ; extra == "onnx"
104
104
  Requires-Dist: onnxruntime~=1.17.0,!=1.16.0 ; extra == "onnx" and ( python_version < '3.12')
105
- Requires-Dist: onnxruntime ; extra == "onnx" and ( python_version >= '3.12')
105
+ Requires-Dist: onnxruntime~=1.22.0 ; extra == "onnx" and ( python_version >= '3.12')
106
106
  Requires-Dist: oracle_ads[viz] ; extra == "onnx"
107
107
  Requires-Dist: protobuf ; extra == "onnx"
108
- Requires-Dist: skl2onnx>=1.10.4 ; extra == "onnx"
108
+ Requires-Dist: skl2onnx>=1.10.4 ; extra == "onnx" and ( python_version < '3.12')
109
+ Requires-Dist: skl2onnx~=1.18.0 ; extra == "onnx" and ( python_version >= '3.12')
109
110
  Requires-Dist: tf2onnx ; extra == "onnx"
110
111
  Requires-Dist: xgboost<=1.7 ; extra == "onnx"
111
112
  Requires-Dist: conda-pack ; extra == "opctl"
@@ -1,23 +1,23 @@
1
1
  ads/__init__.py,sha256=OxHySbHbMqPgZ8sUj33Bxy-smSiNgRjtcSUV77oBL08,3787
2
2
  ads/cli.py,sha256=WkOpZv8jWgFYN9BNkt2LJBs9KzJHgFqq3pIymsqc8Q4,4292
3
- ads/config.py,sha256=yrCvWEEYcMwWkk9_6IJJZnxbvrOVzsQNMBrCJVafYU8,8106
3
+ ads/config.py,sha256=ZFZpp0SgKgB1-7yQ6MEdVdyJ2nwzixbH91sJ4_XnG8Y,8170
4
4
  ads/aqua/__init__.py,sha256=7DjwtmZaX-_atIkmZu6XQKHqJUEeemJGR2TlxzMHSXs,973
5
- ads/aqua/app.py,sha256=KesfIyVm3T8mj3ugsdVSp05b9RwQAEVw7QN1UB4o4qU,18397
5
+ ads/aqua/app.py,sha256=PmG8-XnOfMRJ0GQgJDl6TSGF95EBTrMXGRO8p1FG43Y,18475
6
6
  ads/aqua/cli.py,sha256=8S0JnhWY9IBZjMyB-5r4I-2nl-WK6yw1iirPsAXICF0,3358
7
7
  ads/aqua/constants.py,sha256=dUl02j5XTAG6sL7XJ9HS5fT0Z869WceRLFIbBwCzmtw,5081
8
8
  ads/aqua/data.py,sha256=HfxLfKiNiPJecMQy0JAztUsT3IdZilHHHOrCJnjZMc4,408
9
- ads/aqua/ui.py,sha256=AyX1vFW9f6hoyKN55M6s4iKBLHsOHC41hwRjDfD4NlI,20191
9
+ ads/aqua/ui.py,sha256=PYyr46ewx9Qygcsv6BryUF6rLHU0t5YjUgKSb1uZK2Y,20971
10
10
  ads/aqua/client/__init__.py,sha256=-46EcKQjnWEXxTt85bQzXjA5xsfoBXIGm_syKFlVL1c,178
11
11
  ads/aqua/client/client.py,sha256=zlscNhFZVgGnkJ-aj5iZ5v5FedOzpQc4RJDxGPl9VvQ,31388
12
12
  ads/aqua/client/openai_client.py,sha256=Gi8nSrtPAUOjxRNu-6UUAqtxWyQIQ5CAvatnm7XfnaM,12501
13
13
  ads/aqua/common/__init__.py,sha256=rZrmh1nho40OCeabXCNWtze-mXi-PGKetcZdxZSn3_0,204
14
14
  ads/aqua/common/decorator.py,sha256=JEN6Cy4DYgQbmIR3ShCjTuBMCnilDxq7jkYMJse1rcM,4112
15
- ads/aqua/common/entities.py,sha256=2_Sv07SvekPmU77DfQIycdv0UJOaT6TZM5WyNJyq7GM,9188
16
- ads/aqua/common/enums.py,sha256=rTZDOQzTfcgwEl7gjVY3_JotHXkz7wB_edEIB0i6AeQ,3739
15
+ ads/aqua/common/entities.py,sha256=ZHlnW2gf6gQ-TmRCjRcobR5qWoM3Vj7RaGYpAIzFKro,9474
16
+ ads/aqua/common/enums.py,sha256=fBJczGd4Trv9Lf0O4_TAEDWYkp5ou9oGeKhxdSW2-84,4274
17
17
  ads/aqua/common/errors.py,sha256=QONm-2jKBg8AjgOKXm6x-arAV1KIW9pdhfNN1Ys21Wo,3044
18
- ads/aqua/common/utils.py,sha256=z93NqufjGzmEpsd7VmSvIpFUawcaoLjBFPSiBCjq2Wk,42001
18
+ ads/aqua/common/utils.py,sha256=OBFfvtAyI-CkM0ezF8unfYH596KzNkul-o8XMFgwep0,41833
19
19
  ads/aqua/config/__init__.py,sha256=2a_1LI4jWtJpbic5_v4EoOUTXCAH7cmsy9BW5prDHjU,179
20
- ads/aqua/config/container_config.py,sha256=WkxaBZ-6TlKXbhrLD5q-BAmXXZp_crLoZGp8TNtbGHg,9844
20
+ ads/aqua/config/container_config.py,sha256=W6V5VZOLyEAbiY3rEbHyv4KY8yRhj8Qp6k1nWX_FwWg,9590
21
21
  ads/aqua/config/evaluation/__init__.py,sha256=2a_1LI4jWtJpbic5_v4EoOUTXCAH7cmsy9BW5prDHjU,179
22
22
  ads/aqua/config/evaluation/evaluation_service_config.py,sha256=NuaQoLVYPHJiWjGfq1-F6-DK0DyOAGjVS87K1SXFVvw,4497
23
23
  ads/aqua/config/utils/__init__.py,sha256=2a_1LI4jWtJpbic5_v4EoOUTXCAH7cmsy9BW5prDHjU,179
@@ -36,7 +36,7 @@ ads/aqua/extension/aqua_ws_msg_handler.py,sha256=VDa9vQOsYKX6flsUkDEx6nl-5MFCH5R
36
36
  ads/aqua/extension/base_handler.py,sha256=W-eBXn9XYypCZuY84e9cSKRuY0CDyuou_znV6Yn9YzU,3047
37
37
  ads/aqua/extension/common_handler.py,sha256=okjFJlJv0FLXsMM1td6upqqA6tJEJIj1IIfTiughC5Q,3809
38
38
  ads/aqua/extension/common_ws_msg_handler.py,sha256=PAy98ZsM8VAXcy11ahsuam3QUDdmE-Hz4F5pISVkNHY,1242
39
- ads/aqua/extension/deployment_handler.py,sha256=Q5EHfAWcEqiE9rH0lQeFXPn0WQdwiRlrl4lZI1OXPqo,10394
39
+ ads/aqua/extension/deployment_handler.py,sha256=9ncV1H1pWnyoZuF4iva7n4xpSpGZauZJs2455Vxg2YE,13929
40
40
  ads/aqua/extension/deployment_ws_msg_handler.py,sha256=JX3ZHRtscrflSxT7ZTEEI_p_owtk3m5FZq3QXE96AGY,2013
41
41
  ads/aqua/extension/errors.py,sha256=4LbzZdCoDEtOcrVI-1dgiza4oAYGof6w5LbN6HqroYk,1396
42
42
  ads/aqua/extension/evaluation_handler.py,sha256=fJH73fa0xmkEiP8SxKL4A4dJgj-NoL3z_G-w_WW2zJs,4353
@@ -44,7 +44,7 @@ ads/aqua/extension/evaluation_ws_msg_handler.py,sha256=dv0iwOSTxYj1kQ1rPEoDmGgFB
44
44
  ads/aqua/extension/finetune_handler.py,sha256=97obbhITswTrBvl88g7gk4GvF2SUHBGUAq4rOylFbtQ,3079
45
45
  ads/aqua/extension/model_handler.py,sha256=LlfBqGI4YVXio0gUnqi7Tpe3yfkc7-ToZCcQ3cds6rY,14094
46
46
  ads/aqua/extension/models_ws_msg_handler.py,sha256=VyPbtBZrbRMIYJqOy5DR7j4M4qJK1RBqkxX6RbIvPGE,1851
47
- ads/aqua/extension/ui_handler.py,sha256=Q0LkrV6VtVUI4GpNgqJQt8SGzxHzp4X5hdHF6KgPp9M,11217
47
+ ads/aqua/extension/ui_handler.py,sha256=OAyRgEQ26rpNA5CwBGG6YXM9qCuPrZAUXW490a-fkxs,12136
48
48
  ads/aqua/extension/ui_websocket_handler.py,sha256=oLFjaDrqkSERbhExdvxjLJX0oRcP-DVJ_aWn0qy0uvo,5084
49
49
  ads/aqua/extension/utils.py,sha256=-uppIKADKl8TFzZB2QWEIei_wtVwWN63qffhuh4Q_KA,5159
50
50
  ads/aqua/extension/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -57,12 +57,12 @@ ads/aqua/model/__init__.py,sha256=j2iylvERdANxgrEDp7b_mLcKMz1CF5Go0qgYCiMwdos,27
57
57
  ads/aqua/model/constants.py,sha256=oOAb4ulsdWBtokCE5SPX7wg8X8SaisLPayua58zhWfY,1856
58
58
  ads/aqua/model/entities.py,sha256=JiKB8SnaUxerRMlwrgpyfQLRuTOB8I14J-Rg5RFPwqw,12660
59
59
  ads/aqua/model/enums.py,sha256=bN8GKmgRl40PQrTmd1r-Pqr9VXTIV8gic5-3SAGNnwg,1152
60
- ads/aqua/model/model.py,sha256=AjsM7o5Dcas4G5imdCQ1VX2Y5bCooMZvDQBKQX8KTUA,88217
61
- ads/aqua/modeldeployment/__init__.py,sha256=RJCfU1yazv3hVWi5rS08QVLTpTwZLnlC8wU8diwFjnM,391
60
+ ads/aqua/model/model.py,sha256=nq9PehumfFyh_UZDhltVl7Vi_L4TMM9KCx6yqZL3oDw,89027
61
+ ads/aqua/model/utils.py,sha256=8lYaD51JpAPb7U_xQzRSzFflRefU5Yz6vA80cuZOL0w,2087
62
+ ads/aqua/modeldeployment/__init__.py,sha256=k5fGG2b6mae-uiQyuTAHqPjlzcUyJ4NFaF-uoMnK5Uc,277
62
63
  ads/aqua/modeldeployment/constants.py,sha256=lJF77zwxmlECljDYjwFAMprAUR_zctZHmawiP-4alLg,296
63
- ads/aqua/modeldeployment/deployment.py,sha256=hWpjomp9UyRRsUDAa9VN5ezpqNOpLB7lOZJX8mYwDjI,56265
64
+ ads/aqua/modeldeployment/deployment.py,sha256=V0ZJY63NXE2uqv_Lm5zdT6wSiqXR7QydZh-IL0ObGEo,55603
64
65
  ads/aqua/modeldeployment/entities.py,sha256=qwNH-8eHv-C2QPMITGQkb6haaJRvZ5c0i1H0Aoxeiu4,27100
65
- ads/aqua/modeldeployment/inference.py,sha256=rjTF-AM_rHLzL5HCxdLRTrsaSMdB-SzFYUp9dIy5ejw,2109
66
66
  ads/aqua/modeldeployment/utils.py,sha256=Aky4WZ5E564JVZ96X9RYJz_KlB_cAHGzV6mihtd3HV8,22009
67
67
  ads/aqua/resources/gpu_shapes_index.json,sha256=-6rSkyQ04T1z_Yfr3cxGPI7NAtgTwG7beIEjLYuMMIc,1948
68
68
  ads/aqua/server/__init__.py,sha256=fswoO0kX0hrp2b1owF4f-bv_OodntvvUY3FvhL6FCMk,179
@@ -98,7 +98,7 @@ ads/common/model_artifact_schema.json,sha256=aNwC9bW5HHMXJK-XAWV56RosqOqiCkzKHBi
98
98
  ads/common/model_export_util.py,sha256=rQjL_bb0ecGV2fj0jQXS2-aRbXl4ONDwuNVqdr3DiAQ,26574
99
99
  ads/common/model_metadata.py,sha256=Md1soURHww8GHMG3q_HV0RHVb6dPtg9FZ_7Wmd9L-Yc,641
100
100
  ads/common/object_storage_details.py,sha256=bvqIyB-zLpr5NMnZW8YtSupVH3RpWLBgbR3wPYlQhPU,9531
101
- ads/common/oci_client.py,sha256=SmME1qdCFtOdMtC7-703C732e4lEK71kNfTSqBRFkSM,6053
101
+ ads/common/oci_client.py,sha256=HcGUWdc0GQLksJmn6GIrcBJvuhcanwhMlJhdt85_JIA,6164
102
102
  ads/common/oci_datascience.py,sha256=biBgm-udtSYRL46XYfBFJjpkPFcw2ew-xvp3rbbpwmI,1698
103
103
  ads/common/oci_logging.py,sha256=U0HRAUkpnycGpo2kWMrT3wjQVFZaWqLL6pZ2B6_epsM,41925
104
104
  ads/common/oci_mixin.py,sha256=mhja5UomrhXH43uB0jT-u2KaT37op9tM-snxvtGfc40,34548
@@ -728,7 +728,7 @@ ads/opctl/operator/lowcode/forecast/model/factory.py,sha256=5a9A3ql-bU412BiTB20o
728
728
  ads/opctl/operator/lowcode/forecast/model/forecast_datasets.py,sha256=2NsWE2WtD_O7uAXw42_3tmG3vb5lk3mdnzCZTph4hao,18903
729
729
  ads/opctl/operator/lowcode/forecast/model/ml_forecast.py,sha256=t5x6EBxOd7XwfT3FGdt-n9gscxaHMm3R2A4Evvxbj38,9646
730
730
  ads/opctl/operator/lowcode/forecast/model/neuralprophet.py,sha256=-AS3PPd8Fqn1uaMybJwTnFbmIfUxNPDlgYjGtjy9-E8,19944
731
- ads/opctl/operator/lowcode/forecast/model/prophet.py,sha256=jb8bshJf5lDdGJkNH-2SrwN4tdHImP7iD9I8KS4EmZU,17321
731
+ ads/opctl/operator/lowcode/forecast/model/prophet.py,sha256=U0M3M7yzy7ea-mEG1c-dELL6t1Pf_LnnnbrZB08CG_Y,17402
732
732
  ads/opctl/operator/lowcode/forecast/whatifserve/__init__.py,sha256=JNDDjLrNorKXMHUuXMifqXea3eheST-lnrcwCl2bWrk,242
733
733
  ads/opctl/operator/lowcode/forecast/whatifserve/deployment_manager.py,sha256=w42anuqAScEQ0vBG3vW4LVLNq1bPdpAWGQEmNhMwZ08,12052
734
734
  ads/opctl/operator/lowcode/forecast/whatifserve/score.py,sha256=JjEDtrqUfL4x9t-vvafXMLNwY9-vgc6QPX_Ee-wmI58,8709
@@ -807,7 +807,7 @@ ads/secrets/oracledb.py,sha256=VAbsY206gc_Ru8FBOCKNGnIlX4VprIIQ9PmBoujRy_k,6146
807
807
  ads/secrets/secrets.py,sha256=k_f3hwh5RI7Hv7zEKDDuxh7kGB-F29bK15jxgu4sxVw,15197
808
808
  ads/telemetry/__init__.py,sha256=_pKx4hDK7DUXHjvAq4Zbeg6wl9_UkgGE7O77KWezu8g,230
809
809
  ads/telemetry/base.py,sha256=6kKVSfTxx2Dr0XL7R8OfjTy3hJoJpKMvP6D7RdVddl4,2199
810
- ads/telemetry/client.py,sha256=33xG082IGoWCbhD5xmYkDgI2znqL9LgqLM2kfvbg6fw,4975
810
+ ads/telemetry/client.py,sha256=71hUqn-fF24zlb84ew5A0gugdkhBmzn30JEuNHDnMyM,5000
811
811
  ads/telemetry/telemetry.py,sha256=xCu64tUEzYzFaXEMxnMdtQJPme5-9sW8l3uxibN4E04,7930
812
812
  ads/templates/dataflow_pyspark.jinja2,sha256=JiTuaGt5LC7z1mrDoDIbZ5UskBETLpm0lMpn5VZYNGs,254
813
813
  ads/templates/dataflow_sparksql.jinja2,sha256=8MvGzj7PWgUNo-9dg6zil8WTpBL3eNcR815fz64v1yM,466
@@ -851,8 +851,8 @@ ads/type_discovery/unknown_detector.py,sha256=yZuYQReO7PUyoWZE7onhhtYaOg6088wf1y
851
851
  ads/type_discovery/zipcode_detector.py,sha256=3AlETg_ZF4FT0u914WXvTT3F3Z6Vf51WiIt34yQMRbw,1421
852
852
  ads/vault/__init__.py,sha256=x9tMdDAOdF5iDHk9u2di_K-ze5Nq068x25EWOBoWwqY,245
853
853
  ads/vault/vault.py,sha256=hFBkpYE-Hfmzu1L0sQwUfYcGxpWmgG18JPndRl0NOXI,8624
854
- oracle_ads-2.13.9rc1.dist-info/entry_points.txt,sha256=9VFnjpQCsMORA4rVkvN8eH6D3uHjtegb9T911t8cqV0,35
855
- oracle_ads-2.13.9rc1.dist-info/licenses/LICENSE.txt,sha256=zoGmbfD1IdRKx834U0IzfFFFo5KoFK71TND3K9xqYqo,1845
856
- oracle_ads-2.13.9rc1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
857
- oracle_ads-2.13.9rc1.dist-info/METADATA,sha256=322tybBGPwpm9eAuQEcS9dQ_7qwMye0YfNFu75RxQhs,16656
858
- oracle_ads-2.13.9rc1.dist-info/RECORD,,
854
+ oracle_ads-2.13.10rc0.dist-info/entry_points.txt,sha256=9VFnjpQCsMORA4rVkvN8eH6D3uHjtegb9T911t8cqV0,35
855
+ oracle_ads-2.13.10rc0.dist-info/licenses/LICENSE.txt,sha256=zoGmbfD1IdRKx834U0IzfFFFo5KoFK71TND3K9xqYqo,1845
856
+ oracle_ads-2.13.10rc0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
857
+ oracle_ads-2.13.10rc0.dist-info/METADATA,sha256=MZ4kGFRBnDsst32Mrvla6SR2ufMpOvR9p48bBBuQkKs,16782
858
+ oracle_ads-2.13.10rc0.dist-info/RECORD,,
@@ -1,74 +0,0 @@
1
- #!/usr/bin/env python
2
-
3
- # Copyright (c) 2024, 2025 Oracle and/or its affiliates.
4
- # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
5
-
6
- import json
7
- from dataclasses import dataclass, field
8
-
9
- import requests
10
-
11
- from ads.aqua.app import AquaApp
12
- from ads.aqua.modeldeployment.entities import ModelParams
13
- from ads.common.auth import default_signer
14
- from ads.telemetry import telemetry
15
-
16
-
17
- @dataclass
18
- class MDInferenceResponse(AquaApp):
19
- """Contains APIs for Aqua Model deployments Inference.
20
-
21
- Attributes
22
- ----------
23
-
24
- model_params: Dict
25
- prompt: string
26
-
27
- Methods
28
- -------
29
- get_model_deployment_response(self, **kwargs) -> "String"
30
- Creates an instance of model deployment via Aqua
31
- """
32
-
33
- prompt: str = None
34
- model_params: field(default_factory=ModelParams) = None
35
-
36
- @telemetry(entry_point="plugin=inference&action=get_response", name="aqua")
37
- def get_model_deployment_response(self, endpoint):
38
- """
39
- Returns MD inference response
40
-
41
- Parameters
42
- ----------
43
- endpoint: str
44
- MD predict url
45
- prompt: str
46
- User prompt.
47
-
48
- model_params: (Dict, optional)
49
- Model parameters to be associated with the message.
50
- Currently supported VLLM+OpenAI parameters.
51
-
52
- --model-params '{
53
- "max_tokens":500,
54
- "temperature": 0.5,
55
- "top_k": 10,
56
- "top_p": 0.5,
57
- "model": "/opt/ds/model/deployed_model",
58
- ...}'
59
-
60
- Returns
61
- -------
62
- model_response_content
63
- """
64
-
65
- params_dict = self.model_params.to_dict()
66
- params_dict = {
67
- key: value for key, value in params_dict.items() if value is not None
68
- }
69
- body = {"prompt": self.prompt, **params_dict}
70
- request_kwargs = {"json": body, "headers": {"Content-Type": "application/json"}}
71
- response = requests.post(
72
- endpoint, auth=default_signer()["signer"], **request_kwargs
73
- )
74
- return json.loads(response.content)