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.
@@ -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-name",
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-name",
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-name",
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-name",
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
- judge_model_name: str,
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
- model_to_evaluate_name: Optional[str],
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
- model_a_name: Optional[str],
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
- model_b_name: Optional[str],
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
- model_to_evaluate_name,
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
- "model_name": model_to_evaluate_name,
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
- model_a_name,
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
- "model_name": model_a_name,
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
- model_b_name,
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
- "model_name": model_b_name,
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
- judge_model_name=judge_model_name,
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,
@@ -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))
@@ -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"]