clarifai 11.1.5rc1__py3-none-any.whl → 11.1.5rc3__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 (25) hide show
  1. clarifai/__init__.py +1 -1
  2. clarifai/cli/__pycache__/model.cpython-310.pyc +0 -0
  3. clarifai/client/model.py +10 -2
  4. clarifai/client/model_client.py +53 -27
  5. clarifai/runners/__pycache__/__init__.cpython-310.pyc +0 -0
  6. clarifai/runners/dockerfile_template/Dockerfile.template +2 -2
  7. clarifai/runners/models/__pycache__/base_typed_model.cpython-310.pyc +0 -0
  8. clarifai/runners/models/__pycache__/model_builder.cpython-310.pyc +0 -0
  9. clarifai/runners/models/__pycache__/model_class.cpython-310.pyc +0 -0
  10. clarifai/runners/models/__pycache__/model_runner.cpython-310.pyc +0 -0
  11. clarifai/runners/models/model_class.py +59 -42
  12. clarifai/runners/models/model_run_locally.py +3 -78
  13. clarifai/runners/utils/__pycache__/data_handler.cpython-310.pyc +0 -0
  14. clarifai/runners/utils/__pycache__/data_types.cpython-310.pyc +0 -0
  15. clarifai/runners/utils/__pycache__/method_signatures.cpython-310.pyc +0 -0
  16. clarifai/runners/utils/__pycache__/serializers.cpython-310.pyc +0 -0
  17. clarifai/runners/utils/data_types.py +334 -0
  18. clarifai/runners/utils/method_signatures.py +44 -29
  19. clarifai/runners/utils/serializers.py +1 -1
  20. {clarifai-11.1.5rc1.dist-info → clarifai-11.1.5rc3.dist-info}/METADATA +1 -1
  21. {clarifai-11.1.5rc1.dist-info → clarifai-11.1.5rc3.dist-info}/RECORD +25 -23
  22. {clarifai-11.1.5rc1.dist-info → clarifai-11.1.5rc3.dist-info}/LICENSE +0 -0
  23. {clarifai-11.1.5rc1.dist-info → clarifai-11.1.5rc3.dist-info}/WHEEL +0 -0
  24. {clarifai-11.1.5rc1.dist-info → clarifai-11.1.5rc3.dist-info}/entry_points.txt +0 -0
  25. {clarifai-11.1.5rc1.dist-info → clarifai-11.1.5rc3.dist-info}/top_level.txt +0 -0
clarifai/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "11.1.5rc1"
1
+ __version__ = "11.1.5rc3"
clarifai/client/model.py CHANGED
@@ -443,6 +443,15 @@ class Model(Lister, BaseClient):
443
443
  output_config=output_config,
444
444
  )
445
445
 
446
+ def predict2(self, inputs):
447
+ """Predicts the model based on the given inputs.
448
+
449
+ Args:
450
+ inputs (list[Input]): The inputs to predict, must be less than 128.
451
+ """
452
+
453
+ return self.model_client._predict(inputs=inputs,)
454
+
446
455
  def _check_predict_input_type(self, input_type: str) -> None:
447
456
  """Checks if the input type is valid for the model.
448
457
 
@@ -494,8 +503,7 @@ class Model(Lister, BaseClient):
494
503
  nodepool_id: str = None,
495
504
  deployment_id: str = None,
496
505
  user_id: str = None):
497
- runner_selector = resources_pb2.RunnerSelector()
498
-
506
+ runner_selector = None
499
507
  if deployment_id and (compute_cluster_id or nodepool_id):
500
508
  raise UserError(
501
509
  "You can only specify one of deployment_id or compute_cluster_id and nodepool_id.")
@@ -1,3 +1,4 @@
1
+ import inspect
1
2
  import time
2
3
  from typing import Any, Dict, Iterator, List
3
4
 
@@ -6,7 +7,9 @@ from clarifai_grpc.grpc.api.status import status_code_pb2
6
7
 
7
8
  from clarifai.constants.model import MAX_MODEL_PREDICT_INPUTS
8
9
  from clarifai.errors import UserError
9
- from clarifai.runners.utils.method_signatures import deserialize, serialize, signatures_from_json
10
+ from clarifai.runners.utils.method_signatures import (deserialize, get_stream_from_signature,
11
+ serialize, signatures_from_json,
12
+ unflatten_nested_keys)
10
13
  from clarifai.utils.misc import BackoffIterator, status_is_retryable
11
14
 
12
15
 
@@ -45,8 +48,10 @@ class ModelClient:
45
48
 
46
49
  request = service_pb2.PostModelOutputsRequest()
47
50
  request.CopyFrom(self.request_template)
48
- request.model.model_version.output_info.params['_method_name'] = '_GET_SIGNATURES'
49
- request.inputs.add() # empty input for this method
51
+ # request.model.model_version.output_info.params['_method_name'] = '_GET_SIGNATURES'
52
+ inp = request.inputs.add() # empty input for this method
53
+ inp.data.parts.add() # empty part for this input
54
+ inp.data.metadata['method_name'] = '_GET_SIGNATURES'
50
55
  start_time = time.time()
51
56
  backoff_iterator = BackoffIterator(10)
52
57
  while True:
@@ -56,13 +61,16 @@ class ModelClient:
56
61
  self.logger.info(f"Retrying model info fetch with response {response.status!r}")
57
62
  time.sleep(next(backoff_iterator))
58
63
  continue
59
-
60
- if response.status.code != status_code_pb2.SUCCESS:
61
- raise Exception(f"Model failed with response {response.status!r}")
62
64
  break
65
+ if response.status.code == status_code_pb2.INPUT_UNSUPPORTED_FORMAT:
66
+ # return code from older models that don't support _GET_SIGNATURES
67
+ self._method_signatures = {}
68
+ return
63
69
  if response.status.code != status_code_pb2.SUCCESS:
64
- raise Exception(response.status)
70
+ raise Exception(f"Model failed with response {response!r}")
65
71
  self._method_signatures = signatures_from_json(response.outputs[0].data.string_value)
72
+ import pdb
73
+ pdb.set_trace()
66
74
 
67
75
  def _define_functions(self):
68
76
  '''
@@ -105,26 +113,47 @@ class ModelClient:
105
113
  # need to bind method_name to the value, not the mutating loop variable
106
114
  f = bind_f(method_name, method_argnames, call_func)
107
115
 
108
- # set names and docstrings
109
- # note we could also have used exec with strings from the signature to define the
110
- # function, but this is safer (no xss), and docstrings with the signature is ok enough
116
+ # set names, annotations and docstrings
111
117
  f.__name__ = method_name
112
118
  f.__qualname__ = f'{self.__class__.__name__}.{method_name}'
113
- input_spec = ', '.join(
114
- f'{var.name}: {var.data_type}{" = " + str(var.default) if not var.required else ""}'
115
- for var in method_signature.inputs)
116
- output_vars = method_signature.outputs
117
- if len(output_vars) == 1 and output_vars[0].name == 'return':
119
+ input_annos = {var.name: var.data_type for var in method_signature.inputs}
120
+ output_annos = {var.name: var.data_type for var in method_signature.outputs}
121
+ # unflatten nested keys to match the user function args for docs
122
+ input_annos = unflatten_nested_keys(input_annos, method_signature.inputs, is_output=False)
123
+ output_annos = unflatten_nested_keys(output_annos, method_signature.outputs, is_output=True)
124
+
125
+ # add Stream[] to the stream input annotations for docs
126
+ input_stream_argname, _ = get_stream_from_signature(method_signature.inputs)
127
+ if input_stream_argname:
128
+ input_annos[input_stream_argname] = 'Stream[' + str(
129
+ input_annos[input_stream_argname]) + ']'
130
+
131
+ # handle multiple outputs in the return annotation
132
+ return_annotation = output_annos
133
+ name = next(iter(output_annos.keys()))
134
+ if len(output_annos) == 1 and name == 'return':
118
135
  # single output
119
- output_spec = output_vars[0].data_type
120
- elif output_vars[0].name == 'return.0':
136
+ return_annotation = output_annos[name]
137
+ elif name.startswith('return.') and name.split('.', 1)[1].isnumeric():
121
138
  # tuple output
122
- output_spec = '(' + ', '.join(var.data_type for var in output_vars) + ')'
139
+ return_annotation = '(' + ", ".join(output_annos[f'return.{i}']
140
+ for i in range(len(output_annos))) + ')'
123
141
  else:
124
142
  # named output
125
- output_spec = f'Output({", ".join(f"{var.name}={var.data_type}" for var in output_vars)})'
126
- f.__doc__ = f'''{method_name}(self, {input_spec}) -> {output_spec}\n'''
127
- #f.__doc__ += method_signature.description # TODO
143
+ return_annotation = f'Output({", ".join(f"{k}={t}" for k, t in output_annos.items())})'
144
+ if method_signature.method_type in ['generate', 'stream']:
145
+ return_annotation = f'Stream[{return_annotation}]'
146
+
147
+ # set annotations and docstrings
148
+ sig = inspect.signature(f).replace(
149
+ parameters=[
150
+ inspect.Parameter(k, inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=v)
151
+ for k, v in input_annos.items()
152
+ ],
153
+ return_annotation=return_annotation,
154
+ )
155
+ f.__signature__ = sig
156
+ f.__doc__ = method_signature.docstring
128
157
  setattr(self, method_name, f)
129
158
 
130
159
  def _predict(
@@ -190,7 +219,8 @@ class ModelClient:
190
219
  if inference_params:
191
220
  request.model.model_version.output_info.params.update(inference_params)
192
221
  if output_config:
193
- request.model.model_version.output_info.output_config.MergeFromDict(output_config)
222
+ request.model.model_version.output_info.output_config.MergeFrom(
223
+ resources_pb2.OutputConfig(**output_config))
194
224
 
195
225
  start_time = time.time()
196
226
  backoff_iterator = BackoffIterator(10)
@@ -312,11 +342,7 @@ class ModelClient:
312
342
  kwargs = inputs
313
343
 
314
344
  # find the streaming vars in the input signature, and the streaming input python param
315
- streaming_var_signatures = [var for var in input_signature if var.streaming]
316
- stream_argname = set([var.name.split('.', 1)[0] for var in streaming_var_signatures])
317
- assert len(
318
- stream_argname) == 1, 'streaming methods must have exactly one streaming function arg'
319
- stream_argname = stream_argname.pop()
345
+ stream_argname, streaming_var_signatures = get_stream_from_signature(input_signature)
320
346
 
321
347
  # get the streaming input generator from the user-provided function arg values
322
348
  user_inputs_generator = kwargs.pop(stream_argname)
@@ -44,8 +44,8 @@ ENV PYTHONPATH=${PYTHONPATH}:/home/nonroot/main \
44
44
  CLARIFAI_COMPUTE_CLUSTER_ID=${CLARIFAI_COMPUTE_CLUSTER_ID} \
45
45
  CLARIFAI_API_BASE=${CLARIFAI_API_BASE:-https://api.clarifai.com}
46
46
 
47
- # Write out the model function signatures
48
- RUN ["python", "-m", "clarifai.cli", "model", "signatures", "--model_path", "/home/nonroot/main", "--out_path", "/home/nonroot/main/signatures.yaml"]
47
+ # # Write out the model function signatures
48
+ # RUN ["python", "-m", "clarifai.cli", "model", "signatures", "--model_path", "/home/nonroot/main", "--out_path", "/home/nonroot/main/signatures.yaml"]
49
49
 
50
50
  # Finally run the clarifai entrypoint to start the runner loop and local dev server.
51
51
  # Note(zeiler): we may want to make this a clarifai CLI call.
@@ -3,39 +3,73 @@ import itertools
3
3
  import logging
4
4
  import os
5
5
  import traceback
6
- import types
7
6
  from abc import ABC
8
7
  from typing import Any, Dict, Iterator, List
9
8
 
10
9
  from clarifai_grpc.grpc.api import resources_pb2, service_pb2
11
10
  from clarifai_grpc.grpc.api.status import status_code_pb2, status_pb2
12
11
 
13
- from clarifai.runners.utils import data_handler
12
+ from clarifai.runners.utils import data_types
14
13
  from clarifai.runners.utils.method_signatures import (build_function_signature, deserialize,
15
- serialize, signatures_to_json)
14
+ get_stream_from_signature, serialize,
15
+ signatures_to_json)
16
16
 
17
17
  _METHOD_INFO_ATTR = '_cf_method_info'
18
18
 
19
19
  _RAISE_EXCEPTIONS = os.getenv("RAISE_EXCEPTIONS", "false").lower() == "true"
20
20
 
21
21
 
22
+ class methods:
23
+ '''
24
+ Decorators to mark methods as predict, generate, or stream methods.
25
+ '''
26
+
27
+ @staticmethod
28
+ def predict(method):
29
+ setattr(method, _METHOD_INFO_ATTR, _MethodInfo(method, 'predict'))
30
+ return method
31
+
32
+ @staticmethod
33
+ def generate(method):
34
+ setattr(method, _METHOD_INFO_ATTR, _MethodInfo(method, 'generate'))
35
+ return method
36
+
37
+ @staticmethod
38
+ def stream(method):
39
+ setattr(method, _METHOD_INFO_ATTR, _MethodInfo(method, 'stream'))
40
+ return method
41
+
42
+
22
43
  class ModelClass(ABC):
44
+ '''
45
+ Base class for model classes that can be run as a service.
23
46
 
24
- def load_model(self):
25
- """Load the model."""
26
- pass
47
+ Define methods as predict, generate, or stream methods using the @methods decorators.
48
+
49
+ Example:
50
+
51
+ from clarifai.runners.model_class import ModelClass, methods
52
+ from clarifai.runners.utils.data_types import Input, Stream
27
53
 
28
- def predict(self, **kwargs):
29
- """Predict method for single or batched inputs."""
30
- raise NotImplementedError("predict() not implemented")
54
+ class MyModel(ModelClass):
31
55
 
32
- def generate(self, **kwargs) -> Iterator:
33
- """Generate method for streaming outputs."""
34
- raise NotImplementedError("generate() not implemented")
56
+ @methods.predict
57
+ def predict(self, x: str, y: int) -> List[str]:
58
+ return [x] * y
35
59
 
36
- def stream(self, **kwargs) -> Iterator:
37
- """Stream method for streaming inputs and outputs."""
38
- raise NotImplementedError("stream() not implemented")
60
+ @methods.generate
61
+ def generate(self, x: str, y: int) -> Stream[str]:
62
+ for i in range(y):
63
+ yield x + str(i)
64
+
65
+ @methods.stream
66
+ def stream(self, input_stream: Stream[Input(x=str, y=int)]) -> Stream[str]:
67
+ for item in input_stream:
68
+ yield item.x + ' ' + str(item.y)
69
+ '''
70
+
71
+ def load_model(self):
72
+ """Load the model."""
39
73
 
40
74
  def _handle_get_signatures_request(self) -> service_pb2.MultiOutputResponse:
41
75
  methods = self._get_method_info()
@@ -63,7 +97,9 @@ class ModelClass(ABC):
63
97
  outputs = []
64
98
  try:
65
99
  # TODO add method name field to proto
66
- method_name = request.model.model_version.output_info.params['_method_name']
100
+ method_name = request.inputs[0].data.metadata['method_name']
101
+ # call_params = dict(request.model.model_version.output_info.params)
102
+ # method_name = call_params.get('_method_name', 'predict')
67
103
  if method_name == '_GET_SIGNATURES': # special case to fetch signatures, TODO add endpoint for this
68
104
  return self._handle_get_signatures_request()
69
105
  if method_name not in self._get_method_info():
@@ -96,7 +132,8 @@ class ModelClass(ABC):
96
132
  def generate_wrapper(self, request: service_pb2.PostModelOutputsRequest
97
133
  ) -> Iterator[service_pb2.MultiOutputResponse]:
98
134
  try:
99
- method_name = request.model.model_version.output_info.params['_method_name']
135
+ call_params = dict(request.model.model_version.output_info.params)
136
+ method_name = call_params.get('_method_name', 'generate')
100
137
  method = getattr(self, method_name)
101
138
  method_info = method._cf_method_info
102
139
  signature = method_info.signature
@@ -133,18 +170,15 @@ class ModelClass(ABC):
133
170
  request = next(request_iterator) # get first request to determine method
134
171
  assert len(request.inputs) == 1, "Streaming requires exactly one input"
135
172
 
136
- method_name = request.model.model_version.output_info.params['_method_name']
173
+ call_params = dict(request.model.model_version.output_info.params)
174
+ method_name = call_params.get('_method_name', 'stream')
137
175
  method = getattr(self, method_name)
138
176
  method_info = method._cf_method_info
139
177
  signature = method_info.signature
140
178
  python_param_types = method_info.python_param_types
141
179
 
142
180
  # find the streaming vars in the signature
143
- streaming_var_signatures = [var for var in signature.inputs if var.streaming]
144
- stream_argname = set([var.name.split('.', 1)[0] for var in streaming_var_signatures])
145
- assert len(
146
- stream_argname) == 1, 'streaming methods must have exactly one streaming function arg'
147
- stream_argname = stream_argname.pop()
181
+ stream_argname, streaming_var_signatures = get_stream_from_signature(signature.inputs)
148
182
 
149
183
  # convert all inputs for the first request, including the first stream value
150
184
  inputs = self._convert_input_protos_to_python(request.inputs, signature.inputs,
@@ -190,7 +224,7 @@ class ModelClass(ABC):
190
224
  for k, v in kwargs.items():
191
225
  if k not in python_param_types:
192
226
  continue
193
- kwargs[k] = data_handler.cast(v, python_param_types[k])
227
+ kwargs[k] = data_types.cast(v, python_param_types[k])
194
228
  result.append(kwargs)
195
229
  return result
196
230
 
@@ -203,6 +237,7 @@ class ModelClass(ABC):
203
237
  if not isinstance(output, dict): # TODO Output type, not just dict
204
238
  output = {'return': output}
205
239
  serialize(output, variables_signature, proto.data, is_output=True)
240
+ proto.status.code = status_code_pb2.SUCCESS
206
241
  return proto
207
242
 
208
243
  @classmethod
@@ -245,21 +280,3 @@ class _MethodInfo:
245
280
  if p.annotation != inspect.Parameter.empty
246
281
  }
247
282
  self.python_param_types.pop('self', None)
248
-
249
-
250
- def predict(method):
251
- setattr(method, _METHOD_INFO_ATTR, _MethodInfo(method, 'predict'))
252
- return method
253
-
254
-
255
- def generate(method):
256
- setattr(method, _METHOD_INFO_ATTR, _MethodInfo(method, 'generate'))
257
- return method
258
-
259
-
260
- def stream(method):
261
- setattr(method, _METHOD_INFO_ATTR, _MethodInfo(method, 'stream'))
262
- return method
263
-
264
-
265
- methods = types.SimpleNamespace(predict=predict, generate=generate, stream=stream)
@@ -7,14 +7,11 @@ import subprocess
7
7
  import sys
8
8
  import tempfile
9
9
  import time
10
- import traceback
11
10
  import venv
12
11
 
13
12
  from clarifai_grpc.grpc.api import resources_pb2, service_pb2
14
- from clarifai_grpc.grpc.api.status import status_code_pb2, status_pb2
15
13
 
16
14
  from clarifai.runners.models.model_builder import ModelBuilder
17
- from clarifai.runners.utils.url_fetcher import ensure_urls_downloaded
18
15
  from clarifai.utils.logging import logger
19
16
 
20
17
 
@@ -111,85 +108,13 @@ class ModelRunLocally:
111
108
  for i in range(1):
112
109
  yield request
113
110
 
114
- def _run_model_inference(self, model):
115
- """Perform inference using the model."""
116
- request = self._build_request()
117
- stream_request = self._build_stream_request()
118
-
119
- ensure_urls_downloaded(request)
120
- predict_response = None
121
- generate_response = None
122
- stream_response = None
123
- try:
124
- predict_response = model.predict(request)
125
- except NotImplementedError:
126
- logger.info("Model does not implement predict() method.")
127
- except Exception as e:
128
- logger.error(f"Model Prediction failed: {e}")
129
- traceback.print_exc()
130
- predict_response = service_pb2.MultiOutputResponse(status=status_pb2.Status(
131
- code=status_code_pb2.MODEL_PREDICTION_FAILED,
132
- description="Prediction failed",
133
- details="",
134
- internal_details=str(e),
135
- ))
136
-
137
- if predict_response:
138
- if predict_response.outputs[0].status.code != status_code_pb2.SUCCESS:
139
- logger.error(f"Moddel Prediction failed: {predict_response}")
140
- else:
141
- logger.info(f"Model Prediction succeeded: {predict_response}")
142
-
143
- try:
144
- generate_response = model.generate(request)
145
- except NotImplementedError:
146
- logger.info("Model does not implement generate() method.")
147
- except Exception as e:
148
- logger.error(f"Model Generation failed: {e}")
149
- traceback.print_exc()
150
- generate_response = service_pb2.MultiOutputResponse(status=status_pb2.Status(
151
- code=status_code_pb2.MODEL_GENERATION_FAILED,
152
- description="Generation failed",
153
- details="",
154
- internal_details=str(e),
155
- ))
156
-
157
- if generate_response:
158
- generate_first_res = next(generate_response)
159
- if generate_first_res.outputs[0].status.code != status_code_pb2.SUCCESS:
160
- logger.error(f"Moddel Prediction failed: {generate_first_res}")
161
- else:
162
- logger.info(
163
- f"Model Prediction succeeded for generate and first response: {generate_first_res}")
164
-
165
- try:
166
- stream_response = model.stream(stream_request)
167
- except NotImplementedError:
168
- logger.info("Model does not implement stream() method.")
169
- except Exception as e:
170
- logger.error(f"Model Stream failed: {e}")
171
- traceback.print_exc()
172
- stream_response = service_pb2.MultiOutputResponse(status=status_pb2.Status(
173
- code=status_code_pb2.MODEL_STREAM_FAILED,
174
- description="Stream failed",
175
- details="",
176
- internal_details=str(e),
177
- ))
178
-
179
- if stream_response:
180
- stream_first_res = next(stream_response)
181
- if stream_first_res.outputs[0].status.code != status_code_pb2.SUCCESS:
182
- logger.error(f"Moddel Prediction failed: {stream_first_res}")
183
- else:
184
- logger.info(
185
- f"Model Prediction succeeded for stream and first response: {stream_first_res}")
186
-
187
111
  def _run_test(self):
188
112
  """Test the model locally by making a prediction."""
189
113
  # Create the model
190
114
  model = self.builder.create_model_instance()
191
- # send an inference.
192
- self._run_model_inference(model)
115
+ # call its test method, if it has one
116
+ if hasattr(model, "test"):
117
+ model.test()
193
118
 
194
119
  def test_model(self):
195
120
  """Test the model by running it locally in the virtual environment."""
@@ -0,0 +1,334 @@
1
+ import io
2
+ from typing import Iterable, List, get_args, get_origin
3
+
4
+ import numpy as np
5
+ from clarifai_grpc.grpc.api.resources_pb2 import Audio as AudioProto
6
+ from clarifai_grpc.grpc.api.resources_pb2 import Concept as ConceptProto
7
+ from clarifai_grpc.grpc.api.resources_pb2 import Frame as FrameProto
8
+ from clarifai_grpc.grpc.api.resources_pb2 import Image as ImageProto
9
+ from clarifai_grpc.grpc.api.resources_pb2 import Region as RegionProto
10
+ from clarifai_grpc.grpc.api.resources_pb2 import Text as TextProto
11
+ from clarifai_grpc.grpc.api.resources_pb2 import Video as VideoProto
12
+ from PIL import Image as PILImage
13
+
14
+
15
+ class MessageData:
16
+
17
+ def to_proto(self):
18
+ raise NotImplementedError
19
+
20
+ @classmethod
21
+ def from_proto(cls, proto):
22
+ raise NotImplementedError
23
+
24
+ def cast(self, python_type):
25
+ if python_type == self.__class__:
26
+ return self
27
+ raise TypeError(f'Incompatible type for {self.__class__.__name__}: {python_type}')
28
+
29
+
30
+ class Output(dict):
31
+ __getattr__ = dict.__getitem__
32
+ __setattr__ = dict.__setitem__
33
+
34
+ def __origin__(self):
35
+ return self
36
+
37
+ def __args__(self):
38
+ return list(self.keys())
39
+
40
+
41
+ class Input(dict):
42
+ __getattr__ = dict.__getitem__
43
+ __setattr__ = dict.__setitem__
44
+
45
+ def __origin__(self):
46
+ return self
47
+
48
+ def __args__(self):
49
+ return list(self.keys())
50
+
51
+
52
+ class Stream(Iterable):
53
+ pass
54
+
55
+
56
+ class Text(MessageData):
57
+
58
+ def __init__(self, text: str, url: str = None):
59
+ self.text = text
60
+ self.url = url
61
+
62
+ def to_proto(self) -> TextProto:
63
+ return TextProto(raw=self.text or '', url=self.url or '')
64
+
65
+ @classmethod
66
+ def from_proto(cls, proto: TextProto) -> "Text":
67
+ return cls(proto.raw, proto.url or None)
68
+
69
+ def cast(self, python_type):
70
+ if python_type == str:
71
+ return self.text
72
+ if python_type == Text:
73
+ return self
74
+ raise TypeError(f'Incompatible type for Text: {python_type}')
75
+
76
+
77
+ class Concept(MessageData):
78
+
79
+ def __init__(self, name: str, value: float = 0):
80
+ self.name = name
81
+ self.value = value
82
+
83
+ def __repr__(self) -> str:
84
+ return f"Concept(name={self.name!r}, value={self.value})"
85
+
86
+ def to_proto(self):
87
+ return ConceptProto(name=self.name, value=self.value)
88
+
89
+ @classmethod
90
+ def from_proto(cls, proto: ConceptProto) -> "Concept":
91
+ return cls(proto.name, proto.value)
92
+
93
+
94
+ class Region(MessageData):
95
+
96
+ def __init__(self, proto_region: RegionProto):
97
+ self.proto = proto_region
98
+
99
+ @property
100
+ def box(self) -> List[float]:
101
+ bbox = self.proto.region_info.bounding_box
102
+ return [bbox.left_col, bbox.top_row, bbox.right_col, bbox.bottom_row] # x1, y1, x2, y2
103
+
104
+ @box.setter
105
+ def box(self, value: List[float]):
106
+ bbox = self.proto.region_info.bounding_box
107
+ bbox.left_col, bbox.top_row, bbox.right_col, bbox.bottom_row = value
108
+
109
+ @property
110
+ def concepts(self) -> List[Concept]:
111
+ return [Concept.from_proto(proto) for proto in self.proto.data.concepts]
112
+
113
+ @concepts.setter
114
+ def concepts(self, value: List[Concept]):
115
+ self.proto.data.concepts.extend([concept.to_proto() for concept in value])
116
+
117
+ def __repr__(self) -> str:
118
+ return f"Region(box={self.box}, concepts={self.concepts})"
119
+
120
+ def to_proto(self) -> RegionProto:
121
+ return self.proto
122
+
123
+ @classmethod
124
+ def from_proto(cls, proto: RegionProto) -> "Region":
125
+ return cls(proto)
126
+
127
+
128
+ class Image(MessageData):
129
+
130
+ def __init__(self, proto_image: ImageProto = None, url: str = None, bytes: bytes = None):
131
+ if proto_image is None:
132
+ proto_image = ImageProto()
133
+ self.proto = proto_image
134
+ # use setters for init vals
135
+ if url:
136
+ self.url = url
137
+ if bytes:
138
+ self.bytes = bytes
139
+
140
+ @property
141
+ def url(self) -> str:
142
+ return self.proto.url
143
+
144
+ @url.setter
145
+ def url(self, value: str):
146
+ self.proto.url = value
147
+
148
+ @property
149
+ def bytes(self) -> bytes:
150
+ return self.proto.base64
151
+
152
+ @bytes.setter
153
+ def bytes(self, value: bytes):
154
+ self.proto.base64 = value
155
+
156
+ def __repr__(self) -> str:
157
+ attrs = []
158
+ if self.url:
159
+ attrs.append(f"url={self.url!r}")
160
+ if self.bytes:
161
+ attrs.append(f"bytes=<{len(self.bytes)} bytes>")
162
+ return f"Image({', '.join(attrs)})"
163
+
164
+ @classmethod
165
+ def from_url(cls, url: str) -> "Image":
166
+ proto_image = ImageProto(url=url)
167
+ return cls(proto_image)
168
+
169
+ @classmethod
170
+ def from_pil(cls, pil_image: PILImage.Image) -> "Image":
171
+ with io.BytesIO() as output:
172
+ pil_image.save(output, format="PNG")
173
+ image_bytes = output.getvalue()
174
+ proto_image = ImageProto(base64=image_bytes)
175
+ return cls(proto_image)
176
+
177
+ def to_pil(self) -> PILImage.Image:
178
+ if not self.proto.base64:
179
+ raise ValueError("Image has no bytes")
180
+ return PILImage.open(io.BytesIO(self.proto.base64))
181
+
182
+ def to_numpy(self) -> np.ndarray:
183
+ return np.asarray(self.to_pil())
184
+
185
+ def to_proto(self) -> ImageProto:
186
+ return self.proto
187
+
188
+ @classmethod
189
+ def from_proto(cls, proto: ImageProto) -> "Image":
190
+ return cls(proto)
191
+
192
+ def cast(self, python_type):
193
+ if python_type == Image:
194
+ return self
195
+ if python_type in (PILImage.Image, PILImage):
196
+ return self.to_pil()
197
+ if python_type == np.ndarray or get_origin(python_type) == np.ndarray:
198
+ return self.to_numpy()
199
+ raise TypeError(f'Incompatible type for Image: {python_type}')
200
+
201
+
202
+ class Audio(MessageData):
203
+
204
+ def __init__(self, proto_audio: AudioProto):
205
+ self.proto = proto_audio
206
+
207
+ @property
208
+ def url(self) -> str:
209
+ return self.proto.url
210
+
211
+ @url.setter
212
+ def url(self, value: str):
213
+ self.proto.url = value
214
+
215
+ @property
216
+ def bytes(self) -> bytes:
217
+ return self.proto.base64
218
+
219
+ @bytes.setter
220
+ def bytes(self, value: bytes):
221
+ self.proto.base64 = value
222
+
223
+ @classmethod
224
+ def from_url(cls, url: str) -> "Audio":
225
+ proto_audio = AudioProto(url=url)
226
+ return cls(proto_audio)
227
+
228
+ def __repr__(self) -> str:
229
+ attrs = []
230
+ if self.url:
231
+ attrs.append(f"url={self.url!r}")
232
+ if self.bytes:
233
+ attrs.append(f"bytes=<{len(self.bytes)} bytes>")
234
+ return f"Audio({', '.join(attrs)})"
235
+
236
+ def to_proto(self) -> AudioProto:
237
+ return self.proto
238
+
239
+ @classmethod
240
+ def from_proto(cls, proto: AudioProto) -> "Audio":
241
+ return cls(proto)
242
+
243
+
244
+ class Frame(MessageData):
245
+
246
+ def __init__(self, proto_frame: FrameProto):
247
+ self.proto = proto_frame
248
+
249
+ @property
250
+ def time(self) -> float:
251
+ # TODO: time is a uint32, so this will overflow at 49.7 days
252
+ # we should be using double or uint64 in the proto instead
253
+ return self.proto.frame_info.time / 1000.0
254
+
255
+ @time.setter
256
+ def time(self, value: float):
257
+ self.proto.frame_info.time = int(value * 1000)
258
+
259
+ @property
260
+ def image(self) -> Image:
261
+ return Image.from_proto(self.proto.data.image)
262
+
263
+ @image.setter
264
+ def image(self, value: Image):
265
+ self.proto.data.image.CopyFrom(value.to_proto())
266
+
267
+ @property
268
+ def regions(self) -> List[Region]:
269
+ return [Region(region) for region in self.proto.data.regions]
270
+
271
+ @regions.setter
272
+ def regions(self, value: List[Region]):
273
+ self.proto.data.regions.extend([region.proto for region in value])
274
+
275
+ def to_proto(self) -> FrameProto:
276
+ return self.proto
277
+
278
+ @classmethod
279
+ def from_proto(cls, proto: FrameProto) -> "Frame":
280
+ return cls(proto)
281
+
282
+
283
+ class Video(MessageData):
284
+
285
+ def __init__(self, proto_video: VideoProto):
286
+ self.proto = proto_video
287
+
288
+ @property
289
+ def url(self) -> str:
290
+ return self.proto.url
291
+
292
+ @url.setter
293
+ def url(self, value: str):
294
+ self.proto.url = value
295
+
296
+ @property
297
+ def bytes(self) -> bytes:
298
+ return self.proto.base64
299
+
300
+ @bytes.setter
301
+ def bytes(self, value: bytes):
302
+ self.proto.base64 = value
303
+
304
+ @classmethod
305
+ def from_url(cls, url: str) -> "Video":
306
+ proto_video = VideoProto(url=url)
307
+ return cls(proto_video)
308
+
309
+ def __repr__(self) -> str:
310
+ attrs = []
311
+ if self.url:
312
+ attrs.append(f"url={self.url!r}")
313
+ if self.bytes:
314
+ attrs.append(f"bytes=<{len(self.bytes)} bytes>")
315
+ return f"Video({', '.join(attrs)})"
316
+
317
+ def to_proto(self) -> VideoProto:
318
+ return self.proto
319
+
320
+ @classmethod
321
+ def from_proto(cls, proto: VideoProto) -> "Video":
322
+ return cls(proto)
323
+
324
+
325
+ def cast(value, python_type):
326
+ list_type = (get_origin(python_type) == list)
327
+ if isinstance(value, MessageData):
328
+ return value.cast(python_type)
329
+ if list_type and isinstance(value, np.ndarray):
330
+ return value.tolist()
331
+ if list_type and isinstance(value, list):
332
+ inner_type = get_args(python_type)[0]
333
+ return [cast(item, inner_type) for item in value]
334
+ return value
@@ -2,7 +2,7 @@ import inspect
2
2
  import json
3
3
  import re
4
4
  import types
5
- from collections import namedtuple
5
+ from collections import OrderedDict, namedtuple
6
6
  from typing import List, get_args, get_origin
7
7
 
8
8
  import numpy as np
@@ -11,7 +11,7 @@ import yaml
11
11
  from clarifai_grpc.grpc.api import resources_pb2
12
12
  from google.protobuf.message import Message as MessageProto
13
13
 
14
- from clarifai.runners.utils import data_handler
14
+ from clarifai.runners.utils import data_types
15
15
  from clarifai.runners.utils.serializers import (AtomicFieldSerializer, ImageSerializer,
16
16
  ListSerializer, MessageSerializer,
17
17
  NDArraySerializer, NullValueSerializer, Serializer)
@@ -33,7 +33,7 @@ def build_function_signature(func, method_type: str):
33
33
  raise ValueError('Function must have a return annotation')
34
34
  # check for multiple return values and convert to dict for named values
35
35
  return_streaming = False
36
- if get_origin(return_annotation) == data_handler.Stream:
36
+ if get_origin(return_annotation) == data_types.Stream:
37
37
  return_annotation = get_args(return_annotation)[0]
38
38
  return_streaming = True
39
39
  if get_origin(return_annotation) == tuple:
@@ -73,7 +73,7 @@ def build_function_signature(func, method_type: str):
73
73
  input_stream_vars = [var for var in input_vars if var.streaming]
74
74
  if len(input_stream_vars) == 0:
75
75
  raise TypeError('Stream methods must include a Stream input')
76
- if len(output_vars) != 1 or not output_vars[0].streaming:
76
+ if not all(var.streaming for var in output_vars):
77
77
  raise TypeError('Stream methods must return a single Stream')
78
78
  else:
79
79
  raise TypeError('Invalid method type: %s' % method_type)
@@ -85,6 +85,7 @@ def build_function_signature(func, method_type: str):
85
85
  #method_signature.method_type = getattr(resources_pb2.RunnerMethodType, method_type)
86
86
  assert method_type in ('predict', 'generate', 'stream')
87
87
  method_signature.method_type = method_type
88
+ method_signature.docstring = func.__doc__
88
89
 
89
90
  #method_signature.inputs.extend(input_vars)
90
91
  #method_signature.outputs.extend(output_vars)
@@ -163,7 +164,7 @@ def serialize(kwargs, signatures, proto=None, is_output=False):
163
164
  if proto is None:
164
165
  proto = resources_pb2.Data()
165
166
  if not is_output: # TODO: use this consistently for return keys also
166
- flatten_nested_keys(kwargs, signatures, is_output)
167
+ kwargs = flatten_nested_keys(kwargs, signatures, is_output)
167
168
  unknown = set(kwargs.keys()) - set(sig.name for sig in signatures)
168
169
  if unknown:
169
170
  if unknown == {'return'} and len(signatures) > 1:
@@ -204,8 +205,8 @@ def deserialize(proto, signatures, is_output=False):
204
205
  return kwargs['return']
205
206
  if kwargs and 'return.0' in kwargs: # case for tuple return values
206
207
  return tuple(kwargs[f'return.{i}'] for i in range(len(kwargs)))
207
- return data_handler.Output(kwargs)
208
- unflatten_nested_keys(kwargs, signatures, is_output)
208
+ return data_types.Output(kwargs)
209
+ kwargs = unflatten_nested_keys(kwargs, signatures, is_output)
209
210
  return kwargs
210
211
 
211
212
 
@@ -238,18 +239,32 @@ def unflatten_nested_keys(kwargs, signatures, is_output):
238
239
  Unflatten nested keys in kwargs into a dict, e.g. {'a.b': 1} -> {'a': {'b': 1}}
239
240
  Uses the signatures to determine which keys are nested.
240
241
  The dict subclass is Input or Output, depending on the is_output flag.
242
+ Preserves the order of args from the signatures.
241
243
  '''
244
+ unflattened = OrderedDict()
242
245
  for sig in signatures:
243
246
  if '.' not in sig.name:
247
+ if sig.name in kwargs:
248
+ unflattened[sig.name] = kwargs[sig.name]
244
249
  continue
245
250
  if sig.name not in kwargs:
246
251
  continue
247
252
  parts = sig.name.split('.')
248
253
  assert len(parts) == 2, 'Only one level of nested keys is supported'
249
- if parts[0] not in kwargs:
250
- kwargs[parts[0]] = data_handler.Output() if is_output else data_handler.Input()
251
- kwargs[parts[0]][parts[1]] = kwargs.pop(sig.name)
252
- return kwargs
254
+ if parts[0] not in unflattened:
255
+ unflattened[parts[0]] = data_types.Output() if is_output else data_types.Input()
256
+ unflattened[parts[0]][parts[1]] = kwargs[sig.name]
257
+ return unflattened
258
+
259
+
260
+ def get_stream_from_signature(signatures):
261
+ streaming_signatures = [var for var in signatures if var.streaming]
262
+ if not streaming_signatures:
263
+ return None, []
264
+ stream_argname = set([var.name.split('.', 1)[0] for var in streaming_signatures])
265
+ assert len(stream_argname) == 1, 'streaming methods must have exactly one streaming function arg'
266
+ stream_argname = stream_argname.pop()
267
+ return stream_argname, streaming_signatures
253
268
 
254
269
 
255
270
  def _is_empty_proto_data(data):
@@ -314,20 +329,20 @@ def _normalize_types(param, is_output=False):
314
329
  tp = param.annotation
315
330
 
316
331
  # stream type indicates streaming, not part of the data itself
317
- streaming = (get_origin(tp) == data_handler.Stream)
332
+ streaming = (get_origin(tp) == data_types.Stream)
318
333
  if streaming:
319
334
  tp = get_args(tp)[0]
320
335
 
321
336
  if is_output or streaming: # named types can be used for outputs or streaming inputs
322
337
  # output type used for named return values, each with their own data type
323
- if isinstance(tp, (dict, data_handler.Output, data_handler.Input)):
338
+ if isinstance(tp, (dict, data_types.Output, data_types.Input)):
324
339
  return {param.name + '.' + name: _normalize_data_type(val)
325
340
  for name, val in tp.items()}, streaming
326
- if tp == data_handler.Output: # check for Output type without values
341
+ if tp == data_types.Output: # check for Output type without values
327
342
  if not is_output:
328
343
  raise TypeError('Output types can only be used for output values')
329
344
  raise TypeError('Output types must be instantiated with inner type values for each key')
330
- if tp == data_handler.Input: # check for Output type without values
345
+ if tp == data_types.Input: # check for Output type without values
331
346
  if is_output:
332
347
  raise TypeError('Input types can only be used for input values')
333
348
  raise TypeError(
@@ -349,7 +364,7 @@ def _normalize_data_type(tp):
349
364
  # check for PIL images (sometimes types use the module, sometimes the class)
350
365
  # set these to use the Image data handler
351
366
  if tp in (PIL.Image, PIL.Image.Image):
352
- tp = data_handler.Image
367
+ tp = data_types.Image
353
368
 
354
369
  # put back list
355
370
  if is_list:
@@ -388,20 +403,20 @@ _DATA_TYPES = {
388
403
  _DataType('None', '', NullValueSerializer()),
389
404
  np.ndarray:
390
405
  _DataType('ndarray', 'ndarray', NDArraySerializer()),
391
- data_handler.Text:
392
- _DataType('Text', 'text', MessageSerializer(data_handler.Text)),
393
- data_handler.Image:
406
+ data_types.Text:
407
+ _DataType('Text', 'text', MessageSerializer(data_types.Text)),
408
+ data_types.Image:
394
409
  _DataType('Image', 'image', ImageSerializer()),
395
- data_handler.Concept:
396
- _DataType('Concept', 'concepts', MessageSerializer(data_handler.Concept)),
397
- data_handler.Region:
398
- _DataType('Region', 'regions', MessageSerializer(data_handler.Region)),
399
- data_handler.Frame:
400
- _DataType('Frame', 'frames', MessageSerializer(data_handler.Frame)),
401
- data_handler.Audio:
402
- _DataType('Audio', 'audio', MessageSerializer(data_handler.Audio)),
403
- data_handler.Video:
404
- _DataType('Video', 'video', MessageSerializer(data_handler.Video)),
410
+ data_types.Concept:
411
+ _DataType('Concept', 'concepts', MessageSerializer(data_types.Concept)),
412
+ data_types.Region:
413
+ _DataType('Region', 'regions', MessageSerializer(data_types.Region)),
414
+ data_types.Frame:
415
+ _DataType('Frame', 'frames', MessageSerializer(data_types.Frame)),
416
+ data_types.Audio:
417
+ _DataType('Audio', 'audio', MessageSerializer(data_types.Audio)),
418
+ data_types.Video:
419
+ _DataType('Video', 'video', MessageSerializer(data_types.Video)),
405
420
 
406
421
  # lists handled specially, not as generic lists using parts
407
422
  List[int]:
@@ -4,7 +4,7 @@ import numpy as np
4
4
  from clarifai_grpc.grpc.api import resources_pb2
5
5
  from PIL import Image as PILImage
6
6
 
7
- from clarifai.runners.utils.data_handler import Image, MessageData
7
+ from clarifai.runners.utils.data_types import Image, MessageData
8
8
 
9
9
 
10
10
  class Serializer:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: clarifai
3
- Version: 11.1.5rc1
3
+ Version: 11.1.5rc3
4
4
  Summary: Clarifai Python SDK
5
5
  Home-page: https://github.com/Clarifai/clarifai-python
6
6
  Author: Clarifai
@@ -1,4 +1,4 @@
1
- clarifai/__init__.py,sha256=5B7b93t2VQEf7mnj6P0kUJcGZiWQD7DaL9EA8x7K2I4,26
1
+ clarifai/__init__.py,sha256=cQU5SXsYznf1FLV9LeeLMrjUc1vlOnCbQLM5_Z--QKI,26
2
2
  clarifai/cli.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  clarifai/errors.py,sha256=RwzTajwds51wLD0MVlMC5kcpBnzRpreDLlazPSBZxrg,2605
4
4
  clarifai/versions.py,sha256=jctnczzfGk_S3EnVqb2FjRKfSREkNmvNEwAAa_VoKiQ,222
@@ -19,7 +19,7 @@ clarifai/cli/__pycache__/__main__.cpython-310.pyc,sha256=CM9FOqcSyt-DLnck7FovGDx
19
19
  clarifai/cli/__pycache__/base.cpython-310.pyc,sha256=a7mN_r511p_Ao8aXrWU9KPSe8wkDZJW4p8UhlD6EoB8,3151
20
20
  clarifai/cli/__pycache__/compute_cluster.cpython-310.pyc,sha256=NHLAcVEwqUhci0KB5DpnPWUqXcCttpWrA3F5zld4qN8,1985
21
21
  clarifai/cli/__pycache__/deployment.cpython-310.pyc,sha256=AhfbPlwjjj_TmC2UayjuRbNr00dOukDl6NfLhm2rIng,2278
22
- clarifai/cli/__pycache__/model.cpython-310.pyc,sha256=Rory2IgsnFWkAiHMM3XkA-zShxX_zHwEWTKFP1V1Weo,8542
22
+ clarifai/cli/__pycache__/model.cpython-310.pyc,sha256=1boWk53FmE7FjNVWSH-azhFxPqzoDbDmtu30eHUxFYY,9075
23
23
  clarifai/cli/__pycache__/nodepool.cpython-310.pyc,sha256=nEmM-s1HFg7xM5x-bpnqHFWAVLWj0J0ZskYtd6NSq20,2473
24
24
  clarifai/client/__init__.py,sha256=xI1U0l5AZdRThvQAXCLsd9axxyFzXXJ22m8LHqVjQRU,662
25
25
  clarifai/client/app.py,sha256=6pckYme1urV2YJjLIYfeZ-vH0Z5YSQa51jzIMcEfwug,38342
@@ -29,8 +29,8 @@ clarifai/client/dataset.py,sha256=y3zKT_VhP1gyN3OO-b3cPeW21ZXyKbQ7ZJkEG06bsTU,32
29
29
  clarifai/client/deployment.py,sha256=w7Y6pA1rYG4KRK1SwusRZc2sQRXlG8wezuVdzSWpCo0,2586
30
30
  clarifai/client/input.py,sha256=obMAHMDU1OwfXZ8KraOnGFlWzlW-3F7Ob_2lcOQMlhY,46339
31
31
  clarifai/client/lister.py,sha256=03KGMvs5RVyYqxLsSrWhNc34I8kiF1Ph0NeyEwu7nMU,2082
32
- clarifai/client/model.py,sha256=aZFeU4rjTIjC9IlWmJ-Gg9lHLrHDVKXWv80AFYdPEhc,75127
33
- clarifai/client/model_client.py,sha256=OfJvOvP-n61WrB-ZdtJVYkeM8HtM1T388V4yhP8OVJc,15494
32
+ clarifai/client/model.py,sha256=Z4cz-qXznbttETnH3W_LyyscGawvtBkRfaSCsdOgAvs,75334
33
+ clarifai/client/model_client.py,sha256=vPdNZbLV8IaTDhyi6dUV_WoPx6we-EFq5gX4MufAAD4,16653
34
34
  clarifai/client/module.py,sha256=FTkm8s9m-EaTKN7g9MnLhGJ9eETUfKG7aWZ3o1RshYs,4204
35
35
  clarifai/client/nodepool.py,sha256=la3vTFrO4LX8zm2eQ5jqf2L0-kQ63Dano8FibadoZbk,10152
36
36
  clarifai/client/search.py,sha256=GaPWN6JmTQGZaCHr6U1yv0zqR6wKFl7i9IVLg2ul1CI,14254
@@ -128,41 +128,43 @@ clarifai/rag/__pycache__/rag.cpython-310.pyc,sha256=_xylc1DvMu1KYcDr-dtfUU2uzUjL
128
128
  clarifai/rag/__pycache__/utils.cpython-310.pyc,sha256=IDUXR7Iv4KfHSY3sbx_bgPdJQn2ozyRCuz01EUTmCUw,3694
129
129
  clarifai/runners/__init__.py,sha256=cDJ31l41dDsqW4Xn6sFMkKxxdIMTnGH9IW6sVkq0TNw,207
130
130
  clarifai/runners/server.py,sha256=xHDLdhQApCgYG19QOKXqJNCGNyw1Vsvobq3UdryDrVc,4132
131
- clarifai/runners/__pycache__/__init__.cpython-310.pyc,sha256=VGSCzJUpHYJvSUMVIKhz3kmq0X5Kt8KFC6RnngonzDc,530
131
+ clarifai/runners/__pycache__/__init__.cpython-310.pyc,sha256=jVTodJyP53yeIEk2sPufcafNVxxCWiHOD50my0nwFcw,365
132
132
  clarifai/runners/__pycache__/server.cpython-310.pyc,sha256=HfZ6_Vrr5q78nznFqP_aWhPENplHIol_qPaf8lLlotE,3229
133
133
  clarifai/runners/dockerfile_template/Dockerfile.debug,sha256=sRlfRmSLE_TiLORcVRx-3-B0vvSNeUYgm0CCrWmLvAA,667
134
134
  clarifai/runners/dockerfile_template/Dockerfile.debug~,sha256=7YOVg3adIaiudfSkfLGeyxt-FfIBbD3UIIYccrIVJTs,426
135
- clarifai/runners/dockerfile_template/Dockerfile.template,sha256=cibinDDE4uRGt2d2ho2T7CduSeDF6R2n7U4_4MAouPw,2521
135
+ clarifai/runners/dockerfile_template/Dockerfile.template,sha256=MWGjj0My6d18v-nyhWuNbSXUzCzR6KWkohRB1yInb7Q,2525
136
136
  clarifai/runners/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
137
137
  clarifai/runners/models/model_builder.py,sha256=UCAeJiP_fRFfIuVI1sOge7LMwe-psgvdBuZ0LsJQMpM,33062
138
- clarifai/runners/models/model_class.py,sha256=S-Bgs9c5SKzbg20ZaBFZ5XMLfgGahdgkhSli-b3wlN8,10658
139
- clarifai/runners/models/model_run_locally.py,sha256=V770O-7yQQQlh80u48NZTEHkX3gj1HyclHbu1tjvaQ8,20864
138
+ clarifai/runners/models/model_class.py,sha256=7pZ8ci4M8Qh91OW-C6yuWAhl3psLDfyvGypaGyFRkLs,11122
139
+ clarifai/runners/models/model_run_locally.py,sha256=VZetm9Mko8MBjcjwr6PCnTU9gF3glgD5qvpbj-8tW2s,17962
140
140
  clarifai/runners/models/model_runner.py,sha256=qyc73pe4xc9BsUKHwnOyC9g-RNCARiFis4GTh-yg0vg,6219
141
141
  clarifai/runners/models/model_servicer.py,sha256=A--b1P71PBCAMJCpy_-fpNDkfCVdvdMh1LleW15dSas,3037
142
142
  clarifai/runners/models/__pycache__/__init__.cpython-310.pyc,sha256=GTFjzypyx5wnDGqxYeY01iya1CELKb5fOFBFLV031yU,171
143
- clarifai/runners/models/__pycache__/base_typed_model.cpython-310.pyc,sha256=7yG3KnWmyOBjHF6eTXPO-P8nKZXf8pOXozFu1eCL0ws,8271
144
- clarifai/runners/models/__pycache__/model_builder.cpython-310.pyc,sha256=0i6pT3F86bi6XX3TlkxoKPKvSs5dDnEpXWmnKselYZo,26683
145
- clarifai/runners/models/__pycache__/model_class.cpython-310.pyc,sha256=beH4ssWg-EX2xO9yB2H-UzwvfN87TZIoxRpX7D1Rpaw,1889
143
+ clarifai/runners/models/__pycache__/base_typed_model.cpython-310.pyc,sha256=rr_Pxrq9MaT1keVVxBHF59pKv8-dX53B2uLscDXfbfY,8271
144
+ clarifai/runners/models/__pycache__/model_builder.cpython-310.pyc,sha256=0C76O8ZOXrT3y6CVs53h_9cg7XkZKbSxyd6zp0UoAug,27487
145
+ clarifai/runners/models/__pycache__/model_class.cpython-310.pyc,sha256=0pXfvIxFEOhPMscFYUT3Up6KuVOy9Hw_Aj3B2rx-q0k,9498
146
146
  clarifai/runners/models/__pycache__/model_run_locally.cpython-310.pyc,sha256=maLshBrvhTy0C6grT26JPAA14P-nD9WDWN25E2BErsE,16976
147
- clarifai/runners/models/__pycache__/model_runner.cpython-310.pyc,sha256=FkdOM1ZovcqILVO1Hqbus2QtlvEbC3L_Ams3UhTHHFA,4964
147
+ clarifai/runners/models/__pycache__/model_runner.cpython-310.pyc,sha256=u4ZYB_TJJgvqkQ-7_yPUoKU0tT2ycwzBXuqfORwUF3Y,4999
148
148
  clarifai/runners/models/__pycache__/model_servicer.cpython-310.pyc,sha256=9QTYk4zVHBUtlTfkH3WaE6frNdN6ba57EVj4bKe18YA,2501
149
149
  clarifai/runners/models/__pycache__/model_upload.cpython-310.pyc,sha256=erkIUHtJv1ohMOFT8EAJuVfBsEY4o0GxpeXrZqjrfGk,21046
150
150
  clarifai/runners/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
151
151
  clarifai/runners/utils/const.py,sha256=bwj-Pcw558-pasdIFbNhnkn-9oiCdojYH1fNTTUG2gU,1048
152
152
  clarifai/runners/utils/data_handler.py,sha256=zCA_C3mbxgMroqrygMa5xsyuMF476mgd697MUPlOR0E,8327
153
+ clarifai/runners/utils/data_types.py,sha256=5_1S0tJEqhW8BY0ohREVyfsyObPMLkN7H78n7mQ_4Rs,8322
153
154
  clarifai/runners/utils/data_utils.py,sha256=R1iQ82TuQ9JwxCJk8yEB1Lyb0BYVhVbWJI9YDi1zGOs,318
154
155
  clarifai/runners/utils/loader.py,sha256=SgNHMwRmCCymFQm8aDp73NmIUHhM-N60CBlTKbPzmVc,7470
155
- clarifai/runners/utils/method_signatures.py,sha256=BmljuTasajCFeEhwGjYqe5O6G2p3zLU1dGVC95_N9uw,16778
156
- clarifai/runners/utils/serializers.py,sha256=ZtI32AI2Vcjri54KNwBZ0CmTpaJOTfJ5I5mSI5nTQLY,3928
156
+ clarifai/runners/utils/method_signatures.py,sha256=HHaU_KYxtZxwGD_1tAU1K6dYsTtOEcfl892ApovcGmw,17408
157
+ clarifai/runners/utils/serializers.py,sha256=NLLR3E40qbw2vJ1psKyo9vUL56jKIJMwDM3C6JRGvaI,3926
157
158
  clarifai/runners/utils/url_fetcher.py,sha256=v_8JOWmkyFAzsBulsieKX7Nfjy1Yg7wGSZeqfEvw2cg,1640
158
159
  clarifai/runners/utils/__pycache__/__init__.cpython-310.pyc,sha256=PRPZOzUV5Z8grWizu5RKOkki0iLYxZDJBgsLfmCcieE,170
159
160
  clarifai/runners/utils/__pycache__/const.cpython-310.pyc,sha256=EBpjmzlqWBxRGqu_KXeVx80uDslhufrErs57SbLr3DE,953
160
- clarifai/runners/utils/__pycache__/data_handler.cpython-310.pyc,sha256=REXKSnzTcwbRu09ygCQ_41EdpJa-lmTkc5oMx8nL07U,7961
161
+ clarifai/runners/utils/__pycache__/data_handler.cpython-310.pyc,sha256=0rmmZ0AKL0z2ahf90g0xnqRy2GvgbSRkNYE9lSzSn_Q,7961
162
+ clarifai/runners/utils/__pycache__/data_types.cpython-310.pyc,sha256=RdIGmYmmh0LmmiLMgSQRT7K6A8BKvVb9O4F3RJ9AE_4,12385
161
163
  clarifai/runners/utils/__pycache__/data_utils.cpython-310.pyc,sha256=1e6NiK6bnJiiAo2KPsDmm91BSlbI3mVkQZKbDfh5hBI,642
162
164
  clarifai/runners/utils/__pycache__/loader.cpython-310.pyc,sha256=X1MwgLanVXLs-QLot1X145A36W29ONXZRZe5q6_jARo,7319
163
165
  clarifai/runners/utils/__pycache__/logging.cpython-310.pyc,sha256=VV0KFcnuYpFFtaG4EeDIgg7c4QEsBLo-eX_NnsyFEhA,331
164
- clarifai/runners/utils/__pycache__/method_signatures.cpython-310.pyc,sha256=YQwROEZupQao2V6oNRiXi4IeWyk1iZRs07jsKsxtzO0,12882
165
- clarifai/runners/utils/__pycache__/serializers.cpython-310.pyc,sha256=9chtKBxIfQmUrJo284HV4307Ltul8fqfuoPzzPU_NGs,5277
166
+ clarifai/runners/utils/__pycache__/method_signatures.cpython-310.pyc,sha256=CLfkuYN95CQXad8D9lrb1ZOZ340uWfVZ2_-CgHs_WTQ,13678
167
+ clarifai/runners/utils/__pycache__/serializers.cpython-310.pyc,sha256=5D-aRO-GTdkAF-6gRFHE_fPyxOZRH4aE6wq9FZeEP0M,5275
166
168
  clarifai/runners/utils/__pycache__/url_fetcher.cpython-310.pyc,sha256=jFxVdOmm7DCkgatv1GwIXeefHthpvlkg4ybBlMnmxss,1739
167
169
  clarifai/schema/search.py,sha256=JjTi8ammJgZZ2OGl4K6tIA4zEJ1Fr2ASZARXavI1j5c,2448
168
170
  clarifai/schema/__pycache__/search.cpython-310.pyc,sha256=aYuMHmn0ovwmeOhTDj7QAURrQAjlyLm1CwKaz6xktZU,2484
@@ -193,9 +195,9 @@ clarifai/workflows/__pycache__/__init__.cpython-310.pyc,sha256=oRKg6B7Z-wWQy0EW2
193
195
  clarifai/workflows/__pycache__/export.cpython-310.pyc,sha256=cNmGLnww7xVpm4htd1vRhQJoEZ1dhpN1oD8iLLAtVzM,2418
194
196
  clarifai/workflows/__pycache__/utils.cpython-310.pyc,sha256=rm2kWk4a3GOKWoerXpEAEeRvGhEe7wPd0ZZ6jHtEGqY,1925
195
197
  clarifai/workflows/__pycache__/validate.cpython-310.pyc,sha256=QA1i6YdDpY824cqtQvkEaFPpaCa2iqfOwFouqwZfAKY,2139
196
- clarifai-11.1.5rc1.dist-info/LICENSE,sha256=mUqF_d12-qE2n41g7C5_sq-BMLOcj6CNN-jevr15YHU,555
197
- clarifai-11.1.5rc1.dist-info/METADATA,sha256=0gulnBxVFgowYwuRa_TxiyNRYZ5X1pXIi5q02DRz4_k,22229
198
- clarifai-11.1.5rc1.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
199
- clarifai-11.1.5rc1.dist-info/entry_points.txt,sha256=X9FZ4Z-i_r2Ud1RpZ9sNIFYuu_-9fogzCMCRUD9hyX0,51
200
- clarifai-11.1.5rc1.dist-info/top_level.txt,sha256=wUMdCQGjkxaynZ6nZ9FAnvBUCgp5RJUVFSy2j-KYo0s,9
201
- clarifai-11.1.5rc1.dist-info/RECORD,,
198
+ clarifai-11.1.5rc3.dist-info/LICENSE,sha256=mUqF_d12-qE2n41g7C5_sq-BMLOcj6CNN-jevr15YHU,555
199
+ clarifai-11.1.5rc3.dist-info/METADATA,sha256=Zl3cY8_BDZ33bV5M1VWnPiAMUGT4EIwE3ZqFHWaW0EY,22229
200
+ clarifai-11.1.5rc3.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
201
+ clarifai-11.1.5rc3.dist-info/entry_points.txt,sha256=X9FZ4Z-i_r2Ud1RpZ9sNIFYuu_-9fogzCMCRUD9hyX0,51
202
+ clarifai-11.1.5rc3.dist-info/top_level.txt,sha256=wUMdCQGjkxaynZ6nZ9FAnvBUCgp5RJUVFSy2j-KYo0s,9
203
+ clarifai-11.1.5rc3.dist-info/RECORD,,