oracle-ads 2.12.8__py3-none-any.whl → 2.12.10__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/__init__.py +4 -3
- ads/aqua/app.py +40 -18
- ads/aqua/client/__init__.py +3 -0
- ads/aqua/client/client.py +799 -0
- ads/aqua/common/enums.py +3 -0
- ads/aqua/common/utils.py +62 -2
- ads/aqua/data.py +2 -19
- ads/aqua/evaluation/entities.py +6 -0
- ads/aqua/evaluation/evaluation.py +45 -15
- ads/aqua/extension/aqua_ws_msg_handler.py +14 -7
- ads/aqua/extension/base_handler.py +12 -9
- ads/aqua/extension/deployment_handler.py +8 -4
- ads/aqua/extension/finetune_handler.py +8 -14
- ads/aqua/extension/model_handler.py +30 -6
- ads/aqua/extension/ui_handler.py +13 -1
- ads/aqua/finetuning/constants.py +5 -2
- ads/aqua/finetuning/entities.py +73 -17
- ads/aqua/finetuning/finetuning.py +110 -82
- ads/aqua/model/entities.py +5 -1
- ads/aqua/model/model.py +230 -104
- ads/aqua/modeldeployment/deployment.py +35 -11
- ads/aqua/modeldeployment/entities.py +7 -4
- ads/aqua/ui.py +24 -2
- ads/cli.py +16 -8
- ads/common/auth.py +9 -9
- ads/llm/autogen/__init__.py +2 -0
- ads/llm/autogen/constants.py +15 -0
- ads/llm/autogen/reports/__init__.py +2 -0
- ads/llm/autogen/reports/base.py +67 -0
- ads/llm/autogen/reports/data.py +103 -0
- ads/llm/autogen/reports/session.py +526 -0
- ads/llm/autogen/reports/templates/chat_box.html +13 -0
- ads/llm/autogen/reports/templates/chat_box_lt.html +5 -0
- ads/llm/autogen/reports/templates/chat_box_rt.html +6 -0
- ads/llm/autogen/reports/utils.py +56 -0
- ads/llm/autogen/v02/__init__.py +4 -0
- ads/llm/autogen/{client_v02.py → v02/client.py} +23 -10
- ads/llm/autogen/v02/log_handlers/__init__.py +2 -0
- ads/llm/autogen/v02/log_handlers/oci_file_handler.py +83 -0
- ads/llm/autogen/v02/loggers/__init__.py +6 -0
- ads/llm/autogen/v02/loggers/metric_logger.py +320 -0
- ads/llm/autogen/v02/loggers/session_logger.py +580 -0
- ads/llm/autogen/v02/loggers/utils.py +86 -0
- ads/llm/autogen/v02/runtime_logging.py +163 -0
- ads/llm/guardrails/base.py +6 -5
- ads/llm/langchain/plugins/chat_models/oci_data_science.py +46 -20
- ads/llm/langchain/plugins/llms/oci_data_science_model_deployment_endpoint.py +38 -11
- ads/model/__init__.py +11 -13
- ads/model/artifact.py +47 -8
- ads/model/extractor/embedding_onnx_extractor.py +80 -0
- ads/model/framework/embedding_onnx_model.py +438 -0
- ads/model/generic_model.py +26 -24
- ads/model/model_metadata.py +8 -7
- ads/opctl/config/merger.py +13 -14
- ads/opctl/operator/common/operator_config.py +4 -4
- ads/opctl/operator/lowcode/common/transformations.py +50 -8
- ads/opctl/operator/lowcode/common/utils.py +22 -6
- ads/opctl/operator/lowcode/forecast/__main__.py +10 -0
- ads/opctl/operator/lowcode/forecast/const.py +3 -0
- ads/opctl/operator/lowcode/forecast/model/arima.py +19 -13
- ads/opctl/operator/lowcode/forecast/model/automlx.py +129 -36
- ads/opctl/operator/lowcode/forecast/model/autots.py +1 -0
- ads/opctl/operator/lowcode/forecast/model/base_model.py +58 -17
- ads/opctl/operator/lowcode/forecast/model/forecast_datasets.py +1 -1
- ads/opctl/operator/lowcode/forecast/model/neuralprophet.py +10 -3
- ads/opctl/operator/lowcode/forecast/model/prophet.py +25 -18
- ads/opctl/operator/lowcode/forecast/model_evaluator.py +3 -2
- ads/opctl/operator/lowcode/forecast/operator_config.py +31 -0
- ads/opctl/operator/lowcode/forecast/schema.yaml +76 -0
- ads/opctl/operator/lowcode/forecast/utils.py +8 -6
- ads/opctl/operator/lowcode/forecast/whatifserve/__init__.py +7 -0
- ads/opctl/operator/lowcode/forecast/whatifserve/deployment_manager.py +233 -0
- ads/opctl/operator/lowcode/forecast/whatifserve/score.py +238 -0
- ads/telemetry/base.py +18 -11
- ads/telemetry/client.py +33 -13
- ads/templates/schemas/openapi.json +1740 -0
- ads/templates/score_embedding_onnx.jinja2 +202 -0
- {oracle_ads-2.12.8.dist-info → oracle_ads-2.12.10.dist-info}/METADATA +11 -10
- {oracle_ads-2.12.8.dist-info → oracle_ads-2.12.10.dist-info}/RECORD +82 -56
- {oracle_ads-2.12.8.dist-info → oracle_ads-2.12.10.dist-info}/LICENSE.txt +0 -0
- {oracle_ads-2.12.8.dist-info → oracle_ads-2.12.10.dist-info}/WHEEL +0 -0
- {oracle_ads-2.12.8.dist-info → oracle_ads-2.12.10.dist-info}/entry_points.txt +0 -0
@@ -1,8 +1,7 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
|
-
# Copyright (c) 2024 Oracle and/or its affiliates.
|
2
|
+
# Copyright (c) 2024, 2025 Oracle and/or its affiliates.
|
3
3
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
4
4
|
|
5
|
-
import logging
|
6
5
|
import shlex
|
7
6
|
from typing import Dict, List, Optional, Union
|
8
7
|
|
@@ -110,6 +109,8 @@ class AquaDeploymentApp(AquaApp):
|
|
110
109
|
private_endpoint_id: Optional[str] = None,
|
111
110
|
container_image_uri: Optional[None] = None,
|
112
111
|
cmd_var: List[str] = None,
|
112
|
+
freeform_tags: Optional[dict] = None,
|
113
|
+
defined_tags: Optional[dict] = None,
|
113
114
|
) -> "AquaDeployment":
|
114
115
|
"""
|
115
116
|
Creates a new Aqua deployment
|
@@ -163,6 +164,10 @@ class AquaDeploymentApp(AquaApp):
|
|
163
164
|
Required parameter for BYOC based deployments if this parameter was not set during model registration.
|
164
165
|
cmd_var: List[str]
|
165
166
|
The cmd of model deployment container runtime.
|
167
|
+
freeform_tags: dict
|
168
|
+
Freeform tags for the model deployment
|
169
|
+
defined_tags: dict
|
170
|
+
Defined tags for the model deployment
|
166
171
|
Returns
|
167
172
|
-------
|
168
173
|
AquaDeployment
|
@@ -172,7 +177,11 @@ class AquaDeploymentApp(AquaApp):
|
|
172
177
|
# TODO validate if the service model has no artifact and if it requires import step before deployment.
|
173
178
|
# Create a model catalog entry in the user compartment
|
174
179
|
aqua_model = AquaModelApp().create(
|
175
|
-
model_id=model_id,
|
180
|
+
model_id=model_id,
|
181
|
+
compartment_id=compartment_id,
|
182
|
+
project_id=project_id,
|
183
|
+
freeform_tags=freeform_tags,
|
184
|
+
defined_tags=defined_tags,
|
176
185
|
)
|
177
186
|
|
178
187
|
tags = {}
|
@@ -261,7 +270,7 @@ class AquaDeploymentApp(AquaApp):
|
|
261
270
|
f"field. Either re-register the model with custom container URI, or set container_image_uri "
|
262
271
|
f"parameter when creating this deployment."
|
263
272
|
) from err
|
264
|
-
|
273
|
+
logger.info(
|
265
274
|
f"Aqua Image used for deploying {aqua_model.id} : {container_image_uri}"
|
266
275
|
)
|
267
276
|
|
@@ -272,14 +281,14 @@ class AquaDeploymentApp(AquaApp):
|
|
272
281
|
default_cmd_var = shlex.split(cmd_var_string)
|
273
282
|
if default_cmd_var:
|
274
283
|
cmd_var = validate_cmd_var(default_cmd_var, cmd_var)
|
275
|
-
|
284
|
+
logger.info(f"CMD used for deploying {aqua_model.id} :{cmd_var}")
|
276
285
|
except ValueError:
|
277
|
-
|
286
|
+
logger.debug(
|
278
287
|
f"CMD will be ignored for this deployment as {AQUA_DEPLOYMENT_CONTAINER_CMD_VAR_METADATA_NAME} "
|
279
288
|
f"key is not available in the custom metadata field for this model."
|
280
289
|
)
|
281
290
|
except Exception as e:
|
282
|
-
|
291
|
+
logger.error(
|
283
292
|
f"There was an issue processing CMD arguments. Error: {str(e)}"
|
284
293
|
)
|
285
294
|
|
@@ -375,7 +384,7 @@ class AquaDeploymentApp(AquaApp):
|
|
375
384
|
if key not in env_var:
|
376
385
|
env_var.update(env)
|
377
386
|
|
378
|
-
|
387
|
+
logger.info(f"Env vars used for deploying {aqua_model.id} :{env_var}")
|
379
388
|
|
380
389
|
# Start model deployment
|
381
390
|
# configure model deployment infrastructure
|
@@ -418,20 +427,26 @@ class AquaDeploymentApp(AquaApp):
|
|
418
427
|
if cmd_var:
|
419
428
|
container_runtime.with_cmd(cmd_var)
|
420
429
|
|
430
|
+
tags = {**tags, **(freeform_tags or {})}
|
421
431
|
# configure model deployment and deploy model on container runtime
|
422
432
|
deployment = (
|
423
433
|
ModelDeployment()
|
424
434
|
.with_display_name(display_name)
|
425
435
|
.with_description(description)
|
426
436
|
.with_freeform_tags(**tags)
|
437
|
+
.with_defined_tags(**(defined_tags or {}))
|
427
438
|
.with_infrastructure(infrastructure)
|
428
439
|
.with_runtime(container_runtime)
|
429
440
|
).deploy(wait_for_completion=False)
|
430
441
|
|
442
|
+
deployment_id = deployment.dsc_model_deployment.id
|
443
|
+
logger.info(
|
444
|
+
f"Aqua model deployment {deployment_id} created for model {aqua_model.id}."
|
445
|
+
)
|
431
446
|
model_type = (
|
432
447
|
AQUA_MODEL_TYPE_CUSTOM if is_fine_tuned_model else AQUA_MODEL_TYPE_SERVICE
|
433
448
|
)
|
434
|
-
|
449
|
+
|
435
450
|
# we arbitrarily choose last 8 characters of OCID to identify MD in telemetry
|
436
451
|
telemetry_kwargs = {"ocid": get_ocid_substring(deployment_id, key_len=8)}
|
437
452
|
|
@@ -527,6 +542,9 @@ class AquaDeploymentApp(AquaApp):
|
|
527
542
|
value=state,
|
528
543
|
)
|
529
544
|
|
545
|
+
logger.info(
|
546
|
+
f"Fetched {len(results)} model deployments from compartment_id={compartment_id}."
|
547
|
+
)
|
530
548
|
# tracks number of times deployment listing was called
|
531
549
|
self.telemetry.record_event_async(category="aqua/deployment", action="list")
|
532
550
|
|
@@ -534,18 +552,21 @@ class AquaDeploymentApp(AquaApp):
|
|
534
552
|
|
535
553
|
@telemetry(entry_point="plugin=deployment&action=delete", name="aqua")
|
536
554
|
def delete(self, model_deployment_id: str):
|
555
|
+
logger.info(f"Deleting model deployment {model_deployment_id}.")
|
537
556
|
return self.ds_client.delete_model_deployment(
|
538
557
|
model_deployment_id=model_deployment_id
|
539
558
|
).data
|
540
559
|
|
541
560
|
@telemetry(entry_point="plugin=deployment&action=deactivate", name="aqua")
|
542
561
|
def deactivate(self, model_deployment_id: str):
|
562
|
+
logger.info(f"Deactivating model deployment {model_deployment_id}.")
|
543
563
|
return self.ds_client.deactivate_model_deployment(
|
544
564
|
model_deployment_id=model_deployment_id
|
545
565
|
).data
|
546
566
|
|
547
567
|
@telemetry(entry_point="plugin=deployment&action=activate", name="aqua")
|
548
568
|
def activate(self, model_deployment_id: str):
|
569
|
+
logger.info(f"Activating model deployment {model_deployment_id}.")
|
549
570
|
return self.ds_client.activate_model_deployment(
|
550
571
|
model_deployment_id=model_deployment_id
|
551
572
|
).data
|
@@ -567,6 +588,8 @@ class AquaDeploymentApp(AquaApp):
|
|
567
588
|
AquaDeploymentDetail:
|
568
589
|
The instance of the Aqua model deployment details.
|
569
590
|
"""
|
591
|
+
logger.info(f"Fetching model deployment details for {model_deployment_id}.")
|
592
|
+
|
570
593
|
model_deployment = self.ds_client.get_model_deployment(
|
571
594
|
model_deployment_id=model_deployment_id, **kwargs
|
572
595
|
).data
|
@@ -582,7 +605,8 @@ class AquaDeploymentApp(AquaApp):
|
|
582
605
|
|
583
606
|
if not oci_aqua:
|
584
607
|
raise AquaRuntimeError(
|
585
|
-
f"Target deployment {model_deployment_id} is not Aqua deployment
|
608
|
+
f"Target deployment {model_deployment_id} is not Aqua deployment as it does not contain "
|
609
|
+
f"{Tags.AQUA_TAG} tag."
|
586
610
|
)
|
587
611
|
|
588
612
|
log_id = ""
|
@@ -640,7 +664,7 @@ class AquaDeploymentApp(AquaApp):
|
|
640
664
|
config = self.get_config(model_id, AQUA_MODEL_DEPLOYMENT_CONFIG)
|
641
665
|
if not config:
|
642
666
|
logger.debug(
|
643
|
-
f"Deployment config for custom model: {model_id} is not available."
|
667
|
+
f"Deployment config for custom model: {model_id} is not available. Use defaults."
|
644
668
|
)
|
645
669
|
return config
|
646
670
|
|
@@ -98,9 +98,12 @@ class AquaDeployment(DataClassSerializable):
|
|
98
98
|
),
|
99
99
|
)
|
100
100
|
|
101
|
-
|
102
|
-
|
103
|
-
|
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=
|
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
|
484
|
+
"""Lists all available job shapes for the specified compartment.
|
485
485
|
|
486
486
|
Parameters
|
487
487
|
----------
|
488
488
|
**kwargs
|
489
|
-
|
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.
|
ads/cli.py
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
|
-
#
|
3
|
-
|
4
|
-
# Copyright (c) 2021, 2024 Oracle and/or its affiliates.
|
2
|
+
# Copyright (c) 2021, 2025 Oracle and/or its affiliates.
|
5
3
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
6
4
|
|
5
|
+
import json
|
6
|
+
import logging
|
7
7
|
import sys
|
8
8
|
import traceback
|
9
|
-
|
9
|
+
import uuid
|
10
10
|
|
11
11
|
import fire
|
12
|
+
from pydantic import BaseModel
|
12
13
|
|
13
14
|
from ads.common import logger
|
14
15
|
|
@@ -27,7 +28,7 @@ except Exception as ex:
|
|
27
28
|
)
|
28
29
|
logger.debug(ex)
|
29
30
|
logger.debug(traceback.format_exc())
|
30
|
-
exit()
|
31
|
+
sys.exit()
|
31
32
|
|
32
33
|
# https://packaging.python.org/en/latest/guides/single-sourcing-package-version/#single-sourcing-the-package-version
|
33
34
|
if sys.version_info >= (3, 8):
|
@@ -84,7 +85,13 @@ def serialize(data):
|
|
84
85
|
The string representation of each dataclass object.
|
85
86
|
"""
|
86
87
|
if isinstance(data, list):
|
87
|
-
|
88
|
+
for item in data:
|
89
|
+
if isinstance(item, BaseModel):
|
90
|
+
print(json.dumps(item.dict(), indent=4))
|
91
|
+
else:
|
92
|
+
print(str(item))
|
93
|
+
elif isinstance(data, BaseModel):
|
94
|
+
print(json.dumps(data.dict(), indent=4))
|
88
95
|
else:
|
89
96
|
print(str(data))
|
90
97
|
|
@@ -122,8 +129,9 @@ def exit_program(ex: Exception, logger: "logging.Logger") -> None:
|
|
122
129
|
... exit_program(e, logger)
|
123
130
|
"""
|
124
131
|
|
125
|
-
|
126
|
-
logger.
|
132
|
+
request_id = str(uuid.uuid4())
|
133
|
+
logger.debug(f"Error Request ID: {request_id}\nError: {traceback.format_exc()}")
|
134
|
+
logger.error(f"Error Request ID: {request_id}\n" f"Error: {str(ex)}")
|
127
135
|
|
128
136
|
exit_code = getattr(ex, "exit_code", 1)
|
129
137
|
logger.error(f"Exit code: {exit_code}")
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
1023
|
+
logger.debug(f"OCI profile set to {self.profile}")
|
1024
1024
|
else:
|
1025
1025
|
ads.set_auth(auth=AuthType.RESOURCE_PRINCIPAL)
|
1026
|
-
logger.
|
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):
|
ads/llm/autogen/__init__.py
CHANGED
@@ -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,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
|