oracle-ads 2.12.8__py3-none-any.whl → 2.12.9__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
@@ -2,6 +2,7 @@
2
2
  # Copyright (c) 2024 Oracle and/or its affiliates.
3
3
  # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
4
4
 
5
+ import json
5
6
  import os
6
7
  from dataclasses import fields
7
8
  from typing import Dict, Union
@@ -135,6 +136,8 @@ class AquaApp:
135
136
  description: str = None,
136
137
  compartment_id: str = None,
137
138
  project_id: str = None,
139
+ freeform_tags: dict = None,
140
+ defined_tags: dict = None,
138
141
  **kwargs,
139
142
  ) -> tuple:
140
143
  """Creates ModelVersionSet from given ID or Name.
@@ -153,7 +156,10 @@ class AquaApp:
153
156
  Project OCID.
154
157
  tag: (str, optional)
155
158
  calling tag, can be Tags.AQUA_FINE_TUNING or Tags.AQUA_EVALUATION
156
-
159
+ freeform_tags: (dict, optional)
160
+ Freeform tags for the model version set
161
+ defined_tags: (dict, optional)
162
+ Defined tags for the model version set
157
163
  Returns
158
164
  -------
159
165
  tuple: (model_version_set_id, model_version_set_name)
@@ -182,6 +188,7 @@ class AquaApp:
182
188
  mvs_freeform_tags = {
183
189
  tag: tag,
184
190
  }
191
+ mvs_freeform_tags = {**mvs_freeform_tags, **(freeform_tags or {})}
185
192
  model_version_set = (
186
193
  ModelVersionSet()
187
194
  .with_compartment_id(compartment_id)
@@ -189,6 +196,7 @@ class AquaApp:
189
196
  .with_name(model_version_set_name)
190
197
  .with_description(description)
191
198
  .with_freeform_tags(**mvs_freeform_tags)
199
+ .with_defined_tags(**(defined_tags or {}))
192
200
  # TODO: decide what parameters will be needed
193
201
  # when refactor eval to use this method, we need to pass tag here.
194
202
  .create(**kwargs)
@@ -340,7 +348,9 @@ class CLIBuilderMixin:
340
348
  """
341
349
  cmd = f"ads aqua {self._command}"
342
350
  params = [
343
- f"--{field.name} {getattr(self,field.name)}"
351
+ f"--{field.name} {json.dumps(getattr(self, field.name))}"
352
+ if isinstance(getattr(self, field.name), dict)
353
+ else f"--{field.name} {getattr(self, field.name)}"
344
354
  for field in fields(self.__class__)
345
355
  if getattr(self, field.name) is not None
346
356
  ]
@@ -64,6 +64,10 @@ class CreateAquaEvaluationDetails(Serializable):
64
64
  The metrics for the evaluation.
65
65
  force_overwrite: (bool, optional). Defaults to `False`.
66
66
  Whether to force overwrite the existing file in object storage.
67
+ freeform_tags: (dict, optional)
68
+ Freeform tags for the evaluation model
69
+ defined_tags: (dict, optional)
70
+ Defined tags for the evaluation model
67
71
  """
68
72
 
69
73
  evaluation_source_id: str
@@ -85,6 +89,8 @@ class CreateAquaEvaluationDetails(Serializable):
85
89
  log_id: Optional[str] = None
86
90
  metrics: Optional[List[Dict[str, Any]]] = None
87
91
  force_overwrite: Optional[bool] = False
92
+ freeform_tags: Optional[dict] = None
93
+ defined_tags: Optional[dict] = None
88
94
 
89
95
  class Config:
90
96
  extra = "ignore"
@@ -297,6 +297,10 @@ class AquaEvaluationApp(AquaApp):
297
297
  evaluation_mvs_freeform_tags = {
298
298
  Tags.AQUA_EVALUATION: Tags.AQUA_EVALUATION,
299
299
  }
300
+ evaluation_mvs_freeform_tags = {
301
+ **evaluation_mvs_freeform_tags,
302
+ **(create_aqua_evaluation_details.freeform_tags or {}),
303
+ }
300
304
 
301
305
  model_version_set = (
302
306
  ModelVersionSet()
@@ -307,6 +311,9 @@ class AquaEvaluationApp(AquaApp):
307
311
  create_aqua_evaluation_details.experiment_description
308
312
  )
309
313
  .with_freeform_tags(**evaluation_mvs_freeform_tags)
314
+ .with_defined_tags(
315
+ **(create_aqua_evaluation_details.defined_tags or {})
316
+ )
310
317
  # TODO: decide what parameters will be needed
311
318
  .create(**kwargs)
312
319
  )
@@ -369,6 +376,10 @@ class AquaEvaluationApp(AquaApp):
369
376
  Tags.AQUA_EVALUATION: Tags.AQUA_EVALUATION,
370
377
  Tags.AQUA_EVALUATION_MODEL_ID: evaluation_model.id,
371
378
  }
379
+ evaluation_job_freeform_tags = {
380
+ **evaluation_job_freeform_tags,
381
+ **(create_aqua_evaluation_details.freeform_tags or {}),
382
+ }
372
383
 
373
384
  evaluation_job = Job(name=evaluation_model.display_name).with_infrastructure(
374
385
  DataScienceJob()
@@ -379,6 +390,7 @@ class AquaEvaluationApp(AquaApp):
379
390
  .with_shape_name(create_aqua_evaluation_details.shape_name)
380
391
  .with_block_storage_size(create_aqua_evaluation_details.block_storage_size)
381
392
  .with_freeform_tag(**evaluation_job_freeform_tags)
393
+ .with_defined_tag(**(create_aqua_evaluation_details.defined_tags or {}))
382
394
  )
383
395
  if (
384
396
  create_aqua_evaluation_details.memory_in_gbs
@@ -425,6 +437,7 @@ class AquaEvaluationApp(AquaApp):
425
437
  evaluation_job_run = evaluation_job.run(
426
438
  name=evaluation_model.display_name,
427
439
  freeform_tags=evaluation_job_freeform_tags,
440
+ defined_tags=(create_aqua_evaluation_details.defined_tags or {}),
428
441
  wait=False,
429
442
  )
430
443
  logger.debug(
@@ -444,13 +457,20 @@ class AquaEvaluationApp(AquaApp):
444
457
  for metadata in evaluation_model_custom_metadata.to_dict()["data"]
445
458
  ]
446
459
 
460
+ evaluation_model_freeform_tags = {
461
+ Tags.AQUA_EVALUATION: Tags.AQUA_EVALUATION,
462
+ **(create_aqua_evaluation_details.freeform_tags or {}),
463
+ }
464
+ evaluation_model_defined_tags = (
465
+ create_aqua_evaluation_details.defined_tags or {}
466
+ )
467
+
447
468
  self.ds_client.update_model(
448
469
  model_id=evaluation_model.id,
449
470
  update_model_details=UpdateModelDetails(
450
471
  custom_metadata_list=updated_custom_metadata_list,
451
- freeform_tags={
452
- Tags.AQUA_EVALUATION: Tags.AQUA_EVALUATION,
453
- },
472
+ freeform_tags=evaluation_model_freeform_tags,
473
+ defined_tags=evaluation_model_defined_tags,
454
474
  ),
455
475
  )
456
476
 
@@ -524,6 +544,8 @@ class AquaEvaluationApp(AquaApp):
524
544
  "evaluation_job_id": evaluation_job.id,
525
545
  "evaluation_source": create_aqua_evaluation_details.evaluation_source_id,
526
546
  "evaluation_experiment_id": experiment_model_version_set_id,
547
+ **evaluation_model_freeform_tags,
548
+ **evaluation_model_defined_tags,
527
549
  },
528
550
  parameters=AquaEvalParams(),
529
551
  )
@@ -59,7 +59,7 @@ class AquaDeploymentHandler(AquaAPIhandler):
59
59
  return self.finish(AquaDeploymentApp().delete(model_deployment_id))
60
60
 
61
61
  @handle_exceptions
62
- def put(self, *args, **kwargs):
62
+ def put(self, *args, **kwargs): # noqa: ARG002
63
63
  """
64
64
  Handles put request for the activating and deactivating OCI datascience model deployments
65
65
  Raises
@@ -82,7 +82,7 @@ class AquaDeploymentHandler(AquaAPIhandler):
82
82
  raise HTTPError(400, f"The request {self.request.path} is invalid.")
83
83
 
84
84
  @handle_exceptions
85
- def post(self, *args, **kwargs):
85
+ def post(self, *args, **kwargs): # noqa: ARG002
86
86
  """
87
87
  Handles post request for the deployment APIs
88
88
  Raises
@@ -132,6 +132,8 @@ class AquaDeploymentHandler(AquaAPIhandler):
132
132
  private_endpoint_id = input_data.get("private_endpoint_id")
133
133
  container_image_uri = input_data.get("container_image_uri")
134
134
  cmd_var = input_data.get("cmd_var")
135
+ freeform_tags = input_data.get("freeform_tags")
136
+ defined_tags = input_data.get("defined_tags")
135
137
 
136
138
  self.finish(
137
139
  AquaDeploymentApp().create(
@@ -157,6 +159,8 @@ class AquaDeploymentHandler(AquaAPIhandler):
157
159
  private_endpoint_id=private_endpoint_id,
158
160
  container_image_uri=container_image_uri,
159
161
  cmd_var=cmd_var,
162
+ freeform_tags=freeform_tags,
163
+ defined_tags=defined_tags,
160
164
  )
161
165
  )
162
166
 
@@ -196,7 +200,7 @@ class AquaDeploymentInferenceHandler(AquaAPIhandler):
196
200
  return False
197
201
 
198
202
  @handle_exceptions
199
- def post(self, *args, **kwargs):
203
+ def post(self, *args, **kwargs): # noqa: ARG002
200
204
  """
