sarvamai 0.1.5a6__py3-none-any.whl → 0.1.5a8__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.
- sarvamai/__init__.py +45 -1
- sarvamai/chat/__init__.py +2 -0
- sarvamai/chat/client.py +9 -10
- sarvamai/chat/raw_client.py +48 -37
- sarvamai/client.py +13 -31
- sarvamai/core/__init__.py +5 -0
- sarvamai/core/api_error.py +13 -5
- sarvamai/core/client_wrapper.py +17 -20
- sarvamai/core/events.py +30 -0
- sarvamai/core/force_multipart.py +16 -0
- sarvamai/core/http_client.py +70 -24
- sarvamai/core/http_response.py +19 -11
- sarvamai/core/pydantic_utilities.py +69 -108
- sarvamai/environment.py +10 -3
- sarvamai/errors/__init__.py +2 -0
- sarvamai/errors/bad_request_error.py +4 -3
- sarvamai/errors/forbidden_error.py +4 -3
- sarvamai/errors/internal_server_error.py +4 -3
- sarvamai/errors/service_unavailable_error.py +4 -2
- sarvamai/errors/too_many_requests_error.py +4 -3
- sarvamai/errors/unprocessable_entity_error.py +4 -3
- sarvamai/requests/__init__.py +18 -0
- sarvamai/requests/audio_data.py +21 -0
- sarvamai/requests/audio_message.py +8 -0
- sarvamai/requests/chat_completion_request_message.py +3 -1
- sarvamai/requests/create_chat_completion_response.py +2 -2
- sarvamai/requests/diarized_transcript.py +2 -1
- sarvamai/requests/error_data.py +15 -0
- sarvamai/requests/error_details.py +0 -1
- sarvamai/requests/events_data.py +17 -0
- sarvamai/requests/language_identification_response.py +0 -1
- sarvamai/requests/speech_to_text_response.py +1 -2
- sarvamai/requests/speech_to_text_streaming_response.py +10 -0
- sarvamai/requests/speech_to_text_streaming_response_data.py +9 -0
- sarvamai/requests/speech_to_text_translate_response.py +0 -1
- sarvamai/requests/text_to_speech_response.py +2 -2
- sarvamai/requests/timestamps_model.py +2 -1
- sarvamai/requests/transcription_data.py +35 -0
- sarvamai/requests/transcription_metrics.py +15 -0
- sarvamai/requests/translation_response.py +0 -1
- sarvamai/requests/transliteration_response.py +0 -1
- sarvamai/speech_to_text/__init__.py +2 -0
- sarvamai/speech_to_text/client.py +13 -14
- sarvamai/speech_to_text/raw_client.py +99 -68
- sarvamai/speech_to_text_streaming/__init__.py +7 -0
- sarvamai/speech_to_text_streaming/client.py +189 -0
- sarvamai/speech_to_text_streaming/raw_client.py +166 -0
- sarvamai/speech_to_text_streaming/socket_client.py +133 -0
- sarvamai/speech_to_text_streaming/types/__init__.py +8 -0
- sarvamai/speech_to_text_streaming/types/speech_to_text_streaming_language_code.py +8 -0
- sarvamai/speech_to_text_streaming/types/speech_to_text_streaming_model.py +5 -0
- sarvamai/text/__init__.py +2 -0
- sarvamai/text/client.py +24 -25
- sarvamai/text/raw_client.py +126 -91
- sarvamai/text_to_speech/__init__.py +2 -0
- sarvamai/text_to_speech/client.py +10 -11
- sarvamai/text_to_speech/raw_client.py +49 -38
- sarvamai/types/__init__.py +24 -0
- sarvamai/types/audio_data.py +33 -0
- sarvamai/types/audio_data_encoding.py +5 -0
- sarvamai/types/audio_message.py +20 -0
- sarvamai/types/chat_completion_request_assistant_message.py +3 -3
- sarvamai/types/chat_completion_request_message.py +3 -2
- sarvamai/types/chat_completion_request_system_message.py +3 -3
- sarvamai/types/chat_completion_request_user_message.py +3 -3
- sarvamai/types/chat_completion_response_message.py +3 -3
- sarvamai/types/choice.py +4 -4
- sarvamai/types/completion_usage.py +3 -3
- sarvamai/types/create_chat_completion_response.py +3 -3
- sarvamai/types/diarized_entry.py +3 -3
- sarvamai/types/diarized_transcript.py +3 -3
- sarvamai/types/error_data.py +27 -0
- sarvamai/types/error_details.py +3 -3
- sarvamai/types/error_message.py +4 -4
- sarvamai/types/events_data.py +28 -0
- sarvamai/types/format.py +5 -0
- sarvamai/types/language_identification_response.py +2 -2
- sarvamai/types/speech_to_text_response.py +3 -3
- sarvamai/types/speech_to_text_streaming_response.py +22 -0
- sarvamai/types/speech_to_text_streaming_response_data.py +9 -0
- sarvamai/types/speech_to_text_streaming_response_type.py +5 -0
- sarvamai/types/speech_to_text_translate_response.py +3 -3
- sarvamai/types/text_to_speech_response.py +2 -2
- sarvamai/types/timestamps_model.py +2 -2
- sarvamai/types/transcription_data.py +45 -0
- sarvamai/types/transcription_metrics.py +27 -0
- sarvamai/types/translation_response.py +2 -2
- sarvamai/types/transliteration_response.py +2 -2
- sarvamai-0.1.5a8.dist-info/METADATA +28 -0
- sarvamai-0.1.5a8.dist-info/RECORD +134 -0
- sarvamai-0.1.5a6.dist-info/METADATA +0 -174
- sarvamai-0.1.5a6.dist-info/RECORD +0 -106
- {sarvamai-0.1.5a6.dist-info → sarvamai-0.1.5a8.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ForceMultipartDict(dict):
|
|
5
|
+
"""
|
|
6
|
+
A dictionary subclass that always evaluates to True in boolean contexts.
|
|
7
|
+
|
|
8
|
+
This is used to force multipart/form-data encoding in HTTP requests even when
|
|
9
|
+
the dictionary is empty, which would normally evaluate to False.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __bool__(self):
|
|
13
|
+
return True
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
FORCE_MULTIPART = ForceMultipartDict()
|
sarvamai/core/http_client.py
CHANGED
|
@@ -11,10 +11,12 @@ from random import random
|
|
|
11
11
|
|
|
12
12
|
import httpx
|
|
13
13
|
from .file import File, convert_file_dict_to_httpx_tuples
|
|
14
|
+
from .force_multipart import FORCE_MULTIPART
|
|
14
15
|
from .jsonable_encoder import jsonable_encoder
|
|
15
16
|
from .query_encoder import encode_query
|
|
16
17
|
from .remove_none_from_dict import remove_none_from_dict
|
|
17
18
|
from .request_options import RequestOptions
|
|
19
|
+
from httpx._types import RequestFiles
|
|
18
20
|
|
|
19
21
|
INITIAL_RETRY_DELAY_SECONDS = 0.5
|
|
20
22
|
MAX_RETRY_DELAY_SECONDS = 10
|
|
@@ -178,11 +180,17 @@ class HttpClient:
|
|
|
178
180
|
json: typing.Optional[typing.Any] = None,
|
|
179
181
|
data: typing.Optional[typing.Any] = None,
|
|
180
182
|
content: typing.Optional[typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]]] = None,
|
|
181
|
-
files: typing.Optional[
|
|
183
|
+
files: typing.Optional[
|
|
184
|
+
typing.Union[
|
|
185
|
+
typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]],
|
|
186
|
+
typing.List[typing.Tuple[str, File]],
|
|
187
|
+
]
|
|
188
|
+
] = None,
|
|
182
189
|
headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
|
|
183
190
|
request_options: typing.Optional[RequestOptions] = None,
|
|
184
191
|
retries: int = 2,
|
|
185
192
|
omit: typing.Optional[typing.Any] = None,
|
|
193
|
+
force_multipart: typing.Optional[bool] = None,
|
|
186
194
|
) -> httpx.Response:
|
|
187
195
|
base_url = self.get_base_url(base_url)
|
|
188
196
|
timeout = (
|
|
@@ -193,6 +201,15 @@ class HttpClient:
|
|
|
193
201
|
|
|
194
202
|
json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
|
|
195
203
|
|
|
204
|
+
request_files: typing.Optional[RequestFiles] = (
|
|
205
|
+
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
|
|
206
|
+
if (files is not None and files is not omit and isinstance(files, dict))
|
|
207
|
+
else None
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
if (request_files is None or len(request_files) == 0) and force_multipart:
|
|
211
|
+
request_files = FORCE_MULTIPART
|
|
212
|
+
|
|
196
213
|
response = self.httpx_client.request(
|
|
197
214
|
method=method,
|
|
198
215
|
url=urllib.parse.urljoin(f"{base_url}/", path),
|
|
@@ -225,11 +242,7 @@ class HttpClient:
|
|
|
225
242
|
json=json_body,
|
|
226
243
|
data=data_body,
|
|
227
244
|
content=content,
|
|
228
|
-
files=
|
|
229
|
-
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
|
|
230
|
-
if (files is not None and files is not omit)
|
|
231
|
-
else None
|
|
232
|
-
),
|
|
245
|
+
files=request_files,
|
|
233
246
|
timeout=timeout,
|
|
234
247
|
)
|
|
235
248
|
|
|
@@ -264,11 +277,17 @@ class HttpClient:
|
|
|
264
277
|
json: typing.Optional[typing.Any] = None,
|
|
265
278
|
data: typing.Optional[typing.Any] = None,
|
|
266
279
|
content: typing.Optional[typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]]] = None,
|
|
267
|
-
files: typing.Optional[
|
|
280
|
+
files: typing.Optional[
|
|
281
|
+
typing.Union[
|
|
282
|
+
typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]],
|
|
283
|
+
typing.List[typing.Tuple[str, File]],
|
|
284
|
+
]
|
|
285
|
+
] = None,
|
|
268
286
|
headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
|
|
269
287
|
request_options: typing.Optional[RequestOptions] = None,
|
|
270
288
|
retries: int = 2,
|
|
271
289
|
omit: typing.Optional[typing.Any] = None,
|
|
290
|
+
force_multipart: typing.Optional[bool] = None,
|
|
272
291
|
) -> typing.Iterator[httpx.Response]:
|
|
273
292
|
base_url = self.get_base_url(base_url)
|
|
274
293
|
timeout = (
|
|
@@ -277,6 +296,15 @@ class HttpClient:
|
|
|
277
296
|
else self.base_timeout()
|
|
278
297
|
)
|
|
279
298
|
|
|
299
|
+
request_files: typing.Optional[RequestFiles] = (
|
|
300
|
+
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
|
|
301
|
+
if (files is not None and files is not omit and isinstance(files, dict))
|
|
302
|
+
else None
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
if (request_files is None or len(request_files) == 0) and force_multipart:
|
|
306
|
+
request_files = FORCE_MULTIPART
|
|
307
|
+
|
|
280
308
|
json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
|
|
281
309
|
|
|
282
310
|
with self.httpx_client.stream(
|
|
@@ -311,11 +339,7 @@ class HttpClient:
|
|
|
311
339
|
json=json_body,
|
|
312
340
|
data=data_body,
|
|
313
341
|
content=content,
|
|
314
|
-
files=
|
|
315
|
-
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
|
|
316
|
-
if (files is not None and files is not omit)
|
|
317
|
-
else None
|
|
318
|
-
),
|
|
342
|
+
files=request_files,
|
|
319
343
|
timeout=timeout,
|
|
320
344
|
) as stream:
|
|
321
345
|
yield stream
|
|
@@ -354,11 +378,17 @@ class AsyncHttpClient:
|
|
|
354
378
|
json: typing.Optional[typing.Any] = None,
|
|
355
379
|
data: typing.Optional[typing.Any] = None,
|
|
356
380
|
content: typing.Optional[typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]]] = None,
|
|
357
|
-
files: typing.Optional[
|
|
381
|
+
files: typing.Optional[
|
|
382
|
+
typing.Union[
|
|
383
|
+
typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]],
|
|
384
|
+
typing.List[typing.Tuple[str, File]],
|
|
385
|
+
]
|
|
386
|
+
] = None,
|
|
358
387
|
headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
|
|
359
388
|
request_options: typing.Optional[RequestOptions] = None,
|
|
360
389
|
retries: int = 2,
|
|
361
390
|
omit: typing.Optional[typing.Any] = None,
|
|
391
|
+
force_multipart: typing.Optional[bool] = None,
|
|
362
392
|
) -> httpx.Response:
|
|
363
393
|
base_url = self.get_base_url(base_url)
|
|
364
394
|
timeout = (
|
|
@@ -367,6 +397,15 @@ class AsyncHttpClient:
|
|
|
367
397
|
else self.base_timeout()
|
|
368
398
|
)
|
|
369
399
|
|
|
400
|
+
request_files: typing.Optional[RequestFiles] = (
|
|
401
|
+
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
|
|
402
|
+
if (files is not None and files is not omit and isinstance(files, dict))
|
|
403
|
+
else None
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
if (request_files is None or len(request_files) == 0) and force_multipart:
|
|
407
|
+
request_files = FORCE_MULTIPART
|
|
408
|
+
|
|
370
409
|
json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
|
|
371
410
|
|
|
372
411
|
# Add the input to each of these and do None-safety checks
|
|
@@ -402,11 +441,7 @@ class AsyncHttpClient:
|
|
|
402
441
|
json=json_body,
|
|
403
442
|
data=data_body,
|
|
404
443
|
content=content,
|
|
405
|
-
files=
|
|
406
|
-
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
|
|
407
|
-
if files is not None
|
|
408
|
-
else None
|
|
409
|
-
),
|
|
444
|
+
files=request_files,
|
|
410
445
|
timeout=timeout,
|
|
411
446
|
)
|
|
412
447
|
|
|
@@ -440,11 +475,17 @@ class AsyncHttpClient:
|
|
|
440
475
|
json: typing.Optional[typing.Any] = None,
|
|
441
476
|
data: typing.Optional[typing.Any] = None,
|
|
442
477
|
content: typing.Optional[typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]]] = None,
|
|
443
|
-
files: typing.Optional[
|
|
478
|
+
files: typing.Optional[
|
|
479
|
+
typing.Union[
|
|
480
|
+
typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]],
|
|
481
|
+
typing.List[typing.Tuple[str, File]],
|
|
482
|
+
]
|
|
483
|
+
] = None,
|
|
444
484
|
headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
|
|
445
485
|
request_options: typing.Optional[RequestOptions] = None,
|
|
446
486
|
retries: int = 2,
|
|
447
487
|
omit: typing.Optional[typing.Any] = None,
|
|
488
|
+
force_multipart: typing.Optional[bool] = None,
|
|
448
489
|
) -> typing.AsyncIterator[httpx.Response]:
|
|
449
490
|
base_url = self.get_base_url(base_url)
|
|
450
491
|
timeout = (
|
|
@@ -453,6 +494,15 @@ class AsyncHttpClient:
|
|
|
453
494
|
else self.base_timeout()
|
|
454
495
|
)
|
|
455
496
|
|
|
497
|
+
request_files: typing.Optional[RequestFiles] = (
|
|
498
|
+
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
|
|
499
|
+
if (files is not None and files is not omit and isinstance(files, dict))
|
|
500
|
+
else None
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
if (request_files is None or len(request_files) == 0) and force_multipart:
|
|
504
|
+
request_files = FORCE_MULTIPART
|
|
505
|
+
|
|
456
506
|
json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
|
|
457
507
|
|
|
458
508
|
async with self.httpx_client.stream(
|
|
@@ -487,11 +537,7 @@ class AsyncHttpClient:
|
|
|
487
537
|
json=json_body,
|
|
488
538
|
data=data_body,
|
|
489
539
|
content=content,
|
|
490
|
-
files=
|
|
491
|
-
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
|
|
492
|
-
if files is not None
|
|
493
|
-
else None
|
|
494
|
-
),
|
|
540
|
+
files=request_files,
|
|
495
541
|
timeout=timeout,
|
|
496
542
|
) as stream:
|
|
497
543
|
yield stream
|
sarvamai/core/http_response.py
CHANGED
|
@@ -5,20 +5,31 @@ from typing import Dict, Generic, TypeVar
|
|
|
5
5
|
import httpx
|
|
6
6
|
|
|
7
7
|
T = TypeVar("T")
|
|
8
|
+
"""Generic to represent the underlying type of the data wrapped by the HTTP response."""
|
|
8
9
|
|
|
9
10
|
|
|
10
|
-
class
|
|
11
|
+
class BaseHttpResponse:
|
|
12
|
+
"""Minimalist HTTP response wrapper that exposes response headers."""
|
|
13
|
+
|
|
11
14
|
_response: httpx.Response
|
|
12
|
-
_data: T
|
|
13
15
|
|
|
14
|
-
def __init__(self, response: httpx.Response
|
|
16
|
+
def __init__(self, response: httpx.Response):
|
|
15
17
|
self._response = response
|
|
16
|
-
self._data = data
|
|
17
18
|
|
|
18
19
|
@property
|
|
19
20
|
def headers(self) -> Dict[str, str]:
|
|
20
21
|
return dict(self._response.headers)
|
|
21
22
|
|
|
23
|
+
|
|
24
|
+
class HttpResponse(Generic[T], BaseHttpResponse):
|
|
25
|
+
"""HTTP response wrapper that exposes response headers and data."""
|
|
26
|
+
|
|
27
|
+
_data: T
|
|
28
|
+
|
|
29
|
+
def __init__(self, response: httpx.Response, data: T):
|
|
30
|
+
super().__init__(response)
|
|
31
|
+
self._data = data
|
|
32
|
+
|
|
22
33
|
@property
|
|
23
34
|
def data(self) -> T:
|
|
24
35
|
return self._data
|
|
@@ -27,18 +38,15 @@ class HttpResponse(Generic[T]):
|
|
|
27
38
|
self._response.close()
|
|
28
39
|
|
|
29
40
|
|
|
30
|
-
class AsyncHttpResponse(Generic[T]):
|
|
31
|
-
|
|
41
|
+
class AsyncHttpResponse(Generic[T], BaseHttpResponse):
|
|
42
|
+
"""HTTP response wrapper that exposes response headers and data."""
|
|
43
|
+
|
|
32
44
|
_data: T
|
|
33
45
|
|
|
34
46
|
def __init__(self, response: httpx.Response, data: T):
|
|
35
|
-
|
|
47
|
+
super().__init__(response)
|
|
36
48
|
self._data = data
|
|
37
49
|
|
|
38
|
-
@property
|
|
39
|
-
def headers(self) -> Dict[str, str]:
|
|
40
|
-
return dict(self._response.headers)
|
|
41
|
-
|
|
42
50
|
@property
|
|
43
51
|
def data(self) -> T:
|
|
44
52
|
return self._data
|
|
@@ -2,87 +2,65 @@
|
|
|
2
2
|
|
|
3
3
|
# nopycln: file
|
|
4
4
|
import datetime as dt
|
|
5
|
-
import typing
|
|
6
5
|
from collections import defaultdict
|
|
6
|
+
from typing import Any, Callable, ClassVar, Dict, List, Mapping, Optional, Set, Tuple, Type, TypeVar, Union, cast
|
|
7
7
|
|
|
8
8
|
import pydantic
|
|
9
|
-
import typing_extensions
|
|
10
|
-
from .datetime_utils import serialize_datetime
|
|
11
|
-
from .serialization import convert_and_respect_annotation_metadata
|
|
12
9
|
|
|
13
10
|
IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.")
|
|
14
11
|
|
|
15
12
|
if IS_PYDANTIC_V2:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
from pydantic.v1.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
from pydantic.v1.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
from pydantic.v1.json import ( # type: ignore # pyright: ignore[reportMissingImports] # Pydantic v2
|
|
25
|
-
ENCODERS_BY_TYPE as encoders_by_type,
|
|
26
|
-
)
|
|
27
|
-
from pydantic.v1.typing import ( # type: ignore # pyright: ignore[reportMissingImports] # Pydantic v2
|
|
28
|
-
get_args as get_args,
|
|
29
|
-
)
|
|
30
|
-
from pydantic.v1.typing import ( # pyright: ignore[reportMissingImports] # Pydantic v2
|
|
31
|
-
get_origin as get_origin,
|
|
32
|
-
)
|
|
33
|
-
from pydantic.v1.typing import ( # pyright: ignore[reportMissingImports] # Pydantic v2
|
|
34
|
-
is_literal_type as is_literal_type,
|
|
35
|
-
)
|
|
36
|
-
from pydantic.v1.typing import ( # pyright: ignore[reportMissingImports] # Pydantic v2
|
|
37
|
-
is_union as is_union,
|
|
38
|
-
)
|
|
39
|
-
from pydantic.v1.fields import ModelField as ModelField # type: ignore # pyright: ignore[reportMissingImports] # Pydantic v2
|
|
13
|
+
from pydantic.v1.datetime_parse import parse_date as parse_date
|
|
14
|
+
from pydantic.v1.datetime_parse import parse_datetime as parse_datetime
|
|
15
|
+
from pydantic.v1.fields import ModelField as ModelField
|
|
16
|
+
from pydantic.v1.json import ENCODERS_BY_TYPE as encoders_by_type # type: ignore[attr-defined]
|
|
17
|
+
from pydantic.v1.typing import get_args as get_args
|
|
18
|
+
from pydantic.v1.typing import get_origin as get_origin
|
|
19
|
+
from pydantic.v1.typing import is_literal_type as is_literal_type
|
|
20
|
+
from pydantic.v1.typing import is_union as is_union
|
|
40
21
|
else:
|
|
41
|
-
from pydantic.datetime_parse import parse_date as parse_date # type: ignore
|
|
42
|
-
from pydantic.datetime_parse import parse_datetime as parse_datetime # type: ignore
|
|
43
|
-
from pydantic.fields import ModelField as ModelField # type: ignore
|
|
44
|
-
from pydantic.json import ENCODERS_BY_TYPE as encoders_by_type # type: ignore
|
|
45
|
-
from pydantic.typing import get_args as get_args # type: ignore
|
|
46
|
-
from pydantic.typing import get_origin as get_origin # type: ignore
|
|
47
|
-
from pydantic.typing import is_literal_type as is_literal_type # type: ignore
|
|
48
|
-
from pydantic.typing import is_union as is_union # type: ignore
|
|
49
|
-
|
|
50
|
-
# isort: on
|
|
22
|
+
from pydantic.datetime_parse import parse_date as parse_date # type: ignore[no-redef]
|
|
23
|
+
from pydantic.datetime_parse import parse_datetime as parse_datetime # type: ignore[no-redef]
|
|
24
|
+
from pydantic.fields import ModelField as ModelField # type: ignore[attr-defined, no-redef]
|
|
25
|
+
from pydantic.json import ENCODERS_BY_TYPE as encoders_by_type # type: ignore[no-redef]
|
|
26
|
+
from pydantic.typing import get_args as get_args # type: ignore[no-redef]
|
|
27
|
+
from pydantic.typing import get_origin as get_origin # type: ignore[no-redef]
|
|
28
|
+
from pydantic.typing import is_literal_type as is_literal_type # type: ignore[no-redef]
|
|
29
|
+
from pydantic.typing import is_union as is_union # type: ignore[no-redef]
|
|
51
30
|
|
|
31
|
+
from .datetime_utils import serialize_datetime
|
|
32
|
+
from .serialization import convert_and_respect_annotation_metadata
|
|
33
|
+
from typing_extensions import TypeAlias
|
|
52
34
|
|
|
53
|
-
T =
|
|
54
|
-
Model =
|
|
35
|
+
T = TypeVar("T")
|
|
36
|
+
Model = TypeVar("Model", bound=pydantic.BaseModel)
|
|
55
37
|
|
|
56
38
|
|
|
57
|
-
def parse_obj_as(type_:
|
|
39
|
+
def parse_obj_as(type_: Type[T], object_: Any) -> T:
|
|
58
40
|
dealiased_object = convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read")
|
|
59
41
|
if IS_PYDANTIC_V2:
|
|
60
|
-
adapter = pydantic.TypeAdapter(type_) # type: ignore
|
|
42
|
+
adapter = pydantic.TypeAdapter(type_) # type: ignore[attr-defined]
|
|
61
43
|
return adapter.validate_python(dealiased_object)
|
|
62
|
-
|
|
63
|
-
return pydantic.parse_obj_as(type_, dealiased_object)
|
|
44
|
+
return pydantic.parse_obj_as(type_, dealiased_object)
|
|
64
45
|
|
|
65
46
|
|
|
66
|
-
def to_jsonable_with_fallback(
|
|
67
|
-
obj: typing.Any, fallback_serializer: typing.Callable[[typing.Any], typing.Any]
|
|
68
|
-
) -> typing.Any:
|
|
47
|
+
def to_jsonable_with_fallback(obj: Any, fallback_serializer: Callable[[Any], Any]) -> Any:
|
|
69
48
|
if IS_PYDANTIC_V2:
|
|
70
49
|
from pydantic_core import to_jsonable_python
|
|
71
50
|
|
|
72
51
|
return to_jsonable_python(obj, fallback=fallback_serializer)
|
|
73
|
-
|
|
74
|
-
return fallback_serializer(obj)
|
|
52
|
+
return fallback_serializer(obj)
|
|
75
53
|
|
|
76
54
|
|
|
77
55
|
class UniversalBaseModel(pydantic.BaseModel):
|
|
78
56
|
if IS_PYDANTIC_V2:
|
|
79
|
-
model_config:
|
|
57
|
+
model_config: ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( # type: ignore[typeddict-unknown-key]
|
|
80
58
|
# Allow fields beginning with `model_` to be used in the model
|
|
81
59
|
protected_namespaces=(),
|
|
82
|
-
)
|
|
60
|
+
)
|
|
83
61
|
|
|
84
|
-
@pydantic.model_serializer(mode="wrap", when_used="json") # type: ignore
|
|
85
|
-
def serialize_model(self, handler: pydantic.SerializerFunctionWrapHandler) ->
|
|
62
|
+
@pydantic.model_serializer(mode="wrap", when_used="json") # type: ignore[attr-defined]
|
|
63
|
+
def serialize_model(self, handler: pydantic.SerializerFunctionWrapHandler) -> Any: # type: ignore[name-defined]
|
|
86
64
|
serialized = handler(self)
|
|
87
65
|
data = {k: serialize_datetime(v) if isinstance(v, dt.datetime) else v for k, v in serialized.items()}
|
|
88
66
|
return data
|
|
@@ -94,34 +72,28 @@ class UniversalBaseModel(pydantic.BaseModel):
|
|
|
94
72
|
json_encoders = {dt.datetime: serialize_datetime}
|
|
95
73
|
|
|
96
74
|
@classmethod
|
|
97
|
-
def model_construct(
|
|
98
|
-
cls: typing.Type["Model"], _fields_set: typing.Optional[typing.Set[str]] = None, **values: typing.Any
|
|
99
|
-
) -> "Model":
|
|
75
|
+
def model_construct(cls: Type["Model"], _fields_set: Optional[Set[str]] = None, **values: Any) -> "Model":
|
|
100
76
|
dealiased_object = convert_and_respect_annotation_metadata(object_=values, annotation=cls, direction="read")
|
|
101
77
|
return cls.construct(_fields_set, **dealiased_object)
|
|
102
78
|
|
|
103
79
|
@classmethod
|
|
104
|
-
def construct(
|
|
105
|
-
cls: typing.Type["Model"], _fields_set: typing.Optional[typing.Set[str]] = None, **values: typing.Any
|
|
106
|
-
) -> "Model":
|
|
80
|
+
def construct(cls: Type["Model"], _fields_set: Optional[Set[str]] = None, **values: Any) -> "Model":
|
|
107
81
|
dealiased_object = convert_and_respect_annotation_metadata(object_=values, annotation=cls, direction="read")
|
|
108
82
|
if IS_PYDANTIC_V2:
|
|
109
|
-
return super().model_construct(_fields_set, **dealiased_object) # type: ignore
|
|
110
|
-
|
|
111
|
-
return super().construct(_fields_set, **dealiased_object)
|
|
83
|
+
return super().model_construct(_fields_set, **dealiased_object) # type: ignore[misc]
|
|
84
|
+
return super().construct(_fields_set, **dealiased_object)
|
|
112
85
|
|
|
113
|
-
def json(self, **kwargs:
|
|
114
|
-
kwargs_with_defaults
|
|
86
|
+
def json(self, **kwargs: Any) -> str:
|
|
87
|
+
kwargs_with_defaults = {
|
|
115
88
|
"by_alias": True,
|
|
116
89
|
"exclude_unset": True,
|
|
117
90
|
**kwargs,
|
|
118
91
|
}
|
|
119
92
|
if IS_PYDANTIC_V2:
|
|
120
|
-
return super().model_dump_json(**kwargs_with_defaults) # type: ignore
|
|
121
|
-
|
|
122
|
-
return super().json(**kwargs_with_defaults)
|
|
93
|
+
return super().model_dump_json(**kwargs_with_defaults) # type: ignore[misc]
|
|
94
|
+
return super().json(**kwargs_with_defaults)
|
|
123
95
|
|
|
124
|
-
def dict(self, **kwargs:
|
|
96
|
+
def dict(self, **kwargs: Any) -> Dict[str, Any]:
|
|
125
97
|
"""
|
|
126
98
|
Override the default dict method to `exclude_unset` by default. This function patches
|
|
127
99
|
`exclude_unset` to work include fields within non-None default values.
|
|
@@ -132,21 +104,21 @@ class UniversalBaseModel(pydantic.BaseModel):
|
|
|
132
104
|
# We'd ideally do the same for Pydantic V2, but it shells out to a library to serialize models
|
|
133
105
|
# that we have less control over, and this is less intrusive than custom serializers for now.
|
|
134
106
|
if IS_PYDANTIC_V2:
|
|
135
|
-
kwargs_with_defaults_exclude_unset
|
|
107
|
+
kwargs_with_defaults_exclude_unset = {
|
|
136
108
|
**kwargs,
|
|
137
109
|
"by_alias": True,
|
|
138
110
|
"exclude_unset": True,
|
|
139
111
|
"exclude_none": False,
|
|
140
112
|
}
|
|
141
|
-
kwargs_with_defaults_exclude_none
|
|
113
|
+
kwargs_with_defaults_exclude_none = {
|
|
142
114
|
**kwargs,
|
|
143
115
|
"by_alias": True,
|
|
144
116
|
"exclude_none": True,
|
|
145
117
|
"exclude_unset": False,
|
|
146
118
|
}
|
|
147
119
|
dict_dump = deep_union_pydantic_dicts(
|
|
148
|
-
super().model_dump(**kwargs_with_defaults_exclude_unset), # type: ignore
|
|
149
|
-
super().model_dump(**kwargs_with_defaults_exclude_none), # type: ignore
|
|
120
|
+
super().model_dump(**kwargs_with_defaults_exclude_unset), # type: ignore[misc]
|
|
121
|
+
super().model_dump(**kwargs_with_defaults_exclude_none), # type: ignore[misc]
|
|
150
122
|
)
|
|
151
123
|
|
|
152
124
|
else:
|
|
@@ -166,7 +138,7 @@ class UniversalBaseModel(pydantic.BaseModel):
|
|
|
166
138
|
if default is not None:
|
|
167
139
|
self.__fields_set__.add(name)
|
|
168
140
|
|
|
169
|
-
kwargs_with_defaults_exclude_unset_include_fields
|
|
141
|
+
kwargs_with_defaults_exclude_unset_include_fields = {
|
|
170
142
|
"by_alias": True,
|
|
171
143
|
"exclude_unset": True,
|
|
172
144
|
"include": _fields_set,
|
|
@@ -178,12 +150,10 @@ class UniversalBaseModel(pydantic.BaseModel):
|
|
|
178
150
|
return convert_and_respect_annotation_metadata(object_=dict_dump, annotation=self.__class__, direction="write")
|
|
179
151
|
|
|
180
152
|
|
|
181
|
-
def _union_list_of_pydantic_dicts(
|
|
182
|
-
|
|
183
|
-
) -> typing.List[typing.Any]:
|
|
184
|
-
converted_list: typing.List[typing.Any] = []
|
|
153
|
+
def _union_list_of_pydantic_dicts(source: List[Any], destination: List[Any]) -> List[Any]:
|
|
154
|
+
converted_list: List[Any] = []
|
|
185
155
|
for i, item in enumerate(source):
|
|
186
|
-
destination_value = destination[i]
|
|
156
|
+
destination_value = destination[i]
|
|
187
157
|
if isinstance(item, dict):
|
|
188
158
|
converted_list.append(deep_union_pydantic_dicts(item, destination_value))
|
|
189
159
|
elif isinstance(item, list):
|
|
@@ -193,9 +163,7 @@ def _union_list_of_pydantic_dicts(
|
|
|
193
163
|
return converted_list
|
|
194
164
|
|
|
195
165
|
|
|
196
|
-
def deep_union_pydantic_dicts(
|
|
197
|
-
source: typing.Dict[str, typing.Any], destination: typing.Dict[str, typing.Any]
|
|
198
|
-
) -> typing.Dict[str, typing.Any]:
|
|
166
|
+
def deep_union_pydantic_dicts(source: Dict[str, Any], destination: Dict[str, Any]) -> Dict[str, Any]:
|
|
199
167
|
for key, value in source.items():
|
|
200
168
|
node = destination.setdefault(key, {})
|
|
201
169
|
if isinstance(value, dict):
|
|
@@ -213,18 +181,16 @@ def deep_union_pydantic_dicts(
|
|
|
213
181
|
|
|
214
182
|
if IS_PYDANTIC_V2:
|
|
215
183
|
|
|
216
|
-
class V2RootModel(UniversalBaseModel, pydantic.RootModel): # type: ignore
|
|
184
|
+
class V2RootModel(UniversalBaseModel, pydantic.RootModel): # type: ignore[misc, name-defined, type-arg]
|
|
217
185
|
pass
|
|
218
186
|
|
|
219
|
-
UniversalRootModel:
|
|
187
|
+
UniversalRootModel: TypeAlias = V2RootModel # type: ignore[misc]
|
|
220
188
|
else:
|
|
221
|
-
UniversalRootModel:
|
|
189
|
+
UniversalRootModel: TypeAlias = UniversalBaseModel # type: ignore[misc, no-redef]
|
|
222
190
|
|
|
223
191
|
|
|
224
|
-
def encode_by_type(o:
|
|
225
|
-
encoders_by_class_tuples:
|
|
226
|
-
defaultdict(tuple)
|
|
227
|
-
)
|
|
192
|
+
def encode_by_type(o: Any) -> Any:
|
|
193
|
+
encoders_by_class_tuples: Dict[Callable[[Any], Any], Tuple[Any, ...]] = defaultdict(tuple)
|
|
228
194
|
for type_, encoder in encoders_by_type.items():
|
|
229
195
|
encoders_by_class_tuples[encoder] += (type_,)
|
|
230
196
|
|
|
@@ -235,54 +201,49 @@ def encode_by_type(o: typing.Any) -> typing.Any:
|
|
|
235
201
|
return encoder(o)
|
|
236
202
|
|
|
237
203
|
|
|
238
|
-
def update_forward_refs(model:
|
|
204
|
+
def update_forward_refs(model: Type["Model"], **localns: Any) -> None:
|
|
239
205
|
if IS_PYDANTIC_V2:
|
|
240
|
-
model.model_rebuild(raise_errors=False) # type: ignore
|
|
206
|
+
model.model_rebuild(raise_errors=False) # type: ignore[attr-defined]
|
|
241
207
|
else:
|
|
242
208
|
model.update_forward_refs(**localns)
|
|
243
209
|
|
|
244
210
|
|
|
245
211
|
# Mirrors Pydantic's internal typing
|
|
246
|
-
AnyCallable =
|
|
212
|
+
AnyCallable = Callable[..., Any]
|
|
247
213
|
|
|
248
214
|
|
|
249
215
|
def universal_root_validator(
|
|
250
216
|
pre: bool = False,
|
|
251
|
-
) ->
|
|
217
|
+
) -> Callable[[AnyCallable], AnyCallable]:
|
|
252
218
|
def decorator(func: AnyCallable) -> AnyCallable:
|
|
253
219
|
if IS_PYDANTIC_V2:
|
|
254
|
-
return pydantic.model_validator(mode="before" if pre else "after")(func) # type: ignore
|
|
255
|
-
|
|
256
|
-
return pydantic.root_validator(pre=pre)(func) # type: ignore # Pydantic v1
|
|
220
|
+
return cast(AnyCallable, pydantic.model_validator(mode="before" if pre else "after")(func)) # type: ignore[attr-defined]
|
|
221
|
+
return cast(AnyCallable, pydantic.root_validator(pre=pre)(func)) # type: ignore[call-overload]
|
|
257
222
|
|
|
258
223
|
return decorator
|
|
259
224
|
|
|
260
225
|
|
|
261
|
-
def universal_field_validator(field_name: str, pre: bool = False) ->
|
|
226
|
+
def universal_field_validator(field_name: str, pre: bool = False) -> Callable[[AnyCallable], AnyCallable]:
|
|
262
227
|
def decorator(func: AnyCallable) -> AnyCallable:
|
|
263
228
|
if IS_PYDANTIC_V2:
|
|
264
|
-
return pydantic.field_validator(field_name, mode="before" if pre else "after")(func) # type: ignore
|
|
265
|
-
|
|
266
|
-
return pydantic.validator(field_name, pre=pre)(func) # type: ignore # Pydantic v1
|
|
229
|
+
return cast(AnyCallable, pydantic.field_validator(field_name, mode="before" if pre else "after")(func)) # type: ignore[attr-defined]
|
|
230
|
+
return cast(AnyCallable, pydantic.validator(field_name, pre=pre)(func))
|
|
267
231
|
|
|
268
232
|
return decorator
|
|
269
233
|
|
|
270
234
|
|
|
271
|
-
PydanticField =
|
|
235
|
+
PydanticField = Union[ModelField, pydantic.fields.FieldInfo]
|
|
272
236
|
|
|
273
237
|
|
|
274
|
-
def _get_model_fields(
|
|
275
|
-
model: typing.Type["Model"],
|
|
276
|
-
) -> typing.Mapping[str, PydanticField]:
|
|
238
|
+
def _get_model_fields(model: Type["Model"]) -> Mapping[str, PydanticField]:
|
|
277
239
|
if IS_PYDANTIC_V2:
|
|
278
|
-
return model.model_fields # type: ignore
|
|
279
|
-
|
|
280
|
-
return model.__fields__ # type: ignore # Pydantic v1
|
|
240
|
+
return cast(Mapping[str, PydanticField], model.model_fields) # type: ignore[attr-defined]
|
|
241
|
+
return cast(Mapping[str, PydanticField], model.__fields__)
|
|
281
242
|
|
|
282
243
|
|
|
283
|
-
def _get_field_default(field: PydanticField) ->
|
|
244
|
+
def _get_field_default(field: PydanticField) -> Any:
|
|
284
245
|
try:
|
|
285
|
-
value = field.get_default() # type: ignore
|
|
246
|
+
value = field.get_default() # type: ignore[union-attr]
|
|
286
247
|
except:
|
|
287
248
|
value = field.default
|
|
288
249
|
if IS_PYDANTIC_V2:
|
sarvamai/environment.py
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
# This file was auto-generated by Fern from our API Definition.
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
class SarvamAIEnvironment
|
|
7
|
-
PRODUCTION
|
|
6
|
+
class SarvamAIEnvironment:
|
|
7
|
+
PRODUCTION: SarvamAIEnvironment
|
|
8
|
+
|
|
9
|
+
def __init__(self, *, base: str, production: str):
|
|
10
|
+
self.base = base
|
|
11
|
+
self.production = production
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
SarvamAIEnvironment.PRODUCTION = SarvamAIEnvironment(base="https://api.sarvam.ai", production="wss://api.sarvam.ai")
|
sarvamai/errors/__init__.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# This file was auto-generated by Fern from our API Definition.
|
|
2
2
|
|
|
3
|
-
from ..core.api_error import ApiError
|
|
4
3
|
import typing
|
|
5
4
|
|
|
5
|
+
from ..core.api_error import ApiError
|
|
6
|
+
|
|
6
7
|
|
|
7
8
|
class BadRequestError(ApiError):
|
|
8
|
-
def __init__(self, body: typing.Optional[typing.Any]):
|
|
9
|
-
super().__init__(status_code=400, body=body)
|
|
9
|
+
def __init__(self, body: typing.Optional[typing.Any], headers: typing.Optional[typing.Dict[str, str]] = None):
|
|
10
|
+
super().__init__(status_code=400, headers=headers, body=body)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# This file was auto-generated by Fern from our API Definition.
|
|
2
2
|
|
|
3
|
-
from ..core.api_error import ApiError
|
|
4
3
|
import typing
|
|
5
4
|
|
|
5
|
+
from ..core.api_error import ApiError
|
|
6
|
+
|
|
6
7
|
|
|
7
8
|
class ForbiddenError(ApiError):
|
|
8
|
-
def __init__(self, body: typing.Optional[typing.Any]):
|
|
9
|
-
super().__init__(status_code=403, body=body)
|
|
9
|
+
def __init__(self, body: typing.Optional[typing.Any], headers: typing.Optional[typing.Dict[str, str]] = None):
|
|
10
|
+
super().__init__(status_code=403, headers=headers, body=body)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# This file was auto-generated by Fern from our API Definition.
|
|
2
2
|
|
|
3
|
-
from ..core.api_error import ApiError
|
|
4
3
|
import typing
|
|
5
4
|
|
|
5
|
+
from ..core.api_error import ApiError
|
|
6
|
+
|
|
6
7
|
|
|
7
8
|
class InternalServerError(ApiError):
|
|
8
|
-
def __init__(self, body: typing.Optional[typing.Any]):
|
|
9
|
-
super().__init__(status_code=500, body=body)
|
|
9
|
+
def __init__(self, body: typing.Optional[typing.Any], headers: typing.Optional[typing.Dict[str, str]] = None):
|
|
10
|
+
super().__init__(status_code=500, headers=headers, body=body)
|