together 1.5.28__tar.gz → 1.5.30__tar.gz

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 (77) hide show
  1. {together-1.5.28 → together-1.5.30}/PKG-INFO +2 -1
  2. {together-1.5.28 → together-1.5.30}/pyproject.toml +2 -1
  3. {together-1.5.28 → together-1.5.30}/src/together/abstract/api_requestor.py +44 -3
  4. {together-1.5.28 → together-1.5.30}/src/together/cli/api/endpoints.py +49 -2
  5. {together-1.5.28 → together-1.5.30}/src/together/resources/audio/__init__.py +9 -0
  6. {together-1.5.28 → together-1.5.30}/src/together/resources/audio/speech.py +8 -2
  7. {together-1.5.28 → together-1.5.30}/src/together/resources/audio/transcriptions.py +20 -2
  8. together-1.5.30/src/together/resources/audio/voices.py +65 -0
  9. {together-1.5.28 → together-1.5.30}/src/together/resources/endpoints.py +98 -7
  10. {together-1.5.28 → together-1.5.30}/src/together/resources/images.py +4 -10
  11. {together-1.5.28 → together-1.5.30}/src/together/types/__init__.py +4 -0
  12. together-1.5.30/src/together/types/audio_speech.py +311 -0
  13. {together-1.5.28 → together-1.5.30}/src/together/types/images.py +0 -2
  14. {together-1.5.28 → together-1.5.30}/src/together/utils/files.py +175 -52
  15. together-1.5.28/src/together/types/audio_speech.py +0 -198
  16. {together-1.5.28 → together-1.5.30}/LICENSE +0 -0
  17. {together-1.5.28 → together-1.5.30}/README.md +0 -0
  18. {together-1.5.28 → together-1.5.30}/src/together/__init__.py +0 -0
  19. {together-1.5.28 → together-1.5.30}/src/together/abstract/__init__.py +0 -0
  20. {together-1.5.28 → together-1.5.30}/src/together/cli/__init__.py +0 -0
  21. {together-1.5.28 → together-1.5.30}/src/together/cli/api/__init__.py +0 -0
  22. {together-1.5.28 → together-1.5.30}/src/together/cli/api/chat.py +0 -0
  23. {together-1.5.28 → together-1.5.30}/src/together/cli/api/completions.py +0 -0
  24. {together-1.5.28 → together-1.5.30}/src/together/cli/api/evaluation.py +0 -0
  25. {together-1.5.28 → together-1.5.30}/src/together/cli/api/files.py +0 -0
  26. {together-1.5.28 → together-1.5.30}/src/together/cli/api/finetune.py +0 -0
  27. {together-1.5.28 → together-1.5.30}/src/together/cli/api/images.py +0 -0
  28. {together-1.5.28 → together-1.5.30}/src/together/cli/api/models.py +0 -0
  29. {together-1.5.28 → together-1.5.30}/src/together/cli/api/utils.py +0 -0
  30. {together-1.5.28 → together-1.5.30}/src/together/cli/cli.py +0 -0
  31. {together-1.5.28 → together-1.5.30}/src/together/client.py +0 -0
  32. {together-1.5.28 → together-1.5.30}/src/together/constants.py +0 -0
  33. {together-1.5.28 → together-1.5.30}/src/together/error.py +0 -0
  34. {together-1.5.28 → together-1.5.30}/src/together/filemanager.py +0 -0
  35. {together-1.5.28 → together-1.5.30}/src/together/legacy/__init__.py +0 -0
  36. {together-1.5.28 → together-1.5.30}/src/together/legacy/base.py +0 -0
  37. {together-1.5.28 → together-1.5.30}/src/together/legacy/complete.py +0 -0
  38. {together-1.5.28 → together-1.5.30}/src/together/legacy/embeddings.py +0 -0
  39. {together-1.5.28 → together-1.5.30}/src/together/legacy/files.py +0 -0
  40. {together-1.5.28 → together-1.5.30}/src/together/legacy/finetune.py +0 -0
  41. {together-1.5.28 → together-1.5.30}/src/together/legacy/images.py +0 -0
  42. {together-1.5.28 → together-1.5.30}/src/together/legacy/models.py +0 -0
  43. {together-1.5.28 → together-1.5.30}/src/together/resources/__init__.py +0 -0
  44. {together-1.5.28 → together-1.5.30}/src/together/resources/audio/translations.py +0 -0
  45. {together-1.5.28 → together-1.5.30}/src/together/resources/batch.py +0 -0
  46. {together-1.5.28 → together-1.5.30}/src/together/resources/chat/__init__.py +0 -0
  47. {together-1.5.28 → together-1.5.30}/src/together/resources/chat/completions.py +0 -0
  48. {together-1.5.28 → together-1.5.30}/src/together/resources/code_interpreter.py +0 -0
  49. {together-1.5.28 → together-1.5.30}/src/together/resources/completions.py +0 -0
  50. {together-1.5.28 → together-1.5.30}/src/together/resources/embeddings.py +0 -0
  51. {together-1.5.28 → together-1.5.30}/src/together/resources/evaluation.py +0 -0
  52. {together-1.5.28 → together-1.5.30}/src/together/resources/files.py +0 -0
  53. {together-1.5.28 → together-1.5.30}/src/together/resources/finetune.py +0 -0
  54. {together-1.5.28 → together-1.5.30}/src/together/resources/models.py +0 -0
  55. {together-1.5.28 → together-1.5.30}/src/together/resources/rerank.py +0 -0
  56. {together-1.5.28 → together-1.5.30}/src/together/resources/videos.py +0 -0
  57. {together-1.5.28 → together-1.5.30}/src/together/together_response.py +0 -0
  58. {together-1.5.28 → together-1.5.30}/src/together/types/abstract.py +0 -0
  59. {together-1.5.28 → together-1.5.30}/src/together/types/batch.py +0 -0
  60. {together-1.5.28 → together-1.5.30}/src/together/types/chat_completions.py +0 -0
  61. {together-1.5.28 → together-1.5.30}/src/together/types/code_interpreter.py +0 -0
  62. {together-1.5.28 → together-1.5.30}/src/together/types/common.py +0 -0
  63. {together-1.5.28 → together-1.5.30}/src/together/types/completions.py +0 -0
  64. {together-1.5.28 → together-1.5.30}/src/together/types/embeddings.py +0 -0
  65. {together-1.5.28 → together-1.5.30}/src/together/types/endpoints.py +0 -0
  66. {together-1.5.28 → together-1.5.30}/src/together/types/error.py +0 -0
  67. {together-1.5.28 → together-1.5.30}/src/together/types/evaluation.py +0 -0
  68. {together-1.5.28 → together-1.5.30}/src/together/types/files.py +0 -0
  69. {together-1.5.28 → together-1.5.30}/src/together/types/finetune.py +0 -0
  70. {together-1.5.28 → together-1.5.30}/src/together/types/models.py +0 -0
  71. {together-1.5.28 → together-1.5.30}/src/together/types/rerank.py +0 -0
  72. {together-1.5.28 → together-1.5.30}/src/together/types/videos.py +0 -0
  73. {together-1.5.28 → together-1.5.30}/src/together/utils/__init__.py +0 -0
  74. {together-1.5.28 → together-1.5.30}/src/together/utils/_log.py +0 -0
  75. {together-1.5.28 → together-1.5.30}/src/together/utils/api_helpers.py +0 -0
  76. {together-1.5.28 → together-1.5.30}/src/together/utils/tools.py +0 -0
  77. {together-1.5.28 → together-1.5.30}/src/together/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: together