201
205
  Handles inference request for the Active Model Deployments
202
206
  Raises
@@ -262,7 +266,7 @@ class AquaDeploymentParamsHandler(AquaAPIhandler):
262
266
  )
263
267
 
264
268
  @handle_exceptions
265
- def post(self, *args, **kwargs):
269
+ def post(self, *args, **kwargs): # noqa: ARG002
266
270
  """Handles post request for the deployment param handler API.
267
271
 
268
272
  Raises
@@ -96,7 +96,7 @@ class AquaModelHandler(AquaAPIhandler):
96
96
  )
97
97
 
98
98
  @handle_exceptions
99
- def post(self, *args, **kwargs):
99
+ def post(self, *args, **kwargs): # noqa: ARG002
100
100
  """
101
101
  Handles post request for the registering any Aqua model.
102
102
  Raises
@@ -131,6 +131,8 @@ class AquaModelHandler(AquaAPIhandler):
131
131
  inference_container_uri = input_data.get("inference_container_uri")
132
132
  allow_patterns = input_data.get("allow_patterns")
133
133
  ignore_patterns = input_data.get("ignore_patterns")
134
+ freeform_tags = input_data.get("freeform_tags")
135
+ defined_tags = input_data.get("defined_tags")
134
136
 
135
137
  return self.finish(
136
138
  AquaModelApp().register(
@@ -145,6 +147,8 @@ class AquaModelHandler(AquaAPIhandler):
145
147
  inference_container_uri=inference_container_uri,
146
148
  allow_patterns=allow_patterns,
147
149
  ignore_patterns=ignore_patterns,
150
+ freeform_tags=freeform_tags,
151
+ defined_tags=defined_tags,
148
152
  )
149
153
  )
150
154
 
@@ -170,11 +174,9 @@ class AquaModelHandler(AquaAPIhandler):
170
174
 
171
175
  enable_finetuning = input_data.get("enable_finetuning")
172
176
  task = input_data.get("task")
173
- app=AquaModelApp()
177
+ app = AquaModelApp()
174
178
  self.finish(
175
- app.edit_registered_model(
176
- id, inference_container, enable_finetuning, task
177
- )
179
+ app.edit_registered_model(id, inference_container, enable_finetuning, task)
178
180
  )
179
181
  app.clear_model_details_cache(model_id=id)
180
182
 
@@ -218,7 +220,7 @@ class AquaHuggingFaceHandler(AquaAPIhandler):
218
220
  return None
219
221
 
220
222
  @handle_exceptions
221
- def get(self, *args, **kwargs):
223
+ def get(self, *args, **kwargs): # noqa: ARG002
222
224
  """
223
225
  Finds a list of matching models from hugging face based on query string provided from users.
224
226
 
@@ -239,7 +241,7 @@ class AquaHuggingFaceHandler(AquaAPIhandler):
239
241
  return self.finish({"models": models})
240
242
 
241
243
  @handle_exceptions
242
- def post(self, *args, **kwargs):
244
+ def post(self, *args, **kwargs): # noqa: ARG002
243
245
  """Handles post request for the HF Models APIs
244
246
 
245
247
  Raises
@@ -68,6 +68,8 @@ class AquaUIHandler(AquaAPIhandler):
68
68
  return self.list_buckets()
69
69
  elif paths.startswith("aqua/job/shapes"):
70
70
  return self.list_job_shapes()
71
+ elif paths.startswith("aqua/modeldeployment/shapes"):
72
+ return self.list_model_deployment_shapes()
71
73
  elif paths.startswith("aqua/vcn"):
72
74
  return self.list_vcn()
73
75
  elif paths.startswith("aqua/subnets"):
@@ -160,6 +162,15 @@ class AquaUIHandler(AquaAPIhandler):
160
162
  AquaUIApp().list_job_shapes(compartment_id=compartment_id, **kwargs)
161
163
  )
162
164
 
165
+ def list_model_deployment_shapes(self, **kwargs):
166
+ """Lists model deployment shapes available in the specified compartment."""
167
+ compartment_id = self.get_argument("compartment_id", default=COMPARTMENT_OCID)
168
+ return self.finish(
169
+ AquaUIApp().list_model_deployment_shapes(
170
+ compartment_id=compartment_id, **kwargs
171
+ )
172
+ )
173
+
163
174
  def list_vcn(self, **kwargs):
164
175
  """Lists the virtual cloud networks (VCNs) in the specified compartment."""
165
176
  compartment_id = self.get_argument("compartment_id", default=COMPARTMENT_OCID)
