synapsai-python 0.1.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.
@@ -0,0 +1,454 @@
1
+ # Copyright 2026 SynapsAI Technologies Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ Classification resource handlers
17
+ """
18
+
19
+ from typing import TYPE_CHECKING, Optional, Union, List
20
+ from ..types.classifications import (
21
+ AudioClassificationResponse,
22
+ ImageClassificationResponse,
23
+ TextClassificationResponse,
24
+ TokenClassificationResponse,
25
+ VideoClassificationResponse,
26
+ VideoClassificationResponse,
27
+ ZeroShotAudioClassificationResponse,
28
+ ZeroShotClassificationResponse,
29
+ ZeroShotImageClassificationResponse,
30
+ ZeroShotObjectDetectionResponse,
31
+ )
32
+ from PIL import Image
33
+ import numpy as np
34
+ from ..processing import process_image_input, process_audio_input, process_video_input
35
+
36
+
37
+ if TYPE_CHECKING:
38
+ from ..client import SynapsAI, AsyncSynapsAI
39
+
40
+
41
+
42
+ class ZeroShotClassificationsResource:
43
+ """Zero-Shot Classification resource handler"""
44
+
45
+ def __init__(self, client: "SynapsAI"):
46
+ self._client = client
47
+
48
+ def audio(
49
+ self,
50
+ model: str,
51
+ audios,
52
+ candidate_labels: list[str],
53
+ hypothesis_template: Optional[str] = None,
54
+ ) -> ZeroShotAudioClassificationResponse:
55
+ """Assign labels to the audio(s) passed as inputs (zero-shot)."""
56
+
57
+ audios = process_audio_input(audios)
58
+
59
+ request_data = self._client._build_request(
60
+ model=model,
61
+ audios=audios,
62
+ candidate_labels=candidate_labels,
63
+ hypothesis_template=hypothesis_template,
64
+ )
65
+
66
+ endpoint = "classifications/zero-shot/audio"
67
+ response = self._client._post(endpoint, json_data=request_data)
68
+ return ZeroShotAudioClassificationResponse.model_validate(response.json())
69
+
70
+ def text(
71
+ self,
72
+ model: str,
73
+ sequences: Union[str, List[str]],
74
+ candidate_labels: Union[str, List[str]],
75
+ hypothesis_template: Optional[str] = None,
76
+ multi_label: Optional[bool] = None,
77
+ ) -> ZeroShotClassificationResponse:
78
+ """Zero-shot text classification."""
79
+
80
+ request_data = self._client._build_request(
81
+ model=model,
82
+ sequences=sequences,
83
+ candidate_labels=candidate_labels,
84
+ hypothesis_template=hypothesis_template,
85
+ multi_label=multi_label,
86
+ )
87
+
88
+ endpoint = "classifications/zero-shot"
89
+ response = self._client._post(endpoint, json_data=request_data)
90
+ return ZeroShotClassificationResponse.model_validate(response.json())
91
+
92
+ def image(
93
+ self,
94
+ model: str,
95
+ image: Union[str, List[str], Image.Image, List[Image.Image]],
96
+ candidate_labels: list[str],
97
+ hypothesis_template: Optional[str] = None,
98
+ timeout: Optional[float] = None,
99
+ ) -> ZeroShotImageClassificationResponse:
100
+ """Zero-shot image classification."""
101
+
102
+ image = process_image_input(image)
103
+
104
+ request_data = self._client._build_request(
105
+ model=model,
106
+ image=image,
107
+ candidate_labels=candidate_labels,
108
+ hypothesis_template=hypothesis_template,
109
+ timeout=timeout,
110
+ )
111
+
112
+ endpoint = "classifications/zero-shot/image"
113
+ response = self._client._post(endpoint, json_data=request_data)
114
+ return ZeroShotImageClassificationResponse.model_validate(response.json())
115
+
116
+ class ClassificationsResource:
117
+ """Classification resource handler"""
118
+
119
+ def __init__(self, client: "SynapsAI"):
120
+ self._client = client
121
+ self.zero_shot = ZeroShotClassificationsResource(client)
122
+
123
+ def audio(
124
+ self,
125
+ model: str,
126
+ inputs: Union[np.ndarray, bytes, dict],
127
+ top_k: Optional[int] = None,
128
+ function_to_apply: Optional[str] = None,
129
+ ) -> AudioClassificationResponse:
130
+ """Audio classification."""
131
+
132
+ inputs = process_audio_input(inputs)
133
+
134
+ # Build request
135
+ request_data = self._client._build_request(
136
+ model=model,
137
+ inputs=inputs,
138
+ top_k=top_k,
139
+ function_to_apply=function_to_apply
140
+ )
141
+
142
+ endpoint = "classifications/audio"
143
+
144
+ # Make request
145
+ response = self._client._post(endpoint, json_data=request_data)
146
+ response_data = response.json()
147
+ return AudioClassificationResponse(**response_data)
148
+
149
+ def image(
150
+ self,
151
+ model: str,
152
+ inputs: Union[str, list[str], Image.Image, list[Image.Image]],
153
+ function_to_apply: Optional[str] = None,
154
+ top_k: Optional[int] = None,
155
+ timeout: Optional[float] = None,
156
+ ) -> ImageClassificationResponse:
157
+ """Assign labels to the image(s) passed as inputs."""
158
+
159
+ inputs = process_image_input(inputs)
160
+
161
+ # Build request
162
+ request_data = self._client._build_request(
163
+ model=model,
164
+ inputs=inputs,
165
+ function_to_apply=function_to_apply,
166
+ top_k=top_k,
167
+ timeout=timeout
168
+ )
169
+
170
+ endpoint = "classifications/image"
171
+
172
+ # Make request
173
+ response = self._client._post(endpoint, json_data=request_data)
174
+ response_data = response.json()
175
+ return ImageClassificationResponse.model_validate(response_data)
176
+
177
+ def text(
178
+ self,
179
+ model: str,
180
+ inputs: Union[str, list[str], dict[str], list[dict[str]]],
181
+ top_k: Optional[int] = None,
182
+ function_to_apply: Optional[str] = None,
183
+ ) -> TextClassificationResponse:
184
+ """Classify the text(s) given as inputs."""
185
+
186
+ # Build request
187
+ request_data = self._client._build_request(
188
+ model=model,
189
+ inputs=inputs,
190
+ top_k=top_k,
191
+ function_to_apply=function_to_apply
192
+ )
193
+
194
+ endpoint = "classifications/text"
195
+
196
+ # Make request
197
+ response = self._client._post(endpoint, json_data=request_data)
198
+ response_data = response.json()
199
+ return TextClassificationResponse.model_validate(response_data)
200
+
201
+ def token(
202
+ self,
203
+ model: str,
204
+ inputs: Union[str, List[str]],
205
+ ) -> TokenClassificationResponse:
206
+ """Classify each token of the text(s) given as inputs."""
207
+
208
+ # Build request
209
+ request_data = self._client._build_request(
210
+ model=model,
211
+ inputs=inputs
212
+ )
213
+
214
+ endpoint = "classifications/token"
215
+
216
+ # Make request
217
+ response = self._client._post(endpoint, json_data=request_data)
218
+ response_data = response.json()
219
+ return TokenClassificationResponse.model_validate(response_data)
220
+
221
+ def video(
222
+ self,
223
+ model: str,
224
+ inputs: Union[str, list[str]],
225
+ top_k: Optional[int] = None,
226
+ num_frames: Optional[int] = None,
227
+ frame_sampling_rate: Optional[int] = None,
228
+ function_to_apply: Optional[str] = None,
229
+ ) -> VideoClassificationResponse:
230
+ """Assign labels to the video(s) passed as inputs."""
231
+
232
+ inputs = process_video_input(inputs)
233
+
234
+ # Build request
235
+ request_data = self._client._build_request(
236
+ model=model,
237
+ inputs=inputs,
238
+ top_k=top_k,
239
+ num_frames=num_frames,
240
+ frame_sampling_rate=frame_sampling_rate,
241
+ function_to_apply=function_to_apply
242
+ )
243
+
244
+ endpoint = "classifications/video"
245
+
246
+ # Make request
247
+ response = self._client._post(endpoint, json_data=request_data)
248
+ response_data = response.json()
249
+ return VideoClassificationResponse.model_validate(response_data)
250
+
251
+
252
+
253
+ class AsyncZeroShotClassificationsResource:
254
+ """Async Zero-Shot Classification resource handler"""
255
+
256
+ def __init__(self, client: "AsyncSynapsAI"):
257
+ self._client = client
258
+
259
+ async def audio(
260
+ self,
261
+ model: str,
262
+ audios,
263
+ candidate_labels: list[str],
264
+ hypothesis_template: Optional[str] = None,
265
+ ) -> ZeroShotAudioClassificationResponse:
266
+ """Assign labels to the audio(s) passed as inputs (zero-shot)."""
267
+
268
+ request_data = self._client._build_request(
269
+ model=model,
270
+ audios=audios,
271
+ candidate_labels=candidate_labels,
272
+ hypothesis_template=hypothesis_template,
273
+ )
274
+
275
+ endpoint = "classifications/zero-shot/audio"
276
+ response = await self._client._post(endpoint, json_data=request_data)
277
+ return ZeroShotAudioClassificationResponse.model_validate(response.json())
278
+
279
+ async def text(
280
+ self,
281
+ model: str,
282
+ sequences: Union[str, List[str]],
283
+ candidate_labels: Union[str, List[str]],
284
+ hypothesis_template: Optional[str] = None,
285
+ multi_label: Optional[bool] = None,
286
+ ) -> ZeroShotClassificationResponse:
287
+ """Zero-shot text classification."""
288
+
289
+ request_data = self._client._build_request(
290
+ model=model,
291
+ sequences=sequences,
292
+ candidate_labels=candidate_labels,
293
+ hypothesis_template=hypothesis_template,
294
+ multi_label=multi_label,
295
+ )
296
+
297
+ endpoint = "classifications/zero-shot"
298
+ response = await self._client._post(endpoint, json_data=request_data)
299
+ return ZeroShotClassificationResponse.model_validate(response.json())
300
+
301
+ async def image(
302
+ self,
303
+ model: str,
304
+ image: Union[str, List[str], Image.Image, List[Image.Image]],
305
+ candidate_labels: list[str],
306
+ hypothesis_template: Optional[str] = None,
307
+ timeout: Optional[float] = None,
308
+ ) -> ZeroShotImageClassificationResponse:
309
+ """Zero-shot image classification."""
310
+
311
+ request_data = self._client._build_request(
312
+ model=model,
313
+ image=image,
314
+ candidate_labels=candidate_labels,
315
+ hypothesis_template=hypothesis_template,
316
+ timeout=timeout,
317
+ )
318
+
319
+ endpoint = "classifications/zero-shot/image"
320
+ response = await self._client._post(endpoint, json_data=request_data)
321
+ return ZeroShotImageClassificationResponse.model_validate(response.json())
322
+
323
+
324
+ class AsyncClassificationsResource:
325
+ """Async Classification resource handler"""
326
+
327
+ def __init__(self, client: "AsyncSynapsAI"):
328
+ self._client = client
329
+ self.zero_shot = AsyncZeroShotClassificationsResource(client)
330
+
331
+
332
+ async def audio(
333
+ self,
334
+ model: str,
335
+ inputs: Union[np.ndarray, bytes, dict],
336
+ top_k: Optional[int] = None,
337
+ function_to_apply: Optional[str] = None,
338
+ ) -> AudioClassificationResponse:
339
+ """Audio classification."""
340
+
341
+ # Build request
342
+ request_data = self._client._build_request(
343
+ model=model,
344
+ inputs=inputs,
345
+ top_k=top_k,
346
+ function_to_apply=function_to_apply
347
+ )
348
+
349
+ endpoint = "classifications/audio"
350
+
351
+ # Make request
352
+ response = await self._client._post(endpoint, json_data=request_data)
353
+ response_data = response.json()
354
+ return AudioClassificationResponse.model_validate(response_data)
355
+
356
+ async def image(
357
+ self,
358
+ model: str,
359
+ inputs: Union[str, list[str], Image.Image, list[Image.Image]],
360
+ function_to_apply: Optional[str] = None,
361
+ top_k: Optional[int] = None,
362
+ timeout: Optional[float] = None,
363
+ ) -> ImageClassificationResponse:
364
+ """Assign labels to the image(s) passed as inputs."""
365
+
366
+ # Build request
367
+ request_data = self._client._build_request(
368
+ model=model,
369
+ inputs=inputs,
370
+ function_to_apply=function_to_apply,
371
+ top_k=top_k,
372
+ timeout=timeout
373
+ )
374
+
375
+ endpoint = "classifications/image"
376
+
377
+ # Make request
378
+ response = await self._client._post(endpoint, json_data=request_data)
379
+ response_data = response.json()
380
+ return ImageClassificationResponse.model_validate(response_data)
381
+
382
+ async def text(
383
+ self,
384
+ model: str,
385
+ inputs: Union[str, list[str], dict[str], list[dict[str]]],
386
+ top_k: Optional[int] = None,
387
+ function_to_apply: Optional[str] = None,
388
+ ) -> TextClassificationResponse:
389
+ """Classify the text(s) given as inputs."""
390
+
391
+ # Build request
392
+ request_data = self._client._build_request(
393
+ model=model,
394
+ inputs=inputs,
395
+ top_k=top_k,
396
+ function_to_apply=function_to_apply
397
+ )
398
+
399
+ endpoint = "classifications/text"
400
+
401
+ # Make request
402
+ response = await self._client._post(endpoint, json_data=request_data)
403
+ response_data = response.json()
404
+ return TextClassificationResponse.model_validate(response_data)
405
+
406
+ async def token(
407
+ self,
408
+ model: str,
409
+ inputs: Union[str, List[str]],
410
+ ) -> TokenClassificationResponse:
411
+ """Classify each token of the text(s) given as inputs."""
412
+
413
+ # Build request
414
+ request_data = self._client._build_request(
415
+ model=model,
416
+ inputs=inputs
417
+ )
418
+
419
+ endpoint = "classifications/token"
420
+
421
+ # Make request
422
+ response = await self._client._post(endpoint, json_data=request_data)
423
+ response_data = response.json()
424
+ return TokenClassificationResponse.model_validate(response_data)
425
+
426
+ async def video(
427
+ self,
428
+ model: str,
429
+ inputs: Union[str, list[str]],
430
+ top_k: Optional[int] = None,
431
+ num_frames: Optional[int] = None,
432
+ frame_sampling_rate: Optional[int] = None,
433
+ function_to_apply: Optional[str] = None,
434
+ ) -> VideoClassificationResponse:
435
+ """Assign labels to the video(s) passed as inputs."""
436
+
437
+ inputs = process_video_input(inputs)
438
+
439
+ # Build request
440
+ request_data = self._client._build_request(
441
+ model=model,
442
+ inputs=inputs,
443
+ top_k=top_k,
444
+ num_frames=num_frames,
445
+ frame_sampling_rate=frame_sampling_rate,
446
+ function_to_apply=function_to_apply
447
+ )
448
+
449
+ endpoint = "classifications/video"
450
+
451
+ # Make request
452
+ response = await self._client._post(endpoint, json_data=request_data)
453
+ response_data = response.json()
454
+ return VideoClassificationResponse.model_validate(response_data)
@@ -0,0 +1,162 @@
1
+ # Copyright 2026 SynapsAI Technologies Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ Chat completion resource handlers
17
+ """
18
+
19
+ from typing import Union, Iterator, AsyncIterator, TYPE_CHECKING, Optional, Dict
20
+ import json
21
+
22
+ from ..types.completion import (
23
+ CompletionResponse,
24
+ CompletionChunk,
25
+ )
26
+ from ..logging import get_logger
27
+ from ..exceptions import APIError
28
+
29
+ if TYPE_CHECKING:
30
+ from ..client import SynapsAI, AsyncSynapsAI
31
+
32
+ logger = get_logger(__name__)
33
+
34
+ class CompletionsResource:
35
+ """Chat completions resource"""
36
+
37
+ def __init__(self, client: "SynapsAI"):
38
+ self._client = client
39
+
40
+ def create(
41
+ self,
42
+ model: str,
43
+ prompt: str,
44
+ temperature: float = 1.0,
45
+ top_p: float = 1.0,
46
+ n: int = 1,
47
+ stream: bool = False,
48
+ stop = [],
49
+ max_completion_tokens = 128,
50
+ presence_penalty: float = 0.0,
51
+ frequency_penalty: float = 0.0,
52
+ logit_bias: Optional[Dict[int, float]] = None,
53
+ **kwargs
54
+ ) -> Union[CompletionResponse, Iterator[CompletionChunk]]:
55
+ """Create a chat completion"""
56
+
57
+ # Build request
58
+ request_data = self._client._build_request(
59
+ model=model,
60
+ prompt=prompt,
61
+ temperature=temperature,
62
+ top_p=top_p,
63
+ n=n,
64
+ stream=stream,
65
+ stop=stop,
66
+ max_completion_tokens=max_completion_tokens,
67
+ presence_penalty=presence_penalty,
68
+ frequency_penalty=frequency_penalty,
69
+ logit_bias=logit_bias,
70
+ **kwargs
71
+ )
72
+
73
+ endpoint = "completions"
74
+
75
+ if stream:
76
+ return self._stream_completions(endpoint, request_data)
77
+ else:
78
+ response = self._client._post(endpoint, request_data)
79
+ return CompletionResponse.model_validate(response.json())
80
+
81
+ def _stream_completions(self, endpoint, request_data) -> Iterator[CompletionChunk]:
82
+ for chunk_data in self._client._stream_response(endpoint, request_data):
83
+ try:
84
+ error = chunk_data.get("error")
85
+ if error:
86
+ raise APIError(error)
87
+ yield CompletionChunk(**chunk_data)
88
+ except APIError as e:
89
+ raise e
90
+ except Exception as e:
91
+ print(e)
92
+ logger.warning(
93
+ "Failed to parse CompletionChunk",
94
+ exc_info=True,
95
+ extra={"endpoint": endpoint},
96
+ )
97
+ continue
98
+
99
+
100
+
101
+
102
+ class AsyncCompletionsResource:
103
+ """Async chat completions resource"""
104
+
105
+ def __init__(self, client: "AsyncSynapsAI"):
106
+ self._client = client
107
+
108
+ async def create(
109
+ self,
110
+ model: str,
111
+ prompt: str,
112
+ temperature: float = 1.0,
113
+ top_p: float = 1.0,
114
+ n: int = 1,
115
+ stream: bool = False,
116
+ stop = [],
117
+ max_completion_tokens = 128,
118
+ presence_penalty: float = 0.0,
119
+ frequency_penalty: float = 0.0,
120
+ logit_bias = None,
121
+ **kwargs
122
+ ) -> Union[CompletionResponse, AsyncIterator[CompletionChunk]]:
123
+ """Create a chat completion asynchronously"""
124
+
125
+ # Build request
126
+ request_data = self._client._build_request(
127
+ model=model,
128
+ prompt=prompt,
129
+ temperature=temperature,
130
+ top_p=top_p,
131
+ n=n,
132
+ stream=stream,
133
+ stop=stop,
134
+ max_completion_tokens=max_completion_tokens,
135
+ presence_penalty=presence_penalty,
136
+ frequency_penalty=frequency_penalty,
137
+ logit_bias=logit_bias,
138
+ **kwargs
139
+ )
140
+
141
+ endpoint = "completions"
142
+
143
+ # Make request
144
+ if stream:
145
+ return self._stream_completions(endpoint, request_data)
146
+ else:
147
+ response = await self._client._post(endpoint, request_data)
148
+ return CompletionResponse.model_validate(response.json())
149
+
150
+ async def _stream_completions(self, endpoint, request_data) -> AsyncIterator[CompletionChunk]:
151
+ async for chunk_data in self._client._stream_response(endpoint, request_data):
152
+ try:
153
+ yield CompletionChunk(**chunk_data)
154
+ except Exception as e:
155
+ logger.warning(
156
+ "Failed to parse CompletionChunk",
157
+ exc_info=True,
158
+ extra={"endpoint": endpoint},
159
+ )
160
+ continue
161
+
162
+