truefoundry 0.5.0rc6__py3-none-any.whl → 0.5.1__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.
Potentially problematic release.
This version of truefoundry might be problematic. Click here for more details.
- truefoundry/common/auth_service_client.py +2 -2
- truefoundry/common/constants.py +9 -0
- truefoundry/common/utils.py +81 -1
- truefoundry/deploy/__init__.py +5 -0
- truefoundry/deploy/builder/builders/tfy_notebook_buildpack/__init__.py +4 -2
- truefoundry/deploy/builder/builders/tfy_python_buildpack/__init__.py +7 -5
- truefoundry/deploy/builder/builders/tfy_python_buildpack/dockerfile_template.py +87 -28
- truefoundry/deploy/builder/constants.py +8 -0
- truefoundry/deploy/builder/utils.py +9 -4
- truefoundry/deploy/cli/cli.py +2 -0
- truefoundry/deploy/cli/commands/__init__.py +1 -0
- truefoundry/deploy/cli/commands/deploy_init_command.py +22 -0
- truefoundry/deploy/lib/dao/application.py +2 -1
- truefoundry/deploy/v2/lib/patched_models.py +8 -0
- truefoundry/ml/__init__.py +25 -15
- truefoundry/ml/artifact/truefoundry_artifact_repo.py +8 -3
- truefoundry/ml/autogen/client/__init__.py +24 -0
- truefoundry/ml/autogen/client/api/mlfoundry_artifacts_api.py +325 -0
- truefoundry/ml/autogen/client/models/__init__.py +24 -0
- truefoundry/ml/autogen/client/models/artifact_version_manifest.py +2 -2
- truefoundry/ml/autogen/client/models/export_deployment_files_request_dto.py +82 -0
- truefoundry/ml/autogen/client/models/infer_method_name.py +34 -0
- truefoundry/ml/autogen/client/models/model_server.py +34 -0
- truefoundry/ml/autogen/client/models/model_version_environment.py +97 -0
- truefoundry/ml/autogen/client/models/model_version_manifest.py +13 -8
- truefoundry/ml/autogen/client/models/sklearn_framework.py +25 -2
- truefoundry/ml/autogen/client/models/sklearn_model_schema.py +82 -0
- truefoundry/ml/autogen/client/models/sklearn_serialization_format.py +35 -0
- truefoundry/ml/autogen/client/models/transformers_framework.py +2 -2
- truefoundry/ml/autogen/client/models/validate_external_storage_root_request_dto.py +71 -0
- truefoundry/ml/autogen/client/models/validate_external_storage_root_response_dto.py +69 -0
- truefoundry/ml/autogen/client/models/xg_boost_framework.py +28 -3
- truefoundry/ml/autogen/client/models/xg_boost_model_schema.py +88 -0
- truefoundry/ml/autogen/client/models/xg_boost_serialization_format.py +36 -0
- truefoundry/ml/autogen/client_README.md +12 -0
- truefoundry/ml/autogen/entities/artifacts.py +119 -26
- truefoundry/ml/autogen/models/signature.py +6 -3
- truefoundry/ml/autogen/models/utils.py +12 -7
- truefoundry/ml/cli/commands/model_init.py +97 -0
- truefoundry/ml/cli/utils.py +34 -0
- truefoundry/ml/log_types/artifacts/model.py +53 -38
- truefoundry/ml/log_types/artifacts/utils.py +38 -2
- truefoundry/ml/mlfoundry_api.py +77 -81
- truefoundry/ml/mlfoundry_run.py +3 -33
- truefoundry/ml/model_framework.py +372 -3
- truefoundry/ml/validation_utils.py +2 -0
- {truefoundry-0.5.0rc6.dist-info → truefoundry-0.5.1.dist-info}/METADATA +2 -6
- {truefoundry-0.5.0rc6.dist-info → truefoundry-0.5.1.dist-info}/RECORD +50 -55
- truefoundry/deploy/function_service/__init__.py +0 -3
- truefoundry/deploy/function_service/__main__.py +0 -27
- truefoundry/deploy/function_service/app.py +0 -92
- truefoundry/deploy/function_service/build.py +0 -45
- truefoundry/deploy/function_service/remote/__init__.py +0 -6
- truefoundry/deploy/function_service/remote/context.py +0 -3
- truefoundry/deploy/function_service/remote/method.py +0 -67
- truefoundry/deploy/function_service/remote/remote.py +0 -144
- truefoundry/deploy/function_service/route.py +0 -137
- truefoundry/deploy/function_service/service.py +0 -113
- truefoundry/deploy/function_service/utils.py +0 -53
- truefoundry/langchain/__init__.py +0 -12
- truefoundry/langchain/deprecated.py +0 -302
- truefoundry/langchain/truefoundry_chat.py +0 -130
- truefoundry/langchain/truefoundry_embeddings.py +0 -171
- truefoundry/langchain/truefoundry_llm.py +0 -106
- truefoundry/langchain/utils.py +0 -44
- truefoundry/ml/log_types/artifacts/model_extras.py +0 -48
- {truefoundry-0.5.0rc6.dist-info → truefoundry-0.5.1.dist-info}/WHEEL +0 -0
- {truefoundry-0.5.0rc6.dist-info → truefoundry-0.5.1.dist-info}/entry_points.txt +0 -0
|
@@ -8,7 +8,7 @@ import typing
|
|
|
8
8
|
import uuid
|
|
9
9
|
import warnings
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import TYPE_CHECKING, Any, Dict, Optional,
|
|
11
|
+
from typing import TYPE_CHECKING, Any, Dict, Optional, Union
|
|
12
12
|
|
|
13
13
|
from truefoundry.ml.artifact.truefoundry_artifact_repo import (
|
|
14
14
|
ArtifactIdentifier,
|
|
@@ -25,11 +25,13 @@ from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
|
|
|
25
25
|
MlfoundryArtifactsApi,
|
|
26
26
|
ModelDto,
|
|
27
27
|
ModelVersionDto,
|
|
28
|
+
ModelVersionEnvironment,
|
|
28
29
|
ModelVersionManifest,
|
|
29
30
|
NotifyArtifactVersionFailureDto,
|
|
30
31
|
TrueFoundryArtifactSource,
|
|
31
32
|
UpdateModelVersionRequestDto,
|
|
32
33
|
)
|
|
34
|
+
from truefoundry.ml.autogen.models import infer_signature as _infer_signature
|
|
33
35
|
from truefoundry.ml.enums import ModelFramework
|
|
34
36
|
from truefoundry.ml.exceptions import MlFoundryException
|
|
35
37
|
from truefoundry.ml.log_types.artifacts.artifact import BlobStorageDirectory
|
|
@@ -43,11 +45,19 @@ from truefoundry.ml.log_types.artifacts.utils import (
|
|
|
43
45
|
_validate_description,
|
|
44
46
|
calculate_total_size,
|
|
45
47
|
)
|
|
46
|
-
from truefoundry.ml.model_framework import
|
|
48
|
+
from truefoundry.ml.model_framework import (
|
|
49
|
+
ModelFrameworkType,
|
|
50
|
+
_ModelFramework,
|
|
51
|
+
auto_update_environment_details,
|
|
52
|
+
auto_update_model_framework_details,
|
|
53
|
+
)
|
|
47
54
|
from truefoundry.ml.session import _get_api_client
|
|
48
55
|
from truefoundry.pydantic_v1 import BaseModel, Extra
|
|
49
56
|
|
|
50
57
|
if TYPE_CHECKING:
|
|
58
|
+
import numpy as np
|
|
59
|
+
import pandas as pd
|
|
60
|
+
|
|
51
61
|
from truefoundry.ml.mlfoundry_run import MlFoundryRun
|
|
52
62
|
|
|
53
63
|
|
|
@@ -96,7 +106,7 @@ class ModelVersion:
|
|
|
96
106
|
self._deleted = False
|
|
97
107
|
self._description: str = ""
|
|
98
108
|
self._metadata: Dict[str, Any] = {}
|
|
99
|
-
self.
|
|
109
|
+
self._environment: Optional[ModelVersionEnvironment] = None
|
|
100
110
|
self._framework: Optional[ModelFrameworkType] = None
|
|
101
111
|
self._set_mutable_attrs()
|
|
102
112
|
|
|
@@ -139,22 +149,19 @@ class ModelVersion:
|
|
|
139
149
|
if self._model_version.manifest:
|
|
140
150
|
self._description = self._model_version.manifest.description or ""
|
|
141
151
|
self._metadata = copy.deepcopy(self._model_version.manifest.metadata)
|
|
142
|
-
self.
|
|
143
|
-
|
|
152
|
+
self._environment = copy.deepcopy(self._model_version.manifest.environment)
|
|
153
|
+
self._framework = (
|
|
154
|
+
copy.deepcopy(self._model_version.manifest.framework.actual_instance)
|
|
155
|
+
if self._model_version.manifest.framework
|
|
156
|
+
else None
|
|
144
157
|
)
|
|
145
|
-
if self._model_version.manifest.framework:
|
|
146
|
-
self._framework = copy.deepcopy(
|
|
147
|
-
self._model_version.manifest.framework.actual_instance
|
|
148
|
-
)
|
|
149
|
-
else:
|
|
150
|
-
self._framework = None
|
|
151
158
|
else:
|
|
152
159
|
self._description = self._model_version.description or ""
|
|
153
160
|
self._metadata = copy.deepcopy(self._model_version.artifact_metadata)
|
|
161
|
+
self._environment = None
|
|
154
162
|
self._framework = _ModelFramework.to_model_framework_type(
|
|
155
163
|
self._model_version.model_framework
|
|
156
164
|
)
|
|
157
|
-
self._model_schema = None
|
|
158
165
|
|
|
159
166
|
def _refetch_model_version(self, reset_mutable_attrs: bool = True):
|
|
160
167
|
_model_version = self._mlfoundry_artifacts_api.get_model_version_get(
|
|
@@ -225,21 +232,21 @@ class ModelVersion:
|
|
|
225
232
|
self._metadata = copy.deepcopy(value)
|
|
226
233
|
|
|
227
234
|
@property
|
|
228
|
-
def
|
|
229
|
-
"""Get
|
|
230
|
-
return self.
|
|
235
|
+
def environment(self) -> Optional[ModelVersionEnvironment]:
|
|
236
|
+
"""Get the environment details for the model"""
|
|
237
|
+
return self._environment
|
|
231
238
|
|
|
232
|
-
@
|
|
233
|
-
def
|
|
234
|
-
"""set the
|
|
239
|
+
@environment.setter
|
|
240
|
+
def environment(self, value: Optional[Dict[str, Any]]):
|
|
241
|
+
"""set the environment details for the model"""
|
|
235
242
|
if not self._model_version.manifest:
|
|
236
243
|
warnings.warn(
|
|
237
|
-
message="This model version was created using an older serialization format.
|
|
244
|
+
message="This model version was created using an older serialization format. Environment will not be updated",
|
|
238
245
|
category=DeprecationWarning,
|
|
239
246
|
stacklevel=2,
|
|
240
247
|
)
|
|
241
248
|
return
|
|
242
|
-
self.
|
|
249
|
+
self._environment = copy.deepcopy(value)
|
|
243
250
|
|
|
244
251
|
@property
|
|
245
252
|
def framework(self) -> Optional["ModelFrameworkType"]:
|
|
@@ -438,7 +445,7 @@ class ModelVersion:
|
|
|
438
445
|
if self._model_version.manifest:
|
|
439
446
|
self._model_version.manifest.description = self.description
|
|
440
447
|
self._model_version.manifest.metadata = self.metadata
|
|
441
|
-
self._model_version.manifest.
|
|
448
|
+
self._model_version.manifest.environment = self.environment
|
|
442
449
|
self._model_version.manifest.framework = (
|
|
443
450
|
Framework.from_dict(self.framework.dict()) if self.framework else None
|
|
444
451
|
)
|
|
@@ -466,13 +473,12 @@ def _log_model_version( # noqa: C901
|
|
|
466
473
|
model_file_or_folder: Union[str, BlobStorageDirectory],
|
|
467
474
|
mlfoundry_artifacts_api: Optional[MlfoundryArtifactsApi] = None,
|
|
468
475
|
ml_repo_id: Optional[str] = None,
|
|
469
|
-
additional_files: Sequence[Tuple[Union[str, Path], Optional[str]]] = (),
|
|
470
476
|
description: Optional[str] = None,
|
|
471
477
|
metadata: Optional[Dict[str, Any]] = None,
|
|
472
478
|
step: Optional[int] = 0,
|
|
473
479
|
progress: Optional[bool] = None,
|
|
474
480
|
framework: Optional[Union[str, ModelFramework, "ModelFrameworkType"]] = None,
|
|
475
|
-
|
|
481
|
+
environment: Optional[ModelVersionEnvironment] = None,
|
|
476
482
|
) -> ModelVersion:
|
|
477
483
|
if (run and mlfoundry_artifacts_api) or (not run and not mlfoundry_artifacts_api):
|
|
478
484
|
raise MlFoundryException(
|
|
@@ -496,7 +502,6 @@ def _log_model_version( # noqa: C901
|
|
|
496
502
|
step = step or 0
|
|
497
503
|
total_size = None
|
|
498
504
|
metadata = metadata or {}
|
|
499
|
-
additional_files = additional_files or {}
|
|
500
505
|
|
|
501
506
|
_validate_description(description)
|
|
502
507
|
_validate_artifact_metadata(metadata)
|
|
@@ -514,17 +519,6 @@ def _log_model_version( # noqa: C901
|
|
|
514
519
|
ignore_model_dir_dest_conflict=True,
|
|
515
520
|
)
|
|
516
521
|
|
|
517
|
-
# verify additional files and paths, copy additional files
|
|
518
|
-
if additional_files:
|
|
519
|
-
logger.info("Adding `additional_files` to model version contents")
|
|
520
|
-
temp_dest_to_src_map = _copy_additional_files(
|
|
521
|
-
root_dir=temp_dir.name,
|
|
522
|
-
files_dir="",
|
|
523
|
-
model_dir=None,
|
|
524
|
-
additional_files=additional_files,
|
|
525
|
-
ignore_model_dir_dest_conflict=False,
|
|
526
|
-
existing_dest_to_src_map=temp_dest_to_src_map,
|
|
527
|
-
)
|
|
528
522
|
except Exception as e:
|
|
529
523
|
temp_dir.cleanup()
|
|
530
524
|
raise MlFoundryException("Failed to log model") from e
|
|
@@ -578,15 +572,24 @@ def _log_model_version( # noqa: C901
|
|
|
578
572
|
else:
|
|
579
573
|
raise MlFoundryException("Invalid model_file_or_folder provided")
|
|
580
574
|
|
|
581
|
-
_framework = _ModelFramework.to_model_framework_type(framework)
|
|
582
575
|
_source_cls = typing.get_type_hints(ModelVersionManifest)["source"]
|
|
576
|
+
|
|
577
|
+
# Auto fetch the framework & environment details if not provided
|
|
578
|
+
framework = _ModelFramework.to_model_framework_type(framework)
|
|
579
|
+
if framework and isinstance(model_file_or_folder, str):
|
|
580
|
+
auto_update_model_framework_details(
|
|
581
|
+
framework=framework, model_file_or_folder=model_file_or_folder
|
|
582
|
+
)
|
|
583
|
+
environment = environment or ModelVersionEnvironment()
|
|
584
|
+
auto_update_environment_details(environment=environment, framework=framework)
|
|
585
|
+
|
|
583
586
|
model_manifest = ModelVersionManifest(
|
|
584
587
|
description=description,
|
|
585
588
|
metadata=metadata,
|
|
586
589
|
source=_source_cls.from_dict(source.dict()),
|
|
587
|
-
framework=Framework.from_dict(
|
|
590
|
+
framework=Framework.from_dict(framework.dict()) if framework else None,
|
|
591
|
+
environment=environment,
|
|
588
592
|
step=step,
|
|
589
|
-
model_schema=model_schema,
|
|
590
593
|
)
|
|
591
594
|
artifact_version_response = mlfoundry_artifacts_api.finalize_artifact_version_post(
|
|
592
595
|
finalize_artifact_version_request_dto=FinalizeArtifactVersionRequestDto(
|
|
@@ -600,3 +603,15 @@ def _log_model_version( # noqa: C901
|
|
|
600
603
|
)
|
|
601
604
|
)
|
|
602
605
|
return ModelVersion.from_fqn(fqn=artifact_version_response.artifact_version.fqn)
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
def infer_signature(
|
|
609
|
+
model_input: Any = None,
|
|
610
|
+
model_output: Optional[
|
|
611
|
+
Union["pd.DataFrame", "np.ndarray", Dict[str, "np.ndarray"]]
|
|
612
|
+
] = None,
|
|
613
|
+
params: Optional[Dict[str, Any]] = None,
|
|
614
|
+
):
|
|
615
|
+
return _infer_signature(
|
|
616
|
+
model_input=model_input, model_output=model_output, params=params
|
|
617
|
+
)
|
|
@@ -2,7 +2,7 @@ import json
|
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
4
|
import posixpath
|
|
5
|
-
from pathlib import Path
|
|
5
|
+
from pathlib import Path, PureWindowsPath
|
|
6
6
|
from typing import Any, Dict, Optional, Sequence, Tuple, Union
|
|
7
7
|
|
|
8
8
|
from truefoundry.ml.exceptions import MlFoundryException
|
|
@@ -11,6 +11,13 @@ from truefoundry.ml.log_types.artifacts.constants import DESCRIPTION_MAX_LENGTH
|
|
|
11
11
|
logger = logging.getLogger(__name__)
|
|
12
12
|
|
|
13
13
|
|
|
14
|
+
def to_unix_path(path):
|
|
15
|
+
path = os.path.normpath(path)
|
|
16
|
+
if os.path.sep == "\\":
|
|
17
|
+
path = PureWindowsPath(path).as_posix()
|
|
18
|
+
return path
|
|
19
|
+
|
|
20
|
+
|
|
14
21
|
def _copy_tree(
|
|
15
22
|
root_dir: str, src_path: str, dest_path: str, dest_to_src: Dict[str, str]
|
|
16
23
|
):
|
|
@@ -42,6 +49,35 @@ def is_destination_path_dirlike(dest_path) -> bool:
|
|
|
42
49
|
return False
|
|
43
50
|
|
|
44
51
|
|
|
52
|
+
def get_single_file_path_if_only_one_in_directory(path: str) -> Optional[str]:
|
|
53
|
+
"""
|
|
54
|
+
Get the filename from a path, or return a filename from a directory if a single file exists.
|
|
55
|
+
Args:
|
|
56
|
+
path: The file or folder path.
|
|
57
|
+
Returns:
|
|
58
|
+
Optional[str]: The filename or None if no files are found or multiple files are found.
|
|
59
|
+
"""
|
|
60
|
+
# If it's already a file, return it as-is
|
|
61
|
+
if os.path.isfile(path):
|
|
62
|
+
return path
|
|
63
|
+
|
|
64
|
+
# If it's a directory, check if it contains a single file
|
|
65
|
+
if is_destination_path_dirlike(path):
|
|
66
|
+
all_files = []
|
|
67
|
+
for root, _, files in os.walk(path):
|
|
68
|
+
# Collect all files found in any subdirectory
|
|
69
|
+
all_files.extend(os.path.join(root, f) for f in files)
|
|
70
|
+
# If more than one file is found, stop early
|
|
71
|
+
if len(all_files) > 1:
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
# If only one file is found, return it
|
|
75
|
+
if len(all_files) == 1:
|
|
76
|
+
return all_files[0]
|
|
77
|
+
|
|
78
|
+
return None # No file found or Multiple files found
|
|
79
|
+
|
|
80
|
+
|
|
45
81
|
def _copy_additional_files(
|
|
46
82
|
root_dir: str,
|
|
47
83
|
files_dir: str, # relative to root dir e.g. "files/"
|
|
@@ -136,7 +172,7 @@ def _get_src_dest_pairs(
|
|
|
136
172
|
dest_to_src_map: Dict[str, str],
|
|
137
173
|
) -> Sequence[Tuple[str, str]]:
|
|
138
174
|
src_dest_pairs = [
|
|
139
|
-
(src_path, os.path.relpath(dest_abs_path, root_dir))
|
|
175
|
+
(src_path, to_unix_path(os.path.relpath(dest_abs_path, root_dir)))
|
|
140
176
|
for dest_abs_path, src_path in dest_to_src_map.items()
|
|
141
177
|
]
|
|
142
178
|
return src_dest_pairs
|
truefoundry/ml/mlfoundry_api.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import time
|
|
3
3
|
import uuid
|
|
4
|
-
|
|
4
|
+
import zipfile
|
|
5
|
+
from io import BytesIO
|
|
5
6
|
from typing import (
|
|
6
7
|
TYPE_CHECKING,
|
|
7
8
|
Any,
|
|
@@ -15,10 +16,9 @@ from typing import (
|
|
|
15
16
|
)
|
|
16
17
|
|
|
17
18
|
import coolname
|
|
18
|
-
import pandas as pd
|
|
19
19
|
|
|
20
|
-
from truefoundry.common.utils import relogin_error_message
|
|
21
|
-
from truefoundry.ml import constants
|
|
20
|
+
from truefoundry.common.utils import ContextualDirectoryManager, relogin_error_message
|
|
21
|
+
from truefoundry.ml import ModelVersionEnvironment, constants
|
|
22
22
|
from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
|
|
23
23
|
ArtifactDto,
|
|
24
24
|
ArtifactType,
|
|
@@ -27,12 +27,14 @@ from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
|
|
|
27
27
|
CreateRunRequestDto,
|
|
28
28
|
DatasetDto,
|
|
29
29
|
ExperimentsApi,
|
|
30
|
+
ExportDeploymentFilesRequestDto,
|
|
30
31
|
ListArtifactsRequestDto,
|
|
31
32
|
ListArtifactVersionsRequestDto,
|
|
32
33
|
ListDatasetsRequestDto,
|
|
33
34
|
ListModelVersionsRequestDto,
|
|
34
35
|
MlfoundryArtifactsApi,
|
|
35
36
|
ModelDto,
|
|
37
|
+
ModelServer,
|
|
36
38
|
RunsApi,
|
|
37
39
|
RunTagDto,
|
|
38
40
|
SearchRunsRequestDto,
|
|
@@ -75,7 +77,7 @@ if TYPE_CHECKING:
|
|
|
75
77
|
from truefoundry.ml import ModelFrameworkType
|
|
76
78
|
|
|
77
79
|
_SEARCH_MAX_RESULTS_DEFAULT = 1000
|
|
78
|
-
|
|
80
|
+
_ML_FOUNDRY_API_REQUEST_TIMEOUT = 10
|
|
79
81
|
_INTERNAL_ENV_VARS = [
|
|
80
82
|
"TFY_INTERNAL_APPLICATION_ID",
|
|
81
83
|
"TFY_INTERNAL_JOB_RUN_NAME",
|
|
@@ -476,43 +478,6 @@ class MlFoundry:
|
|
|
476
478
|
)
|
|
477
479
|
return mlfoundry_run
|
|
478
480
|
|
|
479
|
-
def get_all_runs(
|
|
480
|
-
self,
|
|
481
|
-
ml_repo: str,
|
|
482
|
-
) -> pd.DataFrame:
|
|
483
|
-
"""Returns all the run name and id present under a ML Repo.
|
|
484
|
-
|
|
485
|
-
The user must have `READ` access to the ML Repo.
|
|
486
|
-
|
|
487
|
-
Args:
|
|
488
|
-
ml_repo (str): Name of the ML Repo.
|
|
489
|
-
Returns:
|
|
490
|
-
pd.DataFrame: dataframe with two columns- run_id and run_name
|
|
491
|
-
|
|
492
|
-
Examples:
|
|
493
|
-
|
|
494
|
-
### get all the runs from a ml_repo
|
|
495
|
-
```python
|
|
496
|
-
from truefoundry.ml import get_client
|
|
497
|
-
|
|
498
|
-
client = get_client()
|
|
499
|
-
|
|
500
|
-
run = client.get_all_runs(ml_repo='my-repo')
|
|
501
|
-
```
|
|
502
|
-
"""
|
|
503
|
-
runs = []
|
|
504
|
-
for run in self.search_runs(ml_repo=ml_repo):
|
|
505
|
-
runs.append((run.run_id, run.run_name))
|
|
506
|
-
|
|
507
|
-
if len(runs) == 0:
|
|
508
|
-
return pd.DataFrame(
|
|
509
|
-
columns=[constants.RUN_ID_COL_NAME, constants.RUN_NAME_COL_NAME]
|
|
510
|
-
)
|
|
511
|
-
|
|
512
|
-
return pd.DataFrame(
|
|
513
|
-
runs, columns=[constants.RUN_ID_COL_NAME, constants.RUN_NAME_COL_NAME]
|
|
514
|
-
)
|
|
515
|
-
|
|
516
481
|
def search_runs(
|
|
517
482
|
self,
|
|
518
483
|
ml_repo: str,
|
|
@@ -658,6 +623,74 @@ class MlFoundry:
|
|
|
658
623
|
"""
|
|
659
624
|
return self._tracking_uri
|
|
660
625
|
|
|
626
|
+
def _initialize_model_server(
|
|
627
|
+
self,
|
|
628
|
+
name: str,
|
|
629
|
+
model_version_fqn: str,
|
|
630
|
+
workspace_fqn: str,
|
|
631
|
+
model_server: ModelServer,
|
|
632
|
+
output_dir: Optional[str] = None,
|
|
633
|
+
) -> str:
|
|
634
|
+
"""
|
|
635
|
+
Initialize the model server for deployment.
|
|
636
|
+
|
|
637
|
+
Args:
|
|
638
|
+
name (str): Name of the application.
|
|
639
|
+
model_version_fqn (str): Fully Qualified Name of the model version.
|
|
640
|
+
workspace_fqn (str): Fully Qualified Name of the workspace.
|
|
641
|
+
model_server (ModelServer): Server type for deployment (e.g., TRITON).
|
|
642
|
+
output_dir (Optional[str]): Directory where the model files will be extracted.
|
|
643
|
+
Defaults to the current working directory.
|
|
644
|
+
|
|
645
|
+
Returns:
|
|
646
|
+
str: Path to the directory where the model files are extracted.
|
|
647
|
+
|
|
648
|
+
Raises:
|
|
649
|
+
MlFoundryException: If an error occurs during API calls, directory creation, or file extraction.
|
|
650
|
+
"""
|
|
651
|
+
|
|
652
|
+
# Using get_with_http_info to get the response object and extract the raw data
|
|
653
|
+
try:
|
|
654
|
+
export_deployment_files_request_dto = ExportDeploymentFilesRequestDto(
|
|
655
|
+
model_version_fqn=model_version_fqn,
|
|
656
|
+
workspace_fqn=workspace_fqn,
|
|
657
|
+
service_name=name,
|
|
658
|
+
model_server=model_server,
|
|
659
|
+
)
|
|
660
|
+
response = self._mlfoundry_artifacts_api.export_deployment_files_by_fqn_post_with_http_info(
|
|
661
|
+
export_deployment_files_request_dto=export_deployment_files_request_dto,
|
|
662
|
+
_preload_content=False,
|
|
663
|
+
_request_timeout=_ML_FOUNDRY_API_REQUEST_TIMEOUT,
|
|
664
|
+
)
|
|
665
|
+
except ApiException as e:
|
|
666
|
+
err_msg = (
|
|
667
|
+
f"Failed to fetch deployment files for name={name}, "
|
|
668
|
+
f"model_version_fqn={model_version_fqn}, workspace_fqn={workspace_fqn}. "
|
|
669
|
+
f"Error: {e}"
|
|
670
|
+
)
|
|
671
|
+
raise MlFoundryException(err_msg) from e
|
|
672
|
+
|
|
673
|
+
output_dir = os.path.abspath(output_dir or os.getcwd())
|
|
674
|
+
codegen_dir = os.path.join(output_dir, name)
|
|
675
|
+
if codegen_dir == output_dir:
|
|
676
|
+
raise ValueError("Name cannot be empty, please provide a valid name")
|
|
677
|
+
|
|
678
|
+
try:
|
|
679
|
+
with ContextualDirectoryManager(dir_path=codegen_dir) as dir_path:
|
|
680
|
+
with zipfile.ZipFile(BytesIO(response.raw_data), mode="r") as zip_file:
|
|
681
|
+
zip_file.extractall(dir_path)
|
|
682
|
+
except FileExistsError as e:
|
|
683
|
+
err_msg = (
|
|
684
|
+
f"Deployment directory {codegen_dir!r} already exists. "
|
|
685
|
+
"Please choose a different deployment name or delete the existing directory."
|
|
686
|
+
)
|
|
687
|
+
raise MlFoundryException(err_msg) from e
|
|
688
|
+
except zipfile.BadZipFile as e:
|
|
689
|
+
raise MlFoundryException(
|
|
690
|
+
f"Failed to extract model files. Error: {e}"
|
|
691
|
+
) from e
|
|
692
|
+
return codegen_dir
|
|
693
|
+
|
|
661
694
|
def get_model_version(
|
|
662
695
|
self,
|
|
663
696
|
ml_repo: str,
|
|
@@ -1227,12 +1260,11 @@ class MlFoundry:
|
|
|
1227
1260
|
ml_repo: str,
|
|
1228
1261
|
name: str,
|
|
1229
1262
|
model_file_or_folder: Union[str, BlobStorageDirectory],
|
|
1230
|
-
additional_files: Sequence[Tuple[Union[str, Path], Optional[str]]] = (),
|
|
1231
1263
|
description: Optional[str] = None,
|
|
1232
1264
|
metadata: Optional[Dict[str, Any]] = None,
|
|
1233
1265
|
progress: Optional[bool] = None,
|
|
1234
1266
|
framework: Optional[Union[str, ModelFramework, "ModelFrameworkType"]] = None,
|
|
1235
|
-
|
|
1267
|
+
environment: Optional[ModelVersionEnvironment] = None,
|
|
1236
1268
|
) -> ModelVersion:
|
|
1237
1269
|
"""
|
|
1238
1270
|
Serialize and log a versioned model under the current ml_repo. Each logged model generates a new version
|
|
@@ -1262,41 +1294,6 @@ class MlFoundry:
|
|
|
1262
1294
|
Can also be `None` if the framework is not known or not supported.
|
|
1263
1295
|
**Deprecated**: Prefer `ModelFrameworkType` over `enums.ModelFramework`.
|
|
1264
1296
|
|
|
1265
|
-
additional_files (Sequence[Tuple[Union[str, Path], Optional[str]]], optional): A list of pairs
|
|
1266
|
-
of (source path, destination path) to add additional files and folders
|
|
1267
|
-
to the model version contents. The first member of the pair should be a file or directory path
|
|
1268
|
-
and the second member should be the path inside the model versions contents to upload to.
|
|
1269
|
-
The model version contents are arranged like follows
|
|
1270
|
-
.
|
|
1271
|
-
└── model/
|
|
1272
|
-
└── # model files are serialized here
|
|
1273
|
-
└── # any additional files and folders can be added here.
|
|
1274
|
-
|
|
1275
|
-
You can also add additional files to model/ subdirectory by specifying the destination path as model/
|
|
1276
|
-
|
|
1277
|
-
```python
|
|
1278
|
-
from truefoundry.ml import TensorFlowFramework
|
|
1279
|
-
|
|
1280
|
-
run.log_model(
|
|
1281
|
-
name="xyz",
|
|
1282
|
-
model_file_or_folder="clf.joblib",
|
|
1283
|
-
framework=TensorFlowFramework(),
|
|
1284
|
-
additional_files=[("foo.txt", "foo/bar/foo.txt"), ("tokenizer/", "foo/tokenizer/")]
|
|
1285
|
-
)
|
|
1286
|
-
```
|
|
1287
|
-
|
|
1288
|
-
would result in
|
|
1289
|
-
|
|
1290
|
-
```
|
|
1291
|
-
.
|
|
1292
|
-
├── model/
|
|
1293
|
-
│ └── clf.joblib # if `model_file_or_folder` is a folder, contents will be added here
|
|
1294
|
-
└── foo/
|
|
1295
|
-
├── bar/
|
|
1296
|
-
│ └── foo.txt
|
|
1297
|
-
└── tokenizer/
|
|
1298
|
-
└── # contents of tokenizer/ directory will be uploaded here
|
|
1299
|
-
```
|
|
1300
1297
|
description (Optional[str], optional): arbitrary text upto 1024 characters to store as description.
|
|
1301
1298
|
This field can be updated at any time after logging. Defaults to `None`
|
|
1302
1299
|
metadata (Optional[Dict[str, Any]], optional): arbitrary json serializable dictionary to store metadata.
|
|
@@ -1386,13 +1383,12 @@ class MlFoundry:
|
|
|
1386
1383
|
ml_repo_id=ml_repo_id,
|
|
1387
1384
|
name=name,
|
|
1388
1385
|
model_file_or_folder=model_file_or_folder,
|
|
1389
|
-
additional_files=additional_files,
|
|
1390
1386
|
description=description,
|
|
1391
1387
|
metadata=metadata,
|
|
1392
1388
|
step=None,
|
|
1393
1389
|
progress=progress,
|
|
1394
1390
|
framework=framework,
|
|
1395
|
-
|
|
1391
|
+
environment=environment,
|
|
1396
1392
|
)
|
|
1397
1393
|
logger.info(f"Logged model successfully with fqn {model_version.fqn!r}")
|
|
1398
1394
|
return model_version
|
truefoundry/ml/mlfoundry_run.py
CHANGED
|
@@ -3,7 +3,6 @@ import os
|
|
|
3
3
|
import platform
|
|
4
4
|
import re
|
|
5
5
|
import time
|
|
6
|
-
from pathlib import Path
|
|
7
6
|
from typing import (
|
|
8
7
|
TYPE_CHECKING,
|
|
9
8
|
Any,
|
|
@@ -12,7 +11,6 @@ from typing import (
|
|
|
12
11
|
Iterator,
|
|
13
12
|
List,
|
|
14
13
|
Optional,
|
|
15
|
-
Sequence,
|
|
16
14
|
Tuple,
|
|
17
15
|
Union,
|
|
18
16
|
)
|
|
@@ -20,7 +18,7 @@ from urllib.parse import urljoin, urlsplit
|
|
|
20
18
|
|
|
21
19
|
from truefoundry import version
|
|
22
20
|
from truefoundry.common.utils import relogin_error_message
|
|
23
|
-
from truefoundry.ml import constants
|
|
21
|
+
from truefoundry.ml import ModelVersionEnvironment, constants
|
|
24
22
|
from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
|
|
25
23
|
ArtifactType,
|
|
26
24
|
DeleteRunRequest,
|
|
@@ -930,13 +928,12 @@ class MlFoundryRun:
|
|
|
930
928
|
*,
|
|
931
929
|
name: str,
|
|
932
930
|
model_file_or_folder: Union[str, BlobStorageDirectory],
|
|
933
|
-
additional_files: Sequence[Tuple[Union[str, Path], Optional[str]]] = (),
|
|
934
931
|
description: Optional[str] = None,
|
|
935
932
|
metadata: Optional[Dict[str, Any]] = None,
|
|
936
933
|
step: int = 0,
|
|
937
934
|
progress: Optional[bool] = None,
|
|
938
935
|
framework: Optional[Union[str, ModelFramework, "ModelFrameworkType"]] = None,
|
|
939
|
-
|
|
936
|
+
environment: Optional[ModelVersionEnvironment] = None,
|
|
940
937
|
) -> ModelVersion:
|
|
941
938
|
# TODO (chiragjn): Document mapping of framework to list of valid model save kwargs
|
|
942
939
|
# TODO (chiragjn): Add more examples
|
|
@@ -964,33 +961,7 @@ class MlFoundryRun:
|
|
|
964
961
|
Supported frameworks can be found in `truefoundry.ml.enums.ModelFramework`.
|
|
965
962
|
Can also be `None` if the framework is not known or not supported.
|
|
966
963
|
**Deprecated**: Prefer `ModelFrameworkType` over `enums.ModelFramework`.
|
|
967
|
-
additional_files (Sequence[Tuple[Union[str, Path], Optional[str]]], optional): A list of pairs
|
|
968
|
-
of (source path, destination path) to add additional files and folders
|
|
969
|
-
to the model version contents. The first member of the pair should be a file or directory path
|
|
970
|
-
and the second member should be the path inside the model versions contents to upload to.
|
|
971
|
-
The model version contents are arranged like follows
|
|
972
|
-
.
|
|
973
|
-
└── model/
|
|
974
|
-
└── # model files are serialized here
|
|
975
|
-
└── # any additional files and folders can be added here.
|
|
976
|
-
|
|
977
|
-
You can also add additional files to model/ subdirectory by specifying the destination path as model/
|
|
978
964
|
|
|
979
|
-
```
|
|
980
|
-
E.g. >>> run.log_model(
|
|
981
|
-
... name="xyz", model_file_or_folder="clf.joblib", framework="sklearn",
|
|
982
|
-
... additional_files=[("foo.txt", "foo/bar/foo.txt"), ("tokenizer/", "foo/tokenizer/")]
|
|
983
|
-
... )
|
|
984
|
-
would result in
|
|
985
|
-
.
|
|
986
|
-
├── model/
|
|
987
|
-
│ └── clf.joblib # if `model_file_or_folder` is a folder, contents will be added here
|
|
988
|
-
└── foo/
|
|
989
|
-
├── bar/
|
|
990
|
-
│ └── foo.txt
|
|
991
|
-
└── tokenizer/
|
|
992
|
-
└── # contents of tokenizer/ directory will be uploaded here
|
|
993
|
-
```
|
|
994
965
|
description (Optional[str], optional): arbitrary text upto 1024 characters to store as description.
|
|
995
966
|
This field can be updated at any time after logging. Defaults to `None`
|
|
996
967
|
metadata (Optional[Dict[str, Any]], optional): arbitrary json serializable dictionary to store metadata.
|
|
@@ -1083,13 +1054,12 @@ class MlFoundryRun:
|
|
|
1083
1054
|
run=self,
|
|
1084
1055
|
name=name,
|
|
1085
1056
|
model_file_or_folder=model_file_or_folder,
|
|
1086
|
-
additional_files=additional_files,
|
|
1087
1057
|
description=description,
|
|
1088
1058
|
metadata=metadata,
|
|
1089
1059
|
step=step,
|
|
1090
1060
|
progress=progress,
|
|
1091
1061
|
framework=framework,
|
|
1092
|
-
|
|
1062
|
+
environment=environment,
|
|
1093
1063
|
)
|
|
1094
1064
|
logger.info(f"Logged model successfully with fqn {model_version.fqn!r}")
|
|
1095
1065
|
return model_version
|