@@ -255,8 +266,9 @@ class AquaCLIHandler(AquaAPIhandler):
255
266
  __handlers__ = [
256
267
  ("logging/?([^/]*)", AquaUIHandler),
257
268
  ("compartments/?([^/]*)", AquaUIHandler),
258
- # TODO: change url to evaluation/experiements/?([^/]*)
269
+ # TODO: change url to evaluation/experiments/?([^/]*)
259
270
  ("experiment/?([^/]*)", AquaUIHandler),
271
+ ("modeldeployment/?([^/]*)", AquaUIHandler),
260
272
  ("versionsets/?([^/]*)", AquaUIHandler),
261
273
  ("buckets/?([^/]*)", AquaUIHandler),
262
274
  ("job/shapes/?([^/]*)", AquaUIHandler),
@@ -80,6 +80,10 @@ class CreateFineTuningDetails(DataClassSerializable):
80
80
  The log id for fine tuning job infrastructure.
81
81
  force_overwrite: (bool, optional). Defaults to `False`.
82
82
  Whether to force overwrite the existing file in object storage.
83
+ freeform_tags: (dict, optional)
84
+ Freeform tags for the fine-tuning model
85
+ defined_tags: (dict, optional)
86
+ Defined tags for the fine-tuning model
83
87
  """
84
88
 
85
89
  ft_source_id: str
@@ -101,3 +105,5 @@ class CreateFineTuningDetails(DataClassSerializable):
101
105
  log_id: Optional[str] = None
102
106
  log_group_id: Optional[str] = None
103
107
  force_overwrite: Optional[bool] = False
108
+ freeform_tags: Optional[dict] = None
109
+ defined_tags: Optional[dict] = None
@@ -35,7 +35,11 @@ from ads.aqua.finetuning.constants import (
35
35
  ENV_AQUA_FINE_TUNING_CONTAINER,
36
36
  FineTuneCustomMetadata,
37
37
  )
38
- from ads.aqua.finetuning.entities import *
38
+ from ads.aqua.finetuning.entities import (
39
+ AquaFineTuningParams,
40
+ AquaFineTuningSummary,
41
+ CreateFineTuningDetails,
42
+ )
39
43
  from ads.common.auth import default_signer
40
44
  from ads.common.object_storage_details import ObjectStorageDetails
41
45
  from ads.common.utils import get_console_link
@@ -100,14 +104,14 @@ class AquaFineTuningApp(AquaApp):
100
104
  if not create_fine_tuning_details:
101
105
  try:
102
106
  create_fine_tuning_details = CreateFineTuningDetails(**kwargs)
103
- except:
107
+ except Exception as ex:
104
108
  allowed_create_fine_tuning_details = ", ".join(
105
109
  field.name for field in fields(CreateFineTuningDetails)
106
110
  ).rstrip()
107
111
  raise AquaValueError(
108
112
  "Invalid create fine tuning parameters. Allowable parameters are: "
109
113
  f"{allowed_create_fine_tuning_details}."
110
- )
114
+ ) from ex
111
115
 
112
116
  source = self.get_source(create_fine_tuning_details.ft_source_id)
113
117
 
@@ -148,28 +152,27 @@ class AquaFineTuningApp(AquaApp):
148
152
  "Specify the subnet id via API or environment variable AQUA_JOB_SUBNET_ID."
149
153
  )
150
154
 
151
- if create_fine_tuning_details.replica > DEFAULT_FT_REPLICA:
152
- if not (
153
- create_fine_tuning_details.log_id
154
- and create_fine_tuning_details.log_group_id
155
- ):
156
- raise AquaValueError(
157
- f"Logging is required for fine tuning if replica is larger than {DEFAULT_FT_REPLICA}."
158
- )
155
+ if create_fine_tuning_details.replica > DEFAULT_FT_REPLICA and not (
156
+ create_fine_tuning_details.log_id
157
+ and create_fine_tuning_details.log_group_id
158
+ ):
159
+ raise AquaValueError(
160
+ f"Logging is required for fine tuning if replica is larger than {DEFAULT_FT_REPLICA}."
161
+ )
159
162
 
160
163
  ft_parameters = None
161
164
  try:
162
165
  ft_parameters = AquaFineTuningParams(
163
166
  **create_fine_tuning_details.ft_parameters,
164
167
  )
165
- except:
168
+ except Exception as ex:
166
169
  allowed_fine_tuning_parameters = ", ".join(
167
170
  field.name for field in fields(AquaFineTuningParams)
168
171
  ).rstrip()
169
172
  raise AquaValueError(
170
173
  "Invalid fine tuning parameters. Fine tuning parameters should "
171
174
  f"be a dictionary with keys: {allowed_fine_tuning_parameters}."
172
- )
175
+ ) from ex
173
176
 
174
177
  experiment_model_version_set_id = create_fine_tuning_details.experiment_id
175
178
  experiment_model_version_set_name = create_fine_tuning_details.experiment_name
@@ -197,11 +200,11 @@ class AquaFineTuningApp(AquaApp):
197
200
  auth=default_signer(),
198
201
  force_overwrite=create_fine_tuning_details.force_overwrite,
199
202
  )
200
- except FileExistsError:
203
+ except FileExistsError as fe:
201
204
  raise AquaFileExistsError(
202
205
  f"Dataset {dataset_file} already exists in {create_fine_tuning_details.report_path}. "
203
206
  "Please use a new dataset file name, report path or set `force_overwrite` as True."
204
- )
207
+ ) from fe
205
208
  logger.debug(
206
209
  f"Uploaded local file {ft_dataset_path} to object storage {dst_uri}."
207
210
  )
@@ -222,6 +225,8 @@ class AquaFineTuningApp(AquaApp):
222
225
  description=create_fine_tuning_details.experiment_description,
223
226
  compartment_id=target_compartment,
224
227
  project_id=target_project,
228
+ freeform_tags=create_fine_tuning_details.freeform_tags,
229
+ defined_tags=create_fine_tuning_details.defined_tags,
225
230
  )
226
231
 
227
232
  ft_model_custom_metadata = ModelCustomMetadata()
@@ -272,6 +277,7 @@ class AquaFineTuningApp(AquaApp):
272
277
  ft_job_freeform_tags = {
273
278
  Tags.AQUA_TAG: UNKNOWN,
274
279
  Tags.AQUA_FINE_TUNED_MODEL_TAG: f"{source.id}#{source.display_name}",
280
+ **(create_fine_tuning_details.freeform_tags or {}),
275
281
  }
276
282
 
277
283
  ft_job = Job(name=ft_model.display_name).with_infrastructure(
@@ -286,6 +292,7 @@ class AquaFineTuningApp(AquaApp):
286
292
  or DEFAULT_FT_BLOCK_STORAGE_SIZE
287
293
  )
288
294
  .with_freeform_tag(**ft_job_freeform_tags)
295
+ .with_defined_tag(**(create_fine_tuning_details.defined_tags or {}))
289
296
  )
290
297
 
291
298
  if not subnet_id:
@@ -353,6 +360,7 @@ class AquaFineTuningApp(AquaApp):
353
360
  ft_job_run = ft_job.run(
354
361
  name=ft_model.display_name,
355
362
  freeform_tags=ft_job_freeform_tags,
363
+ defined_tags=create_fine_tuning_details.defined_tags or {},
356
364
  wait=False,
357
365
  )
358
366
  logger.debug(
@@ -372,22 +380,25 @@ class AquaFineTuningApp(AquaApp):
372
380
  for metadata in ft_model_custom_metadata.to_dict()["data"]
373
381
  ]
374
382
 
375
- source_freeform_tags = source.freeform_tags or {}
376
- source_freeform_tags.pop(Tags.LICENSE, None)
377
- source_freeform_tags.update({Tags.READY_TO_FINE_TUNE: "false"})
378
- source_freeform_tags.update({Tags.AQUA_TAG: UNKNOWN})
379
- source_freeform_tags.pop(Tags.BASE_MODEL_CUSTOM, None)
383
+ model_freeform_tags = source.freeform_tags or {}
384
+ model_freeform_tags.pop(Tags.LICENSE, None)
385
+ model_freeform_tags.pop(Tags.BASE_MODEL_CUSTOM, None)
386
+
387
+ model_freeform_tags = {
388
+ **model_freeform_tags,
389
+ Tags.READY_TO_FINE_TUNE: "false",
390
+ Tags.AQUA_TAG: UNKNOWN,
391
+ Tags.AQUA_FINE_TUNED_MODEL_TAG: f"{source.id}#{source.display_name}",
392
+ **(create_fine_tuning_details.freeform_tags or {}),
393
+ }
394
+ model_defined_tags = create_fine_tuning_details.defined_tags or {}
380
395
 
381
396
  self.update_model(
382
397
  model_id=ft_model.id,
383
398
  update_model_details=UpdateModelDetails(
384
399
  custom_metadata_list=updated_custom_metadata_list,
385
- freeform_tags={
386
- Tags.AQUA_FINE_TUNED_MODEL_TAG: (
387
- f"{source.id}#{source.display_name}"
388
- ),
389
- **source_freeform_tags,
390
- },
400
+ freeform_tags=model_freeform_tags,
401
+ defined_tags=model_defined_tags,
391
402
  ),
392
403
  )
393
404
 
@@ -462,12 +473,14 @@ class AquaFineTuningApp(AquaApp):
462
473
  region=self.region,
463
474
  ),
464
475
  ),
465
- tags=dict(
466
- aqua_finetuning=Tags.AQUA_FINE_TUNING,
467
- finetuning_job_id=ft_job.id,
468
- finetuning_source=source.id,
469
- finetuning_experiment_id=experiment_model_version_set_id,
470
- ),
476
+ tags={
477
+ "aqua_finetuning": Tags.AQUA_FINE_TUNING,
478
+ "finetuning_job_id": ft_job.id,
479
+ "finetuning_source": source.id,
480
+ "finetuning_experiment_id": experiment_model_version_set_id,
481
+ **model_freeform_tags,
482
+ **model_defined_tags,
483
+ },
471
484
  parameters={
472
485
  key: value
473
486
  for key, value in asdict(ft_parameters).items()
@@ -635,6 +648,6 @@ class AquaFineTuningApp(AquaApp):
635
648
  raise AquaValueError(
636
649
  f"Invalid fine tuning parameters. Allowable parameters are: "
637
650
  f"{allowed_fine_tuning_parameters}."
638
- )
651
+ ) from e
639
652
 
640
- return dict(valid=True)
653
+ return {"valid": True}
@@ -291,6 +291,8 @@ class ImportModelDetails(CLIBuilderMixin):
291
291
  inference_container_uri: Optional[str] = None
292
292
  allow_patterns: Optional[List[str]] = None
293
293
  ignore_patterns: Optional[List[str]] = None
294
+ freeform_tags: Optional[dict] = None
295
+ defined_tags: Optional[dict] = None
294
296
 
295
297
  def __post_init__(self):
296
298
  self._command = "model register"
ads/aqua/model/model.py CHANGED
@@ -127,7 +127,13 @@ class AquaModelApp(AquaApp):
127
127
 
128
128
  @telemetry(entry_point="plugin=model&action=create", name="aqua")
129
129
  def create(
130
- self, model_id: str, project_id: str, compartment_id: str = None, **kwargs
130
+ self,
131
+ model_id: str,
132
+ project_id: str,
133
+ compartment_id: str = None,
134
+ freeform_tags: Optional[dict] = None,
135
+ defined_tags: Optional[dict] = None,
136
+ **kwargs,
131
137
  ) -> DataScienceModel:
132
138
  """Creates custom aqua model from service model.
133
139
 
@@ -140,7 +146,10 @@ class AquaModelApp(AquaApp):
140
146
  compartment_id: str
141
147
  The compartment id for custom model. Defaults to None.
142
148
  If not provided, compartment id will be fetched from environment variables.
143
-
149
+ freeform_tags: dict
150
+ Freeform tags for the model
151
+ defined_tags: dict
152
+ Defined tags for the model
144
153
  Returns
145
154
  -------
146
155
  DataScienceModel:
@@ -157,6 +166,16 @@ class AquaModelApp(AquaApp):
157
166
  )
158
167
  return service_model
159
168
 
169
+ # combine tags
170
+ combined_freeform_tags = {
171
+ **(service_model.freeform_tags or {}),
172
+ **(freeform_tags or {}),
173
+ }
174
+ combined_defined_tags = {
175
+ **(service_model.defined_tags or {}),
176
+ **(defined_tags or {}),
177
+ }
178
+
160
179
  custom_model = (
161
180
  DataScienceModel()
162
181
  .with_compartment_id(target_compartment)
@@ -164,8 +183,8 @@ class AquaModelApp(AquaApp):
164
183
  .with_model_file_description(json_dict=service_model.model_file_description)
165
184
  .with_display_name(service_model.display_name)
166
185
  .with_description(service_model.description)
167
- .with_freeform_tags(**(service_model.freeform_tags or {}))
168
- .with_defined_tags(**(service_model.defined_tags or {}))
186
+ .with_freeform_tags(**combined_freeform_tags)
187
+ .with_defined_tags(**combined_defined_tags)
169
188
  .with_custom_metadata_list(service_model.custom_metadata_list)
170
189
  .with_defined_metadata_list(service_model.defined_metadata_list)
171
190
  .with_provenance_metadata(service_model.provenance_metadata)
@@ -414,7 +433,7 @@ class AquaModelApp(AquaApp):
414
433
  except Exception as ex:
415
434
  raise AquaRuntimeError(
416
435
  f"The given model already doesn't support finetuning: {ex}"
417
- )
436
+ ) from ex
418
437
 
419
438
  custom_metadata_list.remove("modelDescription")
420
439
  if task:
@@ -766,6 +785,8 @@ class AquaModelApp(AquaApp):
766
785
  compartment_id: Optional[str],
767
786
  project_id: Optional[str],
768
787
  inference_container_uri: Optional[str],
788
+ freeform_tags: Optional[dict] = None,
789
+ defined_tags: Optional[dict] = None,
769
790
  ) -> DataScienceModel:
770
791
  """Create model by reference from the object storage path
771
792
 
@@ -778,6 +799,8 @@ class AquaModelApp(AquaApp):
778
799
  compartment_id (Optional[str]): Compartment Id of the compartment where the model has to be created
779
800
  project_id (Optional[str]): Project id of the project where the model has to be created
780
801
  inference_container_uri (Optional[str]): Inference container uri for BYOC
802
+ freeform_tags (dict): Freeform tags for the model
803
+ defined_tags (dict): Defined tags for the model
781
804
 
782
805
  Returns:
783
806
  DataScienceModel: Returns Datascience model instance.
@@ -918,6 +941,8 @@ class AquaModelApp(AquaApp):
918
941
  category="Other",
919
942
  replace=True,
920
943
  )
944
+ # override tags with freeform tags if set
945
+ tags = {**tags, **(freeform_tags or {})}
921
946
  model = (
922
947
  model.with_custom_metadata_list(metadata)
923
948
  .with_compartment_id(compartment_id or COMPARTMENT_OCID)
@@ -925,6 +950,7 @@ class AquaModelApp(AquaApp):
925
950
  .with_artifact(os_path)
926
951
  .with_display_name(model_name)
927
952
  .with_freeform_tags(**tags)
953
+ .with_defined_tags(**(defined_tags or {}))
928
954
  ).create(model_by_reference=True)
929
955
  logger.debug(model)
930
956
  return model
@@ -1314,7 +1340,7 @@ class AquaModelApp(AquaApp):
1314
1340
  os_path=os_path,
1315
1341
  local_dir=local_dir,
1316
1342
  model_name=model_name,
1317
- exclude_pattern=f"{HF_METADATA_FOLDER}*"
1343
+ exclude_pattern=f"{HF_METADATA_FOLDER}*",
1318
1344
  )
1319
1345
 
1320
1346
  return model_artifact_path
@@ -1402,6 +1428,8 @@ class AquaModelApp(AquaApp):
1402
1428
  compartment_id=import_model_details.compartment_id,
1403
1429
  project_id=import_model_details.project_id,
1404
1430
  inference_container_uri=import_model_details.inference_container_uri,
1431
+ freeform_tags=import_model_details.freeform_tags,
1432
+ defined_tags=import_model_details.defined_tags,
1405
1433
  )
1406
1434
  # registered model will always have inference and evaluation container, but
1407
1435
  # fine-tuning container may be not set
@@ -110,6 +110,8 @@ class AquaDeploymentApp(AquaApp):
110
110
  private_endpoint_id: Optional[str] = None,
111
111
  container_image_uri: Optional[None] = None,
112
112
  cmd_var: List[str] = None,
113
+ freeform_tags: Optional[dict] = None,
114
+ defined_tags: Optional[dict] = None,
113
115
  ) -> "AquaDeployment":
114
116
  """
115
117
  Creates a new Aqua deployment
@@ -163,6 +165,10 @@ class AquaDeploymentApp(AquaApp):
163
165
  Required parameter for BYOC based deployments if this parameter was not set during model registration.
164
166
  cmd_var: List[str]
165
167
  The cmd of model deployment container runtime.
168
+ freeform_tags: dict
169
+ Freeform tags for the model deployment
170
+ defined_tags: dict
171
+ Defined tags for the model deployment
166
172
  Returns
167
173
  -------
168
174
  AquaDeployment
@@ -172,7 +178,11 @@ class AquaDeploymentApp(AquaApp):
172
178
  # TODO validate if the service model has no artifact and if it requires import step before deployment.
173
179
  # Create a model catalog entry in the user compartment
174
180
  aqua_model = AquaModelApp().create(
175
- model_id=model_id, compartment_id=compartment_id, project_id=project_id
181
+ model_id=model_id,
182
+ compartment_id=compartment_id,
183
+ project_id=project_id,
184
+ freeform_tags=freeform_tags,
185
+ defined_tags=defined_tags,
176
186
  )
177
187
 
178
188
  tags = {}
@@ -418,12 +428,14 @@ class AquaDeploymentApp(AquaApp):
418
428
  if cmd_var:
419
429
  container_runtime.with_cmd(cmd_var)
420
430
 
431
+ tags = {**tags, **(freeform_tags or {})}
421
432
  # configure model deployment and deploy model on container runtime
422
433
  deployment = (
423
434
  ModelDeployment()
424
435
  .with_display_name(display_name)
425
436
  .with_description(description)
426
437
  .with_freeform_tags(**tags)
438
+ .with_defined_tags(**(defined_tags or {}))
427
439
  .with_infrastructure(infrastructure)
428
440
  .with_runtime(container_runtime)
429
441
  ).deploy(wait_for_completion=False)
@@ -98,9 +98,12 @@ class AquaDeployment(DataClassSerializable):
98
98
  ),
99
99
  )
100
100
 
101
- freeform_tags = oci_model_deployment.freeform_tags or UNKNOWN_DICT
102
- aqua_service_model_tag = freeform_tags.get(Tags.AQUA_SERVICE_MODEL_TAG, None)
103
- aqua_model_name = freeform_tags.get(Tags.AQUA_MODEL_NAME_TAG, UNKNOWN)
101
+ tags = {}
102
+ tags.update(oci_model_deployment.freeform_tags or UNKNOWN_DICT)
103
+ tags.update(oci_model_deployment.defined_tags or UNKNOWN_DICT)
104
+
105
+ aqua_service_model_tag = tags.get(Tags.AQUA_SERVICE_MODEL_TAG, None)
106
+ aqua_model_name = tags.get(Tags.AQUA_MODEL_NAME_TAG, UNKNOWN)
104
107
  private_endpoint_id = getattr(
105
108
  instance_configuration, "private_endpoint_id", UNKNOWN
106
109
  )
@@ -125,7 +128,7 @@ class AquaDeployment(DataClassSerializable):
125
128
  ocid=oci_model_deployment.id,
126
129
  region=region,
127
130
  ),
128
- tags=freeform_tags,
131
+ tags=tags,
129
132
  environment_variables=environment_variables,
130
133
  cmd=cmd,
131
134
  )
ads/aqua/ui.py CHANGED
@@ -481,12 +481,12 @@ class AquaUIApp(AquaApp):
481
481
 
482
482
  @telemetry(entry_point="plugin=ui&action=list_job_shapes", name="aqua")
483
483
  def list_job_shapes(self, **kwargs) -> list:
484
- """Lists all availiable job shapes for the specified compartment.
484
+ """Lists all available job shapes for the specified compartment.
485
485
 
486
486
  Parameters
487
487
  ----------
488
488
  **kwargs
489
- Addtional arguments, such as `compartment_id`,
489
+ Additional arguments, such as `compartment_id`,
490
490
  for `list_job_shapes <https://docs.oracle.com/en-us/iaas/tools/python/2.122.0/api/data_science/client/oci.data_science.DataScienceClient.html#oci.data_science.DataScienceClient.list_job_shapes>`_
491
491
 
492
492
  Returns
@@ -500,6 +500,28 @@ class AquaUIApp(AquaApp):
500
500
  ).data
501
501
  return sanitize_response(oci_client=self.ds_client, response=res)
502
502
 
503
+ @telemetry(entry_point="plugin=ui&action=list_model_deployment_shapes", name="aqua")
504
+ def list_model_deployment_shapes(self, **kwargs) -> list:
505
+ """Lists all available shapes for model deployment in the specified compartment.
506
+
507
+ Parameters
508
+ ----------
509
+ **kwargs
510
+ Additional arguments, such as `compartment_id`,
511
+ for `list_model_deployment_shapes <https://docs.oracle.com/en-us/iaas/api/#/en/data-science/20190101/ModelDeploymentShapeSummary/ListModelDeploymentShapes>`_
512
+
513
+ Returns
514
+ -------
515
+ str has json representation of `oci.data_science.models.ModelDeploymentShapeSummary`."""
516
+ compartment_id = kwargs.pop("compartment_id", COMPARTMENT_OCID)
517
+ logger.info(
518
+ f"Loading model deployment shape summary from compartment: {compartment_id}"
519
+ )
520
+ res = self.ds_client.list_model_deployment_shapes(
521
+ compartment_id=compartment_id, **kwargs
522
+ ).data
523
+ return sanitize_response(oci_client=self.ds_client, response=res)
524
+
503
525
  @telemetry(entry_point="plugin=ui&action=list_vcn", name="aqua")
504
526
  def list_vcn(self, **kwargs) -> list:
