together 1.5.34__py3-none-any.whl → 2.0.0a6__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 +65 -81
- 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 -477
- 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.0a6.dist-info/METADATA +729 -0
- together-2.0.0a6.dist-info/RECORD +165 -0
- {together-1.5.34.dist-info → together-2.0.0a6.dist-info}/WHEEL +1 -1
- together-2.0.0a6.dist-info/entry_points.txt +2 -0
- {together-1.5.34.dist-info → together-2.0.0a6.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 -464
- 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.34.dist-info/METADATA +0 -583
- together-1.5.34.dist-info/RECORD +0 -77
- together-1.5.34.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:
|
|
@@ -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,
|
|
@@ -174,21 +166,21 @@ def create(
|
|
|
174
166
|
response = client.endpoints.create(
|
|
175
167
|
model=model,
|
|
176
168
|
hardware=hardware_id,
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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,
|
|
182
176
|
state="STOPPED" if no_auto_start else "STARTED",
|
|
183
177
|
inactive_timeout=inactive_timeout,
|
|
184
|
-
|
|
178
|
+
extra_query={"availability_zone": availability_zone or omit},
|
|
185
179
|
)
|
|
186
|
-
except
|
|
180
|
+
except APIError as e:
|
|
187
181
|
print_api_error(e)
|
|
188
|
-
if "check the hardware api" in str(e).lower():
|
|
189
|
-
fetch_and_print_hardware_options(
|
|
190
|
-
client=client, model=model, print_json=False, available=True
|
|
191
|
-
)
|
|
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)
|
|
192
184
|
|
|
193
185
|
sys.exit(1)
|
|
194
186
|
|
|
@@ -217,7 +209,7 @@ def create(
|
|
|
217
209
|
import time
|
|
218
210
|
|
|
219
211
|
click.echo("Waiting for endpoint to be ready...", err=True)
|
|
220
|
-
while client.endpoints.
|
|
212
|
+
while client.endpoints.retrieve(response.id).state != "STARTED":
|
|
221
213
|
time.sleep(1)
|
|
222
214
|
click.echo("Endpoint ready", err=True)
|
|
223
215
|
|
|
@@ -232,11 +224,11 @@ def create(
|
|
|
232
224
|
@handle_api_errors
|
|
233
225
|
def get(client: Together, endpoint_id: str, json: bool) -> None:
|
|
234
226
|
"""Get a dedicated inference endpoint."""
|
|
235
|
-
endpoint = client.endpoints.
|
|
227
|
+
endpoint = client.endpoints.retrieve(endpoint_id)
|
|
236
228
|
if json:
|
|
237
229
|
import json as json_lib
|
|
238
230
|
|
|
239
|
-
click.echo(json_lib.dumps(endpoint.model_dump(), indent=2))
|
|
231
|
+
click.echo(json_lib.dumps(endpoint.model_dump(), indent=2, default=datetime_serializer))
|
|
240
232
|
else:
|
|
241
233
|
print_endpoint(endpoint)
|
|
242
234
|
|
|
@@ -256,37 +248,31 @@ def hardware(client: Together, model: str | None, json: bool, available: bool) -
|
|
|
256
248
|
fetch_and_print_hardware_options(client, model, json, available)
|
|
257
249
|
|
|
258
250
|
|
|
259
|
-
def fetch_and_print_hardware_options(
|
|
260
|
-
client: Together, model: str | None, print_json: bool, available: bool
|
|
261
|
-
) -> None:
|
|
251
|
+
def fetch_and_print_hardware_options(client: Together, model: str | None, print_json: bool, available: bool) -> None:
|
|
262
252
|
"""Print hardware options for a model."""
|
|
263
253
|
|
|
264
254
|
message = "Available hardware options:" if available else "All hardware options:"
|
|
265
255
|
click.echo(message, err=True)
|
|
266
|
-
hardware_options = client.
|
|
256
|
+
hardware_options = client.hardware.list(model=model or omit)
|
|
257
|
+
# hardware_options = client.endpoints.list_hardware(model)
|
|
267
258
|
if available:
|
|
268
|
-
hardware_options = [
|
|
259
|
+
hardware_options.data = [
|
|
269
260
|
hardware
|
|
270
|
-
for hardware in hardware_options
|
|
271
|
-
if hardware.availability is not None
|
|
272
|
-
and hardware.availability.status == "available"
|
|
261
|
+
for hardware in hardware_options.data
|
|
262
|
+
if hardware.availability is not None and hardware.availability.status == "available"
|
|
273
263
|
]
|
|
274
264
|
|
|
275
265
|
if print_json:
|
|
276
|
-
json_output = [hardware.model_dump() for hardware in hardware_options]
|
|
277
|
-
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))
|
|
278
268
|
else:
|
|
279
|
-
for hardware in hardware_options:
|
|
269
|
+
for hardware in hardware_options.data:
|
|
280
270
|
click.echo(f" {hardware.id}", err=True)
|
|
281
271
|
|
|
282
272
|
|
|
283
273
|
@endpoints.command()
|
|
284
274
|
@click.argument("endpoint-id", required=True)
|
|
285
|
-
@click.option(
|
|
286
|
-
"--wait/--no-wait",
|
|
287
|
-
default=True,
|
|
288
|
-
help="Wait for the endpoint to stop",
|
|
289
|
-
)
|
|
275
|
+
@click.option("--wait", is_flag=True, default=True, help="Wait for the endpoint to stop")
|
|
290
276
|
@click.pass_obj
|
|
291
277
|
@handle_api_errors
|
|
292
278
|
def stop(client: Together, endpoint_id: str, wait: bool) -> None:
|
|
@@ -298,7 +284,7 @@ def stop(client: Together, endpoint_id: str, wait: bool) -> None:
|
|
|
298
284
|
import time
|
|
299
285
|
|
|
300
286
|
click.echo("Waiting for endpoint to stop...", err=True)
|
|
301
|
-
while client.endpoints.
|
|
287
|
+
while client.endpoints.retrieve(endpoint_id).state != "STOPPED":
|
|
302
288
|
time.sleep(1)
|
|
303
289
|
click.echo("Endpoint stopped", err=True)
|
|
304
290
|
|
|
@@ -307,11 +293,7 @@ def stop(client: Together, endpoint_id: str, wait: bool) -> None:
|
|
|
307
293
|
|
|
308
294
|
@endpoints.command()
|
|
309
295
|
@click.argument("endpoint-id", required=True)
|
|
310
|
-
@click.option(
|
|
311
|
-
"--wait/--no-wait",
|
|
312
|
-
default=True,
|
|
313
|
-
help="Wait for the endpoint to start",
|
|
314
|
-
)
|
|
296
|
+
@click.option("--wait", is_flag=True, default=True, help="Wait for the endpoint to start")
|
|
315
297
|
@click.pass_obj
|
|
316
298
|
@handle_api_errors
|
|
317
299
|
def start(client: Together, endpoint_id: str, wait: bool) -> None:
|
|
@@ -323,7 +305,7 @@ def start(client: Together, endpoint_id: str, wait: bool) -> None:
|
|
|
323
305
|
import time
|
|
324
306
|
|
|
325
307
|
click.echo("Waiting for endpoint to start...", err=True)
|
|
326
|
-
while client.endpoints.
|
|
308
|
+
while client.endpoints.retrieve(endpoint_id).state != "STARTED":
|
|
327
309
|
time.sleep(1)
|
|
328
310
|
click.echo("Endpoint started", err=True)
|
|
329
311
|
|
|
@@ -369,8 +351,10 @@ def list(
|
|
|
369
351
|
mine: bool | None,
|
|
370
352
|
) -> None:
|
|
371
353
|
"""List all inference endpoints (includes both dedicated and serverless endpoints)."""
|
|
372
|
-
endpoints
|
|
373
|
-
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,
|
|
374
358
|
)
|
|
375
359
|
|
|
376
360
|
if not endpoints:
|
|
@@ -382,10 +366,12 @@ def list(
|
|
|
382
366
|
import json as json_lib
|
|
383
367
|
|
|
384
368
|
click.echo(
|
|
385
|
-
json_lib.dumps(
|
|
369
|
+
json_lib.dumps(
|
|
370
|
+
[endpoint.model_dump() for endpoint in endpoints.data], default=datetime_serializer, indent=2
|
|
371
|
+
)
|
|
386
372
|
)
|
|
387
373
|
else:
|
|
388
|
-
for endpoint in endpoints:
|
|
374
|
+
for endpoint in endpoints.data:
|
|
389
375
|
print_endpoint(
|
|
390
376
|
endpoint,
|
|
391
377
|
)
|
|
@@ -428,32 +414,30 @@ def update(
|
|
|
428
414
|
click.echo("Error: At least one update option must be specified", err=True)
|
|
429
415
|
sys.exit(1)
|
|
430
416
|
|
|
431
|
-
# If only one of min/max replicas is specified, we need both for the update
|
|
432
|
-
if (min_replicas is None) != (max_replicas is None):
|
|
433
|
-
click.echo(
|
|
434
|
-
"Error: Both --min-replicas and --max-replicas must be specified together",
|
|
435
|
-
err=True,
|
|
436
|
-
)
|
|
437
|
-
sys.exit(1)
|
|
438
|
-
|
|
439
417
|
# Build kwargs for the update
|
|
440
418
|
kwargs: Dict[str, Any] = {}
|
|
441
419
|
if display_name is not None:
|
|
442
420
|
kwargs["display_name"] = display_name
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
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
|
+
|
|
446
429
|
if inactive_timeout is not None:
|
|
447
430
|
kwargs["inactive_timeout"] = inactive_timeout
|
|
448
431
|
|
|
449
|
-
|
|
432
|
+
client.endpoints.update(endpoint_id, **kwargs)
|
|
450
433
|
|
|
451
434
|
# Print what was updated
|
|
452
435
|
click.echo("Updated endpoint configuration:", err=True)
|
|
453
436
|
if display_name:
|
|
454
437
|
click.echo(f" Display name: {display_name}", err=True)
|
|
455
|
-
if min_replicas
|
|
438
|
+
if min_replicas:
|
|
456
439
|
click.echo(f" Min replicas: {min_replicas}", err=True)
|
|
440
|
+
if max_replicas:
|
|
457
441
|
click.echo(f" Max replicas: {max_replicas}", err=True)
|
|
458
442
|
if inactive_timeout is not None:
|
|
459
443
|
click.echo(f" Inactive timeout: {inactive_timeout} minutes", err=True)
|
|
@@ -477,8 +461,8 @@ def availability_zones(client: Together, json: bool) -> None:
|
|
|
477
461
|
if json:
|
|
478
462
|
import json as json_lib
|
|
479
463
|
|
|
480
|
-
click.echo(json_lib.dumps(
|
|
464
|
+
click.echo(json_lib.dumps(avzones.model_dump(), indent=2))
|
|
481
465
|
else:
|
|
482
466
|
click.echo("Available zones:", err=True)
|
|
483
|
-
for availability_zone in sorted(avzones):
|
|
467
|
+
for availability_zone in sorted(avzones.avzones):
|
|
484
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
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import pathlib
|
|
3
|
+
from typing import Any, Dict, List, get_args
|
|
3
4
|
from textwrap import wrap
|
|
4
5
|
|
|
5
6
|
import click
|
|
@@ -7,7 +8,9 @@ from tabulate import tabulate
|
|
|
7
8
|
|
|
8
9
|
from together import Together
|
|
9
10
|
from together.types import FilePurpose
|
|
10
|
-
|
|
11
|
+
|
|
12
|
+
# from together.utils import check_file, convert_bytes, convert_unix_timestamp
|
|
13
|
+
from ...utils import check_file, convert_bytes, convert_unix_timestamp
|
|
11
14
|
|
|
12
15
|
|
|
13
16
|
@click.group()
|
|
@@ -21,15 +24,13 @@ def files(ctx: click.Context) -> None:
|
|
|
21
24
|
@click.pass_context
|
|
22
25
|
@click.argument(
|
|
23
26
|
"file",
|
|
24
|
-
type=click.Path(
|
|
25
|
-
exists=True, file_okay=True, resolve_path=True, readable=True, dir_okay=False
|
|
26
|
-
),
|
|
27
|
+
type=click.Path(exists=True, file_okay=True, resolve_path=True, readable=True, dir_okay=False),
|
|
27
28
|
required=True,
|
|
28
29
|
)
|
|
29
30
|
@click.option(
|
|
30
31
|
"--purpose",
|
|
31
|
-
type=
|
|
32
|
-
default=
|
|
32
|
+
type=click.Choice(get_args(FilePurpose)),
|
|
33
|
+
default="fine-tune",
|
|
33
34
|
help="Purpose of file upload. Acceptable values in enum `together.types.FilePurpose`. Defaults to `fine-tunes`.",
|
|
34
35
|
)
|
|
35
36
|
@click.option(
|
|
@@ -37,7 +38,7 @@ def files(ctx: click.Context) -> None:
|
|
|
37
38
|
default=True,
|
|
38
39
|
help="Whether to check the file before uploading.",
|
|
39
40
|
)
|
|
40
|
-
def upload(ctx: click.Context, file: pathlib.Path, purpose:
|
|
41
|
+
def upload(ctx: click.Context, file: pathlib.Path, purpose: FilePurpose, check: bool) -> None:
|
|
41
42
|
"""Upload file"""
|
|
42
43
|
|
|
43
44
|
client: Together = ctx.obj
|
|
@@ -55,15 +56,13 @@ def list(ctx: click.Context) -> None:
|
|
|
55
56
|
|
|
56
57
|
response = client.files.list()
|
|
57
58
|
|
|
58
|
-
display_list = []
|
|
59
|
+
display_list: List[Dict[str, Any]] = []
|
|
59
60
|
for i in response.data or []:
|
|
60
61
|
display_list.append(
|
|
61
62
|
{
|
|
62
63
|
"File name": "\n".join(wrap(i.filename or "", width=30)),
|
|
63
64
|
"File ID": i.id,
|
|
64
|
-
"Size": convert_bytes(
|
|
65
|
-
float(str(i.bytes))
|
|
66
|
-
), # convert to string for mypy typing
|
|
65
|
+
"Size": convert_bytes(float(str(i.bytes))), # convert to string for mypy typing
|
|
67
66
|
"Created At": convert_unix_timestamp(i.created_at or 0),
|
|
68
67
|
"Line Count": i.line_count,
|
|
69
68
|
}
|
|
@@ -95,9 +94,15 @@ def retrieve_content(ctx: click.Context, id: str, output: str) -> None:
|
|
|
95
94
|
|
|
96
95
|
client: Together = ctx.obj
|
|
97
96
|
|
|
98
|
-
response = client.files.
|
|
97
|
+
response = client.files.content(id=id)
|
|
99
98
|
|
|
100
|
-
|
|
99
|
+
if output:
|
|
100
|
+
with open(output, "wb") as f:
|
|
101
|
+
f.write(response.read())
|
|
102
|
+
click.echo(f"File saved to {output}")
|
|
103
|
+
|
|
104
|
+
else:
|
|
105
|
+
click.echo(response.read().decode("utf-8"))
|
|
101
106
|
|
|
102
107
|
|
|
103
108
|
@files.command()
|
|
@@ -117,12 +122,10 @@ def delete(ctx: click.Context, id: str) -> None:
|
|
|
117
122
|
@click.pass_context
|
|
118
123
|
@click.argument(
|
|
119
124
|
"file",
|
|
120
|
-
type=click.Path(
|
|
121
|
-
exists=True, file_okay=True, resolve_path=True, readable=True, dir_okay=False
|
|
122
|
-
),
|
|
125
|
+
type=click.Path(exists=True, file_okay=True, resolve_path=True, readable=True, dir_okay=False),
|
|
123
126
|
required=True,
|
|
124
127
|
)
|
|
125
|
-
def check(
|
|
128
|
+
def check(_ctx: click.Context, file: pathlib.Path) -> None:
|
|
126
129
|
"""Check file for issues"""
|
|
127
130
|
|
|
128
131
|
report = check_file(file)
|