oracle-ads 2.12.9__py3-none-any.whl → 2.12.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.
Files changed (60) hide show
  1. ads/aqua/__init__.py +4 -4
  2. ads/aqua/common/enums.py +3 -0
  3. ads/aqua/common/utils.py +62 -2
  4. ads/aqua/data.py +2 -19
  5. ads/aqua/extension/finetune_handler.py +8 -14
  6. ads/aqua/extension/model_handler.py +19 -2
  7. ads/aqua/finetuning/constants.py +5 -2
  8. ads/aqua/finetuning/entities.py +64 -17
  9. ads/aqua/finetuning/finetuning.py +38 -54
  10. ads/aqua/model/entities.py +2 -1
  11. ads/aqua/model/model.py +61 -23
  12. ads/common/auth.py +9 -9
  13. ads/llm/autogen/__init__.py +2 -0
  14. ads/llm/autogen/constants.py +15 -0
  15. ads/llm/autogen/reports/__init__.py +2 -0
  16. ads/llm/autogen/reports/base.py +67 -0
  17. ads/llm/autogen/reports/data.py +103 -0
  18. ads/llm/autogen/reports/session.py +526 -0
  19. ads/llm/autogen/reports/templates/chat_box.html +13 -0
  20. ads/llm/autogen/reports/templates/chat_box_lt.html +5 -0
  21. ads/llm/autogen/reports/templates/chat_box_rt.html +6 -0
  22. ads/llm/autogen/reports/utils.py +56 -0
  23. ads/llm/autogen/v02/__init__.py +4 -0
  24. ads/llm/autogen/{client_v02.py → v02/client.py} +23 -10
  25. ads/llm/autogen/v02/log_handlers/__init__.py +2 -0
  26. ads/llm/autogen/v02/log_handlers/oci_file_handler.py +83 -0
  27. ads/llm/autogen/v02/loggers/__init__.py +6 -0
  28. ads/llm/autogen/v02/loggers/metric_logger.py +320 -0
  29. ads/llm/autogen/v02/loggers/session_logger.py +580 -0
  30. ads/llm/autogen/v02/loggers/utils.py +86 -0
  31. ads/llm/autogen/v02/runtime_logging.py +163 -0
  32. ads/llm/langchain/plugins/chat_models/oci_data_science.py +12 -11
  33. ads/model/__init__.py +11 -13
  34. ads/model/artifact.py +47 -8
  35. ads/model/extractor/embedding_onnx_extractor.py +80 -0
  36. ads/model/framework/embedding_onnx_model.py +438 -0
  37. ads/model/generic_model.py +26 -24
  38. ads/model/model_metadata.py +8 -7
  39. ads/opctl/config/merger.py +13 -14
  40. ads/opctl/operator/common/operator_config.py +4 -4
  41. ads/opctl/operator/lowcode/common/transformations.py +12 -5
  42. ads/opctl/operator/lowcode/common/utils.py +11 -5
  43. ads/opctl/operator/lowcode/forecast/const.py +2 -0
  44. ads/opctl/operator/lowcode/forecast/model/arima.py +19 -13
  45. ads/opctl/operator/lowcode/forecast/model/automlx.py +129 -36
  46. ads/opctl/operator/lowcode/forecast/model/autots.py +1 -0
  47. ads/opctl/operator/lowcode/forecast/model/base_model.py +61 -14
  48. ads/opctl/operator/lowcode/forecast/model/neuralprophet.py +10 -3
  49. ads/opctl/operator/lowcode/forecast/model/prophet.py +25 -18
  50. ads/opctl/operator/lowcode/forecast/schema.yaml +13 -0
  51. ads/opctl/operator/lowcode/forecast/utils.py +4 -3
  52. ads/telemetry/base.py +18 -11
  53. ads/telemetry/client.py +33 -13
  54. ads/templates/schemas/openapi.json +1740 -0
  55. ads/templates/score_embedding_onnx.jinja2 +202 -0
  56. {oracle_ads-2.12.9.dist-info → oracle_ads-2.12.10rc0.dist-info}/METADATA +7 -8
  57. {oracle_ads-2.12.9.dist-info → oracle_ads-2.12.10rc0.dist-info}/RECORD +60 -39
  58. {oracle_ads-2.12.9.dist-info → oracle_ads-2.12.10rc0.dist-info}/LICENSE.txt +0 -0
  59. {oracle_ads-2.12.9.dist-info → oracle_ads-2.12.10rc0.dist-info}/WHEEL +0 -0
  60. {oracle_ads-2.12.9.dist-info → oracle_ads-2.12.10rc0.dist-info}/entry_points.txt +0 -0