505
527
  """Lists the virtual cloud networks (VCNs) in the specified compartment.
@@ -1,17 +1,16 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*--
3
2
 
4
- # Copyright (c) 2023 Oracle and/or its affiliates.
3
+ # Copyright (c) 2024 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
 
8
7
  import datetime
9
8
  import functools
10
- import operator
11
9
  import importlib.util
10
+ import operator
12
11
  import sys
12
+ from typing import Any, List, Optional, Union
13
13
 
14
- from typing import Any, List, Dict, Tuple
15
14
  from langchain.schema.prompt import PromptValue
16
15
  from langchain.tools.base import BaseTool, ToolException
17
16
  from pydantic import BaseModel, model_validator
@@ -207,7 +206,9 @@ class Guardrail(BaseTool):
207
206
  return input.to_string()
208
207
  return str(input)
209
208
 
210
- def _to_args_and_kwargs(self, tool_input: Any) -> Tuple[Tuple, Dict]:
209
+ def _to_args_and_kwargs(
210
+ self, tool_input: Union[str, dict], tool_call_id: Optional[str]
211
+ ) -> tuple[tuple, dict]:
211
212
  if isinstance(tool_input, dict):
212
213
  return (), tool_input
213
214
  else:
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*--
3
2
 
4
- # Copyright (c) 2023 Oracle and/or its affiliates.
3
+ # Copyright (c) 2024 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
  """Chat model for OCI data science model deployment endpoint."""
7
6
 
@@ -50,6 +49,7 @@ from ads.llm.langchain.plugins.llms.oci_data_science_model_deployment_endpoint i
50
49
  )
51
50
 
52
51
  logger = logging.getLogger(__name__)
52
+ DEFAULT_INFERENCE_ENDPOINT_CHAT = "/v1/chat/completions"
53
53
 
54
54
 
55
55
  def _is_pydantic_class(obj: Any) -> bool:
@@ -93,6 +93,8 @@ class ChatOCIModelDeployment(BaseChatModel, BaseOCIModelDeployment):
93
93
  Key init args — client params:
94
94
  auth: dict
95
95
  ADS auth dictionary for OCI authentication.
96
+ default_headers: Optional[Dict]
97
+ The headers to be added to the Model Deployment request.
96
98
 
97
99
  Instantiate:
98
100
  .. code-block:: python
@@ -109,6 +111,10 @@ class ChatOCIModelDeployment(BaseChatModel, BaseOCIModelDeployment):
109
111
  "temperature": 0.2,
110
112
  # other model parameters ...
111
113
  },
114
+ default_headers={
115
+ "route": "/v1/chat/completions",
116
+ # other request headers ...
117
+ },
112
118
  )
113
119
 
114
120
  Invocation:
@@ -291,6 +297,25 @@ class ChatOCIModelDeployment(BaseChatModel, BaseOCIModelDeployment):
291
297
  "stream": self.streaming,
292
298
  }
293
299
 
300
+ def _headers(
301
+ self, is_async: Optional[bool] = False, body: Optional[dict] = None
302
+ ) -> Dict:
303
+ """Construct and return the headers for a request.
304
+
305
+ Args:
306
+ is_async (bool, optional): Indicates if the request is asynchronous.
307
+ Defaults to `False`.
308
+ body (optional): The request body to be included in the headers if
309
+ the request is asynchronous.
310
+
311
+ Returns:
312
+ Dict: A dictionary containing the appropriate headers for the request.
313
+ """
314
+ return {
315
+ "route": DEFAULT_INFERENCE_ENDPOINT_CHAT,
316
+ **super()._headers(is_async=is_async, body=body),
317
+ }
318
+
294
319
  def _generate(
295
320
  self,
296
321
  messages: List[BaseMessage],
@@ -704,7 +729,7 @@ class ChatOCIModelDeployment(BaseChatModel, BaseOCIModelDeployment):
704
729
 
705
730
  for choice in choices:
706
731
  message = _convert_dict_to_message(choice["message"])
707
- generation_info = dict(finish_reason=choice.get("finish_reason"))
732
+ generation_info = {"finish_reason": choice.get("finish_reason")}
708
733
  if "logprobs" in choice:
709
734
  generation_info["logprobs"] = choice["logprobs"]
710
735
 
@@ -794,7 +819,7 @@ class ChatOCIModelDeploymentVLLM(ChatOCIModelDeployment):
794
819
  """Number of most likely tokens to consider at each step."""
795
820
 
796
821
  min_p: Optional[float] = 0.0
797
- """Float that represents the minimum probability for a token to be considered.
822
+ """Float that represents the minimum probability for a token to be considered.
798
823
  Must be in [0,1]. 0 to disable this."""
799
824
 
800
825
  repetition_penalty: Optional[float] = 1.0
@@ -818,7 +843,7 @@ class ChatOCIModelDeploymentVLLM(ChatOCIModelDeployment):
818
843
  the EOS token is generated."""
819
844
 
820
845
  min_tokens: Optional[int] = 0
821
- """Minimum number of tokens to generate per output sequence before
846
+ """Minimum number of tokens to generate per output sequence before
822
847
  EOS or stop_token_ids can be generated"""
823
848
 
824
849
  stop_token_ids: Optional[List[int]] = None
@@ -836,7 +861,7 @@ class ChatOCIModelDeploymentVLLM(ChatOCIModelDeployment):
836
861
  tool_choice: Optional[str] = None
837
862
  """Whether to use tool calling.
838
863
  Defaults to None, tool calling is disabled.
839
- Tool calling requires model support and the vLLM to be configured
864
+ Tool calling requires model support and the vLLM to be configured
840
865
  with `--tool-call-parser`.
841
866
  Set this to `auto` for the model to make tool calls automatically.
842
867
  Set this to `required` to force the model to always call one or more tools.
@@ -956,9 +981,9 @@ class ChatOCIModelDeploymentTGI(ChatOCIModelDeployment):
956
981
  """Total probability mass of tokens to consider at each step."""
957
982
 
958
983
  top_logprobs: Optional[int] = None
959
- """An integer between 0 and 5 specifying the number of most
960
- likely tokens to return at each token position, each with an
961
- associated log probability. logprobs must be set to true if
984
+ """An integer between 0 and 5 specifying the number of most
985
+ likely tokens to return at each token position, each with an
986
+ associated log probability. logprobs must be set to true if
962
987
  this parameter is used."""
963
988
 
964
989
  @property
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*--
3
2
 
4
- # Copyright (c) 2023 Oracle and/or its affiliates.
3
+ # Copyright (c) 2024 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
 