3
- Version: 1.5.28
3
+ Version: 1.5.30
4
4
  Summary: Python client for Together's Cloud Platform!
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -17,6 +17,7 @@ Classifier: Programming Language :: Python :: 3.13
17
17
  Classifier: Programming Language :: Python :: 3.14
18
18
  Provides-Extra: pyarrow
19
19
  Requires-Dist: aiohttp (>=3.9.3,<4.0.0)
20
+ Requires-Dist: black (>=25.9.0,<26.0.0)
20
21
  Requires-Dist: click (>=8.1.7,<9.0.0)
21
22
  Requires-Dist: eval-type-backport (>=0.1.3,<0.3.0)
22
23
  Requires-Dist: filelock (>=3.13.1,<4.0.0)
@@ -12,7 +12,7 @@ build-backend = "poetry.masonry.api"
12
12
 
13
13
  [tool.poetry]
14
14
  name = "together"
15
- version = "1.5.28"
15
+ version = "1.5.30"
16
16
  authors = ["Together AI <support@together.ai>"]
17
17
  description = "Python client for Together's Cloud Platform!"
18
18
  readme = "README.md"
@@ -43,6 +43,7 @@ numpy = [
43
43
  { version = ">=1.26.0", python = ">=3.12" },
44
44
  ]
45
45
  pillow = "^11.1.0"
46
+ black = "^25.9.0"
46
47
 
47
48
  [tool.poetry.extras]
48
49
  pyarrow = ["pyarrow"]
