oracle-ads 2.13.6__py3-none-any.whl → 2.13.7__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 +0 -5
- ads/aqua/app.py +133 -20
- ads/aqua/cli.py +2 -15
- ads/aqua/common/utils.py +12 -83
- ads/aqua/config/container_config.py +105 -69
- ads/aqua/config/evaluation/evaluation_service_config.py +40 -0
- ads/aqua/constants.py +22 -20
- ads/aqua/evaluation/evaluation.py +98 -32
- ads/aqua/extension/common_handler.py +3 -12
- ads/aqua/extension/common_ws_msg_handler.py +3 -24
- ads/aqua/extension/model_handler.py +59 -6
- ads/aqua/extension/models/ws_models.py +2 -0
- ads/aqua/extension/models_ws_msg_handler.py +1 -0
- ads/aqua/extension/utils.py +11 -24
- ads/aqua/finetuning/entities.py +23 -1
- ads/aqua/finetuning/finetuning.py +26 -10
- ads/aqua/model/constants.py +8 -0
- ads/aqua/model/entities.py +8 -1
- ads/aqua/model/model.py +269 -105
- ads/aqua/modeldeployment/deployment.py +51 -47
- ads/aqua/modeldeployment/utils.py +23 -5
- ads/aqua/ui.py +3 -4
- ads/config.py +2 -2
- ads/model/datascience_model.py +29 -0
- ads/model/service/oci_datascience_model.py +1 -1
- ads/opctl/operator/lowcode/anomaly/model/anomaly_dataset.py +8 -6
- ads/opctl/operator/lowcode/anomaly/model/base_model.py +1 -1
- ads/opctl/operator/lowcode/anomaly/operator_config.py +5 -3
- ads/opctl/operator/lowcode/common/transformations.py +2 -0
- ads/opctl/operator/lowcode/forecast/model/automlx.py +29 -0
- ads/type_discovery/typed_feature.py +32 -34
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.7.dist-info}/METADATA +1 -1
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.7.dist-info}/RECORD +36 -37
- ads/aqua/config/config.py +0 -31
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.7.dist-info}/WHEEL +0 -0
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.7.dist-info}/entry_points.txt +0 -0
- {oracle_ads-2.13.6.dist-info → oracle_ads-2.13.7.dist-info}/licenses/LICENSE.txt +0 -0
ads/aqua/constants.py
CHANGED
@@ -6,9 +6,10 @@
|
|
6
6
|
UNKNOWN_VALUE = ""
|
7
7
|
READY_TO_IMPORT_STATUS = "TRUE"
|
8
8
|
UNKNOWN_DICT = {}
|
9
|
-
README = "README.md"
|
10
|
-
LICENSE_TXT = "config/LICENSE.txt"
|
11
9
|
DEPLOYMENT_CONFIG = "deployment_config.json"
|
10
|
+
FINE_TUNING_CONFIG = "ft_config.json"
|
11
|
+
README = "README.md"
|
12
|
+
LICENSE = "LICENSE.txt"
|
12
13
|
AQUA_MODEL_TOKENIZER_CONFIG = "tokenizer_config.json"
|
13
14
|
COMPARTMENT_MAPPING_KEY = "service-model-compartment"
|
14
15
|
CONTAINER_INDEX = "container_index.json"
|
@@ -16,6 +17,7 @@ EVALUATION_REPORT_JSON = "report.json"
|
|
16
17
|
EVALUATION_REPORT_MD = "report.md"
|
17
18
|
EVALUATION_REPORT = "report.html"
|
18
19
|
UNKNOWN_JSON_STR = "{}"
|
20
|
+
UNKNOWN_JSON_LIST = "[]"
|
19
21
|
FINE_TUNING_RUNTIME_CONTAINER = "iad.ocir.io/ociodscdev/aqua_ft_cuda121:0.3.17.20"
|
20
22
|
DEFAULT_FT_BLOCK_STORAGE_SIZE = 750
|
21
23
|
DEFAULT_FT_REPLICA = 1
|
@@ -88,25 +90,25 @@ LLAMA_CPP_INFERENCE_RESTRICTED_PARAMS = {
|
|
88
90
|
TEI_CONTAINER_DEFAULT_HOST = "8080"
|
89
91
|
|
90
92
|
OCI_OPERATION_FAILURES = {
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
93
|
+
"list_model_deployments": "Unable to list model deployments. See tips for troubleshooting: ",
|
94
|
+
"list_models": "Unable to list models. See tips for troubleshooting: ",
|
95
|
+
"get_namespace": "Unable to access specified Object Storage Bucket. See tips for troubleshooting: ",
|
96
|
+
"list_log_groups": "Unable to access logs. See tips for troubleshooting: ",
|
97
|
+
"list_buckets": "Unable to list Object Storage Bucket. See tips for troubleshooting: ",
|
98
|
+
"put_object": "Unable to access or find Object Storage Bucket. See tips for troubleshooting: ",
|
99
|
+
"list_model_version_sets": "Unable to create or fetch model version set. See tips for troubleshooting:",
|
100
|
+
"update_model": "Unable to update model. See tips for troubleshooting: ",
|
101
|
+
"list_data_science_private_endpoints": "Unable to access private endpoint. See tips for troubleshooting: ",
|
102
|
+
"create_model": "Unable to register model. See tips for troubleshooting: ",
|
103
|
+
"create_deployment": "Unable to create deployment. See tips for troubleshooting: ",
|
104
|
+
"create_model_version_sets": "Unable to create model version set. See tips for troubleshooting: ",
|
105
|
+
"create_job": "Unable to create job. See tips for troubleshooting: ",
|
106
|
+
"create_job_run": "Unable to create job run. See tips for troubleshooting: ",
|
105
107
|
}
|
106
108
|
|
107
109
|
STATUS_CODE_MESSAGES = {
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
110
|
+
"400": "Could not process your request due to invalid input.",
|
111
|
+
"403": "We're having trouble processing your request with the information provided.",
|
112
|
+
"404": "Authorization Failed: The resource you're looking for isn't accessible.",
|
113
|
+
"408": "Server is taking too long to respond, please try again.",
|
112
114
|
}
|
@@ -41,13 +41,14 @@ from ads.aqua.common.errors import (
|
|
41
41
|
from ads.aqua.common.utils import (
|
42
42
|
extract_id_and_name_from_tag,
|
43
43
|
fire_and_forget,
|
44
|
-
get_container_config,
|
45
|
-
get_container_image,
|
46
44
|
is_valid_ocid,
|
47
45
|
upload_local_to_os,
|
48
46
|
)
|
49
|
-
from ads.aqua.config.
|
50
|
-
|
47
|
+
from ads.aqua.config.evaluation.evaluation_service_config import (
|
48
|
+
DEFAULT_EVALUATION_CONTAINER,
|
49
|
+
EvaluationServiceConfig,
|
50
|
+
MetricConfig,
|
51
|
+
)
|
51
52
|
from ads.aqua.constants import (
|
52
53
|
CONSOLE_LINK_RESOURCE_TYPE_MAPPING,
|
53
54
|
EVALUATION_REPORT,
|
@@ -80,7 +81,13 @@ from ads.aqua.evaluation.errors import EVALUATION_JOB_EXIT_CODE_MESSAGE
|
|
80
81
|
from ads.aqua.model.constants import ModelCustomMetadataFields
|
81
82
|
from ads.common.auth import default_signer
|
82
83
|
from ads.common.object_storage_details import ObjectStorageDetails
|
83
|
-
from ads.common.utils import
|
84
|
+
from ads.common.utils import (
|
85
|
+
UNKNOWN,
|
86
|
+
get_console_link,
|
87
|
+
get_files,
|
88
|
+
get_log_links,
|
89
|
+
read_file,
|
90
|
+
)
|
84
91
|
from ads.config import (
|
85
92
|
AQUA_JOB_SUBNET_ID,
|
86
93
|
COMPARTMENT_OCID,
|
@@ -260,10 +267,10 @@ class AquaEvaluationApp(AquaApp):
|
|
260
267
|
runtime = ModelDeploymentContainerRuntime.from_dict(
|
261
268
|
evaluation_source.runtime.to_dict()
|
262
269
|
)
|
263
|
-
inference_config =
|
264
|
-
|
265
|
-
)
|
266
|
-
for container in inference_config
|
270
|
+
inference_config = (
|
271
|
+
self.get_container_config().to_dict().get("inference")
|
272
|
+
)
|
273
|
+
for container in inference_config:
|
267
274
|
if container.name == runtime.image[: runtime.image.rfind(":")]:
|
268
275
|
eval_inference_configuration = (
|
269
276
|
container.spec.evaluation_configuration
|
@@ -801,14 +808,13 @@ class AquaEvaluationApp(AquaApp):
|
|
801
808
|
|
802
809
|
return source.display_name
|
803
810
|
|
804
|
-
|
805
|
-
def _get_evaluation_container(source_id: str) -> str:
|
811
|
+
def _get_evaluation_container(self, source_id: str) -> str:
|
806
812
|
# todo: use the source, identify if it is a model or a deployment. If latter, then fetch the base model id
|
807
813
|
# from the deployment object, and call ds_client.get_model() to get model details. Use custom metadata to
|
808
814
|
# get the container_type_key. Pass this key as container_type to get_container_image method.
|
809
815
|
|
810
816
|
# fetch image name from config
|
811
|
-
container_image = get_container_image(
|
817
|
+
container_image = self.get_container_image(
|
812
818
|
container_type="odsc-llm-evaluate",
|
813
819
|
)
|
814
820
|
logger.info(f"Aqua Image used for evaluating {source_id} :{container_image}")
|
@@ -1102,11 +1108,18 @@ class AquaEvaluationApp(AquaApp):
|
|
1102
1108
|
"loggroup_url": loggroup_url,
|
1103
1109
|
}
|
1104
1110
|
|
1105
|
-
def get_supported_metrics(self) ->
|
1111
|
+
def get_supported_metrics(self) -> List[MetricConfig]:
|
1106
1112
|
"""Gets a list of supported metrics for evaluation."""
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1113
|
+
containers = self.list_service_containers()
|
1114
|
+
container_item = next(
|
1115
|
+
c
|
1116
|
+
for c in containers
|
1117
|
+
if c.is_latest and c.family_name == DEFAULT_EVALUATION_CONTAINER
|
1118
|
+
)
|
1119
|
+
evaluation_service_config = EvaluationServiceConfig.from_oci_container_config(
|
1120
|
+
container_item
|
1121
|
+
)
|
1122
|
+
return evaluation_service_config.ui_config.metrics
|
1110
1123
|
|
1111
1124
|
@telemetry(entry_point="plugin=evaluation&action=load_metrics", name="aqua")
|
1112
1125
|
def load_metrics(self, eval_id: str) -> AquaEvalMetrics:
|
@@ -1130,17 +1143,31 @@ class AquaEvaluationApp(AquaApp):
|
|
1130
1143
|
|
1131
1144
|
with tempfile.TemporaryDirectory() as temp_dir:
|
1132
1145
|
logger.info(f"Downloading evaluation artifact: {eval_id}.")
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1146
|
+
|
1147
|
+
dsc_model = DataScienceModel.from_id(eval_id)
|
1148
|
+
if dsc_model.if_model_custom_metadata_artifact_exist(
|
1149
|
+
EVALUATION_REPORT_MD
|
1150
|
+
) and dsc_model.if_model_custom_metadata_artifact_exist(
|
1151
|
+
EVALUATION_REPORT_JSON
|
1152
|
+
):
|
1153
|
+
logger.info(
|
1154
|
+
f"Fetching {EVALUATION_REPORT_MD} and {EVALUATION_REPORT_JSON} from custom metadata..."
|
1155
|
+
)
|
1156
|
+
dsc_model.get_custom_metadata_artifact(EVALUATION_REPORT_MD, temp_dir)
|
1157
|
+
dsc_model.get_custom_metadata_artifact(EVALUATION_REPORT_JSON, temp_dir)
|
1158
|
+
else:
|
1159
|
+
logger.info("Fetching Evaluation Reports from OSS bucket...")
|
1160
|
+
dsc_model.download_artifact(
|
1161
|
+
temp_dir,
|
1162
|
+
auth=self._auth,
|
1163
|
+
)
|
1137
1164
|
|
1138
1165
|
files_in_artifact = get_files(temp_dir)
|
1139
1166
|
md_report_content = self._read_from_artifact(
|
1140
1167
|
temp_dir, files_in_artifact, EVALUATION_REPORT_MD
|
1141
1168
|
)
|
1142
1169
|
|
1143
|
-
# json report not
|
1170
|
+
# json report not available for failed evaluation
|
1144
1171
|
try:
|
1145
1172
|
json_report = json.loads(
|
1146
1173
|
self._read_from_artifact(
|
@@ -1239,14 +1266,46 @@ class AquaEvaluationApp(AquaApp):
|
|
1239
1266
|
|
1240
1267
|
with tempfile.TemporaryDirectory() as temp_dir:
|
1241
1268
|
logger.info(f"Downloading evaluation artifact for {eval_id}.")
|
1242
|
-
DataScienceModel.from_id(eval_id)
|
1243
|
-
|
1244
|
-
|
1269
|
+
dsc_model = DataScienceModel.from_id(eval_id)
|
1270
|
+
if_custom_metadata_exists = (
|
1271
|
+
dsc_model.if_model_custom_metadata_artifact_exist(EVALUATION_REPORT)
|
1245
1272
|
)
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1273
|
+
if if_custom_metadata_exists:
|
1274
|
+
logger.info(f"Fetching {EVALUATION_REPORT} from custom metadata.")
|
1275
|
+
dsc_model.get_custom_metadata_artifact(EVALUATION_REPORT, temp_dir)
|
1276
|
+
else:
|
1277
|
+
logger.info(f"Fetching {EVALUATION_REPORT} from Model artifact.")
|
1278
|
+
dsc_model.download_artifact(
|
1279
|
+
temp_dir,
|
1280
|
+
auth=self._auth,
|
1281
|
+
)
|
1282
|
+
files_in_artifact = get_files(temp_dir)
|
1283
|
+
if not len(files_in_artifact):
|
1284
|
+
try:
|
1285
|
+
evaluation_output_path = dsc_model.custom_metadata_list.get(
|
1286
|
+
EvaluationCustomMetadata.EVALUATION_OUTPUT_PATH
|
1287
|
+
).value
|
1288
|
+
report_path = (
|
1289
|
+
evaluation_output_path.rstrip("/")
|
1290
|
+
+ "/"
|
1291
|
+
+ eval_id
|
1292
|
+
+ "/"
|
1293
|
+
+ EVALUATION_REPORT
|
1294
|
+
)
|
1295
|
+
logger.info(
|
1296
|
+
f"Fetching {EVALUATION_REPORT} from {report_path} for evaluation {eval_id}"
|
1297
|
+
)
|
1298
|
+
content = read_file(
|
1299
|
+
file_path=report_path, auth=default_signer()
|
1300
|
+
).encode()
|
1301
|
+
except ValueError as err:
|
1302
|
+
raise AquaValueError(
|
1303
|
+
f"{EvaluationCustomMetadata.EVALUATION_OUTPUT_PATH} is missing from custom metadata for the model {eval_id}"
|
1304
|
+
) from err
|
1305
|
+
else:
|
1306
|
+
content = self._read_from_artifact(
|
1307
|
+
temp_dir, files_in_artifact, EVALUATION_REPORT
|
1308
|
+
)
|
1250
1309
|
report = AquaEvalReport(
|
1251
1310
|
evaluation_id=eval_id, content=base64.b64encode(content).decode()
|
1252
1311
|
)
|
@@ -1376,11 +1435,10 @@ class AquaEvaluationApp(AquaApp):
|
|
1376
1435
|
|
1377
1436
|
@staticmethod
|
1378
1437
|
@fire_and_forget
|
1379
|
-
def _delete_job_and_model(job, model):
|
1438
|
+
def _delete_job_and_model(job: DataScienceJob, model: DataScienceModel):
|
1380
1439
|
try:
|
1381
1440
|
job.dsc_job.delete(force_delete=True)
|
1382
1441
|
logger.info(f"Deleting Job: {job.job_id} for evaluation {model.id}")
|
1383
|
-
|
1384
1442
|
model.delete()
|
1385
1443
|
logger.info(f"Deleting evaluation: {model.id}")
|
1386
1444
|
except oci.exceptions.ServiceError as ex:
|
@@ -1389,12 +1447,20 @@ class AquaEvaluationApp(AquaApp):
|
|
1389
1447
|
f"Exception message: {ex}"
|
1390
1448
|
)
|
1391
1449
|
|
1392
|
-
def load_evaluation_config(
|
1450
|
+
def load_evaluation_config(
|
1451
|
+
self, container: Optional[str] = DEFAULT_EVALUATION_CONTAINER
|
1452
|
+
) -> Dict:
|
1393
1453
|
"""Loads evaluation config."""
|
1394
1454
|
|
1395
1455
|
logger.info("Loading evaluation container config.")
|
1396
1456
|
# retrieve the evaluation config by container family name
|
1397
|
-
|
1457
|
+
containers = self.list_service_containers()
|
1458
|
+
container_item = next(
|
1459
|
+
c for c in containers if c.is_latest and c.family_name == container
|
1460
|
+
)
|
1461
|
+
evaluation_config = EvaluationServiceConfig.from_oci_container_config(
|
1462
|
+
container_item
|
1463
|
+
)
|
1398
1464
|
|
1399
1465
|
# convert the new config representation to the old one
|
1400
1466
|
return {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
|
-
# Copyright (c)
|
2
|
+
# Copyright (c) 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
5
|
|
@@ -12,14 +12,12 @@ from huggingface_hub.utils import LocalTokenNotFoundError
|
|
12
12
|
from tornado.web import HTTPError
|
13
13
|
|
14
14
|
from ads.aqua.common.decorator import handle_exceptions
|
15
|
-
from ads.aqua.common.errors import
|
15
|
+
from ads.aqua.common.errors import AquaRuntimeError
|
16
16
|
from ads.aqua.common.utils import (
|
17
17
|
get_huggingface_login_timeout,
|
18
|
-
known_realm,
|
19
18
|
)
|
20
19
|
from ads.aqua.extension.base_handler import AquaAPIhandler
|
21
20
|
from ads.aqua.extension.errors import Errors
|
22
|
-
from ads.aqua.extension.utils import ui_compatability_check
|
23
21
|
|
24
22
|
|
25
23
|
class ADSVersionHandler(AquaAPIhandler):
|
@@ -50,14 +48,7 @@ class CompatibilityCheckHandler(AquaAPIhandler):
|
|
50
48
|
AquaResourceAccessError: raised when aqua is not accessible in the given session/region.
|
51
49
|
|
52
50
|
"""
|
53
|
-
|
54
|
-
return self.finish({"status": "ok"})
|
55
|
-
elif known_realm():
|
56
|
-
return self.finish({"status": "compatible"})
|
57
|
-
else:
|
58
|
-
raise AquaResourceAccessError(
|
59
|
-
"The AI Quick actions extension is not compatible in the given region."
|
60
|
-
)
|
51
|
+
return self.finish({"status": "ok"})
|
61
52
|
|
62
53
|
|
63
54
|
class NetworkStatusHandler(AquaAPIhandler):
|
@@ -1,22 +1,18 @@
|
|
1
1
|
#!/usr/bin/env python
|
2
2
|
|
3
|
-
# Copyright (c) 2024 Oracle and/or its affiliates.
|
3
|
+
# Copyright (c) 2024, 2025 Oracle and/or its affiliates.
|
4
4
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
5
5
|
|
6
6
|
import json
|
7
7
|
from importlib import metadata
|
8
|
-
from typing import List, Union
|
8
|
+
from typing import List, Optional, Union
|
9
9
|
|
10
10
|
from ads.aqua.common.decorator import handle_exceptions
|
11
|
-
from ads.aqua.common.errors import AquaResourceAccessError
|
12
|
-
from ads.aqua.common.utils import known_realm
|
13
11
|
from ads.aqua.extension.aqua_ws_msg_handler import AquaWSMsgHandler
|
14
12
|
from ads.aqua.extension.models.ws_models import (
|
15
13
|
AdsVersionResponse,
|
16
|
-
CompatibilityCheckResponse,
|
17
14
|
RequestResponseType,
|
18
15
|
)
|
19
|
-
from ads.aqua.extension.utils import ui_compatability_check
|
20
16
|
|
21
17
|
|
22
18
|
class AquaCommonWsMsgHandler(AquaWSMsgHandler):
|
@@ -28,7 +24,7 @@ class AquaCommonWsMsgHandler(AquaWSMsgHandler):
|
|
28
24
|
super().__init__(message)
|
29
25
|
|
30
26
|
@handle_exceptions
|
31
|
-
def process(self) ->
|
27
|
+
def process(self) -> Optional[AdsVersionResponse]:
|
32
28
|
request = json.loads(self.message)
|
33
29
|
if request.get("kind") == "AdsVersion":
|
34
30
|
version = metadata.version("oracle_ads")
|
@@ -38,20 +34,3 @@ class AquaCommonWsMsgHandler(AquaWSMsgHandler):
|
|
38
34
|
data=version,
|
39
35
|
)
|
40
36
|
return response
|
41
|
-
if request.get("kind") == "CompatibilityCheck":
|
42
|
-
if ui_compatability_check():
|
43
|
-
return CompatibilityCheckResponse(
|
44
|
-
message_id=request.get("message_id"),
|
45
|
-
kind=RequestResponseType.CompatibilityCheck,
|
46
|
-
data={"status": "ok"},
|
47
|
-
)
|
48
|
-
elif known_realm():
|
49
|
-
return CompatibilityCheckResponse(
|
50
|
-
message_id=request.get("message_id"),
|
51
|
-
kind=RequestResponseType.CompatibilityCheck,
|
52
|
-
data={"status": "compatible"},
|
53
|
-
)
|
54
|
-
else:
|
55
|
-
raise AquaResourceAccessError(
|
56
|
-
"The AI Quick actions extension is not compatible in the given region."
|
57
|
-
)
|
@@ -9,12 +9,14 @@ from tornado.web import HTTPError
|
|
9
9
|
|
10
10
|
from ads.aqua.common.decorator import handle_exceptions
|
11
11
|
from ads.aqua.common.enums import CustomInferenceContainerTypeFamily
|
12
|
-
from ads.aqua.common.errors import AquaRuntimeError
|
12
|
+
from ads.aqua.common.errors import AquaRuntimeError
|
13
13
|
from ads.aqua.common.utils import get_hf_model_info, is_valid_ocid, list_hf_models
|
14
14
|
from ads.aqua.extension.base_handler import AquaAPIhandler
|
15
15
|
from ads.aqua.extension.errors import Errors
|
16
16
|
from ads.aqua.model import AquaModelApp
|
17
17
|
from ads.aqua.model.entities import AquaModelSummary, HFModelSummary
|
18
|
+
from ads.config import SERVICE
|
19
|
+
from ads.model.common.utils import MetadataArtifactPathType
|
18
20
|
|
19
21
|
|
20
22
|
class AquaModelHandler(AquaAPIhandler):
|
@@ -37,13 +39,11 @@ class AquaModelHandler(AquaAPIhandler):
|
|
37
39
|
raise HTTPError(
|
38
40
|
400, Errors.MISSING_REQUIRED_PARAMETER.format("model_format")
|
39
41
|
)
|
40
|
-
|
42
|
+
|
41
43
|
model_format = model_format.upper()
|
42
|
-
|
44
|
+
|
43
45
|
if os_path:
|
44
|
-
return self.finish(
|
45
|
-
AquaModelApp.get_model_files(os_path, model_format)
|
46
|
-
)
|
46
|
+
return self.finish(AquaModelApp.get_model_files(os_path, model_format))
|
47
47
|
elif model_name:
|
48
48
|
return self.finish(
|
49
49
|
AquaModelApp.get_hf_model_files(model_name, model_format)
|
@@ -82,11 +82,13 @@ class AquaModelHandler(AquaAPIhandler):
|
|
82
82
|
# project_id is no needed.
|
83
83
|
project_id = self.get_argument("project_id", default=None)
|
84
84
|
model_type = self.get_argument("model_type", default=None)
|
85
|
+
category = self.get_argument("category", default=SERVICE)
|
85
86
|
return self.finish(
|
86
87
|
AquaModelApp().list(
|
87
88
|
compartment_id=compartment_id,
|
88
89
|
project_id=project_id,
|
89
90
|
model_type=model_type,
|
91
|
+
category=category,
|
90
92
|
)
|
91
93
|
)
|
92
94
|
|
@@ -206,6 +208,16 @@ class AquaModelLicenseHandler(AquaAPIhandler):
|
|
206
208
|
return self.finish(AquaModelApp().load_license(model_id))
|
207
209
|
|
208
210
|
|
211
|
+
class AquaModelReadmeHandler(AquaAPIhandler):
|
212
|
+
"""
|
213
|
+
Handler for fetching model card for AQUA models
|
214
|
+
"""
|
215
|
+
|
216
|
+
def get(self, model_id):
|
217
|
+
model_id = model_id.split("/")[0]
|
218
|
+
return self.finish(AquaModelApp().load_readme(model_id).model_dump())
|
219
|
+
|
220
|
+
|
209
221
|
class AquaHuggingFaceHandler(AquaAPIhandler):
|
210
222
|
"""Handler for Aqua Hugging Face REST APIs."""
|
211
223
|
|
@@ -329,9 +341,50 @@ class AquaModelTokenizerConfigHandler(AquaAPIhandler):
|
|
329
341
|
raise HTTPError(400, f"The request {self.request.path} is invalid.")
|
330
342
|
|
331
343
|
|
344
|
+
class AquaModelDefinedMetadataArtifactHandler(AquaAPIhandler):
|
345
|
+
"""
|
346
|
+
Handler for Model Defined metadata artifact content
|
347
|
+
|
348
|
+
Raises
|
349
|
+
------
|
350
|
+
HTTPError
|
351
|
+
Raises HTTPError if inputs are missing or are invalid.
|
352
|
+
"""
|
353
|
+
|
354
|
+
@handle_exceptions
|
355
|
+
def get(self, model_id: str, metadata_key: str):
|
356
|
+
"""
|
357
|
+
model_id: ocid of the model
|
358
|
+
metadata_key: the metadata key for which artifact content needs to be downloaded.
|
359
|
+
Can be any of Readme, License , FinetuneConfiguration , DeploymentConfiguration
|
360
|
+
"""
|
361
|
+
|
362
|
+
return self.finish(
|
363
|
+
AquaModelApp().get_defined_metadata_artifact_content(model_id, metadata_key)
|
364
|
+
)
|
365
|
+
|
366
|
+
@handle_exceptions
|
367
|
+
def post(self, model_id: str, metadata_key: str):
|
368
|
+
input_body = self.get_json_body()
|
369
|
+
path_type = input_body.get("path_type")
|
370
|
+
artifact_path_or_content = input_body.get("artifact_path_or_content")
|
371
|
+
if path_type not in MetadataArtifactPathType.values():
|
372
|
+
raise HTTPError(400, f"Invalid value of path_type: {path_type}")
|
373
|
+
return self.finish(
|
374
|
+
AquaModelApp().create_defined_metadata_artifact(
|
375
|
+
model_id, metadata_key, path_type, artifact_path_or_content
|
376
|
+
)
|
377
|
+
)
|
378
|
+
|
379
|
+
|
332
380
|
__handlers__ = [
|
333
381
|
("model/?([^/]*)", AquaModelHandler),
|
334
382
|
("model/?([^/]*)/license", AquaModelLicenseHandler),
|
383
|
+
("model/?([^/]*)/readme", AquaModelReadmeHandler),
|
335
384
|
("model/?([^/]*)/tokenizer", AquaModelTokenizerConfigHandler),
|
336
385
|
("model/hf/search/?([^/]*)", AquaHuggingFaceHandler),
|
386
|
+
(
|
387
|
+
"model/?([^/]*)/definedMetadata/?([^/]*)",
|
388
|
+
AquaModelDefinedMetadataArtifactHandler,
|
389
|
+
),
|
337
390
|
]
|
@@ -6,6 +6,7 @@
|
|
6
6
|
from dataclasses import dataclass
|
7
7
|
from typing import List, Optional
|
8
8
|
|
9
|
+
import ads.config
|
9
10
|
from ads.aqua.evaluation.entities import AquaEvaluationDetail, AquaEvaluationSummary
|
10
11
|
from ads.aqua.model.entities import AquaModel, AquaModelSummary
|
11
12
|
from ads.aqua.modeldeployment.entities import AquaDeployment, AquaDeploymentDetail
|
@@ -57,6 +58,7 @@ class ListModelsRequest(BaseRequest):
|
|
57
58
|
compartment_id: Optional[str] = None
|
58
59
|
project_id: Optional[str] = None
|
59
60
|
model_type: Optional[str] = None
|
61
|
+
category: str = ads.config.USER
|
60
62
|
kind = RequestResponseType.ListDeployments
|
61
63
|
|
62
64
|
|
@@ -32,6 +32,7 @@ class AquaModelWSMsgHandler(AquaWSMsgHandler):
|
|
32
32
|
compartment_id=request.get("compartment_id"),
|
33
33
|
project_id=request.get("project_id"),
|
34
34
|
model_type=request.get("model_type"),
|
35
|
+
category=request.get("category"),
|
35
36
|
)
|
36
37
|
response = ListModelsResponse(
|
37
38
|
message_id=request.get("message_id"),
|
ads/aqua/extension/utils.py
CHANGED
@@ -1,20 +1,17 @@
|
|
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
5
|
import re
|
6
6
|
import traceback
|
7
7
|
import uuid
|
8
8
|
from dataclasses import fields
|
9
|
-
from datetime import datetime, timedelta
|
10
9
|
from http.client import responses
|
11
10
|
from typing import Dict, Optional
|
12
11
|
|
13
|
-
from cachetools import TTLCache, cached
|
14
12
|
from tornado.web import HTTPError
|
15
13
|
|
16
|
-
from ads.aqua import
|
17
|
-
from ads.aqua.common.utils import fetch_service_compartment
|
14
|
+
from ads.aqua import logger
|
18
15
|
from ads.aqua.constants import (
|
19
16
|
AQUA_TROUBLESHOOTING_LINK,
|
20
17
|
OCI_OPERATION_FAILURES,
|
@@ -36,19 +33,11 @@ def validate_function_parameters(data_class, input_data: Dict):
|
|
36
33
|
)
|
37
34
|
|
38
35
|
|
39
|
-
@cached(cache=TTLCache(maxsize=1, ttl=timedelta(minutes=1), timer=datetime.now))
|
40
|
-
def ui_compatability_check():
|
41
|
-
"""This method caches the service compartment OCID details that is set by either the environment variable or if
|
42
|
-
fetched from the configuration. The cached result is returned when multiple calls are made in quick succession
|
43
|
-
from the UI to avoid multiple config file loads."""
|
44
|
-
return ODSC_MODEL_COMPARTMENT_OCID or fetch_service_compartment()
|
45
|
-
|
46
|
-
|
47
36
|
def get_default_error_messages(
|
48
37
|
service_payload: dict,
|
49
38
|
status_code: str,
|
50
39
|
default_msg: str = "Unknown HTTP Error.",
|
51
|
-
)-> str:
|
40
|
+
) -> str:
|
52
41
|
"""Method that maps the error messages based on the operation performed or the status codes encountered."""
|
53
42
|
|
54
43
|
if service_payload and "operation_name" in service_payload:
|
@@ -66,14 +55,13 @@ def get_documentation_link(key: str) -> str:
|
|
66
55
|
return f"{AQUA_TROUBLESHOOTING_LINK}#{github_header}"
|
67
56
|
|
68
57
|
|
69
|
-
def get_troubleshooting_tips(service_payload: dict,
|
70
|
-
status_code: str) -> str:
|
58
|
+
def get_troubleshooting_tips(service_payload: dict, status_code: str) -> str:
|
71
59
|
"""Maps authorization errors to potential solutions on Troubleshooting Page per Aqua Documentation on oci-data-science-ai-samples"""
|
72
60
|
|
73
61
|
tip = f"For general tips on troubleshooting: {AQUA_TROUBLESHOOTING_LINK}"
|
74
62
|
|
75
63
|
if status_code in (404, 400):
|
76
|
-
failed_operation = service_payload.get(
|
64
|
+
failed_operation = service_payload.get("operation_name")
|
77
65
|
|
78
66
|
if failed_operation in OCI_OPERATION_FAILURES:
|
79
67
|
link = get_documentation_link(failed_operation)
|
@@ -118,14 +106,13 @@ def construct_error(status_code: int, **kwargs) -> ReplyDetails:
|
|
118
106
|
|
119
107
|
tips = get_troubleshooting_tips(service_payload, status_code)
|
120
108
|
|
121
|
-
|
122
109
|
reply = ReplyDetails(
|
123
|
-
status
|
124
|
-
troubleshooting_tips
|
125
|
-
message
|
126
|
-
service_payload
|
127
|
-
reason
|
128
|
-
request_id
|
110
|
+
status=status_code,
|
111
|
+
troubleshooting_tips=tips,
|
112
|
+
message=message,
|
113
|
+
service_payload=service_payload,
|
114
|
+
reason=reason,
|
115
|
+
request_id=str(uuid.uuid4()),
|
129
116
|
)
|
130
117
|
|
131
118
|
exc_info = kwargs.get("exc_info")
|
ads/aqua/finetuning/entities.py
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
|
4
4
|
|
5
5
|
import json
|
6
|
-
from typing import List, Literal, Optional, Union
|
6
|
+
from typing import Any, Dict, List, Literal, Optional, Union
|
7
7
|
|
8
8
|
from pydantic import Field, model_validator
|
9
9
|
|
@@ -55,6 +55,28 @@ class AquaFineTuningParams(Serializable):
|
|
55
55
|
return data
|
56
56
|
|
57
57
|
|
58
|
+
class AquaFineTuningConfig(Serializable):
|
59
|
+
"""Represents model's shape list and detailed configuration for fine-tuning.
|
60
|
+
|
61
|
+
Attributes:
|
62
|
+
shape (List[str], optional): A list of shape names (e.g., BM.GPU.A10.4).
|
63
|
+
configuration (Dict[str, Any], optional): Configuration details of fine-tuning.
|
64
|
+
"""
|
65
|
+
|
66
|
+
shape: Optional[Dict[str, Any]] = Field(
|
67
|
+
default_factory=dict, description="List of supported shapes for the model."
|
68
|
+
)
|
69
|
+
finetuning_params: Optional[str] = Field(
|
70
|
+
default_factory=str, description="Fine tuning parameters."
|
71
|
+
)
|
72
|
+
configuration: Optional[Dict[str, Any]] = Field(
|
73
|
+
default_factory=dict, description="Configuration details keyed by shape."
|
74
|
+
)
|
75
|
+
|
76
|
+
class Config:
|
77
|
+
extra = "allow"
|
78
|
+
|
79
|
+
|
58
80
|
class AquaFineTuningSummary(Serializable):
|
59
81
|
"""Represents a summary of Aqua Finetuning job."""
|
60
82
|
|