clarifai 11.4.1__py3-none-any.whl → 11.4.3rc1__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.
- clarifai/__init__.py +1 -1
- clarifai/__pycache__/__init__.cpython-312.pyc +0 -0
- clarifai/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/__pycache__/errors.cpython-312.pyc +0 -0
- clarifai/__pycache__/errors.cpython-39.pyc +0 -0
- clarifai/__pycache__/versions.cpython-312.pyc +0 -0
- clarifai/__pycache__/versions.cpython-39.pyc +0 -0
- clarifai/cli/__pycache__/__init__.cpython-312.pyc +0 -0
- clarifai/cli/__pycache__/base.cpython-312.pyc +0 -0
- clarifai/cli/__pycache__/compute_cluster.cpython-312.pyc +0 -0
- clarifai/cli/__pycache__/deployment.cpython-312.pyc +0 -0
- clarifai/cli/__pycache__/model.cpython-312.pyc +0 -0
- clarifai/cli/__pycache__/nodepool.cpython-312.pyc +0 -0
- clarifai/cli/base.py +8 -0
- clarifai/cli/model.py +6 -6
- clarifai/client/__pycache__/__init__.cpython-312.pyc +0 -0
- clarifai/client/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/client/__pycache__/app.cpython-312.pyc +0 -0
- clarifai/client/__pycache__/app.cpython-39.pyc +0 -0
- clarifai/client/__pycache__/base.cpython-312.pyc +0 -0
- clarifai/client/__pycache__/base.cpython-39.pyc +0 -0
- clarifai/client/__pycache__/compute_cluster.cpython-312.pyc +0 -0
- clarifai/client/__pycache__/dataset.cpython-312.pyc +0 -0
- clarifai/client/__pycache__/deployment.cpython-312.pyc +0 -0
- clarifai/client/__pycache__/input.cpython-312.pyc +0 -0
- clarifai/client/__pycache__/lister.cpython-312.pyc +0 -0
- clarifai/client/__pycache__/model.cpython-312.pyc +0 -0
- clarifai/client/__pycache__/model_client.cpython-312.pyc +0 -0
- clarifai/client/__pycache__/module.cpython-312.pyc +0 -0
- clarifai/client/__pycache__/nodepool.cpython-312.pyc +0 -0
- clarifai/client/__pycache__/runner.cpython-312.pyc +0 -0
- clarifai/client/__pycache__/search.cpython-312.pyc +0 -0
- clarifai/client/__pycache__/user.cpython-312.pyc +0 -0
- clarifai/client/__pycache__/workflow.cpython-312.pyc +0 -0
- clarifai/client/auth/__pycache__/__init__.cpython-312.pyc +0 -0
- clarifai/client/auth/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/client/auth/__pycache__/helper.cpython-312.pyc +0 -0
- clarifai/client/auth/__pycache__/helper.cpython-39.pyc +0 -0
- clarifai/client/auth/__pycache__/register.cpython-312.pyc +0 -0
- clarifai/client/auth/__pycache__/register.cpython-39.pyc +0 -0
- clarifai/client/auth/__pycache__/stub.cpython-312.pyc +0 -0
- clarifai/client/auth/__pycache__/stub.cpython-39.pyc +0 -0
- clarifai/client/dataset.py +6 -0
- clarifai/constants/__pycache__/base.cpython-312.pyc +0 -0
- clarifai/constants/__pycache__/base.cpython-39.pyc +0 -0
- clarifai/constants/__pycache__/dataset.cpython-312.pyc +0 -0
- clarifai/constants/__pycache__/input.cpython-312.pyc +0 -0
- clarifai/constants/__pycache__/model.cpython-312.pyc +0 -0
- clarifai/constants/__pycache__/rag.cpython-312.pyc +0 -0
- clarifai/constants/__pycache__/search.cpython-312.pyc +0 -0
- clarifai/constants/__pycache__/workflow.cpython-312.pyc +0 -0
- clarifai/datasets/__pycache__/__init__.cpython-312.pyc +0 -0
- clarifai/datasets/export/__pycache__/__init__.cpython-312.pyc +0 -0
- clarifai/datasets/export/__pycache__/inputs_annotations.cpython-312.pyc +0 -0
- clarifai/datasets/upload/__pycache__/__init__.cpython-312.pyc +0 -0
- clarifai/datasets/upload/__pycache__/base.cpython-312.pyc +0 -0
- clarifai/datasets/upload/__pycache__/features.cpython-312.pyc +0 -0
- clarifai/datasets/upload/__pycache__/image.cpython-312.pyc +0 -0
- clarifai/datasets/upload/__pycache__/multimodal.cpython-312.pyc +0 -0
- clarifai/datasets/upload/__pycache__/text.cpython-312.pyc +0 -0
- clarifai/datasets/upload/__pycache__/utils.cpython-312.pyc +0 -0
- clarifai/datasets/upload/loaders/__pycache__/__init__.cpython-312.pyc +0 -0
- clarifai/datasets/upload/loaders/__pycache__/coco_detection.cpython-312.pyc +0 -0
- clarifai/datasets/upload/loaders/__pycache__/imagenet_classification.cpython-312.pyc +0 -0
- clarifai/modules/__pycache__/__init__.cpython-312.pyc +0 -0
- clarifai/modules/__pycache__/css.cpython-312.pyc +0 -0
- clarifai/rag/__pycache__/__init__.cpython-312.pyc +0 -0
- clarifai/rag/__pycache__/rag.cpython-312.pyc +0 -0
- clarifai/rag/__pycache__/utils.cpython-312.pyc +0 -0
- clarifai/runners/__pycache__/__init__.cpython-312.pyc +0 -0
- clarifai/runners/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/runners/__pycache__/server.cpython-312.pyc +0 -0
- clarifai/runners/models/__pycache__/__init__.cpython-312.pyc +0 -0
- clarifai/runners/models/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/runners/models/__pycache__/base_typed_model.cpython-312.pyc +0 -0
- clarifai/runners/models/__pycache__/mcp_class.cpython-312.pyc +0 -0
- clarifai/runners/models/__pycache__/model_builder.cpython-312.pyc +0 -0
- clarifai/runners/models/__pycache__/model_builder.cpython-39.pyc +0 -0
- clarifai/runners/models/__pycache__/model_class.cpython-312.pyc +0 -0
- clarifai/runners/models/__pycache__/model_run_locally.cpython-312.pyc +0 -0
- clarifai/runners/models/__pycache__/model_runner.cpython-312.pyc +0 -0
- clarifai/runners/models/__pycache__/model_servicer.cpython-312.pyc +0 -0
- clarifai/runners/models/__pycache__/test_model_builder.cpython-312-pytest-8.3.5.pyc +0 -0
- clarifai/runners/models/base_typed_model.py +238 -0
- clarifai/runners/models/example_mcp_server.py +44 -0
- clarifai/runners/models/mcp_class.py +143 -0
- clarifai/runners/models/mcp_class.py~ +149 -0
- clarifai/runners/models/model_builder.py +167 -38
- clarifai/runners/models/model_class.py +5 -22
- clarifai/runners/models/model_run_locally.py +0 -4
- clarifai/runners/models/test_model_builder.py +89 -0
- clarifai/runners/models/visual_classifier_class.py +75 -0
- clarifai/runners/models/visual_detector_class.py +79 -0
- clarifai/runners/utils/__pycache__/__init__.cpython-312.pyc +0 -0
- clarifai/runners/utils/__pycache__/code_script.cpython-312.pyc +0 -0
- clarifai/runners/utils/__pycache__/const.cpython-312.pyc +0 -0
- clarifai/runners/utils/__pycache__/data_handler.cpython-312.pyc +0 -0
- clarifai/runners/utils/__pycache__/data_types.cpython-312.pyc +0 -0
- clarifai/runners/utils/__pycache__/data_utils.cpython-312.pyc +0 -0
- clarifai/runners/utils/__pycache__/loader.cpython-312.pyc +0 -0
- clarifai/runners/utils/__pycache__/method_signatures.cpython-312.pyc +0 -0
- clarifai/runners/utils/__pycache__/serializers.cpython-312.pyc +0 -0
- clarifai/runners/utils/__pycache__/url_fetcher.cpython-312.pyc +0 -0
- clarifai/runners/utils/code_script.py +41 -44
- clarifai/runners/utils/const.py +15 -0
- clarifai/runners/utils/data_handler.py +231 -0
- clarifai/runners/utils/data_types/__pycache__/__init__.cpython-312.pyc +0 -0
- clarifai/runners/utils/data_types/__pycache__/data_types.cpython-312.pyc +0 -0
- clarifai/runners/utils/data_utils.py +33 -5
- clarifai/runners/utils/loader.py +23 -2
- clarifai/runners/utils/method_signatures.py +4 -4
- clarifai/schema/__pycache__/search.cpython-312.pyc +0 -0
- clarifai/urls/__pycache__/helper.cpython-312.pyc +0 -0
- clarifai/utils/__pycache__/__init__.cpython-312.pyc +0 -0
- clarifai/utils/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/utils/__pycache__/cli.cpython-312.pyc +0 -0
- clarifai/utils/__pycache__/config.cpython-312.pyc +0 -0
- clarifai/utils/__pycache__/constants.cpython-312.pyc +0 -0
- clarifai/utils/__pycache__/constants.cpython-39.pyc +0 -0
- clarifai/utils/__pycache__/logging.cpython-312.pyc +0 -0
- clarifai/utils/__pycache__/logging.cpython-39.pyc +0 -0
- clarifai/utils/__pycache__/misc.cpython-312.pyc +0 -0
- clarifai/utils/__pycache__/misc.cpython-39.pyc +0 -0
- clarifai/utils/__pycache__/model_train.cpython-312.pyc +0 -0
- clarifai/utils/__pycache__/protobuf.cpython-312.pyc +0 -0
- clarifai/utils/config.py +19 -0
- clarifai/utils/config.py~ +145 -0
- clarifai/utils/evaluation/__pycache__/__init__.cpython-312.pyc +0 -0
- clarifai/utils/evaluation/__pycache__/helpers.cpython-312.pyc +0 -0
- clarifai/utils/evaluation/__pycache__/main.cpython-312.pyc +0 -0
- clarifai/utils/logging.py +22 -5
- clarifai/workflows/__pycache__/__init__.cpython-312.pyc +0 -0
- clarifai/workflows/__pycache__/export.cpython-312.pyc +0 -0
- clarifai/workflows/__pycache__/utils.cpython-312.pyc +0 -0
- clarifai/workflows/__pycache__/validate.cpython-312.pyc +0 -0
- {clarifai-11.4.1.dist-info → clarifai-11.4.3rc1.dist-info}/METADATA +2 -14
- clarifai-11.4.3rc1.dist-info/RECORD +230 -0
- {clarifai-11.4.1.dist-info → clarifai-11.4.3rc1.dist-info}/WHEEL +1 -1
- clarifai-11.4.1.dist-info/RECORD +0 -109
- {clarifai-11.4.1.dist-info/licenses → clarifai-11.4.3rc1.dist-info}/LICENSE +0 -0
- {clarifai-11.4.1.dist-info → clarifai-11.4.3rc1.dist-info}/entry_points.txt +0 -0
- {clarifai-11.4.1.dist-info → clarifai-11.4.3rc1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,231 @@
|
|
1
|
+
from typing import Dict, List, Tuple, Union
|
2
|
+
|
3
|
+
import numpy as np
|
4
|
+
from clarifai_grpc.grpc.api import resources_pb2
|
5
|
+
from clarifai_grpc.grpc.api.status import status_code_pb2, status_pb2
|
6
|
+
from PIL import Image
|
7
|
+
|
8
|
+
from clarifai.client.auth.helper import ClarifaiAuthHelper
|
9
|
+
|
10
|
+
from .data_utils import bytes_to_image, image_to_bytes
|
11
|
+
|
12
|
+
|
13
|
+
class BaseDataHandler:
|
14
|
+
|
15
|
+
def __init__(self,
|
16
|
+
proto: Union[resources_pb2.Input, resources_pb2.Output],
|
17
|
+
auth: ClarifaiAuthHelper = None):
|
18
|
+
self._proto = proto
|
19
|
+
self._auth = auth
|
20
|
+
|
21
|
+
#
|
22
|
+
def to_python(self):
|
23
|
+
return dict(text=self.text, image=self.image, audio=self.audio)
|
24
|
+
|
25
|
+
# ---------------- Start get/setters ---------------- #
|
26
|
+
# Proto
|
27
|
+
@property
|
28
|
+
def proto(self):
|
29
|
+
return self._proto
|
30
|
+
|
31
|
+
# Status
|
32
|
+
@property
|
33
|
+
def status(self) -> status_pb2.Status:
|
34
|
+
return self._proto.status
|
35
|
+
|
36
|
+
def set_status(self, code: str, description: str = ""):
|
37
|
+
self._proto.status.code = code
|
38
|
+
self._proto.status.description = description
|
39
|
+
|
40
|
+
# Text
|
41
|
+
@property
|
42
|
+
def text(self) -> Union[None, str]:
|
43
|
+
data = self._proto.data.text
|
44
|
+
text = None
|
45
|
+
if data.ByteSize():
|
46
|
+
if data.raw:
|
47
|
+
text = data.raw
|
48
|
+
else:
|
49
|
+
raise NotImplementedError
|
50
|
+
return text
|
51
|
+
|
52
|
+
def set_text(self, text: str):
|
53
|
+
self._proto.data.text.raw = text
|
54
|
+
|
55
|
+
# Image
|
56
|
+
@property
|
57
|
+
def image(self, format: str = "np") -> Union[None, Image.Image, np.ndarray]:
|
58
|
+
data = self._proto.data.image
|
59
|
+
image = None
|
60
|
+
if data.ByteSize():
|
61
|
+
data: resources_pb2.Image = data
|
62
|
+
if data.base64:
|
63
|
+
image = data.base64
|
64
|
+
elif data.url:
|
65
|
+
raise NotImplementedError
|
66
|
+
image = bytes_to_image(image)
|
67
|
+
image = image if not format == "np" else np.asarray(image).astype("uint8")
|
68
|
+
return image
|
69
|
+
|
70
|
+
def set_image(self, image: Union[Image.Image, np.ndarray]):
|
71
|
+
if isinstance(image, np.ndarray):
|
72
|
+
image = Image.fromarray(image)
|
73
|
+
self._proto.data.image.base64 = image_to_bytes(image)
|
74
|
+
|
75
|
+
# Audio
|
76
|
+
@property
|
77
|
+
def audio(self) -> bytes:
|
78
|
+
data = self._proto.data.audio
|
79
|
+
audio = None
|
80
|
+
if data.ByteSize():
|
81
|
+
if data.base64:
|
82
|
+
audio = data.base64
|
83
|
+
return audio
|
84
|
+
|
85
|
+
def set_audio(self, audio: bytes):
|
86
|
+
self._proto.data.audio.base64 = audio
|
87
|
+
|
88
|
+
# Bboxes
|
89
|
+
@property
|
90
|
+
def bboxes(self, real_coord: bool = False, image_width: int = None,
|
91
|
+
image_height: int = None) -> Tuple[List, List, List]:
|
92
|
+
if real_coord:
|
93
|
+
assert (image_height or image_width
|
94
|
+
), "image_height and image_width are required when when return real coordinates"
|
95
|
+
xyxy = []
|
96
|
+
scores = []
|
97
|
+
concepts = []
|
98
|
+
for _, each in enumerate(self._proto.data.regions):
|
99
|
+
box = each.region_info
|
100
|
+
score = each.value
|
101
|
+
concept = each.data.concepts[0].id
|
102
|
+
x1 = box.left_col
|
103
|
+
y1 = box.top_row
|
104
|
+
x2 = box.right_col
|
105
|
+
y2 = box.bottom_row
|
106
|
+
if real_coord:
|
107
|
+
x1 = x1 * image_width
|
108
|
+
y1 = y1 * image_height
|
109
|
+
x2 = x2 * image_width
|
110
|
+
y2 = y2 * image_height
|
111
|
+
xyxy.append([x1, y1, x2, y2])
|
112
|
+
scores.append(score)
|
113
|
+
concepts.append(concept)
|
114
|
+
|
115
|
+
return xyxy, scores, concepts
|
116
|
+
|
117
|
+
def set_bboxes(self,
|
118
|
+
boxes: list,
|
119
|
+
scores: list,
|
120
|
+
concepts: list,
|
121
|
+
real_coord: bool = False,
|
122
|
+
image_width: int = None,
|
123
|
+
image_height: int = None):
|
124
|
+
if real_coord:
|
125
|
+
assert (image_height and
|
126
|
+
image_width), "image_height and image_width are required when `real_coord` is set"
|
127
|
+
bboxes = [[x[1] / image_height, x[0] / image_width, x[3] / image_height, x[2] / image_width]
|
128
|
+
for x in boxes] # normalize the bboxes to [0,1] and [y1 x1 y2 x2]
|
129
|
+
bboxes = np.clip(bboxes, 0, 1.0)
|
130
|
+
|
131
|
+
regions = []
|
132
|
+
for ith, bbox in enumerate(bboxes):
|
133
|
+
score = scores[ith]
|
134
|
+
concept = concepts[ith]
|
135
|
+
if any([each > 1.0 for each in bbox]):
|
136
|
+
assert ValueError(
|
137
|
+
"Box coordinates is not normalized between [0, 1]. Please set format_box to True and provide image_height and image_width to normalize"
|
138
|
+
)
|
139
|
+
region = resources_pb2.RegionInfo(bounding_box=resources_pb2.BoundingBox(
|
140
|
+
top_row=bbox[0], # y_min
|
141
|
+
left_col=bbox[1], # x_min
|
142
|
+
bottom_row=bbox[2], # y_max
|
143
|
+
right_col=bbox[3], # x_max
|
144
|
+
))
|
145
|
+
data = resources_pb2.Data(concepts=resources_pb2.Concept(id=concept, value=score))
|
146
|
+
regions.append(resources_pb2.Region(region_info=region, data=data))
|
147
|
+
|
148
|
+
self._proto.data.regions = regions
|
149
|
+
|
150
|
+
# Concepts
|
151
|
+
@property
|
152
|
+
def concepts(self) -> Dict[str, float]:
|
153
|
+
con_scores = {}
|
154
|
+
for each in self.proto.data.concepts:
|
155
|
+
con_scores.update({each.id: each.value})
|
156
|
+
return con_scores
|
157
|
+
|
158
|
+
def set_concepts(self, concept_score_pairs: Dict[str, float]):
|
159
|
+
concepts = []
|
160
|
+
for concept, score in concept_score_pairs.items():
|
161
|
+
con_score = resources_pb2.Concept(id=concept, name=concept, value=score)
|
162
|
+
concepts.append(con_score)
|
163
|
+
if concepts:
|
164
|
+
self._proto.data.ClearField("concepts")
|
165
|
+
for each in concepts:
|
166
|
+
self._proto.data.concepts.append(each)
|
167
|
+
|
168
|
+
# Embeddings
|
169
|
+
@property
|
170
|
+
def embeddings(self) -> List[List[float]]:
|
171
|
+
return [each.vector for each in self.proto.data.embeddings]
|
172
|
+
|
173
|
+
def set_embeddings(self, list_vectors: List[List[float]]):
|
174
|
+
if list_vectors[0]:
|
175
|
+
self._proto.data.ClearField("embeddings")
|
176
|
+
for vec in list_vectors:
|
177
|
+
self._proto.data.embeddings.append(
|
178
|
+
resources_pb2.Embedding(vector=vec, num_dimensions=len(vec)))
|
179
|
+
|
180
|
+
# ---------------- End get/setters ---------------- #
|
181
|
+
|
182
|
+
# Constructors
|
183
|
+
@classmethod
|
184
|
+
def from_proto(cls, proto):
|
185
|
+
clss = cls(proto=proto)
|
186
|
+
return clss
|
187
|
+
|
188
|
+
@classmethod
|
189
|
+
def from_data(
|
190
|
+
cls,
|
191
|
+
status_code: int = status_code_pb2.SUCCESS,
|
192
|
+
status_description: str = "",
|
193
|
+
text: str = None,
|
194
|
+
image: Union[Image.Image, np.ndarray] = None,
|
195
|
+
audio: bytes = None,
|
196
|
+
boxes: dict = None,
|
197
|
+
concepts: Dict[str, float] = {},
|
198
|
+
embeddings: List[List[float]] = [],
|
199
|
+
) -> 'OutputDataHandler':
|
200
|
+
clss = cls(proto=resources_pb2.Output())
|
201
|
+
if isinstance(image, Image.Image) or isinstance(image, np.ndarray):
|
202
|
+
clss.set_image(image)
|
203
|
+
if text:
|
204
|
+
clss.set_text(text)
|
205
|
+
if audio:
|
206
|
+
clss.set_audio(audio)
|
207
|
+
if boxes:
|
208
|
+
clss.set_bboxes(**boxes)
|
209
|
+
if concepts:
|
210
|
+
clss.set_concepts(concepts)
|
211
|
+
if embeddings:
|
212
|
+
clss.set_embeddings(embeddings)
|
213
|
+
|
214
|
+
clss.set_status(code=status_code, description=status_description)
|
215
|
+
return clss
|
216
|
+
|
217
|
+
|
218
|
+
class InputDataHandler(BaseDataHandler):
|
219
|
+
|
220
|
+
def __init__(self,
|
221
|
+
proto: resources_pb2.Input = resources_pb2.Input(),
|
222
|
+
auth: ClarifaiAuthHelper = None):
|
223
|
+
super().__init__(proto=proto, auth=auth)
|
224
|
+
|
225
|
+
|
226
|
+
class OutputDataHandler(BaseDataHandler):
|
227
|
+
|
228
|
+
def __init__(self,
|
229
|
+
proto: resources_pb2.Output = resources_pb2.Output(),
|
230
|
+
auth: ClarifaiAuthHelper = None):
|
231
|
+
super().__init__(proto=proto, auth=auth)
|
Binary file
|
Binary file
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import json
|
1
2
|
import math
|
2
3
|
import operator
|
3
4
|
from io import BytesIO
|
@@ -64,7 +65,7 @@ class Param(MessageData):
|
|
64
65
|
|
65
66
|
def __init__(
|
66
67
|
self,
|
67
|
-
default
|
68
|
+
default,
|
68
69
|
description=None,
|
69
70
|
min_value=None,
|
70
71
|
max_value=None,
|
@@ -77,6 +78,7 @@ class Param(MessageData):
|
|
77
78
|
self.max_value = max_value
|
78
79
|
self.choices = choices
|
79
80
|
self.is_param = is_param
|
81
|
+
self._patch_encoder()
|
80
82
|
|
81
83
|
def __repr__(self) -> str:
|
82
84
|
attrs = []
|
@@ -153,6 +155,16 @@ class Param(MessageData):
|
|
153
155
|
def __ge__(self, other):
|
154
156
|
return self.default >= other
|
155
157
|
|
158
|
+
def __getattribute__(self, name):
|
159
|
+
"""Intercept attribute access to mimic default value behavior"""
|
160
|
+
try:
|
161
|
+
# First try to get Param attributes normally
|
162
|
+
return object.__getattribute__(self, name)
|
163
|
+
except AttributeError:
|
164
|
+
# Fall back to the default value's attributes
|
165
|
+
default = object.__getattribute__(self, 'default')
|
166
|
+
return getattr(default, name)
|
167
|
+
|
156
168
|
# Arithmetic operators – # arithmetic & bitwise operators – auto-generated
|
157
169
|
_arith_ops = {
|
158
170
|
"__add__": operator.add,
|
@@ -169,7 +181,6 @@ class Param(MessageData):
|
|
169
181
|
"__rshift__": operator.rshift,
|
170
182
|
}
|
171
183
|
|
172
|
-
# Create both left- and right-hand versions of each operator
|
173
184
|
for _name, _op in _arith_ops.items():
|
174
185
|
|
175
186
|
def _make(op):
|
@@ -243,6 +254,24 @@ class Param(MessageData):
|
|
243
254
|
return self
|
244
255
|
return self.default
|
245
256
|
|
257
|
+
def __json__(self):
|
258
|
+
return self.default if not hasattr(self.default, '__json__') else self.default.__json__()
|
259
|
+
|
260
|
+
@classmethod
|
261
|
+
def _patch_encoder(cls):
|
262
|
+
# only patch once
|
263
|
+
if getattr(json.JSONEncoder, "_user_patched", False):
|
264
|
+
return
|
265
|
+
original = json.JSONEncoder.default
|
266
|
+
|
267
|
+
def default(self, obj):
|
268
|
+
if isinstance(obj, Param):
|
269
|
+
return obj.__json__()
|
270
|
+
return original(self, obj)
|
271
|
+
|
272
|
+
json.JSONEncoder.default = default
|
273
|
+
json.JSONEncoder._user_patched = True
|
274
|
+
|
246
275
|
def to_proto(self, proto=None) -> ParamProto:
|
247
276
|
if proto is None:
|
248
277
|
proto = ParamProto()
|
@@ -254,7 +283,7 @@ class Param(MessageData):
|
|
254
283
|
option = ModelTypeEnumOption(id=str(choice))
|
255
284
|
proto.model_type_enum_options.append(option)
|
256
285
|
|
257
|
-
proto.required =
|
286
|
+
proto.required = False
|
258
287
|
|
259
288
|
if self.min_value is not None or self.max_value is not None:
|
260
289
|
range_info = ModelTypeRangeInfo()
|
@@ -324,8 +353,7 @@ class Param(MessageData):
|
|
324
353
|
|
325
354
|
if proto is None:
|
326
355
|
proto = ParamProto()
|
327
|
-
|
328
|
-
proto.default = json.dumps(default)
|
356
|
+
proto.default = json.dumps(default)
|
329
357
|
return proto
|
330
358
|
except Exception:
|
331
359
|
if default is not None:
|
clarifai/runners/utils/loader.py
CHANGED
@@ -41,7 +41,7 @@ class HuggingFaceLoader:
|
|
41
41
|
return True
|
42
42
|
except Exception as e:
|
43
43
|
logger.error(
|
44
|
-
f"
|
44
|
+
f"Invalid Hugging Face token provided in the config file, this might cause issues with downloading the restricted model checkpoints. Failed reason: {e}"
|
45
45
|
)
|
46
46
|
return False
|
47
47
|
|
@@ -63,7 +63,6 @@ class HuggingFaceLoader:
|
|
63
63
|
try:
|
64
64
|
is_hf_model_exists = self.validate_hf_model()
|
65
65
|
if not is_hf_model_exists:
|
66
|
-
logger.error("Model %s not found on Hugging Face" % (self.repo_id))
|
67
66
|
return False
|
68
67
|
|
69
68
|
self.ignore_patterns = self._get_ignore_patterns()
|
@@ -205,6 +204,28 @@ class HuggingFaceLoader:
|
|
205
204
|
]
|
206
205
|
return self.ignore_patterns
|
207
206
|
|
207
|
+
@classmethod
|
208
|
+
def validate_hf_repo_access(cls, repo_id: str, token: str = None) -> bool:
|
209
|
+
# check if model exists on HF
|
210
|
+
try:
|
211
|
+
from huggingface_hub import auth_check
|
212
|
+
from huggingface_hub.utils import GatedRepoError, RepositoryNotFoundError
|
213
|
+
except ImportError:
|
214
|
+
raise ImportError(cls.HF_DOWNLOAD_TEXT)
|
215
|
+
|
216
|
+
try:
|
217
|
+
auth_check(repo_id, token=token)
|
218
|
+
logger.info("Hugging Face repo access validated")
|
219
|
+
return True
|
220
|
+
except GatedRepoError:
|
221
|
+
logger.error(
|
222
|
+
"Hugging Face repo is gated. Please make sure you have access to the repo."
|
223
|
+
)
|
224
|
+
return False
|
225
|
+
except RepositoryNotFoundError:
|
226
|
+
logger.error("Hugging Face repo not found. Please make sure the repo exists.")
|
227
|
+
return False
|
228
|
+
|
208
229
|
@staticmethod
|
209
230
|
def validate_config(checkpoint_path: str):
|
210
231
|
# check if downloaded config.json exists
|
@@ -302,6 +302,9 @@ def serialize(kwargs, signatures, proto=None, is_output=False):
|
|
302
302
|
raise TypeError(f'Missing required argument: {sig.name}')
|
303
303
|
continue # skip missing fields, they can be set to default on the server
|
304
304
|
data = kwargs[sig.name]
|
305
|
+
default = data_utils.Param.get_default(sig)
|
306
|
+
if data is None and default is None:
|
307
|
+
continue
|
305
308
|
serializer = serializer_from_signature(sig)
|
306
309
|
# TODO determine if any (esp the first) var can go in the proto without parts
|
307
310
|
# and whether to put this in the signature or dynamically determine it
|
@@ -312,7 +315,7 @@ def serialize(kwargs, signatures, proto=None, is_output=False):
|
|
312
315
|
return proto
|
313
316
|
|
314
317
|
|
315
|
-
def deserialize(proto, signatures,
|
318
|
+
def deserialize(proto, signatures, is_output=False):
|
316
319
|
'''
|
317
320
|
Deserialize the given proto into kwargs using the given signatures.
|
318
321
|
'''
|
@@ -323,11 +326,8 @@ def deserialize(proto, signatures, inference_params={}, is_output=False):
|
|
323
326
|
for sig_i, sig in enumerate(signatures):
|
324
327
|
serializer = serializer_from_signature(sig)
|
325
328
|
part = parts_by_name.get(sig.name)
|
326
|
-
inference_params_value = inference_params.get(sig.name)
|
327
329
|
if part is not None:
|
328
330
|
kwargs[sig.name] = serializer.deserialize(part.data)
|
329
|
-
elif inference_params_value is not None:
|
330
|
-
kwargs[sig.name] = inference_params_value
|
331
331
|
else:
|
332
332
|
if sig_i == 0:
|
333
333
|
# possible inlined first value
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
clarifai/utils/config.py
CHANGED
@@ -102,6 +102,25 @@ class Context(OrderedDict):
|
|
102
102
|
envvar_name = 'CLARIFAI_' + envvar_name
|
103
103
|
os.environ[envvar_name] = str(v)
|
104
104
|
|
105
|
+
def print_env_vars(self):
|
106
|
+
"""prints the context env vars to the terminal
|
107
|
+
|
108
|
+
Example:
|
109
|
+
# This is helpful in scripts so you can do
|
110
|
+
|
111
|
+
from clarifai.utils.config import Config
|
112
|
+
|
113
|
+
Config.from_yaml().current.print_env_vars()
|
114
|
+
|
115
|
+
"""
|
116
|
+
for k, v in self['env'].items():
|
117
|
+
if isinstance(v, dict):
|
118
|
+
continue
|
119
|
+
envvar_name = k.upper()
|
120
|
+
if not envvar_name.startswith('CLARIFAI_'):
|
121
|
+
envvar_name = 'CLARIFAI_' + envvar_name
|
122
|
+
print(f"export {envvar_name}=\"{v}\"")
|
123
|
+
|
105
124
|
|
106
125
|
@dataclass
|
107
126
|
class Config:
|
@@ -0,0 +1,145 @@
|
|
1
|
+
import click
|
2
|
+
import sys
|
3
|
+
import os
|
4
|
+
import typing as t
|
5
|
+
import yaml
|
6
|
+
|
7
|
+
from dataclasses import dataclass, field
|
8
|
+
from clarifai.utils.cli import AliasedGroup, TableFormatter, load_command_modules, load_command_modules
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
@dataclass
|
13
|
+
class AccessToken():
|
14
|
+
type: str
|
15
|
+
value: str
|
16
|
+
|
17
|
+
def __str__(self):
|
18
|
+
return f'{self.type}:{self.value}' if self.type == 'env' else '********'
|
19
|
+
|
20
|
+
def to_serializable_dict(self):
|
21
|
+
return self.__dict__
|
22
|
+
|
23
|
+
@classmethod
|
24
|
+
def from_serializable_dict(cls, _dict):
|
25
|
+
return cls(**_dict)
|
26
|
+
|
27
|
+
# Dictionary protocol methods:
|
28
|
+
|
29
|
+
def __getitem__(self, key: str) -> t.Any:
|
30
|
+
if key == 'type':
|
31
|
+
return self.type
|
32
|
+
elif key == 'value':
|
33
|
+
return self.value
|
34
|
+
else:
|
35
|
+
raise KeyError(key)
|
36
|
+
|
37
|
+
def __setitem__(self, key: str, value: t.Any) -> None:
|
38
|
+
if key == 'type':
|
39
|
+
self.type = value
|
40
|
+
elif key == 'value':
|
41
|
+
self.value = value
|
42
|
+
else:
|
43
|
+
raise KeyError(key)
|
44
|
+
|
45
|
+
def __delitem__(self, key: str) -> None:
|
46
|
+
raise TypeError("Cannot delete attributes from AccessToken")
|
47
|
+
|
48
|
+
def __iter__(self):
|
49
|
+
return iter(['type', 'value'])
|
50
|
+
|
51
|
+
def __len__(self) -> int:
|
52
|
+
return 2
|
53
|
+
|
54
|
+
def __contains__(self, key: str) -> bool:
|
55
|
+
return key in ['type', 'value']
|
56
|
+
|
57
|
+
def keys(self):
|
58
|
+
return ['type', 'value']
|
59
|
+
|
60
|
+
def values(self):
|
61
|
+
return [self.type, self.value]
|
62
|
+
|
63
|
+
def items(self):
|
64
|
+
return [('type', self.type), ('value', self.value)]
|
65
|
+
|
66
|
+
def get(self, key: str, default: t.Any = None) -> t.Any:
|
67
|
+
try:
|
68
|
+
return self[key]
|
69
|
+
except KeyError:
|
70
|
+
return default
|
71
|
+
|
72
|
+
|
73
|
+
@dataclass
|
74
|
+
class Context():
|
75
|
+
name: str
|
76
|
+
user_id: str
|
77
|
+
base_url: str
|
78
|
+
access_token: AccessToken = field(default_factory=lambda: AccessToken('env', 'CLARIFAI_PAT'))
|
79
|
+
env: t.Dict[str, str] = field(default_factory=dict)
|
80
|
+
|
81
|
+
pat: str = None
|
82
|
+
|
83
|
+
def _resolve_pat(self) -> str:
|
84
|
+
if self.access_token['type'].lower() == 'env':
|
85
|
+
return os.getenv(self.access_token['value'], '')
|
86
|
+
elif self.access_token['type'].lower() == 'raw':
|
87
|
+
return self.access_token['value']
|
88
|
+
else:
|
89
|
+
raise Exception('Only "env" and "raw" methods are supported')
|
90
|
+
|
91
|
+
def __post_init__(self):
|
92
|
+
self.pat = self._resolve_pat()
|
93
|
+
self.access_token = AccessToken(**self.access_token)
|
94
|
+
|
95
|
+
def to_serializable_dict(self):
|
96
|
+
result = {
|
97
|
+
'name': self.name,
|
98
|
+
'user_id': self.user_id,
|
99
|
+
'base_url': self.base_url,
|
100
|
+
'access_token': self.access_token.to_serializable_dict(),
|
101
|
+
}
|
102
|
+
if self.env:
|
103
|
+
result['env'] = self.env
|
104
|
+
return result
|
105
|
+
|
106
|
+
|
107
|
+
@dataclass
|
108
|
+
class Config():
|
109
|
+
current_context: str
|
110
|
+
filename: str
|
111
|
+
contexts: dict[str, Context] = field(default_factory=dict)
|
112
|
+
|
113
|
+
def __post_init__(self):
|
114
|
+
for k, v in self.contexts.items():
|
115
|
+
if 'name' not in v:
|
116
|
+
v['name'] = k
|
117
|
+
self.contexts = {k: Context(**v) for k, v in self.contexts.items()}
|
118
|
+
|
119
|
+
@classmethod
|
120
|
+
def from_yaml(cls, filename: str = DEFAULT_CONFIG):
|
121
|
+
with open(filename, 'r') as f:
|
122
|
+
cfg = yaml.safe_load(f)
|
123
|
+
return cls(**cfg, filename=filename)
|
124
|
+
|
125
|
+
def to_dict(self):
|
126
|
+
return {
|
127
|
+
'current_context': self.current_context,
|
128
|
+
'contexts': {k: v.to_serializable_dict()
|
129
|
+
for k, v in self.contexts.items()}
|
130
|
+
}
|
131
|
+
|
132
|
+
def to_yaml(self, filename: str = None):
|
133
|
+
if filename is None:
|
134
|
+
filename = self.filename
|
135
|
+
dir = os.path.dirname(filename)
|
136
|
+
if len(dir):
|
137
|
+
os.makedirs(dir, exist_ok=True)
|
138
|
+
_dict = self.to_dict()
|
139
|
+
for k, v in _dict['contexts'].items():
|
140
|
+
v.pop('name', None)
|
141
|
+
with open(filename, 'w') as f:
|
142
|
+
yaml.safe_dump(_dict, f)
|
143
|
+
|
144
|
+
def current(self) -> Context:
|
145
|
+
return self.contexts[self.current_context]
|
Binary file
|
Binary file
|
Binary file
|
clarifai/utils/logging.py
CHANGED
@@ -10,6 +10,8 @@ import traceback
|
|
10
10
|
from collections import defaultdict
|
11
11
|
from typing import Any, Dict, List, Optional, Union
|
12
12
|
|
13
|
+
from clarifai.errors import UserError
|
14
|
+
|
13
15
|
# The default logger to use throughout the SDK is defined at bottom of this file.
|
14
16
|
|
15
17
|
# For the json logger.
|
@@ -80,8 +82,13 @@ def get_req_id_from_context():
|
|
80
82
|
|
81
83
|
def display_workflow_tree(nodes_data: List[Dict]) -> None:
|
82
84
|
"""Displays a tree of the workflow nodes."""
|
83
|
-
|
84
|
-
|
85
|
+
try:
|
86
|
+
from rich import print as rprint
|
87
|
+
from rich.tree import Tree
|
88
|
+
except ImportError:
|
89
|
+
raise UserError(
|
90
|
+
"Rich library is not installed. Please install it using pip install rich>=13.4.2"
|
91
|
+
)
|
85
92
|
|
86
93
|
# Create a mapping of node_id to the list of node_ids that are connected to it.
|
87
94
|
node_adj_mapping = defaultdict(list)
|
@@ -131,7 +138,12 @@ def display_workflow_tree(nodes_data: List[Dict]) -> None:
|
|
131
138
|
|
132
139
|
def table_from_dict(data: List[Dict], column_names: List[str], title: str = "") -> 'rich.Table': # noqa F821
|
133
140
|
"""Use this function for printing tables from a list of dicts."""
|
134
|
-
|
141
|
+
try:
|
142
|
+
from rich.table import Table
|
143
|
+
except ImportError:
|
144
|
+
raise UserError(
|
145
|
+
"Rich library is not installed. Please install it using pip install rich>=13.4.2"
|
146
|
+
)
|
135
147
|
|
136
148
|
table = Table(title=title, show_lines=False, show_header=True, header_style="blue")
|
137
149
|
for column_name in column_names:
|
@@ -233,8 +245,13 @@ def display_concept_relations_tree(relations_dict: Dict[str, Any]) -> None:
|
|
233
245
|
Args:
|
234
246
|
relations_dict (dict): A dict of concept relations info.
|
235
247
|
"""
|
236
|
-
|
237
|
-
|
248
|
+
try:
|
249
|
+
from rich import print as rprint
|
250
|
+
from rich.tree import Tree
|
251
|
+
except ImportError:
|
252
|
+
raise UserError(
|
253
|
+
"Rich library is not installed. Please install it using pip install rich>=13.4.2"
|
254
|
+
)
|
238
255
|
|
239
256
|
for parent, children in relations_dict.items():
|
240
257
|
tree = Tree(parent)
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|