clarifai 11.1.7rc1__py3-none-any.whl → 11.1.7rc3__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 (184) hide show
  1. clarifai/__init__.py +1 -1
  2. clarifai/__pycache__/__init__.cpython-310.pyc +0 -0
  3. clarifai/__pycache__/__init__.cpython-39.pyc +0 -0
  4. clarifai/__pycache__/errors.cpython-310.pyc +0 -0
  5. clarifai/__pycache__/versions.cpython-310.pyc +0 -0
  6. clarifai/cli/__pycache__/__init__.cpython-310.pyc +0 -0
  7. clarifai/cli/__pycache__/base.cpython-310.pyc +0 -0
  8. clarifai/cli/__pycache__/base_cli.cpython-310.pyc +0 -0
  9. clarifai/cli/__pycache__/compute_cluster.cpython-310.pyc +0 -0
  10. clarifai/cli/__pycache__/deployment.cpython-310.pyc +0 -0
  11. clarifai/cli/__pycache__/model.cpython-310.pyc +0 -0
  12. clarifai/cli/__pycache__/model_cli.cpython-310.pyc +0 -0
  13. clarifai/cli/__pycache__/nodepool.cpython-310.pyc +0 -0
  14. clarifai/client/__pycache__/__init__.cpython-310.pyc +0 -0
  15. clarifai/client/__pycache__/__init__.cpython-39.pyc +0 -0
  16. clarifai/client/__pycache__/app.cpython-310.pyc +0 -0
  17. clarifai/client/__pycache__/app.cpython-39.pyc +0 -0
  18. clarifai/client/__pycache__/base.cpython-310.pyc +0 -0
  19. clarifai/client/__pycache__/compute_cluster.cpython-310.pyc +0 -0
  20. clarifai/client/__pycache__/dataset.cpython-310.pyc +0 -0
  21. clarifai/client/__pycache__/deployment.cpython-310.pyc +0 -0
  22. clarifai/client/__pycache__/input.cpython-310.pyc +0 -0
  23. clarifai/client/__pycache__/lister.cpython-310.pyc +0 -0
  24. clarifai/client/__pycache__/model.cpython-310.pyc +0 -0
  25. clarifai/client/__pycache__/module.cpython-310.pyc +0 -0
  26. clarifai/client/__pycache__/nodepool.cpython-310.pyc +0 -0
  27. clarifai/client/__pycache__/search.cpython-310.pyc +0 -0
  28. clarifai/client/__pycache__/user.cpython-310.pyc +0 -0
  29. clarifai/client/__pycache__/workflow.cpython-310.pyc +0 -0
  30. clarifai/client/auth/__pycache__/__init__.cpython-310.pyc +0 -0
  31. clarifai/client/auth/__pycache__/helper.cpython-310.pyc +0 -0
  32. clarifai/client/auth/__pycache__/register.cpython-310.pyc +0 -0
  33. clarifai/client/auth/__pycache__/stub.cpython-310.pyc +0 -0
  34. clarifai/client/cli/__init__.py +0 -0
  35. clarifai/client/cli/__pycache__/__init__.cpython-310.pyc +0 -0
  36. clarifai/client/cli/__pycache__/base_cli.cpython-310.pyc +0 -0
  37. clarifai/client/cli/__pycache__/model_cli.cpython-310.pyc +0 -0
  38. clarifai/client/cli/base_cli.py +88 -0
  39. clarifai/client/cli/model_cli.py +29 -0
  40. clarifai/client/model.py +0 -1
  41. clarifai/client/model_client.py +23 -24
  42. clarifai/constants/__pycache__/base.cpython-310.pyc +0 -0
  43. clarifai/constants/__pycache__/dataset.cpython-310.pyc +0 -0
  44. clarifai/constants/__pycache__/input.cpython-310.pyc +0 -0
  45. clarifai/constants/__pycache__/model.cpython-310.pyc +0 -0
  46. clarifai/constants/__pycache__/rag.cpython-310.pyc +0 -0
  47. clarifai/constants/__pycache__/search.cpython-310.pyc +0 -0
  48. clarifai/constants/__pycache__/workflow.cpython-310.pyc +0 -0
  49. clarifai/datasets/__pycache__/__init__.cpython-310.pyc +0 -0
  50. clarifai/datasets/__pycache__/__init__.cpython-39.pyc +0 -0
  51. clarifai/datasets/export/__pycache__/__init__.cpython-310.pyc +0 -0
  52. clarifai/datasets/export/__pycache__/__init__.cpython-39.pyc +0 -0
  53. clarifai/datasets/export/__pycache__/inputs_annotations.cpython-310.pyc +0 -0
  54. clarifai/datasets/upload/__pycache__/__init__.cpython-310.pyc +0 -0
  55. clarifai/datasets/upload/__pycache__/__init__.cpython-39.pyc +0 -0
  56. clarifai/datasets/upload/__pycache__/base.cpython-310.pyc +0 -0
  57. clarifai/datasets/upload/__pycache__/features.cpython-310.pyc +0 -0
  58. clarifai/datasets/upload/__pycache__/image.cpython-310.pyc +0 -0
  59. clarifai/datasets/upload/__pycache__/multimodal.cpython-310.pyc +0 -0
  60. clarifai/datasets/upload/__pycache__/text.cpython-310.pyc +0 -0
  61. clarifai/datasets/upload/__pycache__/utils.cpython-310.pyc +0 -0
  62. clarifai/datasets/upload/loaders/__pycache__/__init__.cpython-39.pyc +0 -0
  63. clarifai/models/__pycache__/__init__.cpython-39.pyc +0 -0
  64. clarifai/modules/__pycache__/__init__.cpython-39.pyc +0 -0
  65. clarifai/rag/__pycache__/__init__.cpython-310.pyc +0 -0
  66. clarifai/rag/__pycache__/__init__.cpython-39.pyc +0 -0
  67. clarifai/rag/__pycache__/rag.cpython-310.pyc +0 -0
  68. clarifai/rag/__pycache__/rag.cpython-39.pyc +0 -0
  69. clarifai/rag/__pycache__/utils.cpython-310.pyc +0 -0
  70. clarifai/runners/__pycache__/__init__.cpython-310.pyc +0 -0
  71. clarifai/runners/__pycache__/__init__.cpython-39.pyc +0 -0
  72. clarifai/runners/dockerfile_template/Dockerfile.cpu.template +31 -0
  73. clarifai/runners/dockerfile_template/Dockerfile.cuda.template +42 -0
  74. clarifai/runners/dockerfile_template/Dockerfile.nim +71 -0
  75. clarifai/runners/dockerfile_template/Dockerfile.template +0 -3
  76. clarifai/runners/models/__pycache__/__init__.cpython-310.pyc +0 -0
  77. clarifai/runners/models/__pycache__/__init__.cpython-39.pyc +0 -0
  78. clarifai/runners/models/__pycache__/base_typed_model.cpython-310.pyc +0 -0
  79. clarifai/runners/models/__pycache__/base_typed_model.cpython-39.pyc +0 -0
  80. clarifai/runners/models/__pycache__/model_class.cpython-310.pyc +0 -0
  81. clarifai/runners/models/__pycache__/model_run_locally.cpython-310-pytest-7.1.2.pyc +0 -0
  82. clarifai/runners/models/__pycache__/model_run_locally.cpython-310.pyc +0 -0
  83. clarifai/runners/models/__pycache__/model_runner.cpython-310.pyc +0 -0
  84. clarifai/runners/models/__pycache__/model_upload.cpython-310.pyc +0 -0
  85. clarifai/runners/models/model_builder.py +56 -4
  86. clarifai/runners/models/model_class.py +40 -17
  87. clarifai/runners/models/model_class_refract.py +80 -0
  88. clarifai/runners/models/model_upload.py +607 -0
  89. clarifai/runners/models/temp.py +25 -0
  90. clarifai/runners/utils/__pycache__/__init__.cpython-310.pyc +0 -0
  91. clarifai/runners/utils/__pycache__/__init__.cpython-38.pyc +0 -0
  92. clarifai/runners/utils/__pycache__/__init__.cpython-39.pyc +0 -0
  93. clarifai/runners/utils/__pycache__/buffered_stream.cpython-310.pyc +0 -0
  94. clarifai/runners/utils/__pycache__/buffered_stream.cpython-38.pyc +0 -0
  95. clarifai/runners/utils/__pycache__/buffered_stream.cpython-39.pyc +0 -0
  96. clarifai/runners/utils/__pycache__/const.cpython-310.pyc +0 -0
  97. clarifai/runners/utils/__pycache__/constants.cpython-310.pyc +0 -0
  98. clarifai/runners/utils/__pycache__/constants.cpython-38.pyc +0 -0
  99. clarifai/runners/utils/__pycache__/constants.cpython-39.pyc +0 -0
  100. clarifai/runners/utils/__pycache__/data_handler.cpython-310.pyc +0 -0
  101. clarifai/runners/utils/__pycache__/data_handler.cpython-38.pyc +0 -0
  102. clarifai/runners/utils/__pycache__/data_handler.cpython-39.pyc +0 -0
  103. clarifai/runners/utils/__pycache__/data_utils.cpython-310.pyc +0 -0
  104. clarifai/runners/utils/__pycache__/data_utils.cpython-38.pyc +0 -0
  105. clarifai/runners/utils/__pycache__/data_utils.cpython-39.pyc +0 -0
  106. clarifai/runners/utils/__pycache__/grpc_server.cpython-310.pyc +0 -0
  107. clarifai/runners/utils/__pycache__/grpc_server.cpython-38.pyc +0 -0
  108. clarifai/runners/utils/__pycache__/grpc_server.cpython-39.pyc +0 -0
  109. clarifai/runners/utils/__pycache__/health.cpython-310.pyc +0 -0
  110. clarifai/runners/utils/__pycache__/health.cpython-38.pyc +0 -0
  111. clarifai/runners/utils/__pycache__/health.cpython-39.pyc +0 -0
  112. clarifai/runners/utils/__pycache__/loader.cpython-310.pyc +0 -0
  113. clarifai/runners/utils/__pycache__/logging.cpython-310.pyc +0 -0
  114. clarifai/runners/utils/__pycache__/logging.cpython-38.pyc +0 -0
  115. clarifai/runners/utils/__pycache__/logging.cpython-39.pyc +0 -0
  116. clarifai/runners/utils/__pycache__/stream_source.cpython-310.pyc +0 -0
  117. clarifai/runners/utils/__pycache__/stream_source.cpython-39.pyc +0 -0
  118. clarifai/runners/utils/__pycache__/url_fetcher.cpython-310.pyc +0 -0
  119. clarifai/runners/utils/__pycache__/url_fetcher.cpython-38.pyc +0 -0
  120. clarifai/runners/utils/__pycache__/url_fetcher.cpython-39.pyc +0 -0
  121. clarifai/runners/utils/data_handler.py +271 -210
  122. clarifai/runners/utils/data_handler_refract.py +213 -0
  123. clarifai/runners/utils/logger.py +0 -0
  124. clarifai/runners/utils/method_signatures.py +108 -131
  125. clarifai/schema/__pycache__/search.cpython-310.pyc +0 -0
  126. clarifai/urls/__pycache__/helper.cpython-310.pyc +0 -0
  127. clarifai/utils/__pycache__/__init__.cpython-310.pyc +0 -0
  128. clarifai/utils/__pycache__/__init__.cpython-39.pyc +0 -0
  129. clarifai/utils/__pycache__/cli.cpython-310.pyc +0 -0
  130. clarifai/utils/__pycache__/constants.cpython-310.pyc +0 -0
  131. clarifai/utils/__pycache__/logging.cpython-310.pyc +0 -0
  132. clarifai/utils/__pycache__/misc.cpython-310.pyc +0 -0
  133. clarifai/utils/__pycache__/model_train.cpython-310.pyc +0 -0
  134. clarifai/utils/evaluation/__pycache__/__init__.cpython-39.pyc +0 -0
  135. clarifai/utils/evaluation/__pycache__/main.cpython-39.pyc +0 -0
  136. clarifai/workflows/__pycache__/__init__.cpython-310.pyc +0 -0
  137. clarifai/workflows/__pycache__/__init__.cpython-39.pyc +0 -0
  138. clarifai/workflows/__pycache__/export.cpython-310.pyc +0 -0
  139. clarifai/workflows/__pycache__/utils.cpython-310.pyc +0 -0
  140. clarifai/workflows/__pycache__/validate.cpython-310.pyc +0 -0
  141. {clarifai-11.1.7rc1.dist-info → clarifai-11.1.7rc3.dist-info}/METADATA +15 -15
  142. clarifai-11.1.7rc3.dist-info/RECORD +237 -0
  143. {clarifai-11.1.7rc1.dist-info → clarifai-11.1.7rc3.dist-info}/WHEEL +1 -1
  144. clarifai/cli/__main__.py~ +0 -4
  145. clarifai/cli/__pycache__/__main__.cpython-310.pyc +0 -0
  146. clarifai/client/#model_client.py# +0 -430
  147. clarifai/client/__pycache__/runner.cpython-310.pyc +0 -0
  148. clarifai/datasets/upload/loaders/__pycache__/__init__.cpython-310.pyc +0 -0
  149. clarifai/datasets/upload/loaders/__pycache__/coco_detection.cpython-310.pyc +0 -0
  150. clarifai/models/__pycache__/__init__.cpython-310.pyc +0 -0
  151. clarifai/models/model_serving/__pycache__/__init__.cpython-310.pyc +0 -0
  152. clarifai/models/model_serving/__pycache__/constants.cpython-310.pyc +0 -0
  153. clarifai/models/model_serving/cli/__pycache__/__init__.cpython-310.pyc +0 -0
  154. clarifai/models/model_serving/cli/__pycache__/_utils.cpython-310.pyc +0 -0
  155. clarifai/models/model_serving/cli/__pycache__/base.cpython-310.pyc +0 -0
  156. clarifai/models/model_serving/cli/__pycache__/build.cpython-310.pyc +0 -0
  157. clarifai/models/model_serving/cli/__pycache__/create.cpython-310.pyc +0 -0
  158. clarifai/models/model_serving/model_config/__pycache__/__init__.cpython-310.pyc +0 -0
  159. clarifai/models/model_serving/model_config/__pycache__/base.cpython-310.pyc +0 -0
  160. clarifai/models/model_serving/model_config/__pycache__/config.cpython-310.pyc +0 -0
  161. clarifai/models/model_serving/model_config/__pycache__/inference_parameter.cpython-310.pyc +0 -0
  162. clarifai/models/model_serving/model_config/__pycache__/output.cpython-310.pyc +0 -0
  163. clarifai/models/model_serving/model_config/triton/__pycache__/__init__.cpython-310.pyc +0 -0
  164. clarifai/models/model_serving/model_config/triton/__pycache__/serializer.cpython-310.pyc +0 -0
  165. clarifai/models/model_serving/model_config/triton/__pycache__/triton_config.cpython-310.pyc +0 -0
  166. clarifai/models/model_serving/model_config/triton/__pycache__/wrappers.cpython-310.pyc +0 -0
  167. clarifai/models/model_serving/repo_build/__pycache__/__init__.cpython-310.pyc +0 -0
  168. clarifai/models/model_serving/repo_build/__pycache__/build.cpython-310.pyc +0 -0
  169. clarifai/models/model_serving/repo_build/static_files/__pycache__/base_test.cpython-310-pytest-7.2.0.pyc +0 -0
  170. clarifai/runners/__pycache__/server.cpython-310.pyc +0 -0
  171. clarifai/runners/dockerfile_template/Dockerfile.debug +0 -11
  172. clarifai/runners/dockerfile_template/Dockerfile.debug~ +0 -9
  173. clarifai/runners/models/__pycache__/model_builder.cpython-310.pyc +0 -0
  174. clarifai/runners/models/__pycache__/model_servicer.cpython-310.pyc +0 -0
  175. clarifai/runners/utils/__pycache__/data_types.cpython-310.pyc +0 -0
  176. clarifai/runners/utils/__pycache__/method_signatures.cpython-310.pyc +0 -0
  177. clarifai/runners/utils/__pycache__/serializers.cpython-310.pyc +0 -0
  178. clarifai/utils/evaluation/__pycache__/__init__.cpython-310.pyc +0 -0
  179. clarifai/utils/evaluation/__pycache__/helpers.cpython-310.pyc +0 -0
  180. clarifai/utils/evaluation/__pycache__/main.cpython-310.pyc +0 -0
  181. clarifai-11.1.7rc1.dist-info/RECORD +0 -205
  182. {clarifai-11.1.7rc1.dist-info → clarifai-11.1.7rc3.dist-info}/LICENSE +0 -0
  183. {clarifai-11.1.7rc1.dist-info → clarifai-11.1.7rc3.dist-info}/entry_points.txt +0 -0
  184. {clarifai-11.1.7rc1.dist-info → clarifai-11.1.7rc3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,213 @@
1
+ import io
2
+ from typing import Any, Callable, Dict, Type
3
+
4
+ import numpy as np
5
+ from clarifai_grpc.grpc.api import resources_pb2
6
+ from clarifai_grpc.grpc.api.resources_pb2 import Audio as AudioProto
7
+ from clarifai_grpc.grpc.api.resources_pb2 import Image as ImageProto
8
+ from clarifai_grpc.grpc.api.resources_pb2 import NDArray
9
+ from clarifai_grpc.grpc.api.resources_pb2 import Text as TextProto
10
+ from clarifai_grpc.grpc.api.resources_pb2 import Video as VideoProto
11
+ from google.protobuf.json_format import MessageToDict, ParseDict
12
+ from google.protobuf.struct_pb2 import Struct
13
+ from PIL import Image as PILImage
14
+
15
+ # Type registry for conversion between Python types and protobuf
16
+ _TYPE_HANDLERS: Dict[Type, Callable] = {
17
+ # Python type: (to_proto, from_proto)
18
+ TextProto: (
19
+ lambda value: value.to_proto(),
20
+ lambda proto: Text.from_proto(proto)
21
+ ),
22
+ ImageProto: (
23
+ lambda value: value.to_proto(),
24
+ lambda proto: Image(proto)
25
+ ),
26
+ AudioProto: (
27
+ lambda value: value.to_proto(),
28
+ lambda proto: Audio(proto)
29
+ ),
30
+ VideoProto: (
31
+ lambda value: value.to_proto(),
32
+ lambda proto: Video(proto)
33
+ ),
34
+ str: (
35
+ lambda value: TextProto(raw=value),
36
+ lambda proto: proto.raw
37
+ ),
38
+ bytes: (
39
+ lambda value: resources_pb2.Data(base64=value),
40
+ lambda proto: proto.base64
41
+ ),
42
+ int: (
43
+ lambda value: resources_pb2.Data(int_value=value),
44
+ lambda proto: proto.int_value
45
+ ),
46
+ float: (
47
+ lambda value: resources_pb2.Data(float_value=value),
48
+ lambda proto: proto.float_value
49
+ ),
50
+ bool: (
51
+ lambda value: resources_pb2.Data(boolean=value),
52
+ lambda proto: proto.boolean
53
+ ),
54
+ np.ndarray: (
55
+ lambda value: NDArray(buffer=value.tobytes(), shape=value.shape, dtype=str(value.dtype)),
56
+ lambda proto: np.frombuffer(proto.buffer, dtype=np.dtype(proto.dtype)).reshape(proto.shape)
57
+ ),
58
+ PILImage.Image: (
59
+ lambda value: Image.from_pil(value).to_proto(),
60
+ lambda proto: Image(proto).to_pil()
61
+ ),
62
+ dict: (
63
+ lambda value: _dict_to_metadata(value),
64
+ lambda proto: MessageToDict(proto.metadata)
65
+ )
66
+ }
67
+
68
+
69
+ def _dict_to_metadata(metadata: dict) -> Struct:
70
+ struct = Struct()
71
+ ParseDict(metadata, struct)
72
+ return struct
73
+
74
+
75
+ def _value_to_proto(value: Any) -> resources_pb2.Data:
76
+ """Convert a Python value to a protobuf Data message."""
77
+ data = resources_pb2.Data()
78
+ for py_type, (to_proto, _) in _TYPE_HANDLERS.items():
79
+ if isinstance(value, py_type):
80
+ handler = to_proto
81
+ break
82
+ else:
83
+ if isinstance(value, (Text, Image, Audio, Video)):
84
+ data_part = getattr(data, type(value).__name__.lower())
85
+ data_part.CopyFrom(value.to_proto())
86
+ return data
87
+ raise TypeError(f"Unsupported type: {type(value)}")
88
+
89
+ result = handler(value)
90
+ if isinstance(result, resources_pb2.Data):
91
+ data.CopyFrom(result)
92
+ else:
93
+ field_name = type(result).DESCRIPTOR.name.lower()
94
+ getattr(data, field_name).CopyFrom(result)
95
+ return data
96
+
97
+
98
+ def _proto_to_value(proto: resources_pb2.Data) -> Any:
99
+ """Convert a protobuf Data message to a Python value."""
100
+ for field in proto.DESCRIPTOR.fields:
101
+ if proto.HasField(field.name):
102
+ _, from_proto = _TYPE_HANDLERS.get(field.type, (None, None))
103
+ if from_proto:
104
+ return from_proto(getattr(proto, field.name))
105
+ if proto.parts:
106
+ return [_proto_to_value(part.data) for part in proto.parts]
107
+ return None
108
+
109
+
110
+ def kwargs_to_proto(**kwargs) -> resources_pb2.Data:
111
+ """Convert keyword arguments to a Data proto."""
112
+ data_proto = resources_pb2.Data()
113
+ for part_name, part_value in kwargs.items():
114
+ part = data_proto.parts.add()
115
+ part.id = part_name
116
+
117
+ if isinstance(part_value, list):
118
+ for item in part_value:
119
+ item_proto = _value_to_proto(item)
120
+ part_part = part.data.parts.add()
121
+ part_part.data.CopyFrom(item_proto)
122
+ else:
123
+ part_proto = _value_to_proto(part_value)
124
+ part.data.CopyFrom(part_proto)
125
+ return data_proto
126
+
127
+
128
+ def proto_to_kwargs(data: resources_pb2.Data) -> dict:
129
+ """Convert a Data proto to keyword arguments."""
130
+ kwargs = {}
131
+ for part in data.parts:
132
+ part_name = part.id
133
+ if part.data.parts:
134
+ kwargs[part_name] = [_proto_to_value(part.data) for _ in part.data.parts]
135
+ else:
136
+ kwargs[part_name] = _proto_to_value(part.data)
137
+ return kwargs
138
+
139
+
140
+ class Output:
141
+
142
+ def __init__(self, **kwargs: Any):
143
+ if not kwargs:
144
+ raise ValueError("Output must have at least one key-value pair")
145
+ self.parts = kwargs
146
+
147
+ def to_proto(self) -> resources_pb2.Output:
148
+ data_proto = kwargs_to_proto(**self.parts)
149
+ return resources_pb2.Output(data=data_proto)
150
+
151
+
152
+ class Text:
153
+
154
+ def __init__(self, text: str):
155
+ self.text = text
156
+
157
+ def to_proto(self) -> TextProto:
158
+ return TextProto(raw=self.text)
159
+
160
+ @classmethod
161
+ def from_proto(cls, proto: TextProto) -> "Text":
162
+ return cls(proto.raw)
163
+
164
+
165
+ class Image:
166
+
167
+ def __init__(self, proto_image: ImageProto):
168
+ self.proto = proto_image
169
+
170
+ @classmethod
171
+ def from_url(cls, url: str) -> "Image":
172
+ return cls(ImageProto(url=url))
173
+
174
+ @classmethod
175
+ def from_pil(cls, pil_image: PILImage.Image) -> "Image":
176
+ with io.BytesIO() as output:
177
+ pil_image.save(output, format="PNG")
178
+ return cls(ImageProto(base64=output.getvalue()))
179
+
180
+ def to_pil(self) -> PILImage.Image:
181
+ return PILImage.open(io.BytesIO(self.proto.base64))
182
+
183
+ def to_proto(self) -> ImageProto:
184
+ return self.proto
185
+
186
+
187
+ class Audio:
188
+
189
+ def __init__(self, proto_audio: AudioProto):
190
+ self.proto = proto_audio
191
+
192
+ def to_proto(self) -> AudioProto:
193
+ return self.proto
194
+
195
+
196
+ class Video:
197
+
198
+ def __init__(self, proto_video: VideoProto):
199
+ self.proto = proto_video
200
+
201
+ def to_proto(self) -> VideoProto:
202
+ return self.proto
203
+
204
+
205
+ '''
206
+ Type Handling Registry: Centralized conversion logic reduces duplication and enhances extensibility.
207
+ Simplified Conversion Functions: _value_to_proto and _proto_to_value handle all type conversions using the registry.
208
+ Streamlined Wrapper Methods: Common processing logic extracted into _process_request, reducing code duplication.
209
+ Improved Batch Processing: Uses ThreadPoolExecutor.map for cleaner batch prediction.
210
+ Error Handling: Clearer error messages and validation of required parameters.
211
+ Removed Redundant Checks: Simplified Output class initialization.
212
+
213
+ '''
File without changes
@@ -1,7 +1,5 @@
1
- import ast
2
1
  import inspect
3
2
  import json
4
- import textwrap
5
3
  from collections import namedtuple
6
4
  from typing import List, Tuple, get_args, get_origin
7
5
 
@@ -9,6 +7,7 @@ import numpy as np
9
7
  import PIL.Image
10
8
  import yaml
11
9
  from clarifai_grpc.grpc.api import resources_pb2
10
+ from google.protobuf.json_format import MessageToDict, ParseDict
12
11
  from google.protobuf.message import Message as MessageProto
13
12
 
14
13
  from clarifai.runners.utils import data_types
@@ -32,10 +31,13 @@ def build_function_signature(func):
32
31
  if return_annotation == inspect.Parameter.empty:
33
32
  raise TypeError('Function must have a return annotation')
34
33
 
35
- input_sigs = [
36
- build_variable_signature(p.name, p.annotation, p.default) for p in sig.parameters.values()
37
- ]
38
- input_sigs, input_types, input_streaming = zip(*input_sigs)
34
+ input_sigs = []
35
+ input_streaming = []
36
+ for p in sig.parameters.values():
37
+ model_type_field, _, streaming = build_variable_signature(p.name, p.annotation, p.default)
38
+ input_sigs.append(model_type_field)
39
+ input_streaming.append(streaming)
40
+
39
41
  output_sig, output_type, output_streaming = build_variable_signature(
40
42
  'return', return_annotation, is_output=True)
41
43
  # TODO: flatten out "return" layer if not needed
@@ -45,48 +47,45 @@ def build_function_signature(func):
45
47
  raise TypeError('streaming methods must have at most one streaming input')
46
48
  input_streaming = any(input_streaming)
47
49
  if not (input_streaming or output_streaming):
48
- method_type = 'predict'
50
+ method_type = 'UNARY_UNARY'
49
51
  elif not input_streaming and output_streaming:
50
- method_type = 'generate'
52
+ method_type = 'UNARY_STREAMING'
51
53
  elif input_streaming and output_streaming:
52
- method_type = 'stream'
54
+ method_type = 'STREAMING_STREAMING'
53
55
  else:
54
56
  raise TypeError('stream methods with streaming inputs must have streaming outputs')
55
57
 
56
- #method_signature = resources_pb2.MethodSignature() # TODO
57
- method_signature = _SignatureDict() #for now
58
+ method_signature = resources_pb2.MethodSignature()
58
59
 
59
60
  method_signature.name = func.__name__
60
- #method_signature.method_type = getattr(resources_pb2.RunnerMethodType, method_type)
61
- assert method_type in ('predict', 'generate', 'stream')
62
- method_signature.method_type = method_type
63
- method_signature.docstring = func.__doc__
64
- method_signature.annotations_json = json.dumps(_get_annotations_source(func))
65
-
66
- #method_signature.inputs.extend(input_vars)
67
- #method_signature.outputs.extend(output_vars)
68
- method_signature.inputs = input_sigs
69
- method_signature.outputs = [output_sig]
61
+ method_signature.method_type = getattr(resources_pb2.RunnerMethodType, method_type)
62
+ assert method_type in ('UNARY_UNARY', 'UNARY_STREAMING', 'STREAMING_STREAMING')
63
+ # method_signature.method_type = method_type
64
+ method_signature.description = inspect.cleandoc(func.__doc__ or '')
65
+ # method_signature.annotations_json = json.dumps(_get_annotations_source(func))
66
+
67
+ method_signature.input_fields.extend(input_sigs)
68
+ method_signature.output_fields.append(output_sig)
70
69
  return method_signature
71
70
 
72
71
 
73
- def _get_annotations_source(func):
74
- """Extracts raw annotation strings from the function source."""
75
- source = inspect.getsource(func) # Get function source code
76
- source = textwrap.dedent(source) # Dedent source code
77
- tree = ast.parse(source) # Parse into AST
78
- func_node = next(node for node in tree.body
79
- if isinstance(node, ast.FunctionDef)) # Get function node
72
+ # def _get_annotations_source(func):
73
+ # """Extracts raw annotation strings from the function source."""
74
+ # source = inspect.getsource(func) # Get function source code
75
+ # source = textwrap.dedent(source) # Dedent source code
76
+ # tree = ast.parse(source) # Parse into AST
77
+ # func_node = next(node for node in tree.body
78
+ # if isinstance(node, ast.FunctionDef)) # Get function node
80
79
 
81
- annotations = {}
82
- for arg in func_node.args.args: # Process arguments
83
- if arg.annotation:
84
- annotations[arg.arg] = ast.unparse(arg.annotation) # Get raw annotation string
80
+ # annotations = {}
81
+ # for arg in func_node.args.args: # Process arguments
82
+ # if arg.annotation:
83
+ # annotations[arg.arg] = ast.unparse(arg.annotation) # Get raw annotation string
85
84
 
86
- if func_node.returns: # Process return type
87
- annotations["return"] = ast.unparse(func_node.returns)
85
+ # if func_node.returns: # Process return type
86
+ # annotations["return"] = ast.unparse(func_node.returns)
88
87
 
89
- return annotations
88
+ # return annotations
90
89
 
91
90
 
92
91
  def build_variable_signature(name, annotation, default=inspect.Parameter.empty, is_output=False):
@@ -101,19 +100,17 @@ def build_variable_signature(name, annotation, default=inspect.Parameter.empty,
101
100
  # get fields for each variable based on type
102
101
  tp, streaming = _normalize_type(annotation)
103
102
 
104
- #var = resources_pb2.VariableSignature() # TODO
105
- sig = _VariableSignature() #for now
103
+ sig = resources_pb2.ModelTypeField()
106
104
  sig.name = name
107
-
108
- _fill_signature_type(sig, tp)
109
-
110
- sig.streaming = streaming
105
+ sig.iterator = streaming
111
106
 
112
107
  if not is_output:
113
108
  sig.required = (default is inspect.Parameter.empty)
114
109
  if not sig.required:
115
110
  sig.default = str(default)
116
111
 
112
+ _fill_signature_type(sig, tp)
113
+
117
114
  return sig, type, streaming
118
115
 
119
116
 
@@ -125,40 +122,42 @@ def _fill_signature_type(sig, tp):
125
122
  except TypeError:
126
123
  pass # not hashable type
127
124
 
125
+ # Handle NamedFields with annotations
128
126
  # Check for dynamically generated NamedFields subclasses (from type annotations)
129
127
  if inspect.isclass(tp) and issubclass(tp, data_types.NamedFields) and hasattr(
130
128
  tp, '__annotations__'):
131
- sig.type = DataType.NAMED_FIELDS
129
+ sig.type = resources_pb2.ModelTypeField.DataType.NAMED_FIELDS
132
130
  for name, inner_type in tp.__annotations__.items():
133
- inner_sig = _VariableSignature()
131
+ inner_sig = sig.type_args.add()
134
132
  inner_sig.name = name
135
133
  _fill_signature_type(inner_sig, inner_type)
136
- sig.type_args.append(inner_sig)
137
134
  return
138
135
 
136
+ # Handle NamedFields instances (dict-like)
139
137
  if isinstance(tp, data_types.NamedFields):
140
- sig.type = DataType.NAMED_FIELDS
138
+ sig.type = resources_pb2.ModelTypeField.DataType.NAMED_FIELDS
141
139
  for name, inner_type in tp.items():
142
- # inner_sig = sig.type_args.add()
143
- sig.type_args.append(inner_sig := _VariableSignature())
140
+ inner_sig = sig.type_args.add()
144
141
  inner_sig.name = name
145
142
  _fill_signature_type(inner_sig, inner_type)
146
143
  return
147
144
 
148
- if get_origin(tp) == tuple:
149
- sig.type = DataType.TUPLE
150
- for inner_type in get_args(tp):
151
- #inner_sig = sig.type_args.add()
152
- sig.type_args.append(inner_sig := _VariableSignature())
145
+ origin = get_origin(tp)
146
+ args = get_args(tp)
147
+
148
+ # Handle Tuple type
149
+ if origin == tuple:
150
+ sig.type = resources_pb2.ModelTypeField.DataType.TUPLE
151
+ for inner_type in args:
152
+ inner_sig = sig.type_args.add()
153
153
  _fill_signature_type(inner_sig, inner_type)
154
154
  return
155
155
 
156
- if get_origin(tp) == list:
157
- sig.type = DataType.LIST
158
- inner_type = get_args(tp)[0]
159
- #inner_sig = sig.type_args.add()
160
- sig.type_args.append(inner_sig := _VariableSignature())
161
- _fill_signature_type(inner_sig, inner_type)
156
+ # Handle List type
157
+ if origin == list:
158
+ sig.type = resources_pb2.ModelTypeField.DataType.LIST
159
+ inner_sig = sig.type_args.add()
160
+ _fill_signature_type(inner_sig, args[0])
162
161
  return
163
162
 
164
163
  raise TypeError(f'Unsupported type: {tp}')
@@ -170,11 +169,11 @@ def serializer_from_signature(signature):
170
169
  '''
171
170
  if signature.type in _SERIALIZERS_BY_TYPE_ENUM:
172
171
  return _SERIALIZERS_BY_TYPE_ENUM[signature.type]
173
- if signature.type == DataType.LIST:
172
+ if signature.type == resources_pb2.ModelTypeField.DataType.LIST:
174
173
  return ListSerializer(serializer_from_signature(signature.type_args[0]))
175
- if signature.type == DataType.TUPLE:
174
+ if signature.type == resources_pb2.ModelTypeField.DataType.TUPLE:
176
175
  return TupleSerializer([serializer_from_signature(sig) for sig in signature.type_args])
177
- if signature.type == DataType.NAMED_FIELDS:
176
+ if signature.type == resources_pb2.ModelTypeField.DataType.NAMED_FIELDS:
178
177
  return NamedFieldsSerializer(
179
178
  {sig.name: serializer_from_signature(sig)
180
179
  for sig in signature.type_args})
@@ -185,13 +184,20 @@ def signatures_to_json(signatures):
185
184
  assert isinstance(
186
185
  signatures, dict), 'Expected dict of signatures {name: signature}, got %s' % type(signatures)
187
186
  # TODO change to proto when ready
188
- #signatures = {name: MessageToDict(sig) for name, sig in signatures.items()}
187
+ signatures = {name: MessageToDict(sig) for name, sig in signatures.items()}
189
188
  return json.dumps(signatures)
190
189
 
191
190
 
192
191
  def signatures_from_json(json_str):
193
- d = json.loads(json_str, object_pairs_hook=_SignatureDict)
194
- return d
192
+ signatures_dict = json.loads(json_str)
193
+ assert isinstance(signatures_dict, dict), "Expected JSON to decode into a dictionary"
194
+
195
+ return {
196
+ name: ParseDict(sig_dict, resources_pb2.MethodSignature())
197
+ for name, sig_dict in signatures_dict.items()
198
+ }
199
+ # d = json.loads(json_str, object_pairs_hook=_SignatureDict)
200
+ # return d
195
201
 
196
202
 
197
203
  def signatures_to_yaml(signatures):
@@ -254,7 +260,7 @@ def serialize(kwargs, signatures, proto=None, is_output=False):
254
260
  return proto
255
261
 
256
262
 
257
- def deserialize(proto, signatures, is_output=False):
263
+ def deserialize(proto, signatures, inference_params={}, is_output=False):
258
264
  '''
259
265
  Deserialize the given proto into kwargs using the given signatures.
260
266
  '''
@@ -265,7 +271,12 @@ def deserialize(proto, signatures, is_output=False):
265
271
  for sig_i, sig in enumerate(signatures):
266
272
  serializer = serializer_from_signature(sig)
267
273
  part = parts_by_name.get(sig.name)
268
- if part is None:
274
+ inference_params_value = inference_params.get(sig.name)
275
+ if part is not None:
276
+ kwargs[sig.name] = serializer.deserialize(part.data)
277
+ elif inference_params_value is not None:
278
+ kwargs[sig.name] = inference_params_value
279
+ else:
269
280
  if sig_i == 0:
270
281
  # possible inlined first value
271
282
  value = serializer.deserialize(proto)
@@ -274,10 +285,10 @@ def deserialize(proto, signatures, is_output=False):
274
285
  # an actual zero value passed in must be set in an explicit part
275
286
  kwargs[sig.name] = value
276
287
  continue
288
+
277
289
  if sig.required or is_output: # TODO allow optional outputs?
278
290
  raise ValueError(f'Missing required field: {sig.name}')
279
291
  continue
280
- kwargs[sig.name] = serializer.deserialize(part.data)
281
292
  if len(kwargs) == 1 and 'return' in kwargs:
282
293
  return kwargs['return']
283
294
  return kwargs
@@ -288,7 +299,7 @@ def get_stream_from_signature(signatures):
288
299
  Get the stream signature from the given signatures.
289
300
  '''
290
301
  for sig in signatures:
291
- if sig.streaming:
302
+ if sig.iterator:
292
303
  return sig
293
304
  return None
294
305
 
@@ -357,9 +368,7 @@ def _normalize_data_type(tp):
357
368
  return data_types.Image
358
369
 
359
370
  if tp == PIL.Image:
360
- raise TypeError(
361
- 'Use the Image class from the PIL.Image module i.e. `PIL.Image.Image`, not the module itself'
362
- )
371
+ raise TypeError('Use PIL.Image.Image instead of PIL.Image module')
363
372
 
364
373
  # check for known data types
365
374
  try:
@@ -379,90 +388,58 @@ def _is_jsonable(tp):
379
388
  return False
380
389
 
381
390
 
382
- # TODO --- tmp classes to stand-in for protos until they are defined and built into this package
383
- class _SignatureDict(dict):
384
- __getattr__ = dict.__getitem__
385
- __setattr__ = dict.__setitem__
386
-
387
-
388
- class _VariableSignature(_SignatureDict):
389
-
390
- def __init__(self):
391
- super().__init__()
392
- self.name = ''
393
- self.type = ''
394
- self.type_args = []
395
- self.streaming = False
396
- self.required = False
397
- self.default = ''
398
- self.description = ''
399
-
400
-
401
391
  # type: name of the data type
402
392
  # data_field: name of the field in the data proto
403
393
  # serializer: serializer for the data type
404
394
  _DataType = namedtuple('_DataType', ('type', 'serializer'))
405
395
 
406
-
407
- # this will come from the proto module, but for now, define it here
408
- class DataType:
409
- NOT_SET = 'NOT_SET'
410
-
411
- STR = 'STR'
412
- BYTES = 'BYTES'
413
- INT = 'INT'
414
- FLOAT = 'FLOAT'
415
- BOOL = 'BOOL'
416
- NDARRAY = 'NDARRAY'
417
- JSON = 'JSON'
418
-
419
- TEXT = 'TEXT'
420
- IMAGE = 'IMAGE'
421
- CONCEPT = 'CONCEPT'
422
- REGION = 'REGION'
423
- FRAME = 'FRAME'
424
- AUDIO = 'AUDIO'
425
- VIDEO = 'VIDEO'
426
-
427
- NAMED_FIELDS = 'NAMED_FIELDS'
428
- TUPLE = 'TUPLE'
429
- LIST = 'LIST'
430
-
431
-
432
- _NON_INLINABLE_TYPES = {DataType.NAMED_FIELDS, DataType.TUPLE, DataType.LIST}
396
+ _NON_INLINABLE_TYPES = {
397
+ resources_pb2.ModelTypeField.DataType.NAMED_FIELDS,
398
+ resources_pb2.ModelTypeField.DataType.TUPLE, resources_pb2.ModelTypeField.DataType.LIST
399
+ }
433
400
  _ZERO_VALUE_IDS = {id(None), id(''), id(b''), id(0), id(0.0), id(False)}
434
401
 
435
402
  # simple, non-container types that correspond directly to a data field
436
403
  _DATA_TYPES = {
437
404
  str:
438
- _DataType(DataType.STR, AtomicFieldSerializer('string_value')),
405
+ _DataType(resources_pb2.ModelTypeField.DataType.STR,
406
+ AtomicFieldSerializer('string_value')),
439
407
  bytes:
440
- _DataType(DataType.BYTES, AtomicFieldSerializer('bytes_value')),
408
+ _DataType(resources_pb2.ModelTypeField.DataType.BYTES,
409
+ AtomicFieldSerializer('bytes_value')),
441
410
  int:
442
- _DataType(DataType.INT, AtomicFieldSerializer('int_value')),
411
+ _DataType(resources_pb2.ModelTypeField.DataType.INT, AtomicFieldSerializer('int_value')),
443
412
  float:
444
- _DataType(DataType.FLOAT, AtomicFieldSerializer('float_value')),
413
+ _DataType(resources_pb2.ModelTypeField.DataType.FLOAT,
414
+ AtomicFieldSerializer('float_value')),
445
415
  bool:
446
- _DataType(DataType.BOOL, AtomicFieldSerializer('bool_value')),
416
+ _DataType(resources_pb2.ModelTypeField.DataType.BOOL, AtomicFieldSerializer('bool_value')),
447
417
  np.ndarray:
448
- _DataType(DataType.NDARRAY, NDArraySerializer('ndarray')),
418
+ _DataType(resources_pb2.ModelTypeField.DataType.NDARRAY, NDArraySerializer('ndarray')),
449
419
  data_types.JSON:
450
- _DataType(DataType.JSON, JSONSerializer('string_value')
420
+ _DataType(resources_pb2.ModelTypeField.DataType.JSON_DATA, JSONSerializer('string_value')
451
421
  ), # TODO change to json_value when new proto is ready
452
422
  data_types.Text:
453
- _DataType(DataType.TEXT, MessageSerializer('text', data_types.Text)),
423
+ _DataType(resources_pb2.ModelTypeField.DataType.TEXT,
424
+ MessageSerializer('text', data_types.Text)),
454
425
  data_types.Image:
455
- _DataType(DataType.IMAGE, MessageSerializer('image', data_types.Image)),
426
+ _DataType(resources_pb2.ModelTypeField.DataType.IMAGE,
427
+ MessageSerializer('image', data_types.Image)),
456
428
  data_types.Concept:
457
- _DataType(DataType.CONCEPT, MessageSerializer('concepts', data_types.Concept)),
429
+ _DataType(resources_pb2.ModelTypeField.DataType.CONCEPT,
430
+ MessageSerializer('concepts', data_types.Concept)),
458
431
  data_types.Region:
459
- _DataType(DataType.REGION, MessageSerializer('regions', data_types.Region)),
432
+ _DataType(resources_pb2.ModelTypeField.DataType.REGION,
433
+ MessageSerializer('regions', data_types.Region)),
460
434
  data_types.Frame:
461
- _DataType(DataType.FRAME, MessageSerializer('frames', data_types.Frame)),
435
+ _DataType(resources_pb2.ModelTypeField.DataType.FRAME,
436
+ MessageSerializer('frames', data_types.Frame)),
462
437
  data_types.Audio:
463
- _DataType(DataType.AUDIO, MessageSerializer('audio', data_types.Audio)),
438
+ _DataType(resources_pb2.ModelTypeField.DataType.AUDIO,
439
+ MessageSerializer('audio', data_types.Audio)),
464
440
  data_types.Video:
465
- _DataType(DataType.VIDEO, MessageSerializer('video', data_types.Video)),
441
+ _DataType(resources_pb2.ModelTypeField.DataType.VIDEO,
442
+ MessageSerializer('video', data_types.Video)),
466
443
  }
467
444
 
468
445
  _SERIALIZERS_BY_TYPE_ENUM = {dt.type: dt.serializer for dt in _DATA_TYPES.values()}