clarifai 11.1.7rc3__py3-none-any.whl → 11.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- clarifai/__init__.py +1 -1
- clarifai/cli/base.py +16 -3
- clarifai/cli/model.py +0 -25
- clarifai/client/model.py +393 -157
- clarifai/runners/__init__.py +7 -2
- clarifai/runners/models/model_builder.py +12 -80
- clarifai/runners/models/model_class.py +28 -279
- clarifai/runners/models/model_run_locally.py +80 -15
- clarifai/runners/models/model_runner.py +0 -2
- clarifai/runners/models/model_servicer.py +2 -11
- clarifai/runners/utils/data_handler.py +210 -271
- {clarifai-11.1.7rc3.dist-info → clarifai-11.2.0.dist-info}/METADATA +16 -4
- clarifai-11.2.0.dist-info/RECORD +101 -0
- {clarifai-11.1.7rc3.dist-info → clarifai-11.2.0.dist-info}/WHEEL +1 -1
- clarifai/__pycache__/__init__.cpython-310.pyc +0 -0
- clarifai/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/__pycache__/errors.cpython-310.pyc +0 -0
- clarifai/__pycache__/versions.cpython-310.pyc +0 -0
- clarifai/cli/__pycache__/__init__.cpython-310.pyc +0 -0
- clarifai/cli/__pycache__/base.cpython-310.pyc +0 -0
- clarifai/cli/__pycache__/base_cli.cpython-310.pyc +0 -0
- clarifai/cli/__pycache__/compute_cluster.cpython-310.pyc +0 -0
- clarifai/cli/__pycache__/deployment.cpython-310.pyc +0 -0
- clarifai/cli/__pycache__/model.cpython-310.pyc +0 -0
- clarifai/cli/__pycache__/model_cli.cpython-310.pyc +0 -0
- clarifai/cli/__pycache__/nodepool.cpython-310.pyc +0 -0
- clarifai/client/__pycache__/__init__.cpython-310.pyc +0 -0
- clarifai/client/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/client/__pycache__/app.cpython-310.pyc +0 -0
- clarifai/client/__pycache__/app.cpython-39.pyc +0 -0
- clarifai/client/__pycache__/base.cpython-310.pyc +0 -0
- clarifai/client/__pycache__/compute_cluster.cpython-310.pyc +0 -0
- clarifai/client/__pycache__/dataset.cpython-310.pyc +0 -0
- clarifai/client/__pycache__/deployment.cpython-310.pyc +0 -0
- clarifai/client/__pycache__/input.cpython-310.pyc +0 -0
- clarifai/client/__pycache__/lister.cpython-310.pyc +0 -0
- clarifai/client/__pycache__/model.cpython-310.pyc +0 -0
- clarifai/client/__pycache__/module.cpython-310.pyc +0 -0
- clarifai/client/__pycache__/nodepool.cpython-310.pyc +0 -0
- clarifai/client/__pycache__/search.cpython-310.pyc +0 -0
- clarifai/client/__pycache__/user.cpython-310.pyc +0 -0
- clarifai/client/__pycache__/workflow.cpython-310.pyc +0 -0
- clarifai/client/auth/__pycache__/__init__.cpython-310.pyc +0 -0
- clarifai/client/auth/__pycache__/helper.cpython-310.pyc +0 -0
- clarifai/client/auth/__pycache__/register.cpython-310.pyc +0 -0
- clarifai/client/auth/__pycache__/stub.cpython-310.pyc +0 -0
- clarifai/client/cli/__init__.py +0 -0
- clarifai/client/cli/__pycache__/__init__.cpython-310.pyc +0 -0
- clarifai/client/cli/__pycache__/base_cli.cpython-310.pyc +0 -0
- clarifai/client/cli/__pycache__/model_cli.cpython-310.pyc +0 -0
- clarifai/client/cli/base_cli.py +0 -88
- clarifai/client/cli/model_cli.py +0 -29
- clarifai/client/model_client.py +0 -448
- clarifai/constants/__pycache__/base.cpython-310.pyc +0 -0
- clarifai/constants/__pycache__/dataset.cpython-310.pyc +0 -0
- clarifai/constants/__pycache__/input.cpython-310.pyc +0 -0
- clarifai/constants/__pycache__/model.cpython-310.pyc +0 -0
- clarifai/constants/__pycache__/rag.cpython-310.pyc +0 -0
- clarifai/constants/__pycache__/search.cpython-310.pyc +0 -0
- clarifai/constants/__pycache__/workflow.cpython-310.pyc +0 -0
- clarifai/datasets/__pycache__/__init__.cpython-310.pyc +0 -0
- clarifai/datasets/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/datasets/export/__pycache__/__init__.cpython-310.pyc +0 -0
- clarifai/datasets/export/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/datasets/export/__pycache__/inputs_annotations.cpython-310.pyc +0 -0
- clarifai/datasets/upload/__pycache__/__init__.cpython-310.pyc +0 -0
- clarifai/datasets/upload/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/datasets/upload/__pycache__/base.cpython-310.pyc +0 -0
- clarifai/datasets/upload/__pycache__/features.cpython-310.pyc +0 -0
- clarifai/datasets/upload/__pycache__/image.cpython-310.pyc +0 -0
- clarifai/datasets/upload/__pycache__/multimodal.cpython-310.pyc +0 -0
- clarifai/datasets/upload/__pycache__/text.cpython-310.pyc +0 -0
- clarifai/datasets/upload/__pycache__/utils.cpython-310.pyc +0 -0
- clarifai/datasets/upload/loaders/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/models/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/modules/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/rag/__pycache__/__init__.cpython-310.pyc +0 -0
- clarifai/rag/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/rag/__pycache__/rag.cpython-310.pyc +0 -0
- clarifai/rag/__pycache__/rag.cpython-39.pyc +0 -0
- clarifai/rag/__pycache__/utils.cpython-310.pyc +0 -0
- clarifai/runners/__pycache__/__init__.cpython-310.pyc +0 -0
- clarifai/runners/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/runners/dockerfile_template/Dockerfile.cpu.template +0 -31
- clarifai/runners/dockerfile_template/Dockerfile.cuda.template +0 -42
- clarifai/runners/dockerfile_template/Dockerfile.nim +0 -71
- clarifai/runners/models/__pycache__/__init__.cpython-310.pyc +0 -0
- clarifai/runners/models/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/runners/models/__pycache__/base_typed_model.cpython-310.pyc +0 -0
- clarifai/runners/models/__pycache__/base_typed_model.cpython-39.pyc +0 -0
- clarifai/runners/models/__pycache__/model_class.cpython-310.pyc +0 -0
- clarifai/runners/models/__pycache__/model_run_locally.cpython-310-pytest-7.1.2.pyc +0 -0
- clarifai/runners/models/__pycache__/model_run_locally.cpython-310.pyc +0 -0
- clarifai/runners/models/__pycache__/model_runner.cpython-310.pyc +0 -0
- clarifai/runners/models/__pycache__/model_upload.cpython-310.pyc +0 -0
- clarifai/runners/models/model_class_refract.py +0 -80
- clarifai/runners/models/model_upload.py +0 -607
- clarifai/runners/models/temp.py +0 -25
- clarifai/runners/utils/__pycache__/__init__.cpython-310.pyc +0 -0
- clarifai/runners/utils/__pycache__/__init__.cpython-38.pyc +0 -0
- clarifai/runners/utils/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/runners/utils/__pycache__/buffered_stream.cpython-310.pyc +0 -0
- clarifai/runners/utils/__pycache__/buffered_stream.cpython-38.pyc +0 -0
- clarifai/runners/utils/__pycache__/buffered_stream.cpython-39.pyc +0 -0
- clarifai/runners/utils/__pycache__/const.cpython-310.pyc +0 -0
- clarifai/runners/utils/__pycache__/constants.cpython-310.pyc +0 -0
- clarifai/runners/utils/__pycache__/constants.cpython-38.pyc +0 -0
- clarifai/runners/utils/__pycache__/constants.cpython-39.pyc +0 -0
- clarifai/runners/utils/__pycache__/data_handler.cpython-310.pyc +0 -0
- clarifai/runners/utils/__pycache__/data_handler.cpython-38.pyc +0 -0
- clarifai/runners/utils/__pycache__/data_handler.cpython-39.pyc +0 -0
- clarifai/runners/utils/__pycache__/data_utils.cpython-310.pyc +0 -0
- clarifai/runners/utils/__pycache__/data_utils.cpython-38.pyc +0 -0
- clarifai/runners/utils/__pycache__/data_utils.cpython-39.pyc +0 -0
- clarifai/runners/utils/__pycache__/grpc_server.cpython-310.pyc +0 -0
- clarifai/runners/utils/__pycache__/grpc_server.cpython-38.pyc +0 -0
- clarifai/runners/utils/__pycache__/grpc_server.cpython-39.pyc +0 -0
- clarifai/runners/utils/__pycache__/health.cpython-310.pyc +0 -0
- clarifai/runners/utils/__pycache__/health.cpython-38.pyc +0 -0
- clarifai/runners/utils/__pycache__/health.cpython-39.pyc +0 -0
- clarifai/runners/utils/__pycache__/loader.cpython-310.pyc +0 -0
- clarifai/runners/utils/__pycache__/logging.cpython-310.pyc +0 -0
- clarifai/runners/utils/__pycache__/logging.cpython-38.pyc +0 -0
- clarifai/runners/utils/__pycache__/logging.cpython-39.pyc +0 -0
- clarifai/runners/utils/__pycache__/stream_source.cpython-310.pyc +0 -0
- clarifai/runners/utils/__pycache__/stream_source.cpython-39.pyc +0 -0
- clarifai/runners/utils/__pycache__/url_fetcher.cpython-310.pyc +0 -0
- clarifai/runners/utils/__pycache__/url_fetcher.cpython-38.pyc +0 -0
- clarifai/runners/utils/__pycache__/url_fetcher.cpython-39.pyc +0 -0
- clarifai/runners/utils/data_handler_refract.py +0 -213
- clarifai/runners/utils/data_types.py +0 -427
- clarifai/runners/utils/logger.py +0 -0
- clarifai/runners/utils/method_signatures.py +0 -477
- clarifai/runners/utils/serializers.py +0 -222
- clarifai/schema/__pycache__/search.cpython-310.pyc +0 -0
- clarifai/urls/__pycache__/helper.cpython-310.pyc +0 -0
- clarifai/utils/__pycache__/__init__.cpython-310.pyc +0 -0
- clarifai/utils/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/utils/__pycache__/cli.cpython-310.pyc +0 -0
- clarifai/utils/__pycache__/constants.cpython-310.pyc +0 -0
- clarifai/utils/__pycache__/logging.cpython-310.pyc +0 -0
- clarifai/utils/__pycache__/misc.cpython-310.pyc +0 -0
- clarifai/utils/__pycache__/model_train.cpython-310.pyc +0 -0
- clarifai/utils/evaluation/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/utils/evaluation/__pycache__/main.cpython-39.pyc +0 -0
- clarifai/workflows/__pycache__/__init__.cpython-310.pyc +0 -0
- clarifai/workflows/__pycache__/__init__.cpython-39.pyc +0 -0
- clarifai/workflows/__pycache__/export.cpython-310.pyc +0 -0
- clarifai/workflows/__pycache__/utils.cpython-310.pyc +0 -0
- clarifai/workflows/__pycache__/validate.cpython-310.pyc +0 -0
- clarifai-11.1.7rc3.dist-info/RECORD +0 -237
- {clarifai-11.1.7rc3.dist-info → clarifai-11.2.0.dist-info}/entry_points.txt +0 -0
- {clarifai-11.1.7rc3.dist-info → clarifai-11.2.0.dist-info/licenses}/LICENSE +0 -0
- {clarifai-11.1.7rc3.dist-info → clarifai-11.2.0.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,3 @@
|
|
1
|
-
import os
|
2
1
|
from itertools import tee
|
3
2
|
from typing import Iterator
|
4
3
|
|
@@ -7,8 +6,6 @@ from clarifai_grpc.grpc.api.status import status_code_pb2, status_pb2
|
|
7
6
|
|
8
7
|
from ..utils.url_fetcher import ensure_urls_downloaded
|
9
8
|
|
10
|
-
_RAISE_EXCEPTIONS = os.getenv("RAISE_EXCEPTIONS", "false").lower() in ("true", "1")
|
11
|
-
|
12
9
|
|
13
10
|
class ModelServicer(service_pb2_grpc.V2Servicer):
|
14
11
|
"""
|
@@ -36,8 +33,6 @@ class ModelServicer(service_pb2_grpc.V2Servicer):
|
|
36
33
|
try:
|
37
34
|
return self.model.predict_wrapper(request)
|
38
35
|
except Exception as e:
|
39
|
-
if _RAISE_EXCEPTIONS:
|
40
|
-
raise
|
41
36
|
return service_pb2.MultiOutputResponse(status=status_pb2.Status(
|
42
37
|
code=status_code_pb2.MODEL_PREDICTION_FAILED,
|
43
38
|
description="Failed",
|
@@ -55,10 +50,8 @@ class ModelServicer(service_pb2_grpc.V2Servicer):
|
|
55
50
|
ensure_urls_downloaded(request)
|
56
51
|
|
57
52
|
try:
|
58
|
-
|
53
|
+
return self.model.generate_wrapper(request)
|
59
54
|
except Exception as e:
|
60
|
-
if _RAISE_EXCEPTIONS:
|
61
|
-
raise
|
62
55
|
yield service_pb2.MultiOutputResponse(status=status_pb2.Status(
|
63
56
|
code=status_code_pb2.MODEL_PREDICTION_FAILED,
|
64
57
|
description="Failed",
|
@@ -81,10 +74,8 @@ class ModelServicer(service_pb2_grpc.V2Servicer):
|
|
81
74
|
ensure_urls_downloaded(req)
|
82
75
|
|
83
76
|
try:
|
84
|
-
|
77
|
+
return self.model.stream_wrapper(request_copy)
|
85
78
|
except Exception as e:
|
86
|
-
if _RAISE_EXCEPTIONS:
|
87
|
-
raise
|
88
79
|
yield service_pb2.MultiOutputResponse(status=status_pb2.Status(
|
89
80
|
code=status_code_pb2.MODEL_PREDICTION_FAILED,
|
90
81
|
description="Failed",
|
@@ -1,292 +1,231 @@
|
|
1
|
-
import
|
2
|
-
from typing import Any
|
1
|
+
from typing import Dict, List, Tuple, Union
|
3
2
|
|
4
3
|
import numpy as np
|
5
4
|
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 Text as TextProto
|
9
|
-
from clarifai_grpc.grpc.api.resources_pb2 import Video as VideoProto
|
10
5
|
from clarifai_grpc.grpc.api.status import status_code_pb2, status_pb2
|
11
|
-
from
|
12
|
-
from google.protobuf.struct_pb2 import Struct
|
13
|
-
from PIL import Image as PILImage
|
14
|
-
|
15
|
-
|
16
|
-
def metadata_to_dict(data: resources_pb2.Data) -> dict:
|
17
|
-
return MessageToDict(data.metadata)
|
18
|
-
|
19
|
-
|
20
|
-
def dict_to_metadata(data: resources_pb2.Data, metadata_dict: dict):
|
21
|
-
struct = Struct()
|
22
|
-
ParseDict(metadata_dict, struct)
|
23
|
-
data.metadata.CopyFrom(struct)
|
24
|
-
|
25
|
-
|
26
|
-
def kwargs_to_proto(*args, **kwargs) -> resources_pb2.Data:
|
27
|
-
"""Converts the kwargs to a Clarifai protobuf Data message."""
|
28
|
-
|
29
|
-
kwargs = dict(kwargs)
|
30
|
-
if any(k.startswith("_arg_") for k in kwargs.keys()):
|
31
|
-
raise ValueError("Keys starting with '_arg_' are reserved for positional arguments")
|
32
|
-
for arg_i, arg in enumerate(args):
|
33
|
-
kwargs[f"_arg_{arg_i}"] = arg
|
34
|
-
|
35
|
-
def _handle_list(target_data, value_list, part_name):
|
36
|
-
"""Handles list values by processing each item into a new part."""
|
37
|
-
if isinstance(value_list[0], dict):
|
38
|
-
raise ValueError("List of dictionaries is not supported")
|
39
|
-
|
40
|
-
for item in value_list:
|
41
|
-
new_part = target_data.parts.add()
|
42
|
-
_process_value(new_part.data, item, part_name)
|
43
|
-
|
44
|
-
def _process_value(target_data, value, part_name):
|
45
|
-
"""Processes individual values and sets the appropriate proto field."""
|
46
|
-
if isinstance(value, Text):
|
47
|
-
target_data.text.CopyFrom(value.to_proto())
|
48
|
-
elif isinstance(value, Image):
|
49
|
-
target_data.image.CopyFrom(value.to_proto())
|
50
|
-
elif isinstance(value, Audio):
|
51
|
-
target_data.audio.CopyFrom(value.to_proto())
|
52
|
-
elif isinstance(value, Video):
|
53
|
-
target_data.video.CopyFrom(value.to_proto())
|
54
|
-
elif isinstance(value, str):
|
55
|
-
target_data.text.raw = value
|
56
|
-
elif isinstance(value, bytes):
|
57
|
-
target_data.bytes_value = value
|
58
|
-
elif isinstance(value, int):
|
59
|
-
target_data.int_value = value
|
60
|
-
elif isinstance(value, float):
|
61
|
-
target_data.float_value = value
|
62
|
-
elif isinstance(value, bool):
|
63
|
-
target_data.bool_value = value
|
64
|
-
elif isinstance(value, np.ndarray):
|
65
|
-
ndarray_proto = resources_pb2.NDArray(
|
66
|
-
buffer=value.tobytes(), shape=value.shape, dtype=str(value.dtype))
|
67
|
-
target_data.ndarray.CopyFrom(ndarray_proto)
|
68
|
-
elif isinstance(value, PILImage.Image):
|
69
|
-
image = Image.from_pil(value)
|
70
|
-
target_data.image.CopyFrom(image.to_proto())
|
71
|
-
else:
|
72
|
-
raise TypeError(f"Unsupported type {type(value)} for part '{part_name}'")
|
73
|
-
|
74
|
-
data_proto = resources_pb2.Data()
|
75
|
-
for part_name, part_value in kwargs.items():
|
76
|
-
part = data_proto.parts.add()
|
77
|
-
part.id = part_name
|
78
|
-
|
79
|
-
if isinstance(part_value, list):
|
80
|
-
_handle_list(part.data, part_value, part_name)
|
81
|
-
elif isinstance(part_value, dict):
|
82
|
-
dict_to_metadata(part.data, part_value)
|
83
|
-
else:
|
84
|
-
_process_value(part.data, part_value, part_name)
|
85
|
-
return data_proto
|
86
|
-
|
87
|
-
|
88
|
-
def proto_to_kwargs(data: resources_pb2.Data) -> dict:
|
89
|
-
"""Converts the Clarifai protobuf Data message to a dictionary."""
|
90
|
-
|
91
|
-
def process_part(part, allow_metadata: bool = True) -> object:
|
92
|
-
if part.HasField("text"):
|
93
|
-
return Text.from_proto(part.text).text
|
94
|
-
elif part.HasField("image"):
|
95
|
-
return Image(part.image)
|
96
|
-
elif part.HasField("audio"):
|
97
|
-
return Audio(part.audio)
|
98
|
-
elif part.HasField("video"):
|
99
|
-
return Video(part.video)
|
100
|
-
elif part.bytes_value != b'':
|
101
|
-
return part.bytes_value
|
102
|
-
elif part.int_value != 0:
|
103
|
-
return part.int_value
|
104
|
-
elif part.float_value != 0.0:
|
105
|
-
return part.float_value
|
106
|
-
elif part.bool_value is not False:
|
107
|
-
return part.bool_value
|
108
|
-
elif part.HasField("ndarray"):
|
109
|
-
ndarray = part.ndarray
|
110
|
-
return np.frombuffer(ndarray.buffer, dtype=np.dtype(ndarray.dtype)).reshape(ndarray.shape)
|
111
|
-
elif part.HasField("metadata"):
|
112
|
-
if not allow_metadata:
|
113
|
-
raise ValueError("Metadata in list is not supported")
|
114
|
-
return metadata_to_dict(part)
|
115
|
-
elif part.parts:
|
116
|
-
return [process_part(p.data,) for p in part.parts]
|
117
|
-
else:
|
118
|
-
raise ValueError(f"Unknown part data: {part}")
|
119
|
-
|
120
|
-
kwargs = {}
|
121
|
-
part_names = [part.id for part in data.parts]
|
122
|
-
assert "return" not in part_names, "The key 'return' is reserved"
|
123
|
-
for part in data.parts:
|
124
|
-
part_name = part.id
|
125
|
-
part_data = part.data
|
126
|
-
kwargs[part_name] = process_part(part_data)
|
127
|
-
args = [kwargs.pop(f"_arg_{i}") for i in range(len(kwargs)) if f"_arg_{i}" in kwargs]
|
128
|
-
return args, kwargs
|
129
|
-
|
130
|
-
|
131
|
-
class Output:
|
132
|
-
|
133
|
-
def __init__(self, *args, **kwargs: Any):
|
134
|
-
|
135
|
-
if not kwargs:
|
136
|
-
raise ValueError("Output must have at least one key-value pair")
|
137
|
-
if isinstance(kwargs, dict):
|
138
|
-
kwargs = kwargs
|
139
|
-
else:
|
140
|
-
raise ValueError("Output must be a dictionary")
|
141
|
-
self.parts = kwargs
|
142
|
-
self.args = args
|
143
|
-
|
144
|
-
def __repr__(self):
|
145
|
-
args_str = ', '.join(repr(arg) for arg in self.args)
|
146
|
-
kwargs_str = ', '.join(f"{k}={v!r}" for k, v in self.parts.items())
|
147
|
-
parts = []
|
148
|
-
if args_str:
|
149
|
-
parts.append(args_str)
|
150
|
-
if kwargs_str:
|
151
|
-
parts.append(kwargs_str)
|
152
|
-
return f"Output({', '.join(parts)})"
|
153
|
-
|
154
|
-
def to_proto(self) -> resources_pb2.Output:
|
155
|
-
"""Converts the Output instance to a Clarifai protobuf Output message."""
|
156
|
-
data_proto = kwargs_to_proto(*self.args, **self.parts)
|
157
|
-
|
158
|
-
return resources_pb2.Output(
|
159
|
-
data=data_proto, status=status_pb2.Status(code=status_code_pb2.SUCCESS))
|
160
|
-
|
161
|
-
|
162
|
-
class Text:
|
163
|
-
|
164
|
-
def __init__(self, text: str):
|
165
|
-
self.text = text
|
166
|
-
|
167
|
-
def to_proto(self) -> TextProto:
|
168
|
-
return TextProto(raw=self.text)
|
6
|
+
from PIL import Image
|
169
7
|
|
170
|
-
|
171
|
-
def from_proto(cls, proto: TextProto) -> "Text":
|
172
|
-
return cls(proto.raw)
|
8
|
+
from clarifai.client.auth.helper import ClarifaiAuthHelper
|
173
9
|
|
10
|
+
from .data_utils import bytes_to_image, image_to_bytes
|
174
11
|
|
175
|
-
class Image:
|
176
12
|
|
177
|
-
|
178
|
-
self.proto = proto_image
|
13
|
+
class BaseDataHandler:
|
179
14
|
|
180
|
-
|
181
|
-
|
182
|
-
|
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
|
183
20
|
|
184
|
-
|
185
|
-
def
|
186
|
-
self.
|
21
|
+
#
|
22
|
+
def to_python(self):
|
23
|
+
return dict(text=self.text, image=self.image, audio=self.audio)
|
187
24
|
|
25
|
+
# ---------------- Start get/setters ---------------- #
|
26
|
+
# Proto
|
188
27
|
@property
|
189
|
-
def
|
190
|
-
return self.
|
191
|
-
|
192
|
-
@bytes.setter
|
193
|
-
def bytes(self, value: bytes):
|
194
|
-
self.proto.base64 = value
|
195
|
-
|
196
|
-
def __repr__(self) -> str:
|
197
|
-
attrs = []
|
198
|
-
if self.url:
|
199
|
-
attrs.append(f"url={self.url!r}")
|
200
|
-
if self.bytes:
|
201
|
-
attrs.append(f"bytes=<{len(self.bytes)} bytes>")
|
202
|
-
return f"Image({', '.join(attrs)})"
|
203
|
-
|
204
|
-
@classmethod
|
205
|
-
def from_url(cls, url: str) -> "Image":
|
206
|
-
proto_image = ImageProto(url=url)
|
207
|
-
return cls(proto_image)
|
208
|
-
|
209
|
-
@classmethod
|
210
|
-
def from_pil(cls, pil_image: PILImage.Image) -> "Image":
|
211
|
-
with io.BytesIO() as output:
|
212
|
-
pil_image.save(output, format="PNG")
|
213
|
-
image_bytes = output.getvalue()
|
214
|
-
proto_image = ImageProto(base64=image_bytes)
|
215
|
-
return cls(proto_image)
|
216
|
-
|
217
|
-
def to_pil(self) -> PILImage.Image:
|
218
|
-
return PILImage.open(io.BytesIO(self.proto.base64))
|
219
|
-
|
220
|
-
def to_numpy(self) -> np.ndarray:
|
221
|
-
# below is very slow, need to find a better way
|
222
|
-
# return np.array(self.to_pil())
|
223
|
-
pass
|
224
|
-
|
225
|
-
def to_proto(self) -> ImageProto:
|
226
|
-
return self.proto
|
227
|
-
|
228
|
-
|
229
|
-
class Audio:
|
230
|
-
|
231
|
-
def __init__(self, proto_audio: AudioProto):
|
232
|
-
self.proto = proto_audio
|
28
|
+
def proto(self):
|
29
|
+
return self._proto
|
233
30
|
|
31
|
+
# Status
|
234
32
|
@property
|
235
|
-
def
|
236
|
-
return self.
|
33
|
+
def status(self) -> status_pb2.Status:
|
34
|
+
return self._proto.status
|
237
35
|
|
238
|
-
|
239
|
-
|
240
|
-
self.
|
36
|
+
def set_status(self, code: str, description: str = ""):
|
37
|
+
self._proto.status.code = code
|
38
|
+
self._proto.status.description = description
|
241
39
|
|
40
|
+
# Text
|
242
41
|
@property
|
243
|
-
def
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
def
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
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]
|
263
172
|
|
264
|
-
def
|
265
|
-
|
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)))
|
266
179
|
|
267
|
-
|
268
|
-
def url(self) -> str:
|
269
|
-
return self.proto.url
|
180
|
+
# ---------------- End get/setters ---------------- #
|
270
181
|
|
271
|
-
|
272
|
-
|
273
|
-
|
182
|
+
# Constructors
|
183
|
+
@classmethod
|
184
|
+
def from_proto(cls, proto):
|
185
|
+
clss = cls(proto=proto)
|
186
|
+
return clss
|
274
187
|
|
275
|
-
@
|
276
|
-
def
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
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,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: clarifai
|
3
|
-
Version: 11.
|
3
|
+
Version: 11.2.0
|
4
4
|
Summary: Clarifai Python SDK
|
5
5
|
Home-page: https://github.com/Clarifai/clarifai-python
|
6
6
|
Author: Clarifai
|
@@ -20,7 +20,7 @@ Classifier: Operating System :: OS Independent
|
|
20
20
|
Requires-Python: >=3.8
|
21
21
|
Description-Content-Type: text/markdown
|
22
22
|
License-File: LICENSE
|
23
|
-
Requires-Dist: clarifai-grpc>=11.2.
|
23
|
+
Requires-Dist: clarifai-grpc>=11.2.5
|
24
24
|
Requires-Dist: clarifai-protocol>=0.0.20
|
25
25
|
Requires-Dist: numpy>=1.22.0
|
26
26
|
Requires-Dist: tqdm>=4.65.0
|
@@ -32,9 +32,21 @@ Requires-Dist: tabulate>=0.9.0
|
|
32
32
|
Requires-Dist: fsspec>=2024.6.1
|
33
33
|
Requires-Dist: click>=8.1.7
|
34
34
|
Requires-Dist: requests>=2.32.3
|
35
|
-
Requires-Dist: aiohttp>=3.
|
35
|
+
Requires-Dist: aiohttp>=3.10.0
|
36
36
|
Provides-Extra: all
|
37
37
|
Requires-Dist: pycocotools==2.0.6; extra == "all"
|
38
|
+
Dynamic: author
|
39
|
+
Dynamic: author-email
|
40
|
+
Dynamic: classifier
|
41
|
+
Dynamic: description
|
42
|
+
Dynamic: description-content-type
|
43
|
+
Dynamic: home-page
|
44
|
+
Dynamic: license
|
45
|
+
Dynamic: license-file
|
46
|
+
Dynamic: provides-extra
|
47
|
+
Dynamic: requires-dist
|
48
|
+
Dynamic: requires-python
|
49
|
+
Dynamic: summary
|
38
50
|
|
39
51
|
<h1 align="center">
|
40
52
|
<a href="https://www.clarifai.com/"><img alt="Clarifai" title="Clarifai" src="https://github.com/user-attachments/assets/623b883b-7fe5-4b95-bbfa-8691f5779af4"></a>
|