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
ads/aqua/model/model.py CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python
2
- # Copyright (c) 2024 Oracle and/or its affiliates.
2
+ # Copyright (c) 2024, 2025 Oracle and/or its affiliates.
3
3
  # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
4
4
  import os
5
5
  import pathlib
@@ -15,6 +15,7 @@ from oci.data_science.models import JobRun, Metadata, Model, UpdateModelDetails
15
15
  from ads.aqua import ODSC_MODEL_COMPARTMENT_OCID, logger
16
16
  from ads.aqua.app import AquaApp
17
17
  from ads.aqua.common.enums import (
18
+ CustomInferenceContainerTypeFamily,
18
19
  FineTuningContainerTypeFamily,
19
20
  InferenceContainerTypeFamily,
20
21
  Tags,
@@ -23,6 +24,7 @@ from ads.aqua.common.errors import AquaRuntimeError, AquaValueError
23
24
  from ads.aqua.common.utils import (
24
25
  LifecycleStatus,
25
26
  _build_resource_identifier,
27
+ cleanup_local_hf_model_artifact,
26
28
  copy_model_config,
27
29
  create_word_icon,
28
30
  generate_tei_cmd_var,
@@ -376,8 +378,10 @@ class AquaModelApp(AquaApp):
376
378
  f"Failed to delete model:{model_id}. Only registered models or finetuned model can be deleted."
377
379
  )
378
380
 
379
- @telemetry(entry_point="plugin=model&action=delete", name="aqua")
380
- def edit_registered_model(self, id, inference_container, enable_finetuning, task):
381
+ @telemetry(entry_point="plugin=model&action=edit", name="aqua")
382
+ def edit_registered_model(
383
+ self, id, inference_container, inference_container_uri, enable_finetuning, task
384
+ ):
381
385
  """Edits the default config of unverified registered model.
382
386
 
383
387
  Parameters
@@ -386,6 +390,8 @@ class AquaModelApp(AquaApp):
386
390
  The model OCID.
387
391
  inference_container: str.
388
392
  The inference container family name
393
+ inference_container_uri: str
394
+ The inference container uri for embedding models
389
395
  enable_finetuning: str
390
396
  Flag to enable or disable finetuning over the model. Defaults to None
391
397
  task:
@@ -401,19 +407,44 @@ class AquaModelApp(AquaApp):
401
407
  if ds_model.freeform_tags.get(Tags.BASE_MODEL_CUSTOM, None):
402
408
  if ds_model.freeform_tags.get(Tags.AQUA_SERVICE_MODEL_TAG, None):
403
409
  raise AquaRuntimeError(
404
- f"Failed to edit model:{id}. Only registered unverified models can be edited."
410
+ "Only registered unverified models can be edited."
405
411
  )
406
412
  else:
407
413
  custom_metadata_list = ds_model.custom_metadata_list
408
414
  freeform_tags = ds_model.freeform_tags
409
415
  if inference_container:
410
- custom_metadata_list.add(
411
- key=ModelCustomMetadataFields.DEPLOYMENT_CONTAINER,
412
- value=inference_container,
413
- category=MetadataCustomCategory.OTHER,
414
- description="Deployment container mapping for SMC",
415
- replace=True,
416
- )
416
+ if (
417
+ inference_container in CustomInferenceContainerTypeFamily
418
+ and inference_container_uri is None
419
+ ):
420
+ raise AquaRuntimeError(
421
+ "Inference container URI must be provided."
422
+ )
423
+ else:
424
+ custom_metadata_list.add(
425
+ key=ModelCustomMetadataFields.DEPLOYMENT_CONTAINER,
426
+ value=inference_container,
427
+ category=MetadataCustomCategory.OTHER,
428
+ description="Deployment container mapping for SMC",
429
+ replace=True,
430
+ )
431
+ if inference_container_uri:
432
+ if (
433
+ inference_container in CustomInferenceContainerTypeFamily
434
+ or inference_container is None
435
+ ):
436
+ custom_metadata_list.add(
437
+ key=ModelCustomMetadataFields.DEPLOYMENT_CONTAINER_URI,
438
+ value=inference_container_uri,
439
+ category=MetadataCustomCategory.OTHER,
440
+ description=f"Inference container URI for {ds_model.display_name}",
441
+ replace=True,
442
+ )
443
+ else:
444
+ raise AquaRuntimeError(
445
+ f"Inference container URI can be edited only with container values: {CustomInferenceContainerTypeFamily.values()}"
446
+ )
447
+
417
448
  if enable_finetuning is not None:
418
449
  if enable_finetuning.lower() == "true":
419
450
  custom_metadata_list.add(
@@ -448,9 +479,7 @@ class AquaModelApp(AquaApp):
448
479
  )
449
480
  AquaApp().update_model(id, update_model_details)
450
481
  else:
451
- raise AquaRuntimeError(
452
- f"Failed to edit model:{id}. Only registered unverified models can be edited."
453
- )
482
+ raise AquaRuntimeError("Only registered unverified models can be edited.")
454
483
 
455
484
  def _fetch_metric_from_metadata(
456
485
  self,
@@ -869,8 +898,7 @@ class AquaModelApp(AquaApp):
869
898
  # only add cmd vars if inference container is not an SMC
870
899
  if (
871
900
  inference_container not in smc_container_set
872
- and inference_container
873
- == InferenceContainerTypeFamily.AQUA_TEI_CONTAINER_FAMILY
901
+ and inference_container in CustomInferenceContainerTypeFamily.values()
874
902
  ):
875
903
  cmd_vars = generate_tei_cmd_var(os_path)
876
904
  metadata.add(
@@ -1322,20 +1350,20 @@ class AquaModelApp(AquaApp):
1322
1350
  Returns
1323
1351
  -------
1324
1352
  model_artifact_path (str): Location where the model artifacts are downloaded.
1325
-
1326
1353
  """
1327
1354
  # Download the model from hub
1328
- if not local_dir:
1329
- local_dir = os.path.join(os.path.expanduser("~"), "cached-model")
1330
- local_dir = os.path.join(local_dir, model_name)
1331
- os.makedirs(local_dir, exist_ok=True)
1332
- snapshot_download(
1355
+ if local_dir:
1356
+ local_dir = os.path.join(local_dir, model_name)
1357
+ os.makedirs(local_dir, exist_ok=True)
1358
+
1359
+ # if local_dir is not set, the return value points to the cached data folder
1360
+ local_dir = snapshot_download(
1333
1361
  repo_id=model_name,
1334
1362
  local_dir=local_dir,
1335
1363
  allow_patterns=allow_patterns,
1336
1364
  ignore_patterns=ignore_patterns,
1337
1365
  )
1338
- # Upload to object storage and skip .cache/huggingface/ folder
1366
+ # Upload to object storage
1339
1367
  model_artifact_path = upload_folder(
1340
1368
  os_path=os_path,
1341
1369
  local_dir=local_dir,
@@ -1365,6 +1393,8 @@ class AquaModelApp(AquaApp):
1365
1393
  ignore_patterns (list): Model files matching any of the patterns are not downloaded.
1366
1394
  Example: ["*.json"] will ignore all .json files. ["folder/*"] will ignore all files under `folder`.
1367
1395
  Patterns are Standard Wildcards (globbing patterns) and rules can be found here: https://docs.python.org/3/library/fnmatch.html
1396
+ cleanup_model_cache (bool): Deletes downloaded files from local machine after model is successfully
1397
+ registered. Set to True by default.
1368
1398
 
1369
1399
  Returns:
1370
1400
  AquaModel:
@@ -1474,6 +1504,14 @@ class AquaModelApp(AquaApp):
1474
1504
  detail=validation_result.telemetry_model_name,
1475
1505
  )
1476
1506
 
1507
+ if (
1508
+ import_model_details.download_from_hf
1509
+ and import_model_details.cleanup_model_cache
1510
+ ):
1511
+ cleanup_local_hf_model_artifact(
1512
+ model_name=model_name, local_dir=import_model_details.local_dir
1513
+ )
1514
+
1477
1515
  return AquaModel(**aqua_model_attributes)
1478
1516
 
1479
1517
  def _if_show(self, model: DataScienceModel) -> bool:
ads/common/auth.py CHANGED
@@ -424,7 +424,7 @@ def create_signer(
424
424
  "signer": signer,
425
425
  "client_kwargs": client_kwargs,
426
426
  }
427
- logger.info(f"Using authentication signer type {type(signer)}.")
427
+ logger.debug(f"Using authentication signer type {type(signer)}.")
428
428
  return signer_dict
429
429
  else:
430
430
  signer_args = dict(
@@ -492,7 +492,7 @@ def default_signer(client_kwargs: Optional[Dict] = None) -> Dict:
492
492
  **(client_kwargs or {}),
493
493
  },
494
494
  }
495
- logger.info(f"Using authentication signer type {type(signer)}.")
495
+ logger.debug(f"Using authentication signer type {type(signer)}.")
496
496
  return signer_dict
497
497
  else:
498
498
  signer_args = dict(
@@ -621,7 +621,7 @@ class APIKey(AuthSignerGenerator):
621
621
  )
622
622
 
623
623
  oci.config.validate_config(configuration)
624
- logger.info(f"Using 'api_key' authentication.")
624
+ logger.debug(f"Using 'api_key' authentication.")
625
625
  return {
626
626
  "config": configuration,
627
627
  "signer": oci.signer.Signer(
@@ -684,7 +684,7 @@ class ResourcePrincipal(AuthSignerGenerator):
684
684
  "signer": oci.auth.signers.get_resource_principals_signer(),
685
685
  "client_kwargs": self.client_kwargs,
686
686
  }
687
- logger.info(f"Using 'resource_principal' authentication.")
687
+ logger.debug(f"Using 'resource_principal' authentication.")
688
688
  return signer_dict
689
689
 
690
690
  @staticmethod
@@ -747,7 +747,7 @@ class InstancePrincipal(AuthSignerGenerator):
747
747
  ),
748
748
  "client_kwargs": self.client_kwargs,
749
749
  }