@@ -24,6 +23,7 @@ from typing import (
24
23
 
25
24
  import aiohttp
26
25
  import requests
26
+ from langchain_community.utilities.requests import Requests
27
27
  from langchain_core.callbacks import (
28
28
  AsyncCallbackManagerForLLMRun,
29
29
  CallbackManagerForLLMRun,
@@ -34,14 +34,13 @@ from langchain_core.outputs import Generation, GenerationChunk, LLMResult
34
34
  from langchain_core.utils import get_from_dict_or_env
35
35
  from pydantic import Field, model_validator
36
36
 
37
- from langchain_community.utilities.requests import Requests
38
-
39
37
  logger = logging.getLogger(__name__)
40
38
 
41
39
 
42
40
  DEFAULT_TIME_OUT = 300
43
41
  DEFAULT_CONTENT_TYPE_JSON = "application/json"
44
42
  DEFAULT_MODEL_NAME = "odsc-llm"
43
+ DEFAULT_INFERENCE_ENDPOINT = "/v1/completions"
45
44
 
46
45
 
47
46
  class TokenExpiredError(Exception):
@@ -86,6 +85,9 @@ class BaseOCIModelDeployment(Serializable):
86
85
  max_retries: int = 3
87
86
  """Maximum number of retries to make when generating."""
88
87
 
88
+ default_headers: Optional[Dict[str, Any]] = None
89
+ """The headers to be added to the Model Deployment request."""
90
+
89
91
  @model_validator(mode="before")
90
92
  @classmethod
91
93
  def validate_environment(cls, values: Dict) -> Dict:
@@ -101,7 +103,7 @@ class BaseOCIModelDeployment(Serializable):
101
103
  "Please install it with `pip install oracle_ads`."
102
104
  ) from ex
103
105
 
104
- if not values.get("auth", None):
106
+ if not values.get("auth"):
105
107
  values["auth"] = ads.common.auth.default_signer()
106
108
 
107
109
  values["endpoint"] = get_from_dict_or_env(
@@ -125,12 +127,12 @@ class BaseOCIModelDeployment(Serializable):
125
127
  Returns:
126
128
  Dict: A dictionary containing the appropriate headers for the request.
127
129
  """
130
+ headers = self.default_headers or {}
128
131
  if is_async:
129
132
  signer = self.auth["signer"]
130
133
  _req = requests.Request("POST", self.endpoint, json=body)
131
134
  req = _req.prepare()
132
135
  req = signer(req)
133
- headers = {}
134
136
  for key, value in req.headers.items():
135
137
  headers[key] = value
136
138
 
@@ -140,7 +142,7 @@ class BaseOCIModelDeployment(Serializable):
140
142
  )
141
143
  return headers
142
144
 
143
- return (
145
+ headers.update(
144
146
  {
145
147
  "Content-Type": DEFAULT_CONTENT_TYPE_JSON,
146
148
  "enable-streaming": "true",
@@ -152,6 +154,8 @@ class BaseOCIModelDeployment(Serializable):
152
154
  }
153
155
  )
154
156
 
157
+ return headers
158
+
155
159
  def completion_with_retry(
156
160
  self, run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any
157
161
  ) -> Any:
@@ -357,7 +361,7 @@ class BaseOCIModelDeployment(Serializable):
357
361
  self.auth["signer"].refresh_security_token()
358
362
  return True
359
363
  return False
360
-
364
+
361
365
  @classmethod
362
366
  def is_lc_serializable(cls) -> bool:
363
367
  """Return whether this model can be serialized by LangChain."""
@@ -388,6 +392,10 @@ class OCIModelDeploymentLLM(BaseLLM, BaseOCIModelDeployment):
388
392
  model="odsc-llm",
389
393
  streaming=True,
390
394
  model_kwargs={"frequency_penalty": 1.0},
395
+ headers={
396
+ "route": "/v1/completions",
397
+ # other request headers ...
398
+ }
391
399
  )
392
400
  llm.invoke("tell me a joke.")
393
401
 
@@ -477,6 +485,25 @@ class OCIModelDeploymentLLM(BaseLLM, BaseOCIModelDeployment):
477
485
  **self._default_params,
478
486
  }
479
487
 
488
+ def _headers(
489
+ self, is_async: Optional[bool] = False, body: Optional[dict] = None
490
+ ) -> Dict:
491
+ """Construct and return the headers for a request.
492
+
493
+ Args:
494
+ is_async (bool, optional): Indicates if the request is asynchronous.
495
+ Defaults to `False`.
496
+ body (optional): The request body to be included in the headers if
497
+ the request is asynchronous.
498
+
499
+ Returns:
500
+ Dict: A dictionary containing the appropriate headers for the request.
501
+ """
502
+ return {
503
+ "route": DEFAULT_INFERENCE_ENDPOINT,
504
+ **super()._headers(is_async=is_async, body=body),
505
+ }
506
+
480
507
  def _generate(
481
508
  self,
482
509
  prompts: List[str],
@@ -712,9 +739,9 @@ class OCIModelDeploymentLLM(BaseLLM, BaseOCIModelDeployment):
712
739
  def _generate_info(self, choice: dict) -> Any:
713
740
  """Extracts generation info from the response."""
714
741
  gen_info = {}
715
- finish_reason = choice.get("finish_reason", None)
716
- logprobs = choice.get("logprobs", None)
717
- index = choice.get("index", None)
742
+ finish_reason = choice.get("finish_reason")
743
+ logprobs = choice.get("logprobs")
744
+ index = choice.get("index")
718
745
  if finish_reason:
719
746
  gen_info.update({"finish_reason": finish_reason})
720
747
  if logprobs is not None:
@@ -87,3 +87,4 @@ SUMMARY_METRICS_HORIZON_LIMIT = 10
87
87
  PROPHET_INTERNAL_DATE_COL = "ds"
88
88
  RENDER_LIMIT = 5000
89
89
  AUTO_SELECT = "auto-select"
90
+ BACKTEST_REPORT_NAME = "back_test.csv"
@@ -47,6 +47,7 @@ from ..const import (
47
47
  SpeedAccuracyMode,
48
48
  SupportedMetrics,
49
49
  SupportedModels,
50
+ BACKTEST_REPORT_NAME
50
51
  )
51
52
  from ..operator_config import ForecastOperatorConfig, ForecastOperatorSpec
52
53
  from .forecast_datasets import ForecastDatasets
@@ -256,12 +257,9 @@ class ForecastOperatorBaseModel(ABC):
256
257
 
257
258
  backtest_sections = []
258
259
  output_dir = self.spec.output_directory.url
259
- backtest_report_name = "backtest_stats.csv"
260
- file_path = f"{output_dir}/{backtest_report_name}"
260
+ file_path = f"{output_dir}/{BACKTEST_REPORT_NAME}"
261
261
  if self.spec.model == AUTO_SELECT:
262
- backtest_sections.append(
263
- rc.Heading("Auto-select statistics", level=2)
264
- )
262
+ backtest_sections.append(rc.Heading("Auto-Select Backtesting and Performance Metrics", level=2))
265
263
  if not os.path.exists(file_path):
266
264
  failure_msg = rc.Text(
267
265
  "auto-select could not be executed. Please check the "
@@ -270,19 +268,15 @@ class ForecastOperatorBaseModel(ABC):
270
268
  backtest_sections.append(failure_msg)
271
269
  else:
272
270
  backtest_stats = pd.read_csv(file_path)
273
- average_dict = backtest_stats.mean().to_dict()
274
- del average_dict["backtest"]
271
+ model_metric_map = backtest_stats.drop(columns=['metric', 'backtest'])
272
+ average_dict = {k: round(v, 4) for k, v in model_metric_map.mean().to_dict().items()}
275
273
  best_model = min(average_dict, key=average_dict.get)
276
- backtest_text = rc.Heading("Back Testing Metrics", level=3)
277
274
  summary_text = rc.Text(
278
- f"Overall, the average scores for the models are {average_dict}, with {best_model}"
279
- f" being identified as the top-performing model during backtesting."
280
- )
275
+ f"Overall, the average {self.spec.metric} scores for the models are {average_dict}, with"
276
+ f" {best_model} being identified as the top-performing model during backtesting.")
281
277
  backtest_table = rc.DataTable(backtest_stats, index=True)
282
278
  liner_plot = get_auto_select_plot(backtest_stats)
283
- backtest_sections.extend(
284
- [backtest_text, backtest_table, summary_text, liner_plot]
285
- )
279
+ backtest_sections.extend([backtest_table, summary_text, liner_plot])
286
280
 
287
281
  forecast_plots = []
288
282
  if len(self.forecast_output.list_series_ids()) > 0:
@@ -10,6 +10,7 @@ from pathlib import Path
10
10
 
11
11
  from ads.opctl import logger
12
12
  from ads.opctl.operator.lowcode.common.const import DataColumns
13
+ from ads.opctl.operator.lowcode.forecast.const import BACKTEST_REPORT_NAME
13
14
  from .model.forecast_datasets import ForecastDatasets
14
15
  from .operator_config import ForecastOperatorConfig
15
16
  from ads.opctl.operator.lowcode.forecast.model.factory import SupportedModels
@@ -156,8 +157,8 @@ class ModelEvaluator:
156
157
  best_model = min(avg_backtests_metric, key=avg_backtests_metric.get)
157
158
  logger.info(f"Among models {self.models}, {best_model} model shows better performance during backtesting.")
158
159
  backtest_stats = pd.DataFrame(nonempty_metrics).rename_axis('backtest')
160
+ backtest_stats["metric"] = operator_config.spec.metric
159
161
  backtest_stats.reset_index(inplace=True)
160
162
  output_dir = operator_config.spec.output_directory.url
161
- backtest_report_name = "backtest_stats.csv"
162
- backtest_stats.to_csv(f"{output_dir}/{backtest_report_name}", index=False)
163
+ backtest_stats.to_csv(f"{output_dir}/{BACKTEST_REPORT_NAME}", index=False)
163
164
  return best_model
@@ -261,10 +261,11 @@ def _add_unit(num, unit):
261
261
 
262
262
  def get_auto_select_plot(backtest_results):
263
263
  fig = go.Figure()
264
- columns = backtest_results.columns.tolist()
264
+ back_test_csv_columns = backtest_results.columns.tolist()
265
265
  back_test_column = "backtest"
266
- columns.remove(back_test_column)
267
- for column in columns:
266
+ metric_column = "metric"
267
+ models = [x for x in back_test_csv_columns if x not in [back_test_column, metric_column]]
268
+ for i, column in enumerate(models):
268
269
  fig.add_trace(
269
270
  go.Scatter(
270
271
  x=backtest_results[back_test_column],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: oracle_ads
3
- Version: 2.12.8
3
+ Version: 2.12.9
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
6
6
  Author: Oracle Data Science
@@ -30,7 +30,7 @@ Requires-Dist: pandas>=2.2.0; python_version>='3.9'
30
30
  Requires-Dist: psutil>=5.7.2
31
31
  Requires-Dist: python_jsonschema_objects>=0.3.13
32
32
  Requires-Dist: requests
33
- Requires-Dist: scikit-learn>=1.0
33
+ Requires-Dist: scikit-learn>=1.0,<1.6.0
34
34
  Requires-Dist: tabulate>=0.8.9
35
35
  Requires-Dist: tqdm>=4.59.0
36
36
  Requires-Dist: pydantic>=2.6.3
@@ -39,7 +39,7 @@ Requires-Dist: autots ; extra == "anomaly"
39
39
  Requires-Dist: oracledb ; extra == "anomaly"
40
40
  Requires-Dist: report-creator==1.0.28 ; extra == "anomaly"
41
41
  Requires-Dist: rrcf==0.4.4 ; extra == "anomaly"
42
- Requires-Dist: scikit-learn ; extra == "anomaly"
42
+ Requires-Dist: scikit-learn<1.6.0 ; extra == "anomaly"
43
43
  Requires-Dist: salesforce-merlion[all]==2.0.4 ; extra == "anomaly"
44
44
  Requires-Dist: jupyter_server ; extra == "aqua"
45
45
  Requires-Dist: hdfs[kerberos] ; extra == "bds"
@@ -2,11 +2,11 @@ ads/__init__.py,sha256=OxHySbHbMqPgZ8sUj33Bxy-smSiNgRjtcSUV77oBL08,3787
2
2
  ads/cli.py,sha256=hjRcQfXFzkh37fbyUBg95I3R0brslZLf9IQU8nSCxio,3933
3
3
  ads/config.py,sha256=WGFgS5-dxqC9_iRJKakn-mh9545gHJpWB_Y0hT5O3ec,8016
4
4
  ads/aqua/__init__.py,sha256=IUKZAsxUGVicsyeSwsGwK6rAUJ1vIUW9ywduA3U22xc,1015
5
- ads/aqua/app.py,sha256=BQuQ9RERU0rKmn3N3xicKzYaXOd7xBwX1aVuVLNgw98,11993
5
+ ads/aqua/app.py,sha256=i-03u5bf3gCCIIXf5bbWK22rW6ll0skQQlVt-zehOGU,12538
6
6
  ads/aqua/cli.py,sha256=W-0kswzRDEilqHyw5GSMOrARgvOyPRtkEtpy54ew0Jo,3907
7
7
  ads/aqua/constants.py,sha256=fTPrRuWaZB1_THZ2I1nOrwW1pQGpvMC44--Ok5Myr5Y,2978
8
8
  ads/aqua/data.py,sha256=7T7kdHGnEH6FXL_7jv_Da0CjEWXfjQZTFkaZWQikis4,932
9
- ads/aqua/ui.py,sha256=hGl4btUsMImkpzZ-Ae_WVVaRqfpdG_gUeHKD9E1nKbE,26195
9
+ ads/aqua/ui.py,sha256=aRVtvJslhq8Zq8B_2AQdmlFbuLWpHakFTZg6T9uvHU0,27248
10
10
  ads/aqua/common/__init__.py,sha256=rZrmh1nho40OCeabXCNWtze-mXi-PGKetcZdxZSn3_0,204
11
11
  ads/aqua/common/decorator.py,sha256=JEN6Cy4DYgQbmIR3ShCjTuBMCnilDxq7jkYMJse1rcM,4112
12
12
  ads/aqua/common/entities.py,sha256=UsP8CczuifLOLr_gAhulh8VmgGSFir3rli1MMQ-CZhk,537
@@ -26,40 +26,40 @@ ads/aqua/dummy_data/oci_models.json,sha256=mxUU8o3plmAFfr06fQmIQuiGe2qFFBlUB7QNP
26
26
  ads/aqua/dummy_data/readme.md,sha256=AlBPt0HBSOFA5HbYVsFsdTm-BC3R5NRpcKrTxdjEnlI,1256
27
27
  ads/aqua/evaluation/__init__.py,sha256=Fd7WL7MpQ1FtJjlftMY2KHli5cz1wr5MDu3hGmV89a0,298
28
28
  ads/aqua/evaluation/constants.py,sha256=GvcXvPIw-VDKw4a8WNKs36uWdT-f7VJrWSpnnRnthGg,1533
29
- ads/aqua/evaluation/entities.py,sha256=OqD2AfCO31ZO88hfORsjLdmJRqOjZrep2zVESEj6qJc,5488
29
+ ads/aqua/evaluation/entities.py,sha256=pvZWrO-Hlsh0TIFnly84OijKHULRVM13D5a-4ZGxte8,5733
30
30
  ads/aqua/evaluation/errors.py,sha256=qzR63YEIA8haCh4HcBHFFm7j4g6jWDfGszqrPkXx9zQ,4564
31
- ads/aqua/evaluation/evaluation.py,sha256=UGo6Ly148qw3br1tNo-fagvyipDi4P-2AEZ8T4m6GR4,57856
31
+ ads/aqua/evaluation/evaluation.py,sha256=0f6i3G1KWmbwCf_A33YKrnfDVmKu7XHD2nue0y8Ob9k,58915
32
32
  ads/aqua/extension/__init__.py,sha256=mRArjU6UZpZYVr0qHSSkPteA_CKcCZIczOFaK421m9o,1453
33
33
  ads/aqua/extension/aqua_ws_msg_handler.py,sha256=soSRnIFx93JCFf6HsuF_BQEpJ2mre-IVQDUDKUKPijY,3392
34
34
  ads/aqua/extension/base_handler.py,sha256=Zbb-uSNLljRU5NPOndn3_lx8MN_1yxlF2GHVpBT-kWk,5233
35
35
  ads/aqua/extension/common_handler.py,sha256=Oz3riHDy5pFfbArLge5iaaRoK8PEAnkBvhqqVGbUsvE,4196
36
36
  ads/aqua/extension/common_ws_msg_handler.py,sha256=pMX79tmJKTKog684o6vuwZkAD47l8SxtRx5TNn8se7k,2230
37
- ads/aqua/extension/deployment_handler.py,sha256=i2UAZQ8_uVgg32OmM1vif3kplAVuRwxZsjgTfUSKnH8,11025
37
+ ads/aqua/extension/deployment_handler.py,sha256=abTwz9OFJB2_OPbRZaDvNMb3BjRmkSmNh28EtGNstg4,11287
38
38
  ads/aqua/extension/deployment_ws_msg_handler.py,sha256=JX3ZHRtscrflSxT7ZTEEI_p_owtk3m5FZq3QXE96AGY,2013
39
39
  ads/aqua/extension/errors.py,sha256=ojDolyr3_0UCCwKqPtiZZyMQuX35jr8h8MQRP6HcBs4,519
40
40
  ads/aqua/extension/evaluation_handler.py,sha256=fJH73fa0xmkEiP8SxKL4A4dJgj-NoL3z_G-w_WW2zJs,4353
41
41
  ads/aqua/extension/evaluation_ws_msg_handler.py,sha256=dv0iwOSTxYj1kQ1rPEoDmGgFBzLUCLXq5h7rpmY2T1M,2098
42
42
  ads/aqua/extension/finetune_handler.py,sha256=abiDXNhkhtoV9hrYhCzwhDjdQKlqQ_KSqxKWntkvh3E,3288
43
- ads/aqua/extension/model_handler.py,sha256=Ec7NiU3Xvp_sZEvCvN6aVqeoiFrOpJMhDI5xtP_pSuw,10612
43
+ ads/aqua/extension/model_handler.py,sha256=Wli2DIcHrrXpsfJa8oh_KkrFkN8XSoKBMT0L3uOOxRA,10830
44
44
  ads/aqua/extension/models_ws_msg_handler.py,sha256=3CPfzWl1xfrE2Dpn_WYP9zY0kY5zlsAE8tU_6Y2-i18,1801
45
- ads/aqua/extension/ui_handler.py,sha256=3TibTMeqcsSWfPsorspFrhIV0PRh8_4FoWpudycT80g,10664
45
+ ads/aqua/extension/ui_handler.py,sha256=Q0LkrV6VtVUI4GpNgqJQt8SGzxHzp4X5hdHF6KgPp9M,11217
46
46
  ads/aqua/extension/ui_websocket_handler.py,sha256=oLFjaDrqkSERbhExdvxjLJX0oRcP-DVJ_aWn0qy0uvo,5084
47
47
  ads/aqua/extension/utils.py,sha256=UKafTX6tN6ObOkWCLy6c3y_cNmUHfD64PtIaR5B7Sl0,1476
48
48
  ads/aqua/extension/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
49
  ads/aqua/extension/models/ws_models.py,sha256=-m6IJRS-4I6AMLDwgu19XdrvHyOStuBx9t4B0LgS07g,3348
50
50
  ads/aqua/finetuning/__init__.py,sha256=vwYT5PluMR0mDQwVIavn_8Icms7LmvfV_FOrJ8fJx8I,296
51
51
  ads/aqua/finetuning/constants.py,sha256=g0ze760c4LlD6ppN0Lww_ZAkr1IpNJMJDxq_USx4IEk,807
52
- ads/aqua/finetuning/entities.py,sha256=S7Ll_0WyWGh23my-6ow3vwHLDZqTel8CMCoE9oLowOY,4126
53
- ads/aqua/finetuning/finetuning.py,sha256=mwKl8KA2Artp0dXzjXxxKn_UBnkYpNXMYN7ykrZcyEM,25145
52
+ ads/aqua/finetuning/entities.py,sha256=TQxvYFvzm78z_KtuOokFA5WMElDz2aDLYIOpUUX7xnA,4373
53
+ ads/aqua/finetuning/finetuning.py,sha256=xX_B-FyNFC51b2YpEm_thkqMDzc0PPvNb_tNVsqpuBs,25808
54
54
  ads/aqua/model/__init__.py,sha256=j2iylvERdANxgrEDp7b_mLcKMz1CF5Go0qgYCiMwdos,278
55
55
  ads/aqua/model/constants.py,sha256=H239zDu3koa3UTdw-uQveXHX2NDwidclVcS4QIrCTJo,1593
56
- ads/aqua/model/entities.py,sha256=wv1j18OG8NrmKLwIevyJ1ZVw965n3_3titOfwqyzlI8,9765
56
+ ads/aqua/model/entities.py,sha256=JXAQIiF-BW8nU6tTpZ2kgNbpQNmC0Om0MCd15xj3_70,9846
57
57
  ads/aqua/model/enums.py,sha256=t8GbK2nblIPm3gClR8W31RmbtTuqpoSzoN4W3JfD6AI,1004
58
- ads/aqua/model/model.py,sha256=pFG4lkaqtovSpiu3BOCGT7scMtXt4rwup9Rof6Hl_CU,63908
58
+ ads/aqua/model/model.py,sha256=5q1QDrJqbhtUlDL0TrgN7q0t6pbg-IcIvyCiepUcp2Q,64924
59
59
  ads/aqua/modeldeployment/__init__.py,sha256=RJCfU1yazv3hVWi5rS08QVLTpTwZLnlC8wU8diwFjnM,391
60
60
  ads/aqua/modeldeployment/constants.py,sha256=lJF77zwxmlECljDYjwFAMprAUR_zctZHmawiP-4alLg,296
61
- ads/aqua/modeldeployment/deployment.py,sha256=bk58MfjnrUiDUFwjBRJwBR_8b-6z8IuzTts2T0-pK3E,30729
62
- ads/aqua/modeldeployment/entities.py,sha256=7aoE2HemsFEvkQynAI4PCfZBcfPJrvbyZeEYvc7OIAA,5111
61
+ ads/aqua/modeldeployment/deployment.py,sha256=hlaLWjND6DDnwj-DA_7vwA-1UQRmZkNFbauB0SImqfs,31185
62
+ ads/aqua/modeldeployment/entities.py,sha256=EV7hxfKRZNY9kJDy_1IC7PoSIsRQ0yy02pll0gCsCkY,5171
63
63
  ads/aqua/modeldeployment/inference.py,sha256=JPqzbHJoM-PpIU_Ft9lHudO9_1vFr7OPQ2GHjPoAufU,2142
64
64
  ads/aqua/training/__init__.py,sha256=w2DNWltXtASQgbrHyvKo0gMs5_chZoG-CSDMI4qe7i0,202
65
65
  ads/aqua/training/exceptions.py,sha256=S5gHUeUiiPErxuwqG0TB1Yf11mhsAGNYb9o3zd1L1dI,13627
@@ -453,14 +453,14 @@ ads/llm/serialize.py,sha256=WjQNMPACyR8nIh1dB7BLFUmqUrumld6vt91lg1DWzWI,7281
453
453
  ads/llm/autogen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
454
454
  ads/llm/autogen/client_v02.py,sha256=-8fH-u769txu9eCfGi8XDkQ09DMPl5cCOmmywOFUguc,11127
455
455
  ads/llm/guardrails/__init__.py,sha256=sAqmLhogrLXb3xI7dPOj9HmSkpTnLh9wkzysuGd8AXk,204
456
- ads/llm/guardrails/base.py,sha256=scli_YSqDbArIJW5sA5PLjCd6G8_-dNUcpTybvQvZnk,16468
456
+ ads/llm/guardrails/base.py,sha256=L-hAW18PsEVKoh8h8PU3WhAZIAgxKhygfkvD4zHOIts,16503
457
457
  ads/llm/guardrails/huggingface.py,sha256=4DFanCYb3R1SKYSFdcEyGH2ywQgf2yFDDZGJtOcoph0,1304
458
458
  ads/llm/langchain/__init__.py,sha256=sAqmLhogrLXb3xI7dPOj9HmSkpTnLh9wkzysuGd8AXk,204
459
459
  ads/llm/langchain/plugins/__init__.py,sha256=sAqmLhogrLXb3xI7dPOj9HmSkpTnLh9wkzysuGd8AXk,204
460
460
  ads/llm/langchain/plugins/chat_models/__init__.py,sha256=sAqmLhogrLXb3xI7dPOj9HmSkpTnLh9wkzysuGd8AXk,204
461
- ads/llm/langchain/plugins/chat_models/oci_data_science.py,sha256=wWVH7nuN6umNfsHD07NnkuoaAGhFy6IKGgx_v9QgYG0,35405
461
+ ads/llm/langchain/plugins/chat_models/oci_data_science.py,sha256=4JcSMQ5K21Htf07ek5Sg62VywKr95-OfBMG5mYS4mPw,36375
462
462
  ads/llm/langchain/plugins/llms/__init__.py,sha256=sAqmLhogrLXb3xI7dPOj9HmSkpTnLh9wkzysuGd8AXk,204
463
- ads/llm/langchain/plugins/llms/oci_data_science_model_deployment_endpoint.py,sha256=0QGNpDuV_QorZw9i62PEkTqRxOLs4d2aPrg_lXq0akQ,32466
463
+ ads/llm/langchain/plugins/llms/oci_data_science_model_deployment_endpoint.py,sha256=UJ6Wm6fxOWxaBHMIMWlCMyOXlWAqq626gcZ-8TRwrbQ,33448
464
464
  ads/llm/serializers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
465
465
  ads/llm/serializers/retrieval_qa.py,sha256=VQ4rFRrDHOpAcMYNvRbT19LcDGwRrE1lczerLQYKxwU,5133
466
466
  ads/llm/serializers/runnable_parallel.py,sha256=USCVhMNi67AiCmu-s_mmOvc0sK7v4yKVwBTJm60x7wE,835
@@ -681,18 +681,18 @@ ads/opctl/operator/lowcode/forecast/README.md,sha256=kbCCEdo-0pwKlZp9ctnWUK6Z31n
681
681
  ads/opctl/operator/lowcode/forecast/__init__.py,sha256=sAqmLhogrLXb3xI7dPOj9HmSkpTnLh9wkzysuGd8AXk,204
682
682
  ads/opctl/operator/lowcode/forecast/__main__.py,sha256=5Vh-kClwxTsvZLEuECyQBvbZFfH37HQW2G09RwX11Kw,2503
683
683
  ads/opctl/operator/lowcode/forecast/cmd.py,sha256=uwU-QvnYwxoRFXZv7_JFkzAUnjTNoSsHEme2FF-9Rl0,1151
684
- ads/opctl/operator/lowcode/forecast/const.py,sha256=jyoXhrRXFipcATwGIU_3rFRZL-r6hvbKNUVO2uG2siY,2597
684
+ ads/opctl/operator/lowcode/forecast/const.py,sha256=ThGSWojqD6VRDWirdcrWxPxPNboFIq2xLmqLR4d6eQw,2636
685
685
  ads/opctl/operator/lowcode/forecast/environment.yaml,sha256=eVMf9pcjADI14_GRGdZOB_gK5_MyG_-cX037TXqzFho,330
686
686
  ads/opctl/operator/lowcode/forecast/errors.py,sha256=X9zuV2Lqb5N9FuBHHshOFYyhvng5r9KGLHnQijZ5b8c,911
687
- ads/opctl/operator/lowcode/forecast/model_evaluator.py,sha256=HssIlfJlJt5HetwzT87rDeRYRwJAXG1yoSjT4SUB8D0,9266
687
+ ads/opctl/operator/lowcode/forecast/model_evaluator.py,sha256=IutyI2bo_aFopHsWlJ3z7TcBPXs6G3NufdIaXBUD6Tw,9352
688
688
  ads/opctl/operator/lowcode/forecast/operator_config.py,sha256=vG7n-RIiazujH0UtJ0uarx9IKDIAS0b4WcCo1dNLVL0,6422
689
689
  ads/opctl/operator/lowcode/forecast/schema.yaml,sha256=r9vll4zNn3maiEXO0aQdt4bQ9l9DmK_Jy7lpidhVubc,10135
690
- ads/opctl/operator/lowcode/forecast/utils.py,sha256=B7X3vLxmbx3MyUQxoplhQCMb0bgmPk2g-KN-OY768E8,13908
690
+ ads/opctl/operator/lowcode/forecast/utils.py,sha256=pvfEm-OZmouIgB5mXtZDN7e9kib4LEio-6SLLB8bVs8,14021
691
691
  ads/opctl/operator/lowcode/forecast/model/__init__.py,sha256=sAqmLhogrLXb3xI7dPOj9HmSkpTnLh9wkzysuGd8AXk,204
692
692
  ads/opctl/operator/lowcode/forecast/model/arima.py,sha256=lU7NlpXI1-g-O_1rGJLlEL17_ruGXAdzzY7H8nFRvGQ,10943
693
693
  ads/opctl/operator/lowcode/forecast/model/automlx.py,sha256=lrNktixdaJJHHXqIrSmgzCZKEzB_CirQcuquf73AYUQ,14978
694
694
  ads/opctl/operator/lowcode/forecast/model/autots.py,sha256=Y9_EAfDD5r6SPZq7iGp7YMh-vH0lwAGNpyNT2sm7cqo,13027
695
- ads/opctl/operator/lowcode/forecast/model/base_model.py,sha256=H9yQ1DzyfGqnggEaSWgUJjW_bxml6Kto62gohuEO9y4,31006
695
+ ads/opctl/operator/lowcode/forecast/model/base_model.py,sha256=6ORLDA7rcgcGRcMQ71iT9kJbtdXjRgFf3TEVNQLZPTI,30872
696
696
  ads/opctl/operator/lowcode/forecast/model/factory.py,sha256=hSRPPWdpIRSMYPUFMIUuxc2TPZt-SG18MiqhtdfL3mg,3488
697
697
  ads/opctl/operator/lowcode/forecast/model/forecast_datasets.py,sha256=GCwX9Udh4U79wBNG5bjSYabgRDO0u-ElVJkSC_HcBeA,16563
698
698
  ads/opctl/operator/lowcode/forecast/model/ml_forecast.py,sha256=NSZ2L6gRw4S68BUF0Vyu-cUPSsq8LRxgoVajW9Ra63k,9640
@@ -815,8 +815,8 @@ ads/type_discovery/unknown_detector.py,sha256=yZuYQReO7PUyoWZE7onhhtYaOg6088wf1y
815
815
  ads/type_discovery/zipcode_detector.py,sha256=3AlETg_ZF4FT0u914WXvTT3F3Z6Vf51WiIt34yQMRbw,1421
816
816
  ads/vault/__init__.py,sha256=x9tMdDAOdF5iDHk9u2di_K-ze5Nq068x25EWOBoWwqY,245
817
817
  ads/vault/vault.py,sha256=hFBkpYE-Hfmzu1L0sQwUfYcGxpWmgG18JPndRl0NOXI,8624
818
- oracle_ads-2.12.8.dist-info/entry_points.txt,sha256=9VFnjpQCsMORA4rVkvN8eH6D3uHjtegb9T911t8cqV0,35
819
- oracle_ads-2.12.8.dist-info/LICENSE.txt,sha256=zoGmbfD1IdRKx834U0IzfFFFo5KoFK71TND3K9xqYqo,1845
820
- oracle_ads-2.12.8.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
821
- oracle_ads-2.12.8.dist-info/METADATA,sha256=aKjc1EqBFSoyK7K30kgMzGfqvemx9-25hmyl5mZZ-xU,16282
822
- oracle_ads-2.12.8.dist-info/RECORD,,
818
+ oracle_ads-2.12.9.dist-info/entry_points.txt,sha256=9VFnjpQCsMORA4rVkvN8eH6D3uHjtegb9T911t8cqV0,35
819
+ oracle_ads-2.12.9.dist-info/LICENSE.txt,sha256=zoGmbfD1IdRKx834U0IzfFFFo5KoFK71TND3K9xqYqo,1845
820
+ oracle_ads-2.12.9.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
821
+ oracle_ads-2.12.9.dist-info/METADATA,sha256=gdzIbyPkwPxbG4ZbgEDKBs0fz7a-lSnxKVmRuaMcHHQ,16295
822
+ oracle_ads-2.12.9.dist-info/RECORD,,