together 1.5.35__py3-none-any.whl → 2.0.0a7__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.
- together/__init__.py +101 -114
- together/_base_client.py +1995 -0
- together/_client.py +1033 -0
- together/_compat.py +219 -0
- together/_constants.py +14 -0
- together/_exceptions.py +108 -0
- together/_files.py +123 -0
- together/_models.py +857 -0
- together/_qs.py +150 -0
- together/_resource.py +43 -0
- together/_response.py +830 -0
- together/_streaming.py +370 -0
- together/_types.py +260 -0
- together/_utils/__init__.py +64 -0
- together/_utils/_compat.py +45 -0
- together/_utils/_datetime_parse.py +136 -0
- together/_utils/_logs.py +25 -0
- together/_utils/_proxy.py +65 -0
- together/_utils/_reflection.py +42 -0
- together/_utils/_resources_proxy.py +24 -0
- together/_utils/_streams.py +12 -0
- together/_utils/_sync.py +58 -0
- together/_utils/_transform.py +457 -0
- together/_utils/_typing.py +156 -0
- together/_utils/_utils.py +421 -0
- together/_version.py +4 -0
- together/lib/.keep +4 -0
- together/lib/__init__.py +23 -0
- together/{cli → lib/cli}/api/endpoints.py +66 -84
- together/{cli/api/evaluation.py → lib/cli/api/evals.py} +152 -43
- together/{cli → lib/cli}/api/files.py +20 -17
- together/{cli/api/finetune.py → lib/cli/api/fine_tuning.py} +116 -172
- together/{cli → lib/cli}/api/models.py +34 -27
- together/lib/cli/api/utils.py +50 -0
- together/{cli → lib/cli}/cli.py +16 -26
- together/{constants.py → lib/constants.py} +11 -24
- together/lib/resources/__init__.py +11 -0
- together/lib/resources/files.py +999 -0
- together/lib/resources/fine_tuning.py +280 -0
- together/lib/resources/models.py +35 -0
- together/lib/types/__init__.py +13 -0
- together/lib/types/error.py +9 -0
- together/lib/types/fine_tuning.py +397 -0
- together/{utils → lib/utils}/__init__.py +6 -14
- together/{utils → lib/utils}/_log.py +11 -16
- together/{utils → lib/utils}/files.py +90 -288
- together/lib/utils/serializer.py +10 -0
- together/{utils → lib/utils}/tools.py +19 -55
- together/resources/__init__.py +225 -39
- together/resources/audio/__init__.py +72 -48
- together/resources/audio/audio.py +198 -0
- together/resources/audio/speech.py +574 -128
- together/resources/audio/transcriptions.py +247 -261
- together/resources/audio/translations.py +221 -241
- together/resources/audio/voices.py +111 -41
- together/resources/batches.py +417 -0
- together/resources/chat/__init__.py +30 -21
- together/resources/chat/chat.py +102 -0
- together/resources/chat/completions.py +1063 -263
- together/resources/code_interpreter/__init__.py +33 -0
- together/resources/code_interpreter/code_interpreter.py +258 -0
- together/resources/code_interpreter/sessions.py +135 -0
- together/resources/completions.py +884 -225
- together/resources/embeddings.py +172 -68
- together/resources/endpoints.py +589 -490
- together/resources/evals.py +452 -0
- together/resources/files.py +397 -129
- together/resources/fine_tuning.py +1033 -0
- together/resources/hardware.py +181 -0
- together/resources/images.py +258 -104
- together/resources/jobs.py +214 -0
- together/resources/models.py +223 -193
- together/resources/rerank.py +190 -92
- together/resources/videos.py +286 -214
- together/types/__init__.py +66 -167
- together/types/audio/__init__.py +10 -0
- together/types/audio/speech_create_params.py +75 -0
- together/types/audio/transcription_create_params.py +54 -0
- together/types/audio/transcription_create_response.py +111 -0
- together/types/audio/translation_create_params.py +40 -0
- together/types/audio/translation_create_response.py +70 -0
- together/types/audio/voice_list_response.py +23 -0
- together/types/audio_speech_stream_chunk.py +16 -0
- together/types/autoscaling.py +13 -0
- together/types/autoscaling_param.py +15 -0
- together/types/batch_create_params.py +24 -0
- together/types/batch_create_response.py +14 -0
- together/types/batch_job.py +45 -0
- together/types/batch_list_response.py +10 -0
- together/types/chat/__init__.py +18 -0
- together/types/chat/chat_completion.py +60 -0
- together/types/chat/chat_completion_chunk.py +61 -0
- together/types/chat/chat_completion_structured_message_image_url_param.py +18 -0
- together/types/chat/chat_completion_structured_message_text_param.py +13 -0
- together/types/chat/chat_completion_structured_message_video_url_param.py +18 -0
- together/types/chat/chat_completion_usage.py +13 -0
- together/types/chat/chat_completion_warning.py +9 -0
- together/types/chat/completion_create_params.py +329 -0
- together/types/code_interpreter/__init__.py +5 -0
- together/types/code_interpreter/session_list_response.py +31 -0
- together/types/code_interpreter_execute_params.py +45 -0
- together/types/completion.py +42 -0
- together/types/completion_chunk.py +66 -0
- together/types/completion_create_params.py +138 -0
- together/types/dedicated_endpoint.py +44 -0
- together/types/embedding.py +24 -0
- together/types/embedding_create_params.py +31 -0
- together/types/endpoint_create_params.py +43 -0
- together/types/endpoint_list_avzones_response.py +11 -0
- together/types/endpoint_list_params.py +18 -0
- together/types/endpoint_list_response.py +41 -0
- together/types/endpoint_update_params.py +27 -0
- together/types/eval_create_params.py +263 -0
- together/types/eval_create_response.py +16 -0
- together/types/eval_list_params.py +21 -0
- together/types/eval_list_response.py +10 -0
- together/types/eval_status_response.py +100 -0
- together/types/evaluation_job.py +139 -0
- together/types/execute_response.py +108 -0
- together/types/file_delete_response.py +13 -0
- together/types/file_list.py +12 -0
- together/types/file_purpose.py +9 -0
- together/types/file_response.py +31 -0
- together/types/file_type.py +7 -0
- together/types/fine_tuning_cancel_response.py +194 -0
- together/types/fine_tuning_content_params.py +24 -0
- together/types/fine_tuning_delete_params.py +11 -0
- together/types/fine_tuning_delete_response.py +12 -0
- together/types/fine_tuning_list_checkpoints_response.py +21 -0
- together/types/fine_tuning_list_events_response.py +12 -0
- together/types/fine_tuning_list_response.py +199 -0
- together/types/finetune_event.py +41 -0
- together/types/finetune_event_type.py +33 -0
- together/types/finetune_response.py +177 -0
- together/types/hardware_list_params.py +16 -0
- together/types/hardware_list_response.py +58 -0
- together/types/image_data_b64.py +15 -0
- together/types/image_data_url.py +15 -0
- together/types/image_file.py +23 -0
- together/types/image_generate_params.py +85 -0
- together/types/job_list_response.py +47 -0
- together/types/job_retrieve_response.py +43 -0
- together/types/log_probs.py +18 -0
- together/types/model_list_response.py +10 -0
- together/types/model_object.py +42 -0
- together/types/model_upload_params.py +36 -0
- together/types/model_upload_response.py +23 -0
- together/types/rerank_create_params.py +36 -0
- together/types/rerank_create_response.py +36 -0
- together/types/tool_choice.py +23 -0
- together/types/tool_choice_param.py +23 -0
- together/types/tools_param.py +23 -0
- together/types/training_method_dpo.py +22 -0
- together/types/training_method_sft.py +18 -0
- together/types/video_create_params.py +86 -0
- together/types/video_create_response.py +10 -0
- together/types/video_job.py +57 -0
- together-2.0.0a7.dist-info/METADATA +730 -0
- together-2.0.0a7.dist-info/RECORD +165 -0
- {together-1.5.35.dist-info → together-2.0.0a7.dist-info}/WHEEL +1 -1
- together-2.0.0a7.dist-info/entry_points.txt +2 -0
- {together-1.5.35.dist-info → together-2.0.0a7.dist-info}/licenses/LICENSE +1 -1
- together/abstract/api_requestor.py +0 -770
- together/cli/api/chat.py +0 -298
- together/cli/api/completions.py +0 -119
- together/cli/api/images.py +0 -93
- together/cli/api/utils.py +0 -139
- together/client.py +0 -186
- together/error.py +0 -194
- together/filemanager.py +0 -635
- together/legacy/__init__.py +0 -0
- together/legacy/base.py +0 -27
- together/legacy/complete.py +0 -93
- together/legacy/embeddings.py +0 -27
- together/legacy/files.py +0 -146
- together/legacy/finetune.py +0 -177
- together/legacy/images.py +0 -27
- together/legacy/models.py +0 -44
- together/resources/batch.py +0 -165
- together/resources/code_interpreter.py +0 -82
- together/resources/evaluation.py +0 -808
- together/resources/finetune.py +0 -1388
- together/together_response.py +0 -50
- together/types/abstract.py +0 -26
- together/types/audio_speech.py +0 -311
- together/types/batch.py +0 -54
- together/types/chat_completions.py +0 -210
- together/types/code_interpreter.py +0 -57
- together/types/common.py +0 -67
- together/types/completions.py +0 -107
- together/types/embeddings.py +0 -35
- together/types/endpoints.py +0 -123
- together/types/error.py +0 -16
- together/types/evaluation.py +0 -93
- together/types/files.py +0 -93
- together/types/finetune.py +0 -465
- together/types/images.py +0 -42
- together/types/models.py +0 -96
- together/types/rerank.py +0 -43
- together/types/videos.py +0 -69
- together/utils/api_helpers.py +0 -124
- together/version.py +0 -6
- together-1.5.35.dist-info/METADATA +0 -583
- together-1.5.35.dist-info/RECORD +0 -77
- together-1.5.35.dist-info/entry_points.txt +0 -3
- /together/{abstract → lib/cli}/__init__.py +0 -0
- /together/{cli → lib/cli/api}/__init__.py +0 -0
- /together/{cli/api/__init__.py → py.typed} +0 -0
|
@@ -1,34 +1,30 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import json
|
|
4
3
|
import sys
|
|
4
|
+
import json
|
|
5
|
+
from typing import Any, Dict, Literal, TypeVar, Callable, cast
|
|
5
6
|
from functools import wraps
|
|
6
|
-
from typing import Any, Callable, Dict, List, Literal, TypeVar, Union
|
|
7
7
|
|
|
8
8
|
import click
|
|
9
9
|
|
|
10
|
-
from together import Together
|
|
11
|
-
from together.
|
|
12
|
-
from together.
|
|
10
|
+
from together import Together, omit
|
|
11
|
+
from together.types import DedicatedEndpoint
|
|
12
|
+
from together._exceptions import APIError
|
|
13
|
+
from together.lib.utils.serializer import datetime_serializer
|
|
14
|
+
from together.types.endpoint_list_response import Data as DedicatedEndpointListItem
|
|
13
15
|
|
|
14
16
|
|
|
15
|
-
def print_endpoint(
|
|
16
|
-
endpoint: Union[DedicatedEndpoint, ListEndpoint],
|
|
17
|
-
) -> None:
|
|
17
|
+
def print_endpoint(endpoint: DedicatedEndpoint | DedicatedEndpointListItem) -> None:
|
|
18
18
|
"""Print endpoint details in a Docker-like format or JSON."""
|
|
19
19
|
|
|
20
20
|
# Print header info
|
|
21
21
|
click.echo(f"ID:\t\t{endpoint.id}")
|
|
22
22
|
click.echo(f"Name:\t\t{endpoint.name}")
|
|
23
23
|
|
|
24
|
-
# Print type-specific fields
|
|
25
24
|
if isinstance(endpoint, DedicatedEndpoint):
|
|
26
25
|
click.echo(f"Display Name:\t{endpoint.display_name}")
|
|
27
26
|
click.echo(f"Hardware:\t{endpoint.hardware}")
|
|
28
|
-
click.echo(
|
|
29
|
-
f"Autoscaling:\tMin={endpoint.autoscaling.min_replicas}, "
|
|
30
|
-
f"Max={endpoint.autoscaling.max_replicas}"
|
|
31
|
-
)
|
|
27
|
+
click.echo(f"Autoscaling:\tMin={endpoint.autoscaling.min_replicas}, Max={endpoint.autoscaling.max_replicas}")
|
|
32
28
|
|
|
33
29
|
click.echo(f"Model:\t\t{endpoint.model}")
|
|
34
30
|
click.echo(f"Type:\t\t{endpoint.type}")
|
|
@@ -40,15 +36,10 @@ def print_endpoint(
|
|
|
40
36
|
F = TypeVar("F", bound=Callable[..., Any])
|
|
41
37
|
|
|
42
38
|
|
|
43
|
-
def print_api_error(
|
|
44
|
-
|
|
45
|
-
) -> None:
|
|
46
|
-
error_details = e.api_response.message
|
|
39
|
+
def print_api_error(e: APIError) -> None:
|
|
40
|
+
error_details = cast(Dict[str, Any], e.body)["error"]["message"]
|
|
47
41
|
|
|
48
|
-
if error_details and (
|
|
49
|
-
"credentials" in error_details.lower()
|
|
50
|
-
or "authentication" in error_details.lower()
|
|
51
|
-
):
|
|
42
|
+
if error_details and ("credentials" in error_details.lower() or "authentication" in error_details.lower()):
|
|
52
43
|
click.echo("Error: Invalid API key or authentication failed", err=True)
|
|
53
44
|
else:
|
|
54
45
|
click.echo(f"Error: {error_details}", err=True)
|
|
@@ -61,7 +52,7 @@ def handle_api_errors(f: F) -> F:
|
|
|
61
52
|
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
62
53
|
try:
|
|
63
54
|
return f(*args, **kwargs)
|
|
64
|
-
except
|
|
55
|
+
except APIError as e:
|
|
65
56
|
print_api_error(e)
|
|
66
57
|
sys.exit(1)
|
|
67
58
|
except Exception as e:
|
|
@@ -98,7 +89,7 @@ def endpoints(ctx: click.Context) -> None:
|
|
|
98
89
|
)
|
|
99
90
|
@click.option(
|
|
100
91
|
"--gpu",
|
|
101
|
-
type=click.Choice(["
|
|
92
|
+
type=click.Choice(["h100", "a100", "l40", "l40s", "rtx-6000"]),
|
|
102
93
|
required=True,
|
|
103
94
|
help="GPU type to use for inference",
|
|
104
95
|
)
|
|
@@ -137,7 +128,8 @@ def endpoints(ctx: click.Context) -> None:
|
|
|
137
128
|
help="Start endpoint in specified availability zone (e.g., us-central-4b)",
|
|
138
129
|
)
|
|
139
130
|
@click.option(
|
|
140
|
-
"--wait
|
|
131
|
+
"--wait",
|
|
132
|
+
is_flag=True,
|
|
141
133
|
default=True,
|
|
142
134
|
help="Wait for the endpoint to be ready after creation",
|
|
143
135
|
)
|
|
@@ -151,8 +143,8 @@ def create(
|
|
|
151
143
|
gpu: str,
|
|
152
144
|
gpu_count: int,
|
|
153
145
|
display_name: str | None,
|
|
154
|
-
no_prompt_cache: bool,
|
|
155
|
-
no_speculative_decoding: bool,
|
|
146
|
+
no_prompt_cache: bool | None,
|
|
147
|
+
no_speculative_decoding: bool | None,
|
|
156
148
|
no_auto_start: bool,
|
|
157
149
|
inactive_timeout: int | None,
|
|
158
150
|
availability_zone: str | None,
|
|
@@ -161,8 +153,6 @@ def create(
|
|
|
161
153
|
"""Create a new dedicated inference endpoint."""
|
|
162
154
|
# Map GPU types to their full hardware ID names
|
|
163
155
|
gpu_map = {
|
|
164
|
-
"b200": "nvidia_b200_180gb_sxm",
|
|
165
|
-
"h200": "nvidia_h200_140gb_sxm",
|
|
166
156
|
"h100": "nvidia_h100_80gb_sxm",
|
|
167
157
|
"a100": "nvidia_a100_80gb_pcie" if gpu_count == 1 else "nvidia_a100_80gb_sxm",
|
|
168
158
|
"l40": "nvidia_l40",
|
|
@@ -176,21 +166,21 @@ def create(
|
|
|
176
166
|
response = client.endpoints.create(
|
|
177
167
|
model=model,
|
|
178
168
|
hardware=hardware_id,
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
169
|
+
autoscaling={
|
|
170
|
+
"min_replicas": min_replicas,
|
|
171
|
+
"max_replicas": max_replicas,
|
|
172
|
+
},
|
|
173
|
+
display_name=display_name or omit,
|
|
174
|
+
disable_prompt_cache=no_prompt_cache or omit,
|
|
175
|
+
disable_speculative_decoding=no_speculative_decoding or omit,
|
|
184
176
|
state="STOPPED" if no_auto_start else "STARTED",
|
|
185
177
|
inactive_timeout=inactive_timeout,
|
|
186
|
-
|
|
178
|
+
extra_query={"availability_zone": availability_zone or omit},
|
|
187
179
|
)
|
|
188
|
-
except
|
|
180
|
+
except APIError as e:
|
|
189
181
|
print_api_error(e)
|
|
190
|
-
if "check the hardware api" in str(e).lower():
|
|
191
|
-
fetch_and_print_hardware_options(
|
|
192
|
-
client=client, model=model, print_json=False, available=True
|
|
193
|
-
)
|
|
182
|
+
if "check the hardware api" in str(e.args[0]).lower() or "invalid hardware provided" in str(e.args[0]).lower():
|
|
183
|
+
fetch_and_print_hardware_options(client=client, model=model, print_json=False, available=True)
|
|
194
184
|
|
|
195
185
|
sys.exit(1)
|
|
196
186
|
|
|
@@ -219,7 +209,7 @@ def create(
|
|
|
219
209
|
import time
|
|
220
210
|
|
|
221
211
|
click.echo("Waiting for endpoint to be ready...", err=True)
|
|
222
|
-
while client.endpoints.
|
|
212
|
+
while client.endpoints.retrieve(response.id).state != "STARTED":
|
|
223
213
|
time.sleep(1)
|
|
224
214
|
click.echo("Endpoint ready", err=True)
|
|
225
215
|
|
|
@@ -234,11 +224,11 @@ def create(
|
|
|
234
224
|
@handle_api_errors
|
|
235
225
|
def get(client: Together, endpoint_id: str, json: bool) -> None:
|
|
236
226
|
"""Get a dedicated inference endpoint."""
|
|
237
|
-
endpoint = client.endpoints.
|
|
227
|
+
endpoint = client.endpoints.retrieve(endpoint_id)
|
|
238
228
|
if json:
|
|
239
229
|
import json as json_lib
|
|
240
230
|
|
|
241
|
-
click.echo(json_lib.dumps(endpoint.model_dump(), indent=2))
|
|
231
|
+
click.echo(json_lib.dumps(endpoint.model_dump(), indent=2, default=datetime_serializer))
|
|
242
232
|
else:
|
|
243
233
|
print_endpoint(endpoint)
|
|
244
234
|
|
|
@@ -258,37 +248,31 @@ def hardware(client: Together, model: str | None, json: bool, available: bool) -
|
|
|
258
248
|
fetch_and_print_hardware_options(client, model, json, available)
|
|
259
249
|
|
|
260
250
|
|
|
261
|
-
def fetch_and_print_hardware_options(
|
|
262
|
-
client: Together, model: str | None, print_json: bool, available: bool
|
|
263
|
-
) -> None:
|
|
251
|
+
def fetch_and_print_hardware_options(client: Together, model: str | None, print_json: bool, available: bool) -> None:
|
|
264
252
|
"""Print hardware options for a model."""
|
|
265
253
|
|
|
266
254
|
message = "Available hardware options:" if available else "All hardware options:"
|
|
267
255
|
click.echo(message, err=True)
|
|
268
|
-
hardware_options = client.
|
|
256
|
+
hardware_options = client.hardware.list(model=model or omit)
|
|
257
|
+
# hardware_options = client.endpoints.list_hardware(model)
|
|
269
258
|
if available:
|
|
270
|
-
hardware_options = [
|
|
259
|
+
hardware_options.data = [
|
|
271
260
|
hardware
|
|
272
|
-
for hardware in hardware_options
|
|
273
|
-
if hardware.availability is not None
|
|
274
|
-
and hardware.availability.status == "available"
|
|
261
|
+
for hardware in hardware_options.data
|
|
262
|
+
if hardware.availability is not None and hardware.availability.status == "available"
|
|
275
263
|
]
|
|
276
264
|
|
|
277
265
|
if print_json:
|
|
278
|
-
json_output = [hardware.model_dump() for hardware in hardware_options]
|
|
279
|
-
click.echo(json.dumps(json_output, indent=2))
|
|
266
|
+
json_output = [hardware.model_dump() for hardware in hardware_options.data]
|
|
267
|
+
click.echo(json.dumps(json_output, default=datetime_serializer, indent=2))
|
|
280
268
|
else:
|
|
281
|
-
for hardware in hardware_options:
|
|
269
|
+
for hardware in hardware_options.data:
|
|
282
270
|
click.echo(f" {hardware.id}", err=True)
|
|
283
271
|
|
|
284
272
|
|
|
285
273
|
@endpoints.command()
|
|
286
274
|
@click.argument("endpoint-id", required=True)
|
|
287
|
-
@click.option(
|
|
288
|
-
"--wait/--no-wait",
|
|
289
|
-
default=True,
|
|
290
|
-
help="Wait for the endpoint to stop",
|
|
291
|
-
)
|
|
275
|
+
@click.option("--wait", is_flag=True, default=True, help="Wait for the endpoint to stop")
|
|
292
276
|
@click.pass_obj
|
|
293
277
|
@handle_api_errors
|
|
294
278
|
def stop(client: Together, endpoint_id: str, wait: bool) -> None:
|
|
@@ -300,7 +284,7 @@ def stop(client: Together, endpoint_id: str, wait: bool) -> None:
|
|
|
300
284
|
import time
|
|
301
285
|
|
|
302
286
|
click.echo("Waiting for endpoint to stop...", err=True)
|
|
303
|
-
while client.endpoints.
|
|
287
|
+
while client.endpoints.retrieve(endpoint_id).state != "STOPPED":
|
|
304
288
|
time.sleep(1)
|
|
305
289
|
click.echo("Endpoint stopped", err=True)
|
|
306
290
|
|
|
@@ -309,11 +293,7 @@ def stop(client: Together, endpoint_id: str, wait: bool) -> None:
|
|
|
309
293
|
|
|
310
294
|
@endpoints.command()
|
|
311
295
|
@click.argument("endpoint-id", required=True)
|
|
312
|
-
@click.option(
|
|
313
|
-
"--wait/--no-wait",
|
|
314
|
-
default=True,
|
|
315
|
-
help="Wait for the endpoint to start",
|
|
316
|
-
)
|
|
296
|
+
@click.option("--wait", is_flag=True, default=True, help="Wait for the endpoint to start")
|
|
317
297
|
@click.pass_obj
|
|
318
298
|
@handle_api_errors
|
|
319
299
|
def start(client: Together, endpoint_id: str, wait: bool) -> None:
|
|
@@ -325,7 +305,7 @@ def start(client: Together, endpoint_id: str, wait: bool) -> None:
|
|
|
325
305
|
import time
|
|
326
306
|
|
|
327
307
|
click.echo("Waiting for endpoint to start...", err=True)
|
|
328
|
-
while client.endpoints.
|
|
308
|
+
while client.endpoints.retrieve(endpoint_id).state != "STARTED":
|
|
329
309
|
time.sleep(1)
|
|
330
310
|
click.echo("Endpoint started", err=True)
|
|
331
311
|
|
|
@@ -371,8 +351,10 @@ def list(
|
|
|
371
351
|
mine: bool | None,
|
|
372
352
|
) -> None:
|
|
373
353
|
"""List all inference endpoints (includes both dedicated and serverless endpoints)."""
|
|
374
|
-
endpoints
|
|
375
|
-
type=type
|
|
354
|
+
endpoints = client.endpoints.list(
|
|
355
|
+
type=type or omit,
|
|
356
|
+
usage_type=usage_type or omit,
|
|
357
|
+
mine=mine if mine is not None else omit,
|
|
376
358
|
)
|
|
377
359
|
|
|
378
360
|
if not endpoints:
|
|
@@ -384,10 +366,12 @@ def list(
|
|
|
384
366
|
import json as json_lib
|
|
385
367
|
|
|
386
368
|
click.echo(
|
|
387
|
-
json_lib.dumps(
|
|
369
|
+
json_lib.dumps(
|
|
370
|
+
[endpoint.model_dump() for endpoint in endpoints.data], default=datetime_serializer, indent=2
|
|
371
|
+
)
|
|
388
372
|
)
|
|
389
373
|
else:
|
|
390
|
-
for endpoint in endpoints:
|
|
374
|
+
for endpoint in endpoints.data:
|
|
391
375
|
print_endpoint(
|
|
392
376
|
endpoint,
|
|
393
377
|
)
|
|
@@ -430,32 +414,30 @@ def update(
|
|
|
430
414
|
click.echo("Error: At least one update option must be specified", err=True)
|
|
431
415
|
sys.exit(1)
|
|
432
416
|
|
|
433
|
-
# If only one of min/max replicas is specified, we need both for the update
|
|
434
|
-
if (min_replicas is None) != (max_replicas is None):
|
|
435
|
-
click.echo(
|
|
436
|
-
"Error: Both --min-replicas and --max-replicas must be specified together",
|
|
437
|
-
err=True,
|
|
438
|
-
)
|
|
439
|
-
sys.exit(1)
|
|
440
|
-
|
|
441
417
|
# Build kwargs for the update
|
|
442
418
|
kwargs: Dict[str, Any] = {}
|
|
443
419
|
if display_name is not None:
|
|
444
420
|
kwargs["display_name"] = display_name
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
kwargs["
|
|
421
|
+
|
|
422
|
+
if min_replicas is not None or max_replicas is not None:
|
|
423
|
+
kwargs["autoscaling"] = {}
|
|
424
|
+
if min_replicas is not None:
|
|
425
|
+
kwargs["autoscaling"]["min_replicas"] = min_replicas
|
|
426
|
+
if max_replicas is not None:
|
|
427
|
+
kwargs["autoscaling"]["max_replicas"] = max_replicas
|
|
428
|
+
|
|
448
429
|
if inactive_timeout is not None:
|
|
449
430
|
kwargs["inactive_timeout"] = inactive_timeout
|
|
450
431
|
|
|
451
|
-
|
|
432
|
+
client.endpoints.update(endpoint_id, **kwargs)
|
|
452
433
|
|
|
453
434
|
# Print what was updated
|
|
454
435
|
click.echo("Updated endpoint configuration:", err=True)
|
|
455
436
|
if display_name:
|
|
456
437
|
click.echo(f" Display name: {display_name}", err=True)
|
|
457
|
-
if min_replicas
|
|
438
|
+
if min_replicas:
|
|
458
439
|
click.echo(f" Min replicas: {min_replicas}", err=True)
|
|
440
|
+
if max_replicas:
|
|
459
441
|
click.echo(f" Max replicas: {max_replicas}", err=True)
|
|
460
442
|
if inactive_timeout is not None:
|
|
461
443
|
click.echo(f" Inactive timeout: {inactive_timeout} minutes", err=True)
|
|
@@ -479,8 +461,8 @@ def availability_zones(client: Together, json: bool) -> None:
|
|
|
479
461
|
if json:
|
|
480
462
|
import json as json_lib
|
|
481
463
|
|
|
482
|
-
click.echo(json_lib.dumps(
|
|
464
|
+
click.echo(json_lib.dumps(avzones.model_dump(), indent=2))
|
|
483
465
|
else:
|
|
484
466
|
click.echo("Available zones:", err=True)
|
|
485
|
-
for availability_zone in sorted(avzones):
|
|
467
|
+
for availability_zone in sorted(avzones.avzones):
|
|
486
468
|
click.echo(f" {availability_zone}")
|
|
@@ -1,21 +1,72 @@
|
|
|
1
|
+
import sys
|
|
1
2
|
import json
|
|
2
|
-
from typing import
|
|
3
|
+
from typing import Any, Dict, List, Union, Literal, TypeVar, Callable, Optional, cast
|
|
4
|
+
from functools import wraps
|
|
3
5
|
|
|
4
6
|
import click
|
|
5
7
|
from tabulate import tabulate
|
|
6
8
|
|
|
7
|
-
from together import Together
|
|
8
|
-
from together.
|
|
9
|
+
from together import APIError, Together, TogetherError
|
|
10
|
+
from together._types import omit
|
|
11
|
+
from together.lib.utils.serializer import datetime_serializer
|
|
12
|
+
from together.types.eval_create_params import (
|
|
13
|
+
ParametersEvaluationScoreParameters,
|
|
14
|
+
ParametersEvaluationCompareParameters,
|
|
15
|
+
ParametersEvaluationClassifyParameters,
|
|
16
|
+
ParametersEvaluationScoreParametersJudge,
|
|
17
|
+
ParametersEvaluationCompareParametersJudge,
|
|
18
|
+
ParametersEvaluationClassifyParametersJudge,
|
|
19
|
+
ParametersEvaluationScoreParametersModelToEvaluate,
|
|
20
|
+
ParametersEvaluationClassifyParametersModelToEvaluate,
|
|
21
|
+
ParametersEvaluationCompareParametersModelAEvaluationModelRequest,
|
|
22
|
+
ParametersEvaluationCompareParametersModelBEvaluationModelRequest,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def print_api_error(e: Union[APIError, TogetherError]) -> None:
|
|
27
|
+
if isinstance(e, APIError):
|
|
28
|
+
error_details = cast(Dict[str, Any], e.body)["error"]["message"]
|
|
29
|
+
|
|
30
|
+
if error_details and ("credentials" in error_details.lower() or "authentication" in error_details.lower()):
|
|
31
|
+
click.echo("Error: Invalid API key or authentication failed", err=True)
|
|
32
|
+
else:
|
|
33
|
+
click.echo(f"Error: {error_details}", err=True)
|
|
34
|
+
|
|
35
|
+
click.echo(f"Error: {e}", err=True)
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
F = TypeVar("F", bound=Callable[..., Any])
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def handle_api_errors(f: F) -> F:
|
|
43
|
+
"""Decorator to handle common API errors in CLI commands."""
|
|
44
|
+
|
|
45
|
+
@wraps(f)
|
|
46
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
47
|
+
try:
|
|
48
|
+
return f(*args, **kwargs)
|
|
49
|
+
except APIError as e:
|
|
50
|
+
print_api_error(e)
|
|
51
|
+
sys.exit(1)
|
|
52
|
+
except TogetherError as e:
|
|
53
|
+
print_api_error(e)
|
|
54
|
+
sys.exit(1)
|
|
55
|
+
except Exception as e:
|
|
56
|
+
click.echo(f"Error: An unexpected error occurred - {str(e)}", err=True)
|
|
57
|
+
sys.exit(1)
|
|
58
|
+
|
|
59
|
+
return wrapper # type: ignore
|
|
9
60
|
|
|
10
61
|
|
|
11
62
|
@click.group()
|
|
12
63
|
@click.pass_context
|
|
13
|
-
def
|
|
14
|
-
"""
|
|
64
|
+
def evals(ctx: click.Context) -> None:
|
|
65
|
+
"""Evals API commands"""
|
|
15
66
|
pass
|
|
16
67
|
|
|
17
68
|
|
|
18
|
-
@
|
|
69
|
+
@evals.command()
|
|
19
70
|
@click.pass_context
|
|
20
71
|
@click.option(
|
|
21
72
|
"--type",
|
|
@@ -222,11 +273,12 @@ def evaluation(ctx: click.Context) -> None:
|
|
|
222
273
|
type=str,
|
|
223
274
|
help="Input template for model B.",
|
|
224
275
|
)
|
|
276
|
+
@handle_api_errors
|
|
225
277
|
def create(
|
|
226
278
|
ctx: click.Context,
|
|
227
|
-
type:
|
|
279
|
+
type: Literal["classify", "score", "compare"],
|
|
228
280
|
judge_model: str,
|
|
229
|
-
judge_model_source:
|
|
281
|
+
judge_model_source: Literal["serverless", "dedicated", "external"],
|
|
230
282
|
judge_system_template: str,
|
|
231
283
|
judge_external_api_token: Optional[str],
|
|
232
284
|
judge_external_base_url: Optional[str],
|
|
@@ -307,13 +359,9 @@ def create(
|
|
|
307
359
|
"input_template": model_to_evaluate_input_template,
|
|
308
360
|
}
|
|
309
361
|
if model_to_evaluate_external_api_token:
|
|
310
|
-
model_to_evaluate_final["external_api_token"] =
|
|
311
|
-
model_to_evaluate_external_api_token
|
|
312
|
-
)
|
|
362
|
+
model_to_evaluate_final["external_api_token"] = model_to_evaluate_external_api_token
|
|
313
363
|
if model_to_evaluate_external_base_url:
|
|
314
|
-
model_to_evaluate_final["external_base_url"] =
|
|
315
|
-
model_to_evaluate_external_base_url
|
|
316
|
-
)
|
|
364
|
+
model_to_evaluate_final["external_base_url"] = model_to_evaluate_external_base_url
|
|
317
365
|
|
|
318
366
|
# Build model-a configuration
|
|
319
367
|
model_a_final: Union[Dict[str, Any], None, str] = None
|
|
@@ -385,35 +433,55 @@ def create(
|
|
|
385
433
|
if model_b_external_base_url:
|
|
386
434
|
model_b_final["external_base_url"] = model_b_external_base_url
|
|
387
435
|
|
|
388
|
-
|
|
389
|
-
|
|
436
|
+
judge_config = _build_judge(
|
|
437
|
+
type, judge_model, judge_model_source, judge_system_template, judge_external_api_token, judge_external_base_url
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
if type == "classify":
|
|
441
|
+
response = client.evals.create(
|
|
442
|
+
type=type,
|
|
443
|
+
parameters=ParametersEvaluationClassifyParameters(
|
|
444
|
+
input_data_file_path=input_data_file_path,
|
|
445
|
+
judge=judge_config,
|
|
446
|
+
labels=labels_list or [],
|
|
447
|
+
pass_labels=pass_labels_list or [],
|
|
448
|
+
model_to_evaluate=cast(ParametersEvaluationClassifyParametersModelToEvaluate, model_to_evaluate_final),
|
|
449
|
+
),
|
|
450
|
+
)
|
|
451
|
+
elif type == "score":
|
|
452
|
+
if max_score is None or min_score is None or pass_threshold is None:
|
|
453
|
+
raise TogetherError("max_score, min_score, and pass_threshold are required for score type")
|
|
454
|
+
|
|
455
|
+
response = client.evals.create(
|
|
456
|
+
type="score",
|
|
457
|
+
parameters=ParametersEvaluationScoreParameters(
|
|
458
|
+
input_data_file_path=input_data_file_path,
|
|
459
|
+
judge=judge_config,
|
|
460
|
+
max_score=max_score,
|
|
461
|
+
min_score=min_score,
|
|
462
|
+
pass_threshold=pass_threshold,
|
|
463
|
+
model_to_evaluate=cast(ParametersEvaluationScoreParametersModelToEvaluate, model_to_evaluate_final),
|
|
464
|
+
),
|
|
465
|
+
)
|
|
466
|
+
elif type == "compare":
|
|
467
|
+
response = client.evals.create(
|
|
390
468
|
type=type,
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
model_to_evaluate=model_to_evaluate_final,
|
|
398
|
-
labels=labels_list,
|
|
399
|
-
pass_labels=pass_labels_list,
|
|
400
|
-
min_score=min_score,
|
|
401
|
-
max_score=max_score,
|
|
402
|
-
pass_threshold=pass_threshold,
|
|
403
|
-
model_a=model_a_final,
|
|
404
|
-
model_b=model_b_final,
|
|
469
|
+
parameters=ParametersEvaluationCompareParameters(
|
|
470
|
+
input_data_file_path=input_data_file_path,
|
|
471
|
+
judge=judge_config,
|
|
472
|
+
model_a=cast(ParametersEvaluationCompareParametersModelAEvaluationModelRequest, model_a_final),
|
|
473
|
+
model_b=cast(ParametersEvaluationCompareParametersModelBEvaluationModelRequest, model_b_final),
|
|
474
|
+
),
|
|
405
475
|
)
|
|
406
|
-
except ValueError as e:
|
|
407
|
-
raise click.BadParameter(str(e))
|
|
408
476
|
|
|
409
477
|
click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
|
|
410
478
|
|
|
411
479
|
|
|
412
|
-
@
|
|
480
|
+
@evals.command()
|
|
413
481
|
@click.pass_context
|
|
414
482
|
@click.option(
|
|
415
483
|
"--status",
|
|
416
|
-
type=
|
|
484
|
+
type=click.Choice(["pending", "queued", "running", "completed", "error", "user_error"]),
|
|
417
485
|
help="Filter by job status.",
|
|
418
486
|
)
|
|
419
487
|
@click.option(
|
|
@@ -421,14 +489,18 @@ def create(
|
|
|
421
489
|
type=int,
|
|
422
490
|
help="Limit number of results (max 100).",
|
|
423
491
|
)
|
|
424
|
-
def list(
|
|
425
|
-
|
|
492
|
+
def list(
|
|
493
|
+
ctx: click.Context,
|
|
494
|
+
status: Union[Literal["pending", "queued", "running", "completed", "error", "user_error"], None],
|
|
495
|
+
limit: Union[int, None],
|
|
496
|
+
) -> None:
|
|
497
|
+
"""List evals"""
|
|
426
498
|
|
|
427
499
|
client: Together = ctx.obj
|
|
428
500
|
|
|
429
|
-
response = client.
|
|
501
|
+
response = client.evals.list(status=status or omit, limit=limit or omit)
|
|
430
502
|
|
|
431
|
-
display_list = []
|
|
503
|
+
display_list: List[Dict[str, Any]] = []
|
|
432
504
|
for job in response:
|
|
433
505
|
if job.parameters:
|
|
434
506
|
model = job.parameters.get("model_to_evaluate", "")
|
|
@@ -436,6 +508,8 @@ def list(ctx: click.Context, status: Optional[str], limit: Optional[int]) -> Non
|
|
|
436
508
|
model_b = job.parameters.get("model_b", "")
|
|
437
509
|
else:
|
|
438
510
|
model = ""
|
|
511
|
+
model_a = ""
|
|
512
|
+
model_b = ""
|
|
439
513
|
|
|
440
514
|
display_list.append(
|
|
441
515
|
{
|
|
@@ -453,7 +527,7 @@ def list(ctx: click.Context, status: Optional[str], limit: Optional[int]) -> Non
|
|
|
453
527
|
click.echo(table)
|
|
454
528
|
|
|
455
529
|
|
|
456
|
-
@
|
|
530
|
+
@evals.command()
|
|
457
531
|
@click.pass_context
|
|
458
532
|
@click.argument("evaluation_id", type=str, required=True)
|
|
459
533
|
def retrieve(ctx: click.Context, evaluation_id: str) -> None:
|
|
@@ -461,12 +535,12 @@ def retrieve(ctx: click.Context, evaluation_id: str) -> None:
|
|
|
461
535
|
|
|
462
536
|
client: Together = ctx.obj
|
|
463
537
|
|
|
464
|
-
response = client.
|
|
538
|
+
response = client.evals.retrieve(evaluation_id)
|
|
465
539
|
|
|
466
|
-
click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
|
|
540
|
+
click.echo(json.dumps(response.model_dump(exclude_none=True), default=datetime_serializer, indent=4))
|
|
467
541
|
|
|
468
542
|
|
|
469
|
-
@
|
|
543
|
+
@evals.command()
|
|
470
544
|
@click.pass_context
|
|
471
545
|
@click.argument("evaluation_id", type=str, required=True)
|
|
472
546
|
def status(ctx: click.Context, evaluation_id: str) -> None:
|
|
@@ -474,6 +548,41 @@ def status(ctx: click.Context, evaluation_id: str) -> None:
|
|
|
474
548
|
|
|
475
549
|
client: Together = ctx.obj
|
|
476
550
|
|
|
477
|
-
response = client.
|
|
551
|
+
response = client.evals.status(evaluation_id)
|
|
478
552
|
|
|
479
553
|
click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
def _build_judge(
|
|
557
|
+
type: Literal["classify", "score", "compare"],
|
|
558
|
+
judge_model: str,
|
|
559
|
+
judge_model_source: Literal["serverless", "dedicated", "external"],
|
|
560
|
+
judge_system_template: str,
|
|
561
|
+
judge_external_api_token: Optional[str],
|
|
562
|
+
judge_external_base_url: Optional[str],
|
|
563
|
+
) -> ParametersEvaluationClassifyParametersJudge:
|
|
564
|
+
if type == "classify":
|
|
565
|
+
judge_config = ParametersEvaluationClassifyParametersJudge(
|
|
566
|
+
model=judge_model,
|
|
567
|
+
model_source=judge_model_source,
|
|
568
|
+
system_template=judge_system_template,
|
|
569
|
+
)
|
|
570
|
+
elif type == "score":
|
|
571
|
+
judge_config = ParametersEvaluationScoreParametersJudge(
|
|
572
|
+
model=judge_model,
|
|
573
|
+
model_source=judge_model_source,
|
|
574
|
+
system_template=judge_system_template,
|
|
575
|
+
)
|
|
576
|
+
elif type == "compare":
|
|
577
|
+
judge_config = ParametersEvaluationCompareParametersJudge(
|
|
578
|
+
model=judge_model,
|
|
579
|
+
model_source=judge_model_source,
|
|
580
|
+
system_template=judge_system_template,
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
if judge_external_api_token:
|
|
584
|
+
judge_config["external_api_token"] = judge_external_api_token
|
|
585
|
+
if judge_external_base_url:
|
|
586
|
+
judge_config["external_base_url"] = judge_external_base_url
|
|
587
|
+
|
|
588
|
+
return judge_config
|