750
- logger.info(f"Using 'instance_principal' authentication.")
750
+ logger.debug(f"Using 'instance_principal' authentication.")
751
751
  return signer_dict
752
752
 
753
753
 
@@ -814,7 +814,7 @@ class SecurityToken(AuthSignerGenerator):
814
814
  oci.config.from_file(self.oci_config_location, self.oci_key_profile)
815
815
  )
816
816
 
817
- logger.info(f"Using 'security_token' authentication.")
817
+ logger.debug(f"Using 'security_token' authentication.")
818
818
 
819
819
  for parameter in self.SECURITY_TOKEN_REQUIRED:
820
820
  if parameter not in configuration:
@@ -883,7 +883,7 @@ class SecurityToken(AuthSignerGenerator):
883
883
  )
884
884
 
885
885
  date_time = datetime.fromtimestamp(time_expired).strftime("%Y-%m-%d %H:%M:%S")
886
- logger.info(f"Session is valid until {date_time}.")
886
+ logger.debug(f"Session is valid until {date_time}.")
887
887
 
888
888
  def _read_security_token_file(self, security_token_file: str) -> str:
889
889
  """Reads security token from file.
@@ -1020,10 +1020,10 @@ class OCIAuthContext:
1020
1020
  """
1021
1021
  if self.profile:
1022
1022
  ads.set_auth(auth=AuthType.API_KEY, profile=self.profile)
1023
- logger.info(f"OCI profile set to {self.profile}")
1023
+ logger.debug(f"OCI profile set to {self.profile}")
1024
1024
  else:
1025
1025
  ads.set_auth(auth=AuthType.RESOURCE_PRINCIPAL)
1026
- logger.info(f"OCI auth set to resource principal")
1026
+ logger.debug(f"OCI auth set to resource principal")
1027
1027
  return self
1028
1028
 
1029
1029
  def __exit__(self, exc_type, exc_val, exc_tb):
@@ -0,0 +1,2 @@
1
+ # Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
2
+ # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
@@ -0,0 +1,15 @@
1
+ # Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
2
+ # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
3
+
4
+
5
+ class Events:
6
+ KEY = "event_name"
7
+
8
+ EXCEPTION = "exception"
9
+ LLM_CALL = "llm_call"
10
+ TOOL_CALL = "tool_call"
11
+ NEW_AGENT = "new_agent"
12
+ NEW_CLIENT = "new_client"
13
+ RECEIVED_MESSAGE = "received_message"
14
+ SESSION_START = "logging_session_start"
15
+ SESSION_STOP = "logging_session_stop"
@@ -0,0 +1,2 @@
1
+ # Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
2
+ # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
@@ -0,0 +1,67 @@
1
+ # Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
2
+ # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
3
+ import json
4
+ import logging
5
+ import os
6
+
7
+ from jinja2 import Environment, FileSystemLoader
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ class BaseReport:
13
+ """Base class containing utilities for generating reports."""
14
+
15
+ @staticmethod
16
+ def format_json_string(s) -> str:
17
+ """Formats the JSON string in markdown."""
18
+ return f"```json\n{json.dumps(json.loads(s), indent=2)}\n```"
19
+
20
+ @staticmethod
21
+ def _parse_date_time(datetime_string: str):
22
+ """Parses a datetime string in the logs into date and time.
23
+ Keeps only the seconds in the time.
24
+ """
25
+ date_str, time_str = datetime_string.split(" ", 1)
26
+ time_str = time_str.split(".", 1)[0]
27
+ return date_str, time_str
28
+
29
+ @staticmethod
30
+ def _preview_message(message: str, max_length=30) -> str:
31
+ """Shows the beginning part of a string message."""
32
+ # Return the entire string if it is less than the max_length
33
+ if len(message) <= max_length:
34
+ return message
35
+ # Go backward until we find the first whitespace
36
+ idx = 30
37
+ while not message[idx].isspace() and idx > 0:
38
+ idx -= 1
39
+ # If we found a whitespace
40
+ if idx > 0:
41
+ return message[:idx] + "..."
42
+ # If we didn't find a whitespace
43
+ return message[:30] + "..."
44
+
45
+ @classmethod
46
+ def _render_template(cls, template_path, **kwargs) -> str:
47
+ """Render Jinja template with kwargs."""
48
+ template_dir = os.path.join(os.path.dirname(__file__), "templates")
49
+ environment = Environment(
50
+ loader=FileSystemLoader(template_dir), autoescape=True
51
+ )
52
+ template = environment.get_template(template_path)
53
+ try:
54
+ html = template.render(**kwargs)
55
+ except Exception:
56
+ logger.error(
57
+ "Unable to render template %s with data:\n%s",
58
+ template_path,
59
+ str(kwargs),
60
+ )
61
+ return cls._render_template(
62
+ template_path=template_path,
63
+ sender=kwargs.get("sender", "N/A"),
64
+ content="TEMPLATE RENDER ERROR",
65
+ timestamp=kwargs.get("timestamp", ""),
66
+ )
67
+ return html
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env python
2
+ # Copyright (c) 2024 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
+ """Contains the data structure for logging and reporting."""
5
+ import copy
6
+ import json
7
+ from dataclasses import asdict, dataclass, field
8
+ from typing import Optional, Union
9
+
10
+ from ads.llm.autogen.constants import Events
11
+
12
+
13
+ @dataclass
14
+ class LogData:
15
+ """Base class for the data field of LogRecord."""
16
+
17
+ def to_dict(self):
18
+ """Convert the log data to dictionary."""
19
+ return asdict(self)
20
+
21
+
22
+ @dataclass
23
+ class LogRecord:
24
+ """Represents a log record.
25
+
26
+ The `data` field is for pre-defined structured data, which should be an instance of LogData.
27
+ The `kwargs` field is for freeform key value pairs.
28
+ """
29
+
30
+ session_id: str
31
+ thread_id: int
32
+ timestamp: str
33
+ event_name: str
34
+ source_id: Optional[int] = None
35
+ source_name: Optional[str] = None
36
+ # Structured data for specific type of logs
37
+ data: Optional[LogData] = None
38
+ # Freeform data
39
+ kwargs: dict = field(default_factory=dict)
40
+
41
+ def to_dict(self):
42
+ """Convert the log record to dictionary."""
43
+ return asdict(self)
44
+
45
+ def to_string(self):
46
+ """Serialize the log record to JSON string."""
47
+ return json.dumps(self.to_dict(), default=str)
48
+
49
+ @classmethod
50
+ def from_dict(cls, data: dict) -> "LogRecord":
51
+ """Initializes a LogRecord object from dictionary."""
52
+ event_mapping = {
53
+ Events.NEW_AGENT: AgentData,
54
+ Events.TOOL_CALL: ToolCallData,
55
+ Events.LLM_CALL: LLMCompletionData,
56
+ }
57
+ if Events.KEY not in data:
58
+ raise KeyError("event_name not found in data.")
59
+
60
+ data = copy.deepcopy(data)
61
+
62
+ event_name = data["event_name"]
63
+ if event_name in event_mapping and data.get("data"):
64
+ data["data"] = event_mapping[event_name](**data.pop("data"))
65
+
66
+ return cls(**data)
67
+
68
+
69
+ @dataclass
70
+ class AgentData(LogData):
71
+ """Represents agent log Data."""
72
+
73
+ agent_name: str
74
+ agent_class: str
75
+ agent_module: Optional[str] = None
76
+ is_manager: Optional[bool] = None
77
+
78
+
79
+ @dataclass
80
+ class LLMCompletionData(LogData):
81
+ """Represents LLM completion log data."""
82
+
83
+ invocation_id: str
84
+ request: dict
85
+ response: dict
86
+ start_time: str
87
+ end_time: str
88
+ cost: Optional[float] = None
89
+ is_cached: Optional[bool] = None
90
+
91
+
92
+ @dataclass
93
+ class ToolCallData(LogData):
94
+ """Represents tool call log data."""
95
+
96
+ tool_name: str
97
+ start_time: str
98
+ end_time: str
99
+ agent_name: str
100
+ agent_class: str
101
+ agent_module: Optional[str] = None
102
+ input_args: dict = field(default_factory=dict)
103
+ returns: Optional[Union[str, list, dict, tuple]] = None