@@ -360,7 +360,7 @@ class NeuralProphetOperatorModel(ForecastOperatorBaseModel):
360
360
  pd.Series(
361
361
  m.state_dict(),
362
362
  index=m.state_dict().keys(),
363
- name=s_id,
363
+ name=s_id if self.target_cat_col else self.original_target_column,
364
364
  )
365
365
  )
366
366
  all_model_states = pd.concat(model_states, axis=1)
@@ -373,6 +373,13 @@ class NeuralProphetOperatorModel(ForecastOperatorBaseModel):
373
373
  # If the key is present, call the "explain_model" method
374
374
  self.explain_model()
375
375
 
376
+ if not self.target_cat_col:
377
+ self.formatted_global_explanation = self.formatted_global_explanation.rename(
378
+ {"Series 1": self.original_target_column},
379
+ axis=1,
380
+ )
381
+ self.formatted_local_explanation.drop("Series", axis=1, inplace=True)
382
+
376
383
  # Create a markdown section for the global explainability
377
384
  global_explanation_section = rc.Block(
378
385
  rc.Heading("Global Explainability", level=2),
@@ -385,14 +392,14 @@ class NeuralProphetOperatorModel(ForecastOperatorBaseModel):
385
392
  blocks = [
386
393
  rc.DataTable(
387
394
  local_ex_df.drop("Series", axis=1),
388
- label=s_id,
395
+ label=s_id if self.target_cat_col else None,
389
396
  index=True,
390
397
  )
391
398
  for s_id, local_ex_df in self.local_explanation.items()
392
399
  ]
393
400
  local_explanation_section = rc.Block(
394
401
  rc.Heading("Local Explanation of Models", level=2),
395
- rc.Select(blocks=blocks),
402
+ rc.Select(blocks=blocks) if len(blocks) > 1 else blocks[0],
396
403
  )
397
404
 
398
405
  # Append the global explanation text and section to the "all_sections" list
@@ -256,6 +256,7 @@ class ProphetOperatorModel(ForecastOperatorBaseModel):
256
256
  self.outputs[s_id], include_legend=True
257
257
  ),
258
258
  series_ids=series_ids,
259
+ target_category_column=self.target_cat_col
259
260
  )
260
261
  section_1 = rc.Block(
261
262
  rc.Heading("Forecast Overview", level=2),
@@ -268,6 +269,7 @@ class ProphetOperatorModel(ForecastOperatorBaseModel):
268
269
  sec2 = _select_plot_list(
269
270
  lambda s_id: self.models[s_id].plot_components(self.outputs[s_id]),
270
271
  series_ids=series_ids,
272
+ target_category_column=self.target_cat_col
271
273
  )
272
274
  section_2 = rc.Block(
273
275
  rc.Heading("Forecast Broken Down by Trend Component", level=2), sec2
@@ -281,7 +283,9 @@ class ProphetOperatorModel(ForecastOperatorBaseModel):
281
283
  sec3_figs[s_id].gca(), self.models[s_id], self.outputs[s_id]
282
284
  )
283
285
  sec3 = _select_plot_list(
284
- lambda s_id: sec3_figs[s_id], series_ids=series_ids
286
+ lambda s_id: sec3_figs[s_id],
287
+ series_ids=series_ids,
288
+ target_category_column=self.target_cat_col
285
289
  )
286
290
  section_3 = rc.Block(rc.Heading("Forecast Changepoints", level=2), sec3)
287
291
 
@@ -295,7 +299,7 @@ class ProphetOperatorModel(ForecastOperatorBaseModel):
295
299
  pd.Series(
296
300
  m.seasonalities,
297
301
  index=pd.Index(m.seasonalities.keys(), dtype="object"),
298
- name=s_id,
302
+ name=s_id if self.target_cat_col else self.original_target_column,
299
303
  dtype="object",
300
304
  )
301
305
  )
@@ -316,15 +320,6 @@ class ProphetOperatorModel(ForecastOperatorBaseModel):
316
320
  global_explanation_df / global_explanation_df.sum(axis=0) * 100
317
321
  )
318
322
 
319
- # Create a markdown section for the global explainability
320
- global_explanation_section = rc.Block(
321
- rc.Heading("Global Explanation of Models", level=2),
322
- rc.Text(
323
- "The following tables provide the feature attribution for the global explainability."
324
- ),
325
- rc.DataTable(self.formatted_global_explanation, index=True),
326
- )
327
-
328
323
  aggregate_local_explanations = pd.DataFrame()
329
324
  for s_id, local_ex_df in self.local_explanation.items():
330
325
  local_ex_df_copy = local_ex_df.copy()
@@ -334,17 +329,33 @@ class ProphetOperatorModel(ForecastOperatorBaseModel):
334
329
  )
335
330
  self.formatted_local_explanation = aggregate_local_explanations
336
331
 
332
+ if not self.target_cat_col:
333
+ self.formatted_global_explanation = self.formatted_global_explanation.rename(
334
+ {"Series 1": self.original_target_column},
335
+ axis=1,
336
+ )
337
+ self.formatted_local_explanation.drop("Series", axis=1, inplace=True)
338
+
339
+ # Create a markdown section for the global explainability
340
+ global_explanation_section = rc.Block(
341
+ rc.Heading("Global Explanation of Models", level=2),
342
+ rc.Text(
343
+ "The following tables provide the feature attribution for the global explainability."
344
+ ),
345
+ rc.DataTable(self.formatted_global_explanation, index=True),
346
+ )
347
+
337
348
  blocks = [
338
349
  rc.DataTable(
339
350
  local_ex_df.div(local_ex_df.abs().sum(axis=1), axis=0) * 100,
340
- label=s_id,
351
+ label=s_id if self.target_cat_col else None,
341
352
  index=True,
342
353
  )
343
354
  for s_id, local_ex_df in self.local_explanation.items()
344
355
  ]
345
356
  local_explanation_section = rc.Block(
346
357
  rc.Heading("Local Explanation of Models", level=2),
347
- rc.Select(blocks=blocks),
358
+ rc.Select(blocks=blocks) if len(blocks) > 1 else blocks[0],
348
359
  )
349
360
 
350
361
  # Append the global explanation text and section to the "all_sections" list
@@ -358,11 +369,7 @@ class ProphetOperatorModel(ForecastOperatorBaseModel):
358
369
  logger.debug(f"Full Traceback: {traceback.format_exc()}")
359
370
 
360
371
  model_description = rc.Text(
361
- "Prophet is a procedure for forecasting time series data based on an additive "
362
- "model where non-linear trends are fit with yearly, weekly, and daily seasonality, "
363
- "plus holiday effects. It works best with time series that have strong seasonal "
364
- "effects and several seasons of historical data. Prophet is robust to missing "
365
- "data and shifts in the trend, and typically handles outliers well."
372
+ """Prophet is a procedure for forecasting time series data based on an additive model where non-linear trends are fit with yearly, weekly, and daily seasonality, plus holiday effects. It works best with time series that have strong seasonal effects and several seasons of historical data. Prophet is robust to missing data and shifts in the trend, and typically handles outliers well."""
366
373
  )
367
374
  other_sections = all_sections
368
375
 
@@ -37,6 +37,9 @@ spec:
37
37
  nullable: true
38
38
  required: false
39
39
  type: dict
40
+ data:
41
+ nullable: true
42
+ required: false
40
43
  format:
41
44
  allowed:
42
45
  - csv
@@ -48,6 +51,7 @@ spec:
48
51
  - sql_query
49
52
  - hdf
50
53
  - tsv
54
+ - pandas
51
55
  required: false
52
56
  type: string
53
57
  columns:
@@ -92,6 +96,9 @@ spec:
92
96
  nullable: true
93
97
  required: false
94
98
  type: dict
99
+ data:
100
+ nullable: true
101
+ required: false
95
102
  format:
96
103
  allowed:
97
104
  - csv
@@ -103,6 +110,7 @@ spec:
103
110
  - sql_query
104
111
  - hdf
105
112
  - tsv
113
+ - pandas
106
114
  required: false
107
115
  type: string
108
116
  columns:
@@ -146,6 +154,9 @@ spec:
146
154
  nullable: true
147
155
  required: false
148
156
  type: dict
157
+ data:
158
+ nullable: true
159
+ required: false
149
160
  format:
150
161
  allowed:
151
162
  - csv
@@ -157,6 +168,7 @@ spec:
157
168
  - sql_query
158
169
  - hdf
159
170
  - tsv
171
+ - pandas
160
172
  required: false
161
173
  type: string
162
174
  columns:
@@ -332,6 +344,7 @@ spec:
332
344
  - HIGH_ACCURACY
333
345
  - BALANCED
334
346
  - FAST_APPROXIMATE
347
+ - AUTOMLX
335
348
 
336
349
  generate_report:
337
350
  type: boolean
@@ -250,8 +250,8 @@ def evaluate_train_metrics(output):
250
250
  return total_metrics
251
251
 
252
252
 
253
- def _select_plot_list(fn, series_ids):
254
- blocks = [rc.Widget(fn(s_id=s_id), label=s_id) for s_id in series_ids]
253
+ def _select_plot_list(fn, series_ids, target_category_column):
254
+ blocks = [rc.Widget(fn(s_id=s_id), label=s_id if target_category_column else None) for s_id in series_ids]
255
255
  return rc.Select(blocks=blocks) if len(blocks) > 1 else blocks[0]
256
256
 
257
257
 
@@ -283,6 +283,7 @@ def get_forecast_plots(
283
283
  horizon,
284
284
  test_data=None,
285
285
  ci_interval_width=0.95,
286
+ target_category_column=None
286
287
  ):
287
288
  def plot_forecast_plotly(s_id):
288
289
  fig = go.Figure()
@@ -379,7 +380,7 @@ def get_forecast_plots(
379
380
  )
380
381
  return fig
381
382
 
382
- return _select_plot_list(plot_forecast_plotly, forecast_output.list_series_ids())
383
+ return _select_plot_list(plot_forecast_plotly, forecast_output.list_series_ids(), target_category_column)
383
384
 
384
385
 
385
386
  def convert_target(target: str, target_col: str):
ads/telemetry/base.py CHANGED
@@ -1,17 +1,18 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
- # Copyright (c) 2024 Oracle and/or its affiliates.
2
+ # Copyright (c) 2024, 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
 
6
5
  import logging
7
6
 
8
- from ads import set_auth
7
+ import oci
8
+
9
9
  from ads.common import oci_client as oc
10
- from ads.common.auth import default_signer
10
+ from ads.common.auth import default_signer, resource_principal
11
11
  from ads.config import OCI_RESOURCE_PRINCIPAL_VERSION
12
12
 
13
-
14
13
  logger = logging.getLogger(__name__)
14
+
15
+
15
16
  class TelemetryBase:
16
17
  """Base class for Telemetry Client."""
17
18
 
@@ -25,15 +26,21 @@ class TelemetryBase:
25
26
  namespace : str, optional
26
27
  Namespace of the OCI object storage bucket, by default None.
27
28
  """
29
+ # Use resource principal as authentication method if available,
30
+ # however, do not change the ADS authentication if user configured it by set_auth.
28
31
  if OCI_RESOURCE_PRINCIPAL_VERSION:
29
- set_auth("resource_principal")
30
- self._auth = default_signer()
31
- self.os_client = oc.OCIClientFactory(**self._auth).object_storage
32
+ self._auth = resource_principal()
33
+ else:
34
+ self._auth = default_signer()
35
+ self.os_client: oci.object_storage.ObjectStorageClient = oc.OCIClientFactory(
36
+ **self._auth
37
+ ).object_storage
32
38
  self.bucket = bucket
33
39
  self._namespace = namespace
34
40
  self._service_endpoint = None
35
- logger.debug(f"Initialized Telemetry. Namespace: {self.namespace}, Bucket: {self.bucket}")
36
-
41
+ logger.debug(
42
+ f"Initialized Telemetry. Namespace: {self.namespace}, Bucket: {self.bucket}"
43
+ )
37
44
 
38
45
  @property
39
46
  def namespace(self) -> str:
@@ -58,5 +65,5 @@ class TelemetryBase:
58
65
  Tenancy-specific endpoint.
59
66
  """
60
67
  if not self._service_endpoint:
61
- self._service_endpoint = self.os_client.base_client.endpoint
68
+ self._service_endpoint = str(self.os_client.base_client.endpoint)
62
69
  return self._service_endpoint
ads/telemetry/client.py CHANGED
@@ -1,17 +1,19 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
- # Copyright (c) 2024 Oracle and/or its affiliates.
2
+ # Copyright (c) 2024, 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
 
6
5
 
7
6
  import logging
8
7
  import threading
8
+ import traceback
9
9
  import urllib.parse
10
- import requests
11
- from requests import Response
12
- from .base import TelemetryBase
10
+ from typing import Optional
11
+
12
+ import oci
13
+
13
14
  from ads.config import DEBUG_TELEMETRY
14
15
 
16
+ from .base import TelemetryBase
15
17
 
16
18
  logger = logging.getLogger(__name__)
17
19
 
@@ -32,7 +34,7 @@ class TelemetryClient(TelemetryBase):
32
34
  >>> import traceback
33
35
  >>> from ads.telemetry.client import TelemetryClient
34
36
  >>> AQUA_BUCKET = os.environ.get("AQUA_BUCKET", "service-managed-models")
35
- >>> AQUA_BUCKET_NS = os.environ.get("AQUA_BUCKET_NS", "ociodscdev")
37
+ >>> AQUA_BUCKET_NS = os.environ.get("AQUA_BUCKET_NS", "namespace")
36
38
  >>> telemetry = TelemetryClient(bucket=AQUA_BUCKET, namespace=AQUA_BUCKET_NS)
37
39
  >>> telemetry.record_event_async(category="aqua/service/model", action="create") # records create action
38
40
  >>> telemetry.record_event_async(category="aqua/service/model/create", action="shape", detail="VM.GPU.A10.1")
@@ -45,7 +47,7 @@ class TelemetryClient(TelemetryBase):
45
47
 
46
48
  def record_event(
47
49
  self, category: str = None, action: str = None, detail: str = None, **kwargs
48
- ) -> Response:
50
+ ) -> Optional[int]:
49
51
  """Send a head request to generate an event record.
50
52
 
51
53
  Parameters
@@ -62,23 +64,41 @@ class TelemetryClient(TelemetryBase):
62
64
 
63
65
  Returns
64
66
  -------
65
- Response
67
+ int
68
+ The status code for the telemetry request.
69
+ 200: The the object exists for the telemetry request
70
+ 404: The the object does not exist for the telemetry request.
71
+ Note that for telemetry purpose, the object does not need to be exist.
72
+ `None` will be returned if the telemetry request failed.
66
73
  """
67
74
  try:
68
75
  if not category or not action:
69
76
  raise ValueError("Please specify the category and the action.")
70
77
  if detail:
71
78
  category, action = f"{category}/{action}", detail
79
+ # Here `endpoint`` is for debugging purpose
80
+ # For some federated/domain users, the `endpoint` may not be a valid URL
72
81
  endpoint = f"{self.service_endpoint}/n/{self.namespace}/b/{self.bucket}/o/telemetry/{category}/{action}"
73
- headers = {"User-Agent": self._encode_user_agent(**kwargs)}
74
82
  logger.debug(f"Sending telemetry to endpoint: {endpoint}")
75
- signer = self._auth["signer"]
76
- response = requests.head(endpoint, auth=signer, headers=headers)
77
- logger.debug(f"Telemetry status code: {response.status_code}")
78
- return response
83
+
84
+ self.os_client.base_client.user_agent = self._encode_user_agent(**kwargs)
85
+ try:
86
+ response: oci.response.Response = self.os_client.head_object(
87
+ namespace_name=self.namespace,
88
+ bucket_name=self.bucket,
89
+ object_name=f"telemetry/{category}/{action}",
90
+ )
91
+ logger.debug(f"Telemetry status: {response.status}")
92
+ return response.status
93
+ except oci.exceptions.ServiceError as ex:
94
+ if ex.status == 404:
95
+ return ex.status
96
+ raise ex
79
97
  except Exception as e:
80
98
  if DEBUG_TELEMETRY:
81
99
  logger.error(f"There is an error recording telemetry: {e}")
100
+ traceback.print_exc()
101
+ return None
82
102
 
83
103
  def record_event_async(
84
104
  self, category: str = None, action: str = None, detail: str = None, **kwargs