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.
Files changed (142) hide show
  1. clarifai/__init__.py +1 -1
  2. clarifai/__pycache__/__init__.cpython-312.pyc +0 -0
  3. clarifai/__pycache__/__init__.cpython-39.pyc +0 -0
  4. clarifai/__pycache__/errors.cpython-312.pyc +0 -0
  5. clarifai/__pycache__/errors.cpython-39.pyc +0 -0
  6. clarifai/__pycache__/versions.cpython-312.pyc +0 -0
  7. clarifai/__pycache__/versions.cpython-39.pyc +0 -0
  8. clarifai/cli/__pycache__/__init__.cpython-312.pyc +0 -0
  9. clarifai/cli/__pycache__/base.cpython-312.pyc +0 -0
  10. clarifai/cli/__pycache__/compute_cluster.cpython-312.pyc +0 -0
  11. clarifai/cli/__pycache__/deployment.cpython-312.pyc +0 -0
  12. clarifai/cli/__pycache__/model.cpython-312.pyc +0 -0
  13. clarifai/cli/__pycache__/nodepool.cpython-312.pyc +0 -0
  14. clarifai/cli/base.py +8 -0
  15. clarifai/cli/model.py +6 -6
  16. clarifai/client/__pycache__/__init__.cpython-312.pyc +0 -0
  17. clarifai/client/__pycache__/__init__.cpython-39.pyc +0 -0
  18. clarifai/client/__pycache__/app.cpython-312.pyc +0 -0
  19. clarifai/client/__pycache__/app.cpython-39.pyc +0 -0
  20. clarifai/client/__pycache__/base.cpython-312.pyc +0 -0
  21. clarifai/client/__pycache__/base.cpython-39.pyc +0 -0
  22. clarifai/client/__pycache__/compute_cluster.cpython-312.pyc +0 -0
  23. clarifai/client/__pycache__/dataset.cpython-312.pyc +0 -0
  24. clarifai/client/__pycache__/deployment.cpython-312.pyc +0 -0
  25. clarifai/client/__pycache__/input.cpython-312.pyc +0 -0
  26. clarifai/client/__pycache__/lister.cpython-312.pyc +0 -0
  27. clarifai/client/__pycache__/model.cpython-312.pyc +0 -0
  28. clarifai/client/__pycache__/model_client.cpython-312.pyc +0 -0
  29. clarifai/client/__pycache__/module.cpython-312.pyc +0 -0
  30. clarifai/client/__pycache__/nodepool.cpython-312.pyc +0 -0
  31. clarifai/client/__pycache__/runner.cpython-312.pyc +0 -0
  32. clarifai/client/__pycache__/search.cpython-312.pyc +0 -0
  33. clarifai/client/__pycache__/user.cpython-312.pyc +0 -0
  34. clarifai/client/__pycache__/workflow.cpython-312.pyc +0 -0
  35. clarifai/client/auth/__pycache__/__init__.cpython-312.pyc +0 -0
  36. clarifai/client/auth/__pycache__/__init__.cpython-39.pyc +0 -0
  37. clarifai/client/auth/__pycache__/helper.cpython-312.pyc +0 -0
  38. clarifai/client/auth/__pycache__/helper.cpython-39.pyc +0 -0
  39. clarifai/client/auth/__pycache__/register.cpython-312.pyc +0 -0
  40. clarifai/client/auth/__pycache__/register.cpython-39.pyc +0 -0
  41. clarifai/client/auth/__pycache__/stub.cpython-312.pyc +0 -0
  42. clarifai/client/auth/__pycache__/stub.cpython-39.pyc +0 -0
  43. clarifai/client/dataset.py +6 -0
  44. clarifai/constants/__pycache__/base.cpython-312.pyc +0 -0
  45. clarifai/constants/__pycache__/base.cpython-39.pyc +0 -0
  46. clarifai/constants/__pycache__/dataset.cpython-312.pyc +0 -0
  47. clarifai/constants/__pycache__/input.cpython-312.pyc +0 -0
  48. clarifai/constants/__pycache__/model.cpython-312.pyc +0 -0
  49. clarifai/constants/__pycache__/rag.cpython-312.pyc +0 -0
  50. clarifai/constants/__pycache__/search.cpython-312.pyc +0 -0
  51. clarifai/constants/__pycache__/workflow.cpython-312.pyc +0 -0
  52. clarifai/datasets/__pycache__/__init__.cpython-312.pyc +0 -0
  53. clarifai/datasets/export/__pycache__/__init__.cpython-312.pyc +0 -0
  54. clarifai/datasets/export/__pycache__/inputs_annotations.cpython-312.pyc +0 -0
  55. clarifai/datasets/upload/__pycache__/__init__.cpython-312.pyc +0 -0
  56. clarifai/datasets/upload/__pycache__/base.cpython-312.pyc +0 -0
  57. clarifai/datasets/upload/__pycache__/features.cpython-312.pyc +0 -0
  58. clarifai/datasets/upload/__pycache__/image.cpython-312.pyc +0 -0
  59. clarifai/datasets/upload/__pycache__/multimodal.cpython-312.pyc +0 -0
  60. clarifai/datasets/upload/__pycache__/text.cpython-312.pyc +0 -0
  61. clarifai/datasets/upload/__pycache__/utils.cpython-312.pyc +0 -0
  62. clarifai/datasets/upload/loaders/__pycache__/__init__.cpython-312.pyc +0 -0
  63. clarifai/datasets/upload/loaders/__pycache__/coco_detection.cpython-312.pyc +0 -0
  64. clarifai/datasets/upload/loaders/__pycache__/imagenet_classification.cpython-312.pyc +0 -0
  65. clarifai/modules/__pycache__/__init__.cpython-312.pyc +0 -0
  66. clarifai/modules/__pycache__/css.cpython-312.pyc +0 -0
  67. clarifai/rag/__pycache__/__init__.cpython-312.pyc +0 -0
  68. clarifai/rag/__pycache__/rag.cpython-312.pyc +0 -0
  69. clarifai/rag/__pycache__/utils.cpython-312.pyc +0 -0
  70. clarifai/runners/__pycache__/__init__.cpython-312.pyc +0 -0
  71. clarifai/runners/__pycache__/__init__.cpython-39.pyc +0 -0
  72. clarifai/runners/__pycache__/server.cpython-312.pyc +0 -0
  73. clarifai/runners/models/__pycache__/__init__.cpython-312.pyc +0 -0
  74. clarifai/runners/models/__pycache__/__init__.cpython-39.pyc +0 -0
  75. clarifai/runners/models/__pycache__/base_typed_model.cpython-312.pyc +0 -0
  76. clarifai/runners/models/__pycache__/mcp_class.cpython-312.pyc +0 -0
  77. clarifai/runners/models/__pycache__/model_builder.cpython-312.pyc +0 -0
  78. clarifai/runners/models/__pycache__/model_builder.cpython-39.pyc +0 -0
  79. clarifai/runners/models/__pycache__/model_class.cpython-312.pyc +0 -0
  80. clarifai/runners/models/__pycache__/model_run_locally.cpython-312.pyc +0 -0
  81. clarifai/runners/models/__pycache__/model_runner.cpython-312.pyc +0 -0
  82. clarifai/runners/models/__pycache__/model_servicer.cpython-312.pyc +0 -0
  83. clarifai/runners/models/__pycache__/test_model_builder.cpython-312-pytest-8.3.5.pyc +0 -0
  84. clarifai/runners/models/base_typed_model.py +238 -0
  85. clarifai/runners/models/example_mcp_server.py +44 -0
  86. clarifai/runners/models/mcp_class.py +143 -0
  87. clarifai/runners/models/mcp_class.py~ +149 -0
  88. clarifai/runners/models/model_builder.py +167 -38
  89. clarifai/runners/models/model_class.py +5 -22
  90. clarifai/runners/models/model_run_locally.py +0 -4
  91. clarifai/runners/models/test_model_builder.py +89 -0
  92. clarifai/runners/models/visual_classifier_class.py +75 -0
  93. clarifai/runners/models/visual_detector_class.py +79 -0
  94. clarifai/runners/utils/__pycache__/__init__.cpython-312.pyc +0 -0
  95. clarifai/runners/utils/__pycache__/code_script.cpython-312.pyc +0 -0
  96. clarifai/runners/utils/__pycache__/const.cpython-312.pyc +0 -0
  97. clarifai/runners/utils/__pycache__/data_handler.cpython-312.pyc +0 -0
  98. clarifai/runners/utils/__pycache__/data_types.cpython-312.pyc +0 -0
  99. clarifai/runners/utils/__pycache__/data_utils.cpython-312.pyc +0 -0
  100. clarifai/runners/utils/__pycache__/loader.cpython-312.pyc +0 -0
  101. clarifai/runners/utils/__pycache__/method_signatures.cpython-312.pyc +0 -0
  102. clarifai/runners/utils/__pycache__/serializers.cpython-312.pyc +0 -0
  103. clarifai/runners/utils/__pycache__/url_fetcher.cpython-312.pyc +0 -0
  104. clarifai/runners/utils/code_script.py +41 -44
  105. clarifai/runners/utils/const.py +15 -0
  106. clarifai/runners/utils/data_handler.py +231 -0
  107. clarifai/runners/utils/data_types/__pycache__/__init__.cpython-312.pyc +0 -0
  108. clarifai/runners/utils/data_types/__pycache__/data_types.cpython-312.pyc +0 -0
  109. clarifai/runners/utils/data_utils.py +33 -5
  110. clarifai/runners/utils/loader.py +23 -2
  111. clarifai/runners/utils/method_signatures.py +4 -4
  112. clarifai/schema/__pycache__/search.cpython-312.pyc +0 -0
  113. clarifai/urls/__pycache__/helper.cpython-312.pyc +0 -0
  114. clarifai/utils/__pycache__/__init__.cpython-312.pyc +0 -0
  115. clarifai/utils/__pycache__/__init__.cpython-39.pyc +0 -0
  116. clarifai/utils/__pycache__/cli.cpython-312.pyc +0 -0
  117. clarifai/utils/__pycache__/config.cpython-312.pyc +0 -0
  118. clarifai/utils/__pycache__/constants.cpython-312.pyc +0 -0
  119. clarifai/utils/__pycache__/constants.cpython-39.pyc +0 -0
  120. clarifai/utils/__pycache__/logging.cpython-312.pyc +0 -0
  121. clarifai/utils/__pycache__/logging.cpython-39.pyc +0 -0
  122. clarifai/utils/__pycache__/misc.cpython-312.pyc +0 -0
  123. clarifai/utils/__pycache__/misc.cpython-39.pyc +0 -0
  124. clarifai/utils/__pycache__/model_train.cpython-312.pyc +0 -0
  125. clarifai/utils/__pycache__/protobuf.cpython-312.pyc +0 -0
  126. clarifai/utils/config.py +19 -0
  127. clarifai/utils/config.py~ +145 -0
  128. clarifai/utils/evaluation/__pycache__/__init__.cpython-312.pyc +0 -0
  129. clarifai/utils/evaluation/__pycache__/helpers.cpython-312.pyc +0 -0
  130. clarifai/utils/evaluation/__pycache__/main.cpython-312.pyc +0 -0
  131. clarifai/utils/logging.py +22 -5
  132. clarifai/workflows/__pycache__/__init__.cpython-312.pyc +0 -0
  133. clarifai/workflows/__pycache__/export.cpython-312.pyc +0 -0
  134. clarifai/workflows/__pycache__/utils.cpython-312.pyc +0 -0
  135. clarifai/workflows/__pycache__/validate.cpython-312.pyc +0 -0
  136. {clarifai-11.4.1.dist-info → clarifai-11.4.3rc1.dist-info}/METADATA +2 -14
  137. clarifai-11.4.3rc1.dist-info/RECORD +230 -0
  138. {clarifai-11.4.1.dist-info → clarifai-11.4.3rc1.dist-info}/WHEEL +1 -1
  139. clarifai-11.4.1.dist-info/RECORD +0 -109
  140. {clarifai-11.4.1.dist-info/licenses → clarifai-11.4.3rc1.dist-info}/LICENSE +0 -0
  141. {clarifai-11.4.1.dist-info → clarifai-11.4.3rc1.dist-info}/entry_points.txt +0 -0
  142. {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)
@@ -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=None,
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 = self.default is None
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
- if default is not None:
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:
@@ -41,7 +41,7 @@ class HuggingFaceLoader:
41
41
  return True
42
42
  except Exception as e:
43
43
  logger.error(
44
- f"Error setting up Hugging Face token, please make sure you have the correct token: {e}"
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, inference_params={}, is_output=False):
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
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]
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
- from rich import print as rprint
84
- from rich.tree import Tree
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
- from rich.table import Table
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
- from rich import print as rprint
237
- from rich.tree import Tree
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)