@@ -619,14 +619,29 @@ class APIRequestor:
619
619
  ) -> Tuple[TogetherResponse | Iterator[TogetherResponse], bool]:
620
620
  """Returns the response(s) and a bool indicating whether it is a stream."""
621
621
  content_type = result.headers.get("Content-Type", "")
622
+
622
623
  if stream and "text/event-stream" in content_type:
624
+ # SSE format streaming
623
625
  return (
624
626
  self._interpret_response_line(
625
627
  line, result.status_code, result.headers, stream=True
626
628
  )
627
629
  for line in parse_stream(result.iter_lines())
628
630
  ), True
631
+ elif stream and content_type in [
632
+ "audio/wav",
633
+ "audio/mpeg",
634
+ "application/octet-stream",
635
+ ]:
636
+ # Binary audio streaming - return chunks as binary data
637
+ def binary_stream_generator() -> Iterator[TogetherResponse]:
638
+ for chunk in result.iter_content(chunk_size=8192):
639
+ if chunk: # Skip empty chunks
640
+ yield TogetherResponse(chunk, dict(result.headers))
641
+
642
+ return binary_stream_generator(), True
629
643
  else:
644
+ # Non-streaming response
630
645
  if content_type in ["application/octet-stream", "audio/wav", "audio/mpeg"]:
631
646
  content = result.content
632
647
  else:
@@ -648,23 +663,49 @@ class APIRequestor:
648
663
  | tuple[TogetherResponse, bool]
649
664
  ):
650
665
  """Returns the response(s) and a bool indicating whether it is a stream."""
651
- if stream and "text/event-stream" in result.headers.get("Content-Type", ""):
666
+ content_type = result.headers.get("Content-Type", "")
667
+
668
+ if stream and "text/event-stream" in content_type:
669
+ # SSE format streaming
652
670
  return (
653
671
  self._interpret_response_line(
654
672
  line, result.status, result.headers, stream=True
655
673
  )
656
674
  async for line in parse_stream_async(result.content)
657
675
  ), True
676
+ elif stream and content_type in [
677
+ "audio/wav",
678
+ "audio/mpeg",
679
+ "application/octet-stream",
680
+ ]:
681
+ # Binary audio streaming - return chunks as binary data
682
+ async def binary_stream_generator() -> (
683
+ AsyncGenerator[TogetherResponse, None]
684
+ ):
685
+ async for chunk in result.content.iter_chunked(8192):
686
+ if chunk: # Skip empty chunks
687
+ yield TogetherResponse(chunk, dict(result.headers))
688
+
689
+ return binary_stream_generator(), True
658
690
  else:
691
+ # Non-streaming response
659
692
  try:
660
- await result.read()
693
+ content = await result.read()
661
694
  except (aiohttp.ServerTimeoutError, asyncio.TimeoutError) as e:
662
695
  raise error.Timeout("Request timed out") from e
663
696
  except aiohttp.ClientError as e:
664
697
  utils.log_warn(e, body=result.content)
698
+
699
+ if content_type in ["application/octet-stream", "audio/wav", "audio/mpeg"]:
700
+ # Binary content - keep as bytes
701
+ response_content: str | bytes = content
702
+ else:
703
+ # Text content - decode to string
704
+ response_content = content.decode("utf-8")
705
+
665
706
  return (
666
707
  self._interpret_response_line(
667
- (await result.read()).decode("utf-8"),
708
+ response_content,
668
709
  result.status,
669
710
  result.headers,
670
711
  stream=False,
@@ -132,6 +132,10 @@ def endpoints(ctx: click.Context) -> None:
132
132
  type=int,
133
133
  help="Number of minutes of inactivity after which the endpoint will be automatically stopped. Set to 0 to disable.",
134
134
  )
135
+ @click.option(
136
+ "--availability-zone",
137
+ help="Start endpoint in specified availability zone (e.g., us-central-4b)",
138
+ )
135
139
  @click.option(
136
140
  "--wait",
137
141
  is_flag=True,
@@ -152,6 +156,7 @@ def create(
152
156
  no_speculative_decoding: bool,
153
157
  no_auto_start: bool,
154
158
  inactive_timeout: int | None,
159
+ availability_zone: str | None,
155
160
  wait: bool,
156
161
  ) -> None:
157
162
  """Create a new dedicated inference endpoint."""
@@ -177,6 +182,7 @@ def create(
177
182
  disable_speculative_decoding=no_speculative_decoding,
178
183
  state="STOPPED" if no_auto_start else "STARTED",
179
184
  inactive_timeout=inactive_timeout,
185
+ availability_zone=availability_zone,
180
186
  )
181
187
  except InvalidRequestError as e:
182
188
  print_api_error(e)
@@ -203,6 +209,8 @@ def create(
203
209
  click.echo(" Auto-start: disabled", err=True)
204
210
  if inactive_timeout is not None:
205
211
  click.echo(f" Inactive timeout: {inactive_timeout} minutes", err=True)
212
+ if availability_zone:
213
+ click.echo(f" Availability zone: {availability_zone}", err=True)
206
214
 
207
215
  click.echo(f"Endpoint created successfully, id: {response.id}", err=True)
208
216
 
@@ -337,13 +345,30 @@ def delete(client: Together, endpoint_id: str) -> None:
337
345
  type=click.Choice(["dedicated", "serverless"]),
338
346
  help="Filter by endpoint type",
339
347
  )
348
+ @click.option(
349
+ "--mine",
350
+ type=click.BOOL,
351
+ default=None,
352
+ help="true (only mine), default=all",
353
+ )
354
+ @click.option(
355
+ "--usage-type",
356
+ type=click.Choice(["on-demand", "reserved"]),
357
+ help="Filter by endpoint usage type",
358
+ )
340
359
  @click.pass_obj
341
360
  @handle_api_errors
342
361
  def list(
343
- client: Together, json: bool, type: Literal["dedicated", "serverless"] | None
362
+ client: Together,
363
+ json: bool,
364
+ type: Literal["dedicated", "serverless"] | None,
365
+ usage_type: Literal["on-demand", "reserved"] | None,
366
+ mine: bool | None,
344
367
  ) -> None:
345
368
  """List all inference endpoints (includes both dedicated and serverless endpoints)."""
346
- endpoints: List[ListEndpoint] = client.endpoints.list(type=type)
369
+ endpoints: List[ListEndpoint] = client.endpoints.list(
370
+ type=type, usage_type=usage_type, mine=mine
371
+ )
347
372
 
348
373
  if not endpoints:
349
374
  click.echo("No dedicated endpoints found", err=True)
@@ -432,3 +457,25 @@ def update(
432
457
 
433
458
  click.echo("Successfully updated endpoint", err=True)
434
459
  click.echo(endpoint_id)
460
+
461
+
462
+ @endpoints.command()
463
+ @click.option("--json", is_flag=True, help="Print output in JSON format")
464
+ @click.pass_obj
465
+ @handle_api_errors
466
+ def availability_zones(client: Together, json: bool) -> None:
467
+ """List all availability zones."""
468
+ avzones = client.endpoints.list_avzones()
469
+
470
+ if not avzones:
471
+ click.echo("No availability zones found", err=True)
472
+ return
473
+
474
+ if json:
475
+ import json as json_lib
476
+
477
+ click.echo(json_lib.dumps({"avzones": avzones}, indent=2))
478
+ else:
479
+ click.echo("Available zones:", err=True)
480
+ for availability_zone in sorted(avzones):
481
+ click.echo(f" {availability_zone}")
@@ -3,6 +3,7 @@ from functools import cached_property
3
3
  from together.resources.audio.speech import AsyncSpeech, Speech
4
4
  from together.resources.audio.transcriptions import AsyncTranscriptions, Transcriptions
5
5
  from together.resources.audio.translations import AsyncTranslations, Translations
6
+ from together.resources.audio.voices import AsyncVoices, Voices
6
7
  from together.types import (
7
8
  TogetherClient,
8
9
  )
@@ -24,6 +25,10 @@ class Audio:
24
25
  def translations(self) -> Translations:
25
26
  return Translations(self._client)
26
27
 
28
+ @cached_property
29
+ def voices(self) -> Voices:
30
+ return Voices(self._client)
31
+
27
32
 
28
33
  class AsyncAudio:
29
34
  def __init__(self, client: TogetherClient) -> None:
@@ -40,3 +45,7 @@ class AsyncAudio:
40
45
  @cached_property
41
46
  def translations(self) -> AsyncTranslations:
42
47
  return AsyncTranslations(self._client)
48
+
49
+ @cached_property
50
+ def voices(self) -> AsyncVoices:
51
+ return AsyncVoices(self._client)
@@ -30,7 +30,7 @@ class Speech:
30
30
  response_format: str = "wav",
31
31
  language: str = "en",
32
32
  response_encoding: str = "pcm_f32le",
33
- sample_rate: int = 44100,
33
+ sample_rate: int | None = None,
34
34
  stream: bool = False,
35
35
  **kwargs: Any,
36
36
  ) -> AudioSpeechStreamResponse:
@@ -49,7 +49,7 @@ class Speech:
49
49
  response_encoding (str, optional): Audio encoding of response.
50
50
  Defaults to "pcm_f32le".
51
51
  sample_rate (int, optional): Sampling rate to use for the output audio.
52
- Defaults to 44100.
52
+ Defaults to None. If not provided, the default sampling rate for the model will be used.
53
53
  stream (bool, optional): If true, output is streamed for several characters at a time.
54
54
  Defaults to False.
55
55
 
@@ -57,6 +57,12 @@ class Speech:
57
57
  Union[bytes, Iterator[AudioSpeechStreamChunk]]: The generated audio as bytes or an iterator over audio stream chunks.
58
58
  """
59
59
 
60
+ if sample_rate is None:
61
+ if "cartesia" in model:
62
+ sample_rate = 44100
63
+ else:
64
+ sample_rate = 24000
65
+
60
66
  requestor = api_requestor.APIRequestor(
61
67
  client=self._client,
62
68
  )
@@ -30,6 +30,7 @@ class Transcriptions:
30
30
  timestamp_granularities: Optional[
31
31
  Union[str, AudioTimestampGranularities]
32
32
  ] = None,
33
+ diarize: bool = False,
33
34
  **kwargs: Any,
34
35
  ) -> Union[AudioTranscriptionResponse, AudioTranscriptionVerboseResponse]:
35
36
  """
@@ -52,7 +53,11 @@ class Transcriptions:
52
53
  timestamp_granularities: The timestamp granularities to populate for this
53
54
  transcription. response_format must be set verbose_json to use timestamp
54
55
  granularities. Either or both of these options are supported: word, or segment.
55
-
56
+ diarize: Whether to enable speaker diarization. When enabled, you will get the speaker id for each word in the transcription.
57
+ In the response, in the words array, you will get the speaker id for each word.
58
+ In addition, we also return the speaker_segments array which contains the speaker id for each speaker segment along with the start and end time of the segment along with all the words in the segment.
59
+ You can use the speaker_id to group the words by speaker.
60
+ You can use the speaker_segments to get the start and end time of each speaker segment.
56
61
  Returns:
57
62
  The transcribed text in the requested format.
58
63
  """
@@ -103,6 +108,9 @@ class Transcriptions:
103
108
  else timestamp_granularities
104
109
  )
105
110
 
111
+ if diarize:
112
+ params_data["diarize"] = diarize
113
+
106
114
  # Add any additional kwargs
107
115
  # Convert boolean values to lowercase strings for proper form encoding
108
116
  for key, value in kwargs.items():
@@ -135,6 +143,7 @@ class Transcriptions:
135
143
  if (
136
144
  response_format == "verbose_json"
137
145
  or response_format == AudioTranscriptionResponseFormat.VERBOSE_JSON
146
+ or diarize
138
147
  ):
139
148
  # Create response with model validation that preserves extra fields
140
149
  return AudioTranscriptionVerboseResponse.model_validate(response.data)
@@ -158,6 +167,7 @@ class AsyncTranscriptions:
158
167
  timestamp_granularities: Optional[
159
168
  Union[str, AudioTimestampGranularities]
160
169
  ] = None,
170
+ diarize: bool = False,
161
171
  **kwargs: Any,
162
172
  ) -> Union[AudioTranscriptionResponse, AudioTranscriptionVerboseResponse]:
163
173
  """
@@ -180,7 +190,11 @@ class AsyncTranscriptions:
180
190
  timestamp_granularities: The timestamp granularities to populate for this
181
191
  transcription. response_format must be set verbose_json to use timestamp
182
192
  granularities. Either or both of these options are supported: word, or segment.
183
-
193
+ diarize: Whether to enable speaker diarization. When enabled, you will get the speaker id for each word in the transcription.
194
+ In the response, in the words array, you will get the speaker id for each word.
195
+ In addition, we also return the speaker_segments array which contains the speaker id for each speaker segment along with the start and end time of the segment along with all the words in the segment.
196
+ You can use the speaker_id to group the words by speaker.
197
+ You can use the speaker_segments to get the start and end time of each speaker segment.
184
198
  Returns:
185
199
  The transcribed text in the requested format.
186
200
  """
@@ -239,6 +253,9 @@ class AsyncTranscriptions:
239
253
  )
240
254
  )
241
255
 
256
+ if diarize:
257
+ params_data["diarize"] = diarize
258
+
242
259
  # Add any additional kwargs
243
260
  # Convert boolean values to lowercase strings for proper form encoding
244
261
  for key, value in kwargs.items():
@@ -271,6 +288,7 @@ class AsyncTranscriptions:
271
288
  if (
272
289
  response_format == "verbose_json"
273
290
  or response_format == AudioTranscriptionResponseFormat.VERBOSE_JSON
291
+ or diarize
274
292
  ):
275
293
  # Create response with model validation that preserves extra fields
276
294
  return AudioTranscriptionVerboseResponse.model_validate(response.data)
@@ -0,0 +1,65 @@
1
+ from __future__ import annotations
2
+
3
+ from together.abstract import api_requestor
4
+ from together.together_response import TogetherResponse
5
+ from together.types import (
6
+ TogetherClient,
7
+ TogetherRequest,
8
+ VoiceListResponse,
9
+ )
10
+
11
+
12
+ class Voices:
13
+ def __init__(self, client: TogetherClient) -> None:
14
+ self._client = client
15
+
16
+ def list(self) -> VoiceListResponse:
17
+ """
18
+ Method to return list of available voices on the API
19
+
20
+ Returns:
21
+ VoiceListResponse: Response containing models and their available voices
22
+ """
23
+ requestor = api_requestor.APIRequestor(
24
+ client=self._client,
25
+ )
26
+
27
+ response, _, _ = requestor.request(
28
+ options=TogetherRequest(
29
+ method="GET",
30
+ url="voices",
31
+ ),
32
+ stream=False,
33
+ )
34
+
35
+ assert isinstance(response, TogetherResponse)
36
+
37
+ return VoiceListResponse(**response.data)
38
+
39
+
40
+ class AsyncVoices:
41
+ def __init__(self, client: TogetherClient) -> None:
42
+ self._client = client
43
+
44
+ async def list(self) -> VoiceListResponse:
45
+ """
46
+ Async method to return list of available voices on the API
47
+
48
+ Returns:
49
+ VoiceListResponse: Response containing models and their available voices
50
+ """
51
+ requestor = api_requestor.APIRequestor(
52
+ client=self._client,
53
+ )
54
+
55
+ response, _, _ = await requestor.arequest(
56
+ options=TogetherRequest(
57
+ method="GET",
58
+ url="voices",
59
+ ),
60
+ stream=False,
61
+ )
62
+
63
+ assert isinstance(response, TogetherResponse)
64
+
65
+ return VoiceListResponse(**response.data)
@@ -13,13 +13,18 @@ class Endpoints:
13
13
  self._client = client
14
14
 
15
15
  def list(
16
- self, type: Optional[Literal["dedicated", "serverless"]] = None
16
+ self,
17
+ type: Optional[Literal["dedicated", "serverless"]] = None,
18
+ usage_type: Optional[Literal["on-demand", "reserved"]] = None,
19
+ mine: Optional[bool] = None,
17
20
  ) -> List[ListEndpoint]:
18
21
  """
19
- List all endpoints, can be filtered by type.
22
+ List all endpoints, can be filtered by endpoint type and ownership.
20
23
 
21
24
  Args:
22
- type (str, optional): Filter endpoints by type ("dedicated" or "serverless"). Defaults to None.
25
+ type (str, optional): Filter endpoints by endpoint type ("dedicated" or "serverless"). Defaults to None.
26
+ usage_type (str, optional): Filter endpoints by usage type ("on-demand" or "reserved"). Defaults to None.
27
+ mine (bool, optional): If True, return only endpoints owned by the caller. Defaults to None.
23
28
 
24
29
  Returns:
25
30
  List[ListEndpoint]: List of endpoint objects
@@ -28,9 +33,20 @@ class Endpoints:
28
33
  client=self._client,
29
34
  )
30
35
 
31
- params = {}
36
+ params: Dict[
37
+ str,
38
+ Union[
39
+ Literal["dedicated", "serverless"],
40
+ Literal["on-demand", "reserved"],
41
+ bool,
42
+ ],
43
+ ] = {}
32
44
  if type is not None:
33
45
  params["type"] = type
46
+ if usage_type is not None:
47
+ params["usage_type"] = usage_type
48
+ if mine is not None:
49
+ params["mine"] = mine
34
50
 
35
51
  response, _, _ = requestor.request(
36
52
  options=TogetherRequest(
@@ -60,6 +76,7 @@ class Endpoints:
60
76
  disable_speculative_decoding: bool = True,
61
77
  state: Literal["STARTED", "STOPPED"] = "STARTED",
62
78
  inactive_timeout: Optional[int] = None,
79
+ availability_zone: Optional[str] = None,
63
80
  ) -> DedicatedEndpoint:
64
81
  """
65
82
  Create a new dedicated endpoint.
@@ -74,6 +91,7 @@ class Endpoints:
74
91
  disable_speculative_decoding (bool, optional): Whether to disable speculative decoding. Defaults to False.
75
92
  state (str, optional): The desired state of the endpoint. Defaults to "STARTED".
76
93
  inactive_timeout (int, optional): The number of minutes of inactivity after which the endpoint will be automatically stopped. Set to 0 to disable automatic timeout.
94
+ availability_zone (str, optional): Start endpoint in specified availability zone (e.g., us-central-4b).
77
95
 
78
96
  Returns:
79
97
  DedicatedEndpoint: Object containing endpoint information
@@ -100,6 +118,9 @@ class Endpoints:
100
118
  if inactive_timeout is not None:
101
119
  data["inactive_timeout"] = inactive_timeout
102
120
 
121
+ if availability_zone is not None:
122
+ data["availability_zone"] = availability_zone
123
+
103
124
  response, _, _ = requestor.request(
104
125
  options=TogetherRequest(
105
126
  method="POST",
@@ -257,19 +278,49 @@ class Endpoints:
257
278
 
258
279
  return [HardwareWithStatus(**item) for item in response.data["data"]]
259
280
 
281
+ def list_avzones(self) -> List[str]:
282
+ """
283
+ List all available availability zones.
284
+
285
+ Returns:
286
+ List[str]: List of unique availability zones
287
+ """
288
+ requestor = api_requestor.APIRequestor(
289
+ client=self._client,
290
+ )
291
+
292
+ response, _, _ = requestor.request(
293
+ options=TogetherRequest(
294
+ method="GET",
295
+ url="clusters/availability-zones",
296
+ ),
297
+ stream=False,
298
+ )
299
+
300
+ assert isinstance(response, TogetherResponse)
301
+ assert isinstance(response.data, dict)
302
+ assert isinstance(response.data["avzones"], list)
303
+
304
+ return response.data["avzones"]
305
+
260
306
 
261
307
  class AsyncEndpoints:
262
308
  def __init__(self, client: TogetherClient) -> None:
263
309
  self._client = client
264
310
 
265
311
  async def list(
266
- self, type: Optional[Literal["dedicated", "serverless"]] = None
312
+ self,
313
+ type: Optional[Literal["dedicated", "serverless"]] = None,
314
+ usage_type: Optional[Literal["on-demand", "reserved"]] = None,
315
+ mine: Optional[bool] = None,
267
316
  ) -> List[ListEndpoint]:
268
317
  """
269
- List all endpoints, can be filtered by type.
318
+ List all endpoints, can be filtered by type and ownership.
270
319
 
271
320
  Args:
272
321
  type (str, optional): Filter endpoints by type ("dedicated" or "serverless"). Defaults to None.
322
+ usage_type (str, optional): Filter endpoints by usage type ("on-demand" or "reserved"). Defaults to None.
323
+ mine (bool, optional): If True, return only endpoints owned by the caller. Defaults to None.
273
324
 
274
325
  Returns:
275
326
  List[ListEndpoint]: List of endpoint objects
@@ -278,9 +329,20 @@ class AsyncEndpoints:
278
329
  client=self._client,
279
330
  )
280
331
 
281
- params = {}
332
+ params: Dict[
333
+ str,
334
+ Union[
335
+ Literal["dedicated", "serverless"],
336
+ Literal["on-demand", "reserved"],
337
+ bool,
338
+ ],
339
+ ] = {}
282
340
  if type is not None:
283
341
  params["type"] = type
342
+ if usage_type is not None:
343
+ params["usage_type"] = usage_type
344
+ if mine is not None:
345
+ params["mine"] = mine
284
346
 
285
347
  response, _, _ = await requestor.arequest(
286
348
  options=TogetherRequest(
@@ -308,6 +370,7 @@ class AsyncEndpoints:
308
370
  disable_speculative_decoding: bool = True,
309
371
  state: Literal["STARTED", "STOPPED"] = "STARTED",
310
372
  inactive_timeout: Optional[int] = None,
373
+ availability_zone: Optional[str] = None,
311
374
  ) -> DedicatedEndpoint:
312
375
  """
313
376
  Create a new dedicated endpoint.
@@ -348,6 +411,9 @@ class AsyncEndpoints:
348
411
  if inactive_timeout is not None:
349
412
  data["inactive_timeout"] = inactive_timeout
350
413
 
414
+ if availability_zone is not None:
415
+ data["availability_zone"] = availability_zone
416
+
351
417
  response, _, _ = await requestor.arequest(
352
418
  options=TogetherRequest(
353
419
  method="POST",
@@ -506,3 +572,28 @@ class AsyncEndpoints:
506
572
  assert isinstance(response.data["data"], list)
507
573
 
508
574
  return [HardwareWithStatus(**item) for item in response.data["data"]]
575
+
576
+ async def list_avzones(self) -> List[str]:
577
+ """
578
+ List all availability zones.
579
+
580
+ Returns:
581
+ List[str]: List of unique availability zones
582
+ """
583
+ requestor = api_requestor.APIRequestor(
584
+ client=self._client,
585
+ )
586
+
587
+ response, _, _ = await requestor.arequest(
588
+ options=TogetherRequest(
589
+ method="GET",
590
+ url="clusters/availability-zones",
591
+ ),
592
+ stream=False,
593
+ )
594
+
595
+ assert isinstance(response, TogetherResponse)
596
+ assert isinstance(response.data, dict)
597
+ assert isinstance(response.data["avzones"], list)
598
+
599
+ return response.data["avzones"]
@@ -21,7 +21,6 @@ class Images:
21
21
  *,
22
22
  prompt: str,
23
23
  model: str,
24
- steps: int | None = 20,
25
24
  seed: int | None = None,
26
25
  n: int | None = 1,
27
26
  height: int | None = 1024,
@@ -37,8 +36,6 @@ class Images:
37
36
 
38
37
  model (str, optional): The model to use for image generation.
39
38
 
40
- steps (int, optional): Number of generation steps. Defaults to 20
41
-
42
39
  seed (int, optional): Seed used for generation. Can be used to reproduce image generations.
43
40
  Defaults to None.
44
41
 
@@ -51,7 +48,8 @@ class Images:
51
48
  negative_prompt (str, optional): The prompt or prompts not to guide the image generation.
52
49
  Defaults to None
53
50
 
54
- image_base64: (str, optional): Reference image used for generation. Defaults to None.
51
+ **kwargs: Additional parameters like steps (int, optional): Number of generation steps,
52
+ image_base64 (str, optional): Reference image used for generation, etc.
55
53
 
56
54
  Returns:
57
55
  ImageResponse: Object containing image data
@@ -64,7 +62,6 @@ class Images:
64
62
  parameter_payload = ImageRequest(
65
63
  prompt=prompt,
66
64
  model=model,
67
- steps=steps,
68
65
  seed=seed,
69
66
  n=n,
70
67
  height=height,
@@ -96,7 +93,6 @@ class AsyncImages:
96
93
  *,
97
94
  prompt: str,
98
95
  model: str,
99
- steps: int | None = 20,
100
96
  seed: int | None = None,
101
97
  n: int | None = 1,
102
98
  height: int | None = 1024,
@@ -112,8 +108,6 @@ class AsyncImages:
112
108
 
113
109
  model (str, optional): The model to use for image generation.
114
110
 
115
- steps (int, optional): Number of generation steps. Defaults to 20
116
-
117
111
  seed (int, optional): Seed used for generation. Can be used to reproduce image generations.
118
112
  Defaults to None.
119
113
 
@@ -126,7 +120,8 @@ class AsyncImages:
126
120
  negative_prompt (str, optional): The prompt or prompts not to guide the image generation.
127
121
  Defaults to None
128
122
 
129
- image_base64: (str, optional): Reference image used for generation. Defaults to None.
123
+ **kwargs: Additional parameters like steps (int, optional): Number of generation steps,
124
+ image_base64 (str, optional): Reference image used for generation, etc.
130
125
 
131
126
  Returns:
132
127
  ImageResponse: Object containing image data
@@ -139,7 +134,6 @@ class AsyncImages:
139
134
  parameter_payload = ImageRequest(
140
135
  prompt=prompt,
141
136
  model=model,
142
- steps=steps,
143
137
  seed=seed,
144
138
  n=n,
145
139
  height=height,
@@ -15,6 +15,8 @@ from together.types.audio_speech import (
15
15
  AudioTranslationVerboseResponse,
16
16
  AudioTranscriptionResponseFormat,
17
17
  AudioTimestampGranularities,
18
+ ModelVoices,
19
+ VoiceListResponse,
18
20
  )
19
21
  from together.types.chat_completions import (
20
22
  ChatCompletionChunk,
@@ -140,6 +142,8 @@ __all__ = [
140
142
  "AudioTranslationVerboseResponse",
141
143
  "AudioTranscriptionResponseFormat",
142
144
  "AudioTimestampGranularities",
145
+ "ModelVoices",
146
+ "VoiceListResponse",
143
147
  "DedicatedEndpoint",
144
148
  "ListEndpoint",
145
149
  "Autoscaling",