together 1.5.25__py3-none-any.whl → 1.5.27__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/cli/api/evaluation.py +118 -18
- together/cli/api/finetune.py +27 -0
- together/cli/api/models.py +79 -1
- together/client.py +4 -0
- together/constants.py +14 -2
- together/filemanager.py +230 -5
- together/resources/__init__.py +3 -0
- together/resources/audio/transcriptions.py +16 -4
- together/resources/endpoints.py +4 -4
- together/resources/evaluation.py +98 -14
- together/resources/files.py +12 -3
- together/resources/finetune.py +63 -0
- together/resources/models.py +118 -0
- together/resources/videos.py +303 -0
- together/types/__init__.py +13 -1
- together/types/audio_speech.py +13 -0
- together/types/evaluation.py +9 -3
- together/types/files.py +1 -1
- together/types/finetune.py +5 -0
- together/types/models.py +50 -1
- together/types/videos.py +69 -0
- together/utils/files.py +1 -1
- {together-1.5.25.dist-info → together-1.5.27.dist-info}/METADATA +6 -4
- {together-1.5.25.dist-info → together-1.5.27.dist-info}/RECORD +27 -25
- {together-1.5.25.dist-info → together-1.5.27.dist-info}/WHEEL +1 -1
- {together-1.5.25.dist-info → together-1.5.27.dist-info}/entry_points.txt +0 -0
- {together-1.5.25.dist-info → together-1.5.27.dist-info/licenses}/LICENSE +0 -0
together/cli/api/evaluation.py
CHANGED
|
@@ -24,10 +24,28 @@ def evaluation(ctx: click.Context) -> None:
|
|
|
24
24
|
help="Type of evaluation to create.",
|
|
25
25
|
)
|
|
26
26
|
@click.option(
|
|
27
|
-
"--judge-model
|
|
27
|
+
"--judge-model",
|
|
28
28
|
type=str,
|
|
29
29
|
required=True,
|
|
30
|
-
help="Name of the judge model to use for evaluation.",
|
|
30
|
+
help="Name or URL of the judge model to use for evaluation.",
|
|
31
|
+
)
|
|
32
|
+
@click.option(
|
|
33
|
+
"--judge-model-source",
|
|
34
|
+
type=click.Choice(["serverless", "dedicated", "external"]),
|
|
35
|
+
required=True,
|
|
36
|
+
help="Source of the judge model.",
|
|
37
|
+
)
|
|
38
|
+
@click.option(
|
|
39
|
+
"--judge-external-api-token",
|
|
40
|
+
type=str,
|
|
41
|
+
required=False,
|
|
42
|
+
help="Optional external API token for the judge model.",
|
|
43
|
+
)
|
|
44
|
+
@click.option(
|
|
45
|
+
"--judge-external-base-url",
|
|
46
|
+
type=str,
|
|
47
|
+
required=False,
|
|
48
|
+
help="Optional external base URLs for the judge model.",
|
|
31
49
|
)
|
|
32
50
|
@click.option(
|
|
33
51
|
"--judge-system-template",
|
|
@@ -48,10 +66,25 @@ def evaluation(ctx: click.Context) -> None:
|
|
|
48
66
|
"Can not be used when model-a-name and other model config parameters are specified",
|
|
49
67
|
)
|
|
50
68
|
@click.option(
|
|
51
|
-
"--model-to-evaluate
|
|
69
|
+
"--model-to-evaluate",
|
|
52
70
|
type=str,
|
|
53
71
|
help="Model name when using the detailed config",
|
|
54
72
|
)
|
|
73
|
+
@click.option(
|
|
74
|
+
"--model-to-evaluate-source",
|
|
75
|
+
type=click.Choice(["serverless", "dedicated", "external"]),
|
|
76
|
+
help="Source of the model to evaluate.",
|
|
77
|
+
)
|
|
78
|
+
@click.option(
|
|
79
|
+
"--model-to-evaluate-external-api-token",
|
|
80
|
+
type=str,
|
|
81
|
+
help="Optional external API token for the model to evaluate.",
|
|
82
|
+
)
|
|
83
|
+
@click.option(
|
|
84
|
+
"--model-to-evaluate-external-base-url",
|
|
85
|
+
type=str,
|
|
86
|
+
help="Optional external base URL for the model to evaluate.",
|
|
87
|
+
)
|
|
55
88
|
@click.option(
|
|
56
89
|
"--model-to-evaluate-max-tokens",
|
|
57
90
|
type=int,
|
|
@@ -104,9 +137,24 @@ def evaluation(ctx: click.Context) -> None:
|
|
|
104
137
|
Can not be used when model-a-name and other model config parameters are specified",
|
|
105
138
|
)
|
|
106
139
|
@click.option(
|
|
107
|
-
"--model-a
|
|
140
|
+
"--model-a",
|
|
108
141
|
type=str,
|
|
109
|
-
help="Model name for model A when using detailed config.",
|
|
142
|
+
help="Model name or URL for model A when using detailed config.",
|
|
143
|
+
)
|
|
144
|
+
@click.option(
|
|
145
|
+
"--model-a-source",
|
|
146
|
+
type=click.Choice(["serverless", "dedicated", "external"]),
|
|
147
|
+
help="Source of model A.",
|
|
148
|
+
)
|
|
149
|
+
@click.option(
|
|
150
|
+
"--model-a-external-api-token",
|
|
151
|
+
type=str,
|
|
152
|
+
help="Optional external API token for model A.",
|
|
153
|
+
)
|
|
154
|
+
@click.option(
|
|
155
|
+
"--model-a-external-base-url",
|
|
156
|
+
type=str,
|
|
157
|
+
help="Optional external base URL for model A.",
|
|
110
158
|
)
|
|
111
159
|
@click.option(
|
|
112
160
|
"--model-a-max-tokens",
|
|
@@ -135,9 +183,24 @@ def evaluation(ctx: click.Context) -> None:
|
|
|
135
183
|
Can not be used when model-b-name and other model config parameters are specified",
|
|
136
184
|
)
|
|
137
185
|
@click.option(
|
|
138
|
-
"--model-b
|
|
186
|
+
"--model-b",
|
|
139
187
|
type=str,
|
|
140
|
-
help="Model name for model B when using detailed config.",
|
|
188
|
+
help="Model name or URL for model B when using detailed config.",
|
|
189
|
+
)
|
|
190
|
+
@click.option(
|
|
191
|
+
"--model-b-source",
|
|
192
|
+
type=click.Choice(["serverless", "dedicated", "external"]),
|
|
193
|
+
help="Source of model B.",
|
|
194
|
+
)
|
|
195
|
+
@click.option(
|
|
196
|
+
"--model-b-external-api-token",
|
|
197
|
+
type=str,
|
|
198
|
+
help="Optional external API token for model B.",
|
|
199
|
+
)
|
|
200
|
+
@click.option(
|
|
201
|
+
"--model-b-external-base-url",
|
|
202
|
+
type=str,
|
|
203
|
+
help="Optional external base URL for model B.",
|
|
141
204
|
)
|
|
142
205
|
@click.option(
|
|
143
206
|
"--model-b-max-tokens",
|
|
@@ -162,11 +225,17 @@ def evaluation(ctx: click.Context) -> None:
|
|
|
162
225
|
def create(
|
|
163
226
|
ctx: click.Context,
|
|
164
227
|
type: str,
|
|
165
|
-
|
|
228
|
+
judge_model: str,
|
|
229
|
+
judge_model_source: str,
|
|
166
230
|
judge_system_template: str,
|
|
231
|
+
judge_external_api_token: Optional[str],
|
|
232
|
+
judge_external_base_url: Optional[str],
|
|
167
233
|
input_data_file_path: str,
|
|
168
234
|
model_field: Optional[str],
|
|
169
|
-
|
|
235
|
+
model_to_evaluate: Optional[str],
|
|
236
|
+
model_to_evaluate_source: Optional[str],
|
|
237
|
+
model_to_evaluate_external_api_token: Optional[str],
|
|
238
|
+
model_to_evaluate_external_base_url: Optional[str],
|
|
170
239
|
model_to_evaluate_max_tokens: Optional[int],
|
|
171
240
|
model_to_evaluate_temperature: Optional[float],
|
|
172
241
|
model_to_evaluate_system_template: Optional[str],
|
|
@@ -177,13 +246,19 @@ def create(
|
|
|
177
246
|
max_score: Optional[float],
|
|
178
247
|
pass_threshold: Optional[float],
|
|
179
248
|
model_a_field: Optional[str],
|
|
180
|
-
|
|
249
|
+
model_a: Optional[str],
|
|
250
|
+
model_a_source: Optional[str],
|
|
251
|
+
model_a_external_api_token: Optional[str],
|
|
252
|
+
model_a_external_base_url: Optional[str],
|
|
181
253
|
model_a_max_tokens: Optional[int],
|
|
182
254
|
model_a_temperature: Optional[float],
|
|
183
255
|
model_a_system_template: Optional[str],
|
|
184
256
|
model_a_input_template: Optional[str],
|
|
185
257
|
model_b_field: Optional[str],
|
|
186
|
-
|
|
258
|
+
model_b: Optional[str],
|
|
259
|
+
model_b_source: Optional[str],
|
|
260
|
+
model_b_external_api_token: Optional[str],
|
|
261
|
+
model_b_external_base_url: Optional[str],
|
|
187
262
|
model_b_max_tokens: Optional[int],
|
|
188
263
|
model_b_temperature: Optional[float],
|
|
189
264
|
model_b_system_template: Optional[str],
|
|
@@ -203,7 +278,8 @@ def create(
|
|
|
203
278
|
# Check if any config parameters are provided
|
|
204
279
|
config_params_provided = any(
|
|
205
280
|
[
|
|
206
|
-
|
|
281
|
+
model_to_evaluate,
|
|
282
|
+
model_to_evaluate_source,
|
|
207
283
|
model_to_evaluate_max_tokens,
|
|
208
284
|
model_to_evaluate_temperature,
|
|
209
285
|
model_to_evaluate_system_template,
|
|
@@ -223,17 +299,27 @@ def create(
|
|
|
223
299
|
elif config_params_provided:
|
|
224
300
|
# Config mode: config parameters are provided
|
|
225
301
|
model_to_evaluate_final = {
|
|
226
|
-
"
|
|
302
|
+
"model": model_to_evaluate,
|
|
303
|
+
"model_source": model_to_evaluate_source,
|
|
227
304
|
"max_tokens": model_to_evaluate_max_tokens,
|
|
228
305
|
"temperature": model_to_evaluate_temperature,
|
|
229
306
|
"system_template": model_to_evaluate_system_template,
|
|
230
307
|
"input_template": model_to_evaluate_input_template,
|
|
231
308
|
}
|
|
309
|
+
if model_to_evaluate_external_api_token:
|
|
310
|
+
model_to_evaluate_final["external_api_token"] = (
|
|
311
|
+
model_to_evaluate_external_api_token
|
|
312
|
+
)
|
|
313
|
+
if model_to_evaluate_external_base_url:
|
|
314
|
+
model_to_evaluate_final["external_base_url"] = (
|
|
315
|
+
model_to_evaluate_external_base_url
|
|
316
|
+
)
|
|
232
317
|
|
|
233
318
|
# Build model-a configuration
|
|
234
319
|
model_a_final: Union[Dict[str, Any], None, str] = None
|
|
235
320
|
model_a_config_params = [
|
|
236
|
-
|
|
321
|
+
model_a,
|
|
322
|
+
model_a_source,
|
|
237
323
|
model_a_max_tokens,
|
|
238
324
|
model_a_temperature,
|
|
239
325
|
model_a_system_template,
|
|
@@ -252,17 +338,23 @@ def create(
|
|
|
252
338
|
elif any(model_a_config_params):
|
|
253
339
|
# Config mode: config parameters are provided
|
|
254
340
|
model_a_final = {
|
|
255
|
-
"
|
|
341
|
+
"model": model_a,
|
|
342
|
+
"model_source": model_a_source,
|
|
256
343
|
"max_tokens": model_a_max_tokens,
|
|
257
344
|
"temperature": model_a_temperature,
|
|
258
345
|
"system_template": model_a_system_template,
|
|
259
346
|
"input_template": model_a_input_template,
|
|
260
347
|
}
|
|
348
|
+
if model_a_external_api_token:
|
|
349
|
+
model_a_final["external_api_token"] = model_a_external_api_token
|
|
350
|
+
if model_a_external_base_url:
|
|
351
|
+
model_a_final["external_base_url"] = model_a_external_base_url
|
|
261
352
|
|
|
262
353
|
# Build model-b configuration
|
|
263
354
|
model_b_final: Union[Dict[str, Any], None, str] = None
|
|
264
355
|
model_b_config_params = [
|
|
265
|
-
|
|
356
|
+
model_b,
|
|
357
|
+
model_b_source,
|
|
266
358
|
model_b_max_tokens,
|
|
267
359
|
model_b_temperature,
|
|
268
360
|
model_b_system_template,
|
|
@@ -281,18 +373,26 @@ def create(
|
|
|
281
373
|
elif any(model_b_config_params):
|
|
282
374
|
# Config mode: config parameters are provided
|
|
283
375
|
model_b_final = {
|
|
284
|
-
"
|
|
376
|
+
"model": model_b,
|
|
377
|
+
"model_source": model_b_source,
|
|
285
378
|
"max_tokens": model_b_max_tokens,
|
|
286
379
|
"temperature": model_b_temperature,
|
|
287
380
|
"system_template": model_b_system_template,
|
|
288
381
|
"input_template": model_b_input_template,
|
|
289
382
|
}
|
|
383
|
+
if model_b_external_api_token:
|
|
384
|
+
model_b_final["external_api_token"] = model_b_external_api_token
|
|
385
|
+
if model_b_external_base_url:
|
|
386
|
+
model_b_final["external_base_url"] = model_b_external_base_url
|
|
290
387
|
|
|
291
388
|
try:
|
|
292
389
|
response = client.evaluation.create(
|
|
293
390
|
type=type,
|
|
294
|
-
|
|
391
|
+
judge_model=judge_model,
|
|
392
|
+
judge_model_source=judge_model_source,
|
|
295
393
|
judge_system_template=judge_system_template,
|
|
394
|
+
judge_external_api_token=judge_external_api_token,
|
|
395
|
+
judge_external_base_url=judge_external_base_url,
|
|
296
396
|
input_data_file_path=input_data_file_path,
|
|
297
397
|
model_to_evaluate=model_to_evaluate_final,
|
|
298
398
|
labels=labels_list,
|
together/cli/api/finetune.py
CHANGED
|
@@ -543,3 +543,30 @@ def download(
|
|
|
543
543
|
)
|
|
544
544
|
|
|
545
545
|
click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
@fine_tuning.command()
|
|
549
|
+
@click.pass_context
|
|
550
|
+
@click.argument("fine_tune_id", type=str, required=True)
|
|
551
|
+
@click.option("--force", is_flag=True, help="Force deletion without confirmation")
|
|
552
|
+
@click.option(
|
|
553
|
+
"--quiet", is_flag=True, help="Do not prompt for confirmation before deleting job"
|
|
554
|
+
)
|
|
555
|
+
def delete(
|
|
556
|
+
ctx: click.Context, fine_tune_id: str, force: bool = False, quiet: bool = False
|
|
557
|
+
) -> None:
|
|
558
|
+
"""Delete fine-tuning job"""
|
|
559
|
+
client: Together = ctx.obj
|
|
560
|
+
|
|
561
|
+
if not quiet:
|
|
562
|
+
confirm_response = input(
|
|
563
|
+
f"Are you sure you want to delete fine-tuning job {fine_tune_id}? "
|
|
564
|
+
"This action cannot be undone. [y/N] "
|
|
565
|
+
)
|
|
566
|
+
if confirm_response.lower() != "y":
|
|
567
|
+
click.echo("Deletion cancelled")
|
|
568
|
+
return
|
|
569
|
+
|
|
570
|
+
response = client.fine_tuning.delete(fine_tune_id, force=force)
|
|
571
|
+
|
|
572
|
+
click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
|
together/cli/api/models.py
CHANGED
|
@@ -4,7 +4,7 @@ import click
|
|
|
4
4
|
from tabulate import tabulate
|
|
5
5
|
|
|
6
6
|
from together import Together
|
|
7
|
-
from together.types.models import ModelObject
|
|
7
|
+
from together.types.models import ModelObject, ModelUploadResponse
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
@click.group()
|
|
@@ -53,3 +53,81 @@ def list(ctx: click.Context, type: str | None, json: bool) -> None:
|
|
|
53
53
|
click.echo(json_lib.dumps(display_list, indent=2))
|
|
54
54
|
else:
|
|
55
55
|
click.echo(tabulate(display_list, headers="keys", tablefmt="plain"))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@models.command()
|
|
59
|
+
@click.option(
|
|
60
|
+
"--model-name",
|
|
61
|
+
required=True,
|
|
62
|
+
help="The name to give to your uploaded model",
|
|
63
|
+
)
|
|
64
|
+
@click.option(
|
|
65
|
+
"--model-source",
|
|
66
|
+
required=True,
|
|
67
|
+
help="The source location of the model (Hugging Face repo or S3 path)",
|
|
68
|
+
)
|
|
69
|
+
@click.option(
|
|
70
|
+
"--model-type",
|
|
71
|
+
type=click.Choice(["model", "adapter"]),
|
|
72
|
+
default="model",
|
|
73
|
+
help="Whether the model is a full model or an adapter",
|
|
74
|
+
)
|
|
75
|
+
@click.option(
|
|
76
|
+
"--hf-token",
|
|
77
|
+
help="Hugging Face token (if uploading from Hugging Face)",
|
|
78
|
+
)
|
|
79
|
+
@click.option(
|
|
80
|
+
"--description",
|
|
81
|
+
help="A description of your model",
|
|
82
|
+
)
|
|
83
|
+
@click.option(
|
|
84
|
+
"--base-model",
|
|
85
|
+
help="The base model to use for an adapter if setting it to run against a serverless pool. Only used for model_type 'adapter'.",
|
|
86
|
+
)
|
|
87
|
+
@click.option(
|
|
88
|
+
"--lora-model",
|
|
89
|
+
help="The lora pool to use for an adapter if setting it to run against, say, a dedicated pool. Only used for model_type 'adapter'.",
|
|
90
|
+
)
|
|
91
|
+
@click.option(
|
|
92
|
+
"--json",
|
|
93
|
+
is_flag=True,
|
|
94
|
+
help="Output in JSON format",
|
|
95
|
+
)
|
|
96
|
+
@click.pass_context
|
|
97
|
+
def upload(
|
|
98
|
+
ctx: click.Context,
|
|
99
|
+
model_name: str,
|
|
100
|
+
model_source: str,
|
|
101
|
+
model_type: str,
|
|
102
|
+
hf_token: str | None,
|
|
103
|
+
description: str | None,
|
|
104
|
+
base_model: str | None,
|
|
105
|
+
lora_model: str | None,
|
|
106
|
+
json: bool,
|
|
107
|
+
) -> None:
|
|
108
|
+
"""Upload a custom model or adapter from Hugging Face or S3"""
|
|
109
|
+
client: Together = ctx.obj
|
|
110
|
+
|
|
111
|
+
response: ModelUploadResponse = client.models.upload(
|
|
112
|
+
model_name=model_name,
|
|
113
|
+
model_source=model_source,
|
|
114
|
+
model_type=model_type,
|
|
115
|
+
hf_token=hf_token,
|
|
116
|
+
description=description,
|
|
117
|
+
base_model=base_model,
|
|
118
|
+
lora_model=lora_model,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
if json:
|
|
122
|
+
click.echo(json_lib.dumps(response.model_dump(), indent=2))
|
|
123
|
+
else:
|
|
124
|
+
click.echo(f"Model upload job created successfully!")
|
|
125
|
+
if response.job_id:
|
|
126
|
+
click.echo(f"Job ID: {response.job_id}")
|
|
127
|
+
if response.model_name:
|
|
128
|
+
click.echo(f"Model Name: {response.model_name}")
|
|
129
|
+
if response.model_id:
|
|
130
|
+
click.echo(f"Model ID: {response.model_id}")
|
|
131
|
+
if response.model_source:
|
|
132
|
+
click.echo(f"Model Source: {response.model_source}")
|
|
133
|
+
click.echo(f"Message: {response.message}")
|
together/client.py
CHANGED
|
@@ -26,6 +26,7 @@ class Together:
|
|
|
26
26
|
batches: resources.Batches
|
|
27
27
|
code_interpreter: CodeInterpreter
|
|
28
28
|
evaluation: resources.Evaluation
|
|
29
|
+
videos: resources.Videos
|
|
29
30
|
|
|
30
31
|
# client options
|
|
31
32
|
client: TogetherClient
|
|
@@ -94,6 +95,7 @@ class Together:
|
|
|
94
95
|
self.code_interpreter = CodeInterpreter(self.client)
|
|
95
96
|
self.batches = resources.Batches(self.client)
|
|
96
97
|
self.evaluation = resources.Evaluation(self.client)
|
|
98
|
+
self.videos = resources.Videos(self.client)
|
|
97
99
|
|
|
98
100
|
|
|
99
101
|
class AsyncTogether:
|
|
@@ -109,6 +111,7 @@ class AsyncTogether:
|
|
|
109
111
|
code_interpreter: CodeInterpreter
|
|
110
112
|
batches: resources.AsyncBatches
|
|
111
113
|
evaluation: resources.AsyncEvaluation
|
|
114
|
+
videos: resources.AsyncVideos
|
|
112
115
|
# client options
|
|
113
116
|
client: TogetherClient
|
|
114
117
|
|
|
@@ -175,6 +178,7 @@ class AsyncTogether:
|
|
|
175
178
|
self.code_interpreter = CodeInterpreter(self.client)
|
|
176
179
|
self.batches = resources.AsyncBatches(self.client)
|
|
177
180
|
self.evaluation = resources.AsyncEvaluation(self.client)
|
|
181
|
+
self.videos = resources.AsyncVideos(self.client)
|
|
178
182
|
|
|
179
183
|
|
|
180
184
|
Client = Together
|
together/constants.py
CHANGED
|
@@ -15,6 +15,20 @@ BASE_URL = "https://api.together.xyz/v1"
|
|
|
15
15
|
DOWNLOAD_BLOCK_SIZE = 10 * 1024 * 1024 # 10 MB
|
|
16
16
|
DISABLE_TQDM = False
|
|
17
17
|
|
|
18
|
+
# Upload defaults
|
|
19
|
+
MAX_CONCURRENT_PARTS = 4 # Maximum concurrent parts for multipart upload
|
|
20
|
+
|
|
21
|
+
# Multipart upload constants
|
|
22
|
+
MIN_PART_SIZE_MB = 5 # Minimum part size (S3 requirement)
|
|
23
|
+
TARGET_PART_SIZE_MB = 100 # Target part size for optimal performance
|
|
24
|
+
MAX_MULTIPART_PARTS = 250 # Maximum parts per upload (S3 limit)
|
|
25
|
+
MULTIPART_UPLOAD_TIMEOUT = 300 # Timeout in seconds for uploading each part
|
|
26
|
+
MULTIPART_THRESHOLD_GB = 5.0 # threshold for switching to multipart upload
|
|
27
|
+
|
|
28
|
+
# maximum number of GB sized files we support finetuning for
|
|
29
|
+
MAX_FILE_SIZE_GB = 25.0
|
|
30
|
+
|
|
31
|
+
|
|
18
32
|
# Messages
|
|
19
33
|
MISSING_API_KEY_MESSAGE = """TOGETHER_API_KEY not found.
|
|
20
34
|
Please set it as an environment variable or set it as together.api_key
|
|
@@ -26,8 +40,6 @@ MIN_SAMPLES = 1
|
|
|
26
40
|
# the number of bytes in a gigabyte, used to convert bytes to GB for readable comparison
|
|
27
41
|
NUM_BYTES_IN_GB = 2**30
|
|
28
42
|
|
|
29
|
-
# maximum number of GB sized files we support finetuning for
|
|
30
|
-
MAX_FILE_SIZE_GB = 4.9
|
|
31
43
|
|
|
32
44
|
# expected columns for Parquet files
|
|
33
45
|
PARQUET_EXPECTED_COLUMNS = ["input_ids", "attention_mask", "labels"]
|