together 1.5.30__py3-none-any.whl → 1.5.32__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 +51 -0
- together/cli/api/chat.py +24 -2
- together/cli/api/endpoints.py +7 -4
- together/cli/api/finetune.py +38 -4
- together/constants.py +3 -3
- together/filemanager.py +45 -22
- together/resources/finetune.py +204 -1
- together/types/__init__.py +4 -0
- together/types/chat_completions.py +6 -0
- together/types/common.py +1 -0
- together/types/files.py +1 -0
- together/types/finetune.py +26 -0
- together/utils/files.py +8 -2
- {together-1.5.30.dist-info → together-1.5.32.dist-info}/METADATA +30 -2
- {together-1.5.30.dist-info → together-1.5.32.dist-info}/RECORD +18 -18
- {together-1.5.30.dist-info → together-1.5.32.dist-info}/WHEEL +0 -0
- {together-1.5.30.dist-info → together-1.5.32.dist-info}/entry_points.txt +0 -0
- {together-1.5.30.dist-info → together-1.5.32.dist-info}/licenses/LICENSE +0 -0
together/__init__.py
CHANGED
|
@@ -1,5 +1,56 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
# =============================================================================
|
|
7
|
+
# SDK 2.0 ANNOUNCEMENT
|
|
8
|
+
# =============================================================================
|
|
9
|
+
_ANNOUNCEMENT_MESSAGE = """
|
|
10
|
+
================================================================================
|
|
11
|
+
Together Python SDK 2.0 is now available!
|
|
12
|
+
|
|
13
|
+
Install: pip install --pre together
|
|
14
|
+
New SDK: https://github.com/togethercomputer/together-py
|
|
15
|
+
Migration guide: https://docs.together.ai/docs/pythonv2-migration-guide
|
|
16
|
+
|
|
17
|
+
This package will be maintained until January 2026.
|
|
18
|
+
================================================================================
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
# Show info banner (unless suppressed)
|
|
22
|
+
if not os.environ.get("TOGETHER_NO_BANNER"):
|
|
23
|
+
try:
|
|
24
|
+
from rich.console import Console
|
|
25
|
+
from rich.panel import Panel
|
|
26
|
+
|
|
27
|
+
console = Console(stderr=True)
|
|
28
|
+
console.print(
|
|
29
|
+
Panel(
|
|
30
|
+
"[bold cyan]Together Python SDK 2.0 is now available![/bold cyan]\n\n"
|
|
31
|
+
"Install the beta:\n"
|
|
32
|
+
"[green]pip install --pre together[/green] or "
|
|
33
|
+
"[green]uv add together --prerelease allow[/green]\n\n"
|
|
34
|
+
"New SDK: [link=https://github.com/togethercomputer/together-py]"
|
|
35
|
+
"https://github.com/togethercomputer/together-py[/link]\n"
|
|
36
|
+
"Migration guide: [link=https://docs.together.ai/docs/pythonv2-migration-guide]"
|
|
37
|
+
"https://docs.together.ai/docs/pythonv2-migration-guide[/link]\n\n"
|
|
38
|
+
"[dim]This package will be maintained until January 2026.\n"
|
|
39
|
+
"Set TOGETHER_NO_BANNER=1 to hide this message.[/dim]",
|
|
40
|
+
title="🚀 New SDK Available",
|
|
41
|
+
border_style="cyan",
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
except Exception:
|
|
45
|
+
# Fallback for any error (ImportError, OSError in daemons, rich errors, etc.)
|
|
46
|
+
# Banner display should never break module imports
|
|
47
|
+
try:
|
|
48
|
+
print(_ANNOUNCEMENT_MESSAGE, file=sys.stderr)
|
|
49
|
+
except Exception:
|
|
50
|
+
pass # Silently ignore if even stderr is unavailable
|
|
51
|
+
|
|
52
|
+
# =============================================================================
|
|
53
|
+
|
|
3
54
|
from contextvars import ContextVar
|
|
4
55
|
from typing import TYPE_CHECKING, Callable
|
|
5
56
|
|
together/cli/api/chat.py
CHANGED
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import cmd
|
|
4
4
|
import json
|
|
5
|
-
from typing import List, Tuple
|
|
5
|
+
from typing import Any, Dict, List, Tuple
|
|
6
6
|
|
|
7
7
|
import click
|
|
8
8
|
|
|
@@ -181,6 +181,12 @@ def interactive(
|
|
|
181
181
|
"--frequency-penalty", type=float, help="Frequency penalty sampling method"
|
|
182
182
|
)
|
|
183
183
|
@click.option("--min-p", type=float, help="Min p sampling")
|
|
184
|
+
@click.option(
|
|
185
|
+
"--audio-url",
|
|
186
|
+
type=str,
|
|
187
|
+
multiple=True,
|
|
188
|
+
help="Audio URL to attach to the last user message",
|
|
189
|
+
)
|
|
184
190
|
@click.option("--no-stream", is_flag=True, help="Disable streaming")
|
|
185
191
|
@click.option("--logprobs", type=int, help="Return logprobs. Only works with --raw.")
|
|
186
192
|
@click.option("--echo", is_flag=True, help="Echo prompt. Only works with --raw.")
|
|
@@ -200,6 +206,7 @@ def chat(
|
|
|
200
206
|
presence_penalty: float | None = None,
|
|
201
207
|
frequency_penalty: float | None = None,
|
|
202
208
|
min_p: float | None = None,
|
|
209
|
+
audio_url: List[str] | None = None,
|
|
203
210
|
no_stream: bool = False,
|
|
204
211
|
logprobs: int | None = None,
|
|
205
212
|
echo: bool | None = None,
|
|
@@ -210,7 +217,22 @@ def chat(
|
|
|
210
217
|
"""Generate chat completions from messages"""
|
|
211
218
|
client: Together = ctx.obj
|
|
212
219
|
|
|
213
|
-
messages
|
|
220
|
+
messages: List[Dict[str, Any]] = [
|
|
221
|
+
{"role": msg[0], "content": msg[1]} for msg in message
|
|
222
|
+
]
|
|
223
|
+
|
|
224
|
+
if audio_url and messages:
|
|
225
|
+
last_msg = messages[-1]
|
|
226
|
+
if last_msg["role"] == "user":
|
|
227
|
+
# Convert content to list if it is string
|
|
228
|
+
if isinstance(last_msg["content"], str):
|
|
229
|
+
last_msg["content"] = [{"type": "text", "text": last_msg["content"]}]
|
|
230
|
+
|
|
231
|
+
# Append audio URLs
|
|
232
|
+
for url in audio_url:
|
|
233
|
+
last_msg["content"].append(
|
|
234
|
+
{"type": "audio_url", "audio_url": {"url": url}}
|
|
235
|
+
)
|
|
214
236
|
|
|
215
237
|
response = client.chat.completions.create(
|
|
216
238
|
model=model,
|
together/cli/api/endpoints.py
CHANGED
|
@@ -137,8 +137,7 @@ def endpoints(ctx: click.Context) -> None:
|
|
|
137
137
|
help="Start endpoint in specified availability zone (e.g., us-central-4b)",
|
|
138
138
|
)
|
|
139
139
|
@click.option(
|
|
140
|
-
"--wait",
|
|
141
|
-
is_flag=True,
|
|
140
|
+
"--wait/--no-wait",
|
|
142
141
|
default=True,
|
|
143
142
|
help="Wait for the endpoint to be ready after creation",
|
|
144
143
|
)
|
|
@@ -284,7 +283,9 @@ def fetch_and_print_hardware_options(
|
|
|
284
283
|
@endpoints.command()
|
|
285
284
|
@click.argument("endpoint-id", required=True)
|
|
286
285
|
@click.option(
|
|
287
|
-
"--wait",
|
|
286
|
+
"--wait/--no-wait",
|
|
287
|
+
default=True,
|
|
288
|
+
help="Wait for the endpoint to stop",
|
|
288
289
|
)
|
|
289
290
|
@click.pass_obj
|
|
290
291
|
@handle_api_errors
|
|
@@ -307,7 +308,9 @@ def stop(client: Together, endpoint_id: str, wait: bool) -> None:
|
|
|
307
308
|
@endpoints.command()
|
|
308
309
|
@click.argument("endpoint-id", required=True)
|
|
309
310
|
@click.option(
|
|
310
|
-
"--wait",
|
|
311
|
+
"--wait/--no-wait",
|
|
312
|
+
default=True,
|
|
313
|
+
help="Wait for the endpoint to start",
|
|
311
314
|
)
|
|
312
315
|
@click.pass_obj
|
|
313
316
|
@handle_api_errors
|
together/cli/api/finetune.py
CHANGED
|
@@ -17,6 +17,8 @@ from together.types.finetune import (
|
|
|
17
17
|
DownloadCheckpointType,
|
|
18
18
|
FinetuneEventType,
|
|
19
19
|
FinetuneTrainingLimits,
|
|
20
|
+
FullTrainingType,
|
|
21
|
+
LoRATrainingType,
|
|
20
22
|
)
|
|
21
23
|
from together.utils import (
|
|
22
24
|
finetune_price_to_dollars,
|
|
@@ -29,13 +31,21 @@ from together.utils import (
|
|
|
29
31
|
|
|
30
32
|
_CONFIRMATION_MESSAGE = (
|
|
31
33
|
"You are about to create a fine-tuning job. "
|
|
32
|
-
"The
|
|
34
|
+
"The estimated price of this job is {price}. "
|
|
35
|
+
"The actual cost of your job will be determined by the model size, the number of tokens "
|
|
33
36
|
"in the training file, the number of tokens in the validation file, the number of epochs, and "
|
|
34
|
-
"the number of evaluations. Visit https://www.together.ai/pricing to
|
|
37
|
+
"the number of evaluations. Visit https://www.together.ai/pricing to learn more about fine-tuning pricing.\n"
|
|
38
|
+
"{warning}"
|
|
35
39
|
"You can pass `-y` or `--confirm` to your command to skip this message.\n\n"
|
|
36
40
|
"Do you want to proceed?"
|
|
37
41
|
)
|
|
38
42
|
|
|
43
|
+
_WARNING_MESSAGE_INSUFFICIENT_FUNDS = (
|
|
44
|
+
"The estimated price of this job is significantly greater than your current credit limit and balance combined. "
|
|
45
|
+
"It will likely get cancelled due to insufficient funds. "
|
|
46
|
+
"Consider increasing your credit limit at https://api.together.xyz/settings/profile\n"
|
|
47
|
+
)
|
|
48
|
+
|
|
39
49
|
|
|
40
50
|
class DownloadCheckpointTypeChoice(click.Choice):
|
|
41
51
|
def __init__(self) -> None:
|
|
@@ -357,12 +367,36 @@ def create(
|
|
|
357
367
|
"You have specified a number of evaluation loops but no validation file."
|
|
358
368
|
)
|
|
359
369
|
|
|
360
|
-
|
|
370
|
+
finetune_price_estimation_result = client.fine_tuning.estimate_price(
|
|
371
|
+
training_file=training_file,
|
|
372
|
+
validation_file=validation_file,
|
|
373
|
+
model=model,
|
|
374
|
+
n_epochs=n_epochs,
|
|
375
|
+
n_evals=n_evals,
|
|
376
|
+
training_type="lora" if lora else "full",
|
|
377
|
+
training_method=training_method,
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
price = click.style(
|
|
381
|
+
f"${finetune_price_estimation_result.estimated_total_price:.2f}",
|
|
382
|
+
bold=True,
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
if not finetune_price_estimation_result.allowed_to_proceed:
|
|
386
|
+
warning = click.style(_WARNING_MESSAGE_INSUFFICIENT_FUNDS, fg="red", bold=True)
|
|
387
|
+
else:
|
|
388
|
+
warning = ""
|
|
389
|
+
|
|
390
|
+
confirmation_message = _CONFIRMATION_MESSAGE.format(
|
|
391
|
+
price=price,
|
|
392
|
+
warning=warning,
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
if confirm or click.confirm(confirmation_message, default=True, show_default=True):
|
|
361
396
|
response = client.fine_tuning.create(
|
|
362
397
|
**training_args,
|
|
363
398
|
verbose=True,
|
|
364
399
|
)
|
|
365
|
-
|
|
366
400
|
report_string = f"Successfully submitted a fine-tuning job {response.id}"
|
|
367
401
|
if response.created_at is not None:
|
|
368
402
|
created_time = datetime.strptime(
|
together/constants.py
CHANGED
|
@@ -20,13 +20,13 @@ MAX_CONCURRENT_PARTS = 4 # Maximum concurrent parts for multipart upload
|
|
|
20
20
|
|
|
21
21
|
# Multipart upload constants
|
|
22
22
|
MIN_PART_SIZE_MB = 5 # Minimum part size (S3 requirement)
|
|
23
|
-
TARGET_PART_SIZE_MB =
|
|
24
|
-
MAX_MULTIPART_PARTS = 250 # Maximum parts per upload
|
|
23
|
+
TARGET_PART_SIZE_MB = 250 # Target part size
|
|
24
|
+
MAX_MULTIPART_PARTS = 250 # Maximum parts per upload
|
|
25
25
|
MULTIPART_UPLOAD_TIMEOUT = 300 # Timeout in seconds for uploading each part
|
|
26
26
|
MULTIPART_THRESHOLD_GB = 5.0 # threshold for switching to multipart upload
|
|
27
27
|
|
|
28
28
|
# maximum number of GB sized files we support finetuning for
|
|
29
|
-
MAX_FILE_SIZE_GB =
|
|
29
|
+
MAX_FILE_SIZE_GB = 50.1
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
# Messages
|
together/filemanager.py
CHANGED
|
@@ -6,10 +6,10 @@ import shutil
|
|
|
6
6
|
import stat
|
|
7
7
|
import tempfile
|
|
8
8
|
import uuid
|
|
9
|
-
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
9
|
+
from concurrent.futures import Future, ThreadPoolExecutor, as_completed
|
|
10
10
|
from functools import partial
|
|
11
11
|
from pathlib import Path
|
|
12
|
-
from typing import Any, Dict, List, Tuple
|
|
12
|
+
from typing import Any, BinaryIO, Dict, List, Tuple
|
|
13
13
|
|
|
14
14
|
import requests
|
|
15
15
|
from filelock import FileLock
|
|
@@ -212,6 +212,7 @@ class DownloadManager:
|
|
|
212
212
|
),
|
|
213
213
|
remaining_retries=MAX_RETRIES,
|
|
214
214
|
stream=True,
|
|
215
|
+
request_timeout=3600,
|
|
215
216
|
)
|
|
216
217
|
|
|
217
218
|
try:
|
|
@@ -512,6 +513,18 @@ class MultipartUploadManager:
|
|
|
512
513
|
|
|
513
514
|
return response.data
|
|
514
515
|
|
|
516
|
+
def _submit_part(
|
|
517
|
+
self,
|
|
518
|
+
executor: ThreadPoolExecutor,
|
|
519
|
+
f: BinaryIO,
|
|
520
|
+
part_info: Dict[str, Any],
|
|
521
|
+
part_size: int,
|
|
522
|
+
) -> Future[str]:
|
|
523
|
+
"""Submit a single part for upload and return the future"""
|
|
524
|
+
f.seek((part_info["PartNumber"] - 1) * part_size)
|
|
525
|
+
part_data = f.read(part_size)
|
|
526
|
+
return executor.submit(self._upload_single_part, part_info, part_data)
|
|
527
|
+
|
|
515
528
|
def _upload_parts_concurrent(
|
|
516
529
|
self, file: Path, upload_info: Dict[str, Any], part_size: int
|
|
517
530
|
) -> List[Dict[str, Any]]:
|
|
@@ -522,29 +535,39 @@ class MultipartUploadManager:
|
|
|
522
535
|
|
|
523
536
|
with ThreadPoolExecutor(max_workers=self.max_concurrent_parts) as executor:
|
|
524
537
|
with tqdm(total=len(parts), desc="Uploading parts", unit="part") as pbar:
|
|
525
|
-
future_to_part = {}
|
|
526
|
-
|
|
527
538
|
with open(file, "rb") as f:
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
part_data = f.read(part_size)
|
|
539
|
+
future_to_part = {}
|
|
540
|
+
part_index = 0
|
|
531
541
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
542
|
+
# Submit initial batch limited by max_concurrent_parts
|
|
543
|
+
for _ in range(min(self.max_concurrent_parts, len(parts))):
|
|
544
|
+
part_info = parts[part_index]
|
|
545
|
+
future = self._submit_part(executor, f, part_info, part_size)
|
|
535
546
|
future_to_part[future] = part_info["PartNumber"]
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
547
|
+
part_index += 1
|
|
548
|
+
|
|
549
|
+
# Process completions and submit new parts (sliding window)
|
|
550
|
+
while future_to_part:
|
|
551
|
+
done_future = next(as_completed(future_to_part))
|
|
552
|
+
part_number = future_to_part.pop(done_future)
|
|
553
|
+
|
|
554
|
+
try:
|
|
555
|
+
etag = done_future.result()
|
|
556
|
+
completed_parts.append(
|
|
557
|
+
{"part_number": part_number, "etag": etag}
|
|
558
|
+
)
|
|
559
|
+
pbar.update(1)
|
|
560
|
+
except Exception as e:
|
|
561
|
+
raise Exception(f"Failed to upload part {part_number}: {e}")
|
|
562
|
+
|
|
563
|
+
# Submit next part if available
|
|
564
|
+
if part_index < len(parts):
|
|
565
|
+
part_info = parts[part_index]
|
|
566
|
+
future = self._submit_part(
|
|
567
|
+
executor, f, part_info, part_size
|
|
568
|
+
)
|
|
569
|
+
future_to_part[future] = part_info["PartNumber"]
|
|
570
|
+
part_index += 1
|
|
548
571
|
|
|
549
572
|
completed_parts.sort(key=lambda x: x["part_number"])
|
|
550
573
|
return completed_parts
|
together/resources/finetune.py
CHANGED
|
@@ -20,6 +20,8 @@ from together.types import (
|
|
|
20
20
|
FinetuneLRScheduler,
|
|
21
21
|
FinetuneRequest,
|
|
22
22
|
FinetuneResponse,
|
|
23
|
+
FinetunePriceEstimationRequest,
|
|
24
|
+
FinetunePriceEstimationResponse,
|
|
23
25
|
FinetuneTrainingLimits,
|
|
24
26
|
FullTrainingType,
|
|
25
27
|
LinearLRScheduler,
|
|
@@ -31,7 +33,7 @@ from together.types import (
|
|
|
31
33
|
TrainingMethodSFT,
|
|
32
34
|
TrainingType,
|
|
33
35
|
)
|
|
34
|
-
from together.types.finetune import DownloadCheckpointType
|
|
36
|
+
from together.types.finetune import DownloadCheckpointType, TrainingMethod
|
|
35
37
|
from together.utils import log_warn_once, normalize_key
|
|
36
38
|
|
|
37
39
|
|
|
@@ -42,6 +44,12 @@ AVAILABLE_TRAINING_METHODS = {
|
|
|
42
44
|
TrainingMethodSFT().method,
|
|
43
45
|
TrainingMethodDPO().method,
|
|
44
46
|
}
|
|
47
|
+
_WARNING_MESSAGE_INSUFFICIENT_FUNDS = (
|
|
48
|
+
"The estimated price of the fine-tuning job is {} which is significantly "
|
|
49
|
+
"greater than your current credit limit and balance combined. "
|
|
50
|
+
"It will likely get cancelled due to insufficient funds. "
|
|
51
|
+
"Proceed at your own risk."
|
|
52
|
+
)
|
|
45
53
|
|
|
46
54
|
|
|
47
55
|
def create_finetune_request(
|
|
@@ -473,12 +481,34 @@ class FineTuning:
|
|
|
473
481
|
hf_api_token=hf_api_token,
|
|
474
482
|
hf_output_repo_name=hf_output_repo_name,
|
|
475
483
|
)
|
|
484
|
+
if from_checkpoint is None and from_hf_model is None:
|
|
485
|
+
price_estimation_result = self.estimate_price(
|
|
486
|
+
training_file=training_file,
|
|
487
|
+
validation_file=validation_file,
|
|
488
|
+
model=model_name,
|
|
489
|
+
n_epochs=finetune_request.n_epochs,
|
|
490
|
+
n_evals=finetune_request.n_evals,
|
|
491
|
+
training_type="lora" if lora else "full",
|
|
492
|
+
training_method=training_method,
|
|
493
|
+
)
|
|
494
|
+
price_limit_passed = price_estimation_result.allowed_to_proceed
|
|
495
|
+
else:
|
|
496
|
+
# unsupported case
|
|
497
|
+
price_limit_passed = True
|
|
476
498
|
|
|
477
499
|
if verbose:
|
|
478
500
|
rprint(
|
|
479
501
|
"Submitting a fine-tuning job with the following parameters:",
|
|
480
502
|
finetune_request,
|
|
481
503
|
)
|
|
504
|
+
if not price_limit_passed:
|
|
505
|
+
rprint(
|
|
506
|
+
"[red]"
|
|
507
|
+
+ _WARNING_MESSAGE_INSUFFICIENT_FUNDS.format(
|
|
508
|
+
price_estimation_result.estimated_total_price
|
|
509
|
+
)
|
|
510
|
+
+ "[/red]",
|
|
511
|
+
)
|
|
482
512
|
parameter_payload = finetune_request.model_dump(exclude_none=True)
|
|
483
513
|
|
|
484
514
|
response, _, _ = requestor.request(
|
|
@@ -493,6 +523,81 @@ class FineTuning:
|
|
|
493
523
|
|
|
494
524
|
return FinetuneResponse(**response.data)
|
|
495
525
|
|
|
526
|
+
def estimate_price(
|
|
527
|
+
self,
|
|
528
|
+
*,
|
|
529
|
+
training_file: str,
|
|
530
|
+
model: str,
|
|
531
|
+
validation_file: str | None = None,
|
|
532
|
+
n_epochs: int | None = 1,
|
|
533
|
+
n_evals: int | None = 0,
|
|
534
|
+
training_type: str = "lora",
|
|
535
|
+
training_method: str = "sft",
|
|
536
|
+
) -> FinetunePriceEstimationResponse:
|
|
537
|
+
"""
|
|
538
|
+
Estimates the price of a fine-tuning job
|
|
539
|
+
|
|
540
|
+
Args:
|
|
541
|
+
training_file (str): File-ID of a file uploaded to the Together API
|
|
542
|
+
model (str): Name of the base model to run fine-tune job on
|
|
543
|
+
validation_file (str, optional): File ID of a file uploaded to the Together API for validation.
|
|
544
|
+
n_epochs (int, optional): Number of epochs for fine-tuning. Defaults to 1.
|
|
545
|
+
n_evals (int, optional): Number of evaluation loops to run. Defaults to 0.
|
|
546
|
+
training_type (str, optional): Training type. Defaults to "lora".
|
|
547
|
+
training_method (str, optional): Training method. Defaults to "sft".
|
|
548
|
+
|
|
549
|
+
Returns:
|
|
550
|
+
FinetunePriceEstimationResponse: Object containing the price estimation result.
|
|
551
|
+
"""
|
|
552
|
+
training_type_cls: TrainingType
|
|
553
|
+
training_method_cls: TrainingMethod
|
|
554
|
+
|
|
555
|
+
if training_method == "sft":
|
|
556
|
+
training_method_cls = TrainingMethodSFT(method="sft")
|
|
557
|
+
elif training_method == "dpo":
|
|
558
|
+
training_method_cls = TrainingMethodDPO(method="dpo")
|
|
559
|
+
else:
|
|
560
|
+
raise ValueError(f"Unknown training method: {training_method}")
|
|
561
|
+
|
|
562
|
+
if training_type.lower() == "lora":
|
|
563
|
+
# parameters of lora are unused in price estimation
|
|
564
|
+
# but we need to set them to valid values
|
|
565
|
+
training_type_cls = LoRATrainingType(
|
|
566
|
+
type="Lora",
|
|
567
|
+
lora_r=16,
|
|
568
|
+
lora_alpha=16,
|
|
569
|
+
lora_dropout=0.0,
|
|
570
|
+
lora_trainable_modules="all-linear",
|
|
571
|
+
)
|
|
572
|
+
elif training_type.lower() == "full":
|
|
573
|
+
training_type_cls = FullTrainingType(type="Full")
|
|
574
|
+
else:
|
|
575
|
+
raise ValueError(f"Unknown training type: {training_type}")
|
|
576
|
+
|
|
577
|
+
request = FinetunePriceEstimationRequest(
|
|
578
|
+
training_file=training_file,
|
|
579
|
+
validation_file=validation_file,
|
|
580
|
+
model=model,
|
|
581
|
+
n_epochs=n_epochs,
|
|
582
|
+
n_evals=n_evals,
|
|
583
|
+
training_type=training_type_cls,
|
|
584
|
+
training_method=training_method_cls,
|
|
585
|
+
)
|
|
586
|
+
parameter_payload = request.model_dump(exclude_none=True)
|
|
587
|
+
requestor = api_requestor.APIRequestor(
|
|
588
|
+
client=self._client,
|
|
589
|
+
)
|
|
590
|
+
|
|
591
|
+
response, _, _ = requestor.request(
|
|
592
|
+
options=TogetherRequest(
|
|
593
|
+
method="POST", url="fine-tunes/estimate-price", params=parameter_payload
|
|
594
|
+
),
|
|
595
|
+
stream=False,
|
|
596
|
+
)
|
|
597
|
+
assert isinstance(response, TogetherResponse)
|
|
598
|
+
|
|
599
|
+
return FinetunePriceEstimationResponse(**response.data)
|
|
600
|
+
|
|
496
601
|
def list(self) -> FinetuneList:
|
|
497
602
|
"""
|
|
498
603
|
Lists fine-tune job history
|
|
@@ -941,11 +1046,34 @@ class AsyncFineTuning:
|
|
|
941
1046
|
hf_output_repo_name=hf_output_repo_name,
|
|
942
1047
|
)
|
|
943
1048
|
|
|
1049
|
+
if from_checkpoint is None and from_hf_model is None:
|
|
1050
|
+
price_estimation_result = await self.estimate_price(
|
|
1051
|
+
training_file=training_file,
|
|
1052
|
+
validation_file=validation_file,
|
|
1053
|
+
model=model_name,
|
|
1054
|
+
n_epochs=finetune_request.n_epochs,
|
|
1055
|
+
n_evals=finetune_request.n_evals,
|
|
1056
|
+
training_type="lora" if lora else "full",
|
|
1057
|
+
training_method=training_method,
|
|
1058
|
+
)
|
|
1059
|
+
price_limit_passed = price_estimation_result.allowed_to_proceed
|
|
1060
|
+
else:
|
|
1061
|
+
# unsupported case
|
|
1062
|
+
price_limit_passed = True
|
|
1063
|
+
|
|
944
1064
|
if verbose:
|
|
945
1065
|
rprint(
|
|
946
1066
|
"Submitting a fine-tuning job with the following parameters:",
|
|
947
1067
|
finetune_request,
|
|
948
1068
|
)
|
|
1069
|
+
if not price_limit_passed:
|
|
1070
|
+
rprint(
|
|
1071
|
+
"[red]"
|
|
1072
|
+
+ _WARNING_MESSAGE_INSUFFICIENT_FUNDS.format(
|
|
1073
|
+
price_estimation_result.estimated_total_price
|
|
1074
|
+
)
|
|
1075
|
+
+ "[/red]",
|
|
1076
|
+
)
|
|
949
1077
|
parameter_payload = finetune_request.model_dump(exclude_none=True)
|
|
950
1078
|
|
|
951
1079
|
response, _, _ = await requestor.arequest(
|
|
@@ -961,6 +1089,81 @@ class AsyncFineTuning:
|
|
|
961
1089
|
|
|
962
1090
|
return FinetuneResponse(**response.data)
|
|
963
1091
|
|
|
1092
|
+
async def estimate_price(
|
|
1093
|
+
self,
|
|
1094
|
+
*,
|
|
1095
|
+
training_file: str,
|
|
1096
|
+
model: str,
|
|
1097
|
+
validation_file: str | None = None,
|
|
1098
|
+
n_epochs: int | None = 1,
|
|
1099
|
+
n_evals: int | None = 0,
|
|
1100
|
+
training_type: str = "lora",
|
|
1101
|
+
training_method: str = "sft",
|
|
1102
|
+
) -> FinetunePriceEstimationResponse:
|
|
1103
|
+
"""
|
|
1104
|
+
Estimates the price of a fine-tuning job
|
|
1105
|
+
|
|
1106
|
+
Args:
|
|
1107
|
+
training_file (str): File-ID of a file uploaded to the Together API
|
|
1108
|
+
model (str): Name of the base model to run fine-tune job on
|
|
1109
|
+
validation_file (str, optional): File ID of a file uploaded to the Together API for validation.
|
|
1110
|
+
n_epochs (int, optional): Number of epochs for fine-tuning. Defaults to 1.
|
|
1111
|
+
n_evals (int, optional): Number of evaluation loops to run. Defaults to 0.
|
|
1112
|
+
training_type (str, optional): Training type. Defaults to "lora".
|
|
1113
|
+
training_method (str, optional): Training method. Defaults to "sft".
|
|
1114
|
+
|
|
1115
|
+
Returns:
|
|
1116
|
+
FinetunePriceEstimationResponse: Object containing the price estimation result.
|
|
1117
|
+
"""
|
|
1118
|
+
training_type_cls: TrainingType
|
|
1119
|
+
training_method_cls: TrainingMethod
|
|
1120
|
+
|
|
1121
|
+
if training_method == "sft":
|
|
1122
|
+
training_method_cls = TrainingMethodSFT(method="sft")
|
|
1123
|
+
elif training_method == "dpo":
|
|
1124
|
+
training_method_cls = TrainingMethodDPO(method="dpo")
|
|
1125
|
+
else:
|
|
1126
|
+
raise ValueError(f"Unknown training method: {training_method}")
|
|
1127
|
+
|
|
1128
|
+
if training_type.lower() == "lora":
|
|
1129
|
+
# parameters of lora are unused in price estimation
|
|
1130
|
+
# but we need to set them to valid values
|
|
1131
|
+
training_type_cls = LoRATrainingType(
|
|
1132
|
+
type="Lora",
|
|
1133
|
+
lora_r=16,
|
|
1134
|
+
lora_alpha=16,
|
|
1135
|
+
lora_dropout=0.0,
|
|
1136
|
+
lora_trainable_modules="all-linear",
|
|
1137
|
+
)
|
|
1138
|
+
elif training_type.lower() == "full":
|
|
1139
|
+
training_type_cls = FullTrainingType(type="Full")
|
|
1140
|
+
else:
|
|
1141
|
+
raise ValueError(f"Unknown training type: {training_type}")
|
|
1142
|
+
|
|
1143
|
+
request = FinetunePriceEstimationRequest(
|
|
1144
|
+
training_file=training_file,
|
|
1145
|
+
validation_file=validation_file,
|
|
1146
|
+
model=model,
|
|
1147
|
+
n_epochs=n_epochs,
|
|
1148
|
+
n_evals=n_evals,
|
|
1149
|
+
training_type=training_type_cls,
|
|
1150
|
+
training_method=training_method_cls,
|
|
1151
|
+
)
|
|
1152
|
+
parameter_payload = request.model_dump(exclude_none=True)
|
|
1153
|
+
requestor = api_requestor.APIRequestor(
|
|
1154
|
+
client=self._client,
|
|
1155
|
+
)
|
|
1156
|
+
|
|
1157
|
+
response, _, _ = await requestor.arequest(
|
|
1158
|
+
options=TogetherRequest(
|
|
1159
|
+
method="POST", url="fine-tunes/estimate-price", params=parameter_payload
|
|
1160
|
+
),
|
|
1161
|
+
stream=False,
|
|
1162
|
+
)
|
|
1163
|
+
assert isinstance(response, TogetherResponse)
|
|
1164
|
+
|
|
1165
|
+
return FinetunePriceEstimationResponse(**response.data)
|
|
1166
|
+
|
|
964
1167
|
async def list(self) -> FinetuneList:
|
|
965
1168
|
"""
|
|
966
1169
|
Async method to list fine-tune job history
|
together/types/__init__.py
CHANGED
|
@@ -54,6 +54,8 @@ from together.types.finetune import (
|
|
|
54
54
|
FinetuneListEvents,
|
|
55
55
|
FinetuneRequest,
|
|
56
56
|
FinetuneResponse,
|
|
57
|
+
FinetunePriceEstimationRequest,
|
|
58
|
+
FinetunePriceEstimationResponse,
|
|
57
59
|
FinetuneDeleteResponse,
|
|
58
60
|
FinetuneTrainingLimits,
|
|
59
61
|
FullTrainingType,
|
|
@@ -103,6 +105,8 @@ __all__ = [
|
|
|
103
105
|
"FinetuneDeleteResponse",
|
|
104
106
|
"FinetuneDownloadResult",
|
|
105
107
|
"FinetuneLRScheduler",
|
|
108
|
+
"FinetunePriceEstimationRequest",
|
|
109
|
+
"FinetunePriceEstimationResponse",
|
|
106
110
|
"LinearLRScheduler",
|
|
107
111
|
"LinearLRSchedulerArgs",
|
|
108
112
|
"CosineLRScheduler",
|
|
@@ -46,6 +46,7 @@ class ChatCompletionMessageContentType(str, Enum):
|
|
|
46
46
|
TEXT = "text"
|
|
47
47
|
IMAGE_URL = "image_url"
|
|
48
48
|
VIDEO_URL = "video_url"
|
|
49
|
+
AUDIO_URL = "audio_url"
|
|
49
50
|
|
|
50
51
|
|
|
51
52
|
class ChatCompletionMessageContentImageURL(BaseModel):
|
|
@@ -56,11 +57,16 @@ class ChatCompletionMessageContentVideoURL(BaseModel):
|
|
|
56
57
|
url: str
|
|
57
58
|
|
|
58
59
|
|
|
60
|
+
class ChatCompletionMessageContentAudioURL(BaseModel):
|
|
61
|
+
url: str
|
|
62
|
+
|
|
63
|
+
|
|
59
64
|
class ChatCompletionMessageContent(BaseModel):
|
|
60
65
|
type: ChatCompletionMessageContentType
|
|
61
66
|
text: str | None = None
|
|
62
67
|
image_url: ChatCompletionMessageContentImageURL | None = None
|
|
63
68
|
video_url: ChatCompletionMessageContentVideoURL | None = None
|
|
69
|
+
audio_url: ChatCompletionMessageContentAudioURL | None = None
|
|
64
70
|
|
|
65
71
|
|
|
66
72
|
class ChatCompletionMessage(BaseModel):
|
together/types/common.py
CHANGED
together/types/files.py
CHANGED
together/types/finetune.py
CHANGED
|
@@ -308,6 +308,32 @@ class FinetuneResponse(BaseModel):
|
|
|
308
308
|
raise ValueError("Unknown training type")
|
|
309
309
|
|
|
310
310
|
|
|
311
|
+
class FinetunePriceEstimationRequest(BaseModel):
|
|
312
|
+
"""
|
|
313
|
+
Fine-tune price estimation request type
|
|
314
|
+
"""
|
|
315
|
+
|
|
316
|
+
training_file: str
|
|
317
|
+
validation_file: str | None = None
|
|
318
|
+
model: str
|
|
319
|
+
n_epochs: int
|
|
320
|
+
n_evals: int
|
|
321
|
+
training_type: TrainingType
|
|
322
|
+
training_method: TrainingMethod
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
class FinetunePriceEstimationResponse(BaseModel):
|
|
326
|
+
"""
|
|
327
|
+
Fine-tune price estimation response type
|
|
328
|
+
"""
|
|
329
|
+
|
|
330
|
+
estimated_total_price: float
|
|
331
|
+
user_limit: float
|
|
332
|
+
estimated_train_token_count: int
|
|
333
|
+
estimated_eval_token_count: int
|
|
334
|
+
allowed_to_proceed: bool
|
|
335
|
+
|
|
336
|
+
|
|
311
337
|
class FinetuneList(BaseModel):
|
|
312
338
|
# object type
|
|
313
339
|
object: Literal["list"] | None = None
|
together/utils/files.py
CHANGED
|
@@ -7,6 +7,7 @@ from pathlib import Path
|
|
|
7
7
|
from traceback import format_exc
|
|
8
8
|
from typing import Any, Dict, List
|
|
9
9
|
|
|
10
|
+
from tqdm import tqdm
|
|
10
11
|
|
|
11
12
|
from together.constants import (
|
|
12
13
|
MAX_FILE_SIZE_GB,
|
|
@@ -363,14 +364,19 @@ def _check_utf8(file: Path) -> Dict[str, Any]:
|
|
|
363
364
|
Dict[str, Any]: A dictionary with the results of the check.
|
|
364
365
|
"""
|
|
365
366
|
report_dict: Dict[str, Any] = {}
|
|
367
|
+
|
|
366
368
|
try:
|
|
369
|
+
# Dry-run UTF-8 decode: iterate through file to validate encoding
|
|
367
370
|
with file.open(encoding="utf-8") as f:
|
|
368
|
-
f
|
|
371
|
+
for _ in f:
|
|
372
|
+
pass
|
|
373
|
+
|
|
369
374
|
report_dict["utf8"] = True
|
|
370
375
|
except UnicodeDecodeError as e:
|
|
371
376
|
report_dict["utf8"] = False
|
|
372
377
|
report_dict["message"] = f"File is not UTF-8 encoded. Error raised: {e}."
|
|
373
378
|
report_dict["is_check_passed"] = False
|
|
379
|
+
|
|
374
380
|
return report_dict
|
|
375
381
|
|
|
376
382
|
|
|
@@ -470,7 +476,7 @@ def _check_jsonl(file: Path, purpose: FilePurpose | str) -> Dict[str, Any]:
|
|
|
470
476
|
with file.open() as f:
|
|
471
477
|
idx = -1
|
|
472
478
|
try:
|
|
473
|
-
for idx, line in enumerate(f):
|
|
479
|
+
for idx, line in tqdm(enumerate(f), desc="Validating file", unit=" lines"):
|
|
474
480
|
json_line = json.loads(line)
|
|
475
481
|
|
|
476
482
|
if not isinstance(json_line, dict):
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: together
|
|
3
|
-
Version: 1.5.
|
|
4
|
-
Summary: Python client for Together's Cloud Platform!
|
|
3
|
+
Version: 1.5.32
|
|
4
|
+
Summary: Python client for Together's Cloud Platform! Note: SDK 2.0 is now available at https://github.com/togethercomputer/together-py
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
7
7
|
Author: Together AI
|
|
@@ -42,6 +42,34 @@ Description-Content-Type: text/markdown
|
|
|
42
42
|
</a>
|
|
43
43
|
</div>
|
|
44
44
|
|
|
45
|
+
> [!NOTE]
|
|
46
|
+
> ## 🚀 Together Python SDK 2.0 is now available!
|
|
47
|
+
>
|
|
48
|
+
> Check out the new SDK: **[together-py](https://github.com/togethercomputer/together-py)**
|
|
49
|
+
>
|
|
50
|
+
> 📖 **Migration Guide:** [https://docs.together.ai/docs/pythonv2-migration-guide](https://docs.together.ai/docs/pythonv2-migration-guide)
|
|
51
|
+
>
|
|
52
|
+
> ### Install the Beta
|
|
53
|
+
>
|
|
54
|
+
> **Using uv (Recommended):**
|
|
55
|
+
> ```bash
|
|
56
|
+
> # Install uv if you haven't already
|
|
57
|
+
> curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
58
|
+
>
|
|
59
|
+
> # Install together python SDK
|
|
60
|
+
> uv add together --prerelease allow
|
|
61
|
+
>
|
|
62
|
+
> # Or upgrade an existing installation
|
|
63
|
+
> uv sync --upgrade-package together --prerelease allow
|
|
64
|
+
> ```
|
|
65
|
+
>
|
|
66
|
+
> **Using pip:**
|
|
67
|
+
> ```bash
|
|
68
|
+
> pip install --pre together
|
|
69
|
+
> ```
|
|
70
|
+
>
|
|
71
|
+
> This package will be maintained until January 2026.
|
|
72
|
+
|
|
45
73
|
# Together Python API library
|
|
46
74
|
|
|
47
75
|
[](https://pypi.org/project/together/)
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
together/__init__.py,sha256=
|
|
1
|
+
together/__init__.py,sha256=QTmcsqfUFqf6pWGK_NuXKupuK5m5jGGj24HF0za0_yA,3715
|
|
2
2
|
together/abstract/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
together/abstract/api_requestor.py,sha256=CPFsQXEqIoXDcqxlDQyumbTMtGmL7CQYtSYrkb3binU,27556
|
|
4
4
|
together/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
together/cli/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
together/cli/api/chat.py,sha256=
|
|
6
|
+
together/cli/api/chat.py,sha256=auJh0WZwpY16vFLJojkzLJYnjU1IgNz_ybf7sQtKga0,9941
|
|
7
7
|
together/cli/api/completions.py,sha256=l-Zw5t7hojL3w8xd_mitS2NRB72i5Z0xwkzH0rT5XMc,4263
|
|
8
|
-
together/cli/api/endpoints.py,sha256=
|
|
8
|
+
together/cli/api/endpoints.py,sha256=S3px19iGTKy5KS1nuKrvUUMoqc_KtrZHyIwjwjqX7uQ,14624
|
|
9
9
|
together/cli/api/evaluation.py,sha256=36SsujC5qicf-8l8GA8wqRtEC8NKzsAjL-_nYhePpQM,14691
|
|
10
10
|
together/cli/api/files.py,sha256=QLYEXRkY8J2Gg1SbTCtzGfoTMvosoeACNK83L_oLubs,3397
|
|
11
|
-
together/cli/api/finetune.py,sha256=
|
|
11
|
+
together/cli/api/finetune.py,sha256=Hmn8UrDNCPiLPDilnKPjnx8V27WliAVTZgQKb6SnHwc,19625
|
|
12
12
|
together/cli/api/images.py,sha256=GADSeaNUHUVMtWovmccGuKc28IJ9E_v4vAEwYHJhu5o,2645
|
|
13
13
|
together/cli/api/models.py,sha256=BRWRiguuJ8OwAD8crajpZ7RyCHA35tyOZvi3iLWQ7k4,3679
|
|
14
14
|
together/cli/api/utils.py,sha256=IuqYWPnLI38_Bqd7lj8V_SnGdYc59pRmMbQmciS4FsM,1326
|
|
15
15
|
together/cli/cli.py,sha256=PVahUjOfAQIjo209FoPKljcCA_OIpOYQ9MAsCjfEMu0,2134
|
|
16
16
|
together/client.py,sha256=KD33kAPkWTcnXjge4rLK_L3UsJYsxNUkvL6b9SgTEf0,6324
|
|
17
|
-
together/constants.py,sha256=
|
|
17
|
+
together/constants.py,sha256=IaKMIamFia9nyq8jPrmqu5y0YL5mC_474AAIUXYFsdk,1964
|
|
18
18
|
together/error.py,sha256=HU6247CyzCFjaxL9A0XYbXZ6fY_ebRg0FEYjI4Skogs,5515
|
|
19
|
-
together/filemanager.py,sha256=
|
|
19
|
+
together/filemanager.py,sha256=bynQp2yGoFMZcgVtgFlkYxTbnk6n_GxdiEpY0q50kbk,19448
|
|
20
20
|
together/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
21
|
together/legacy/base.py,sha256=ehrX1SCfRbK5OA83wL1q7-tfF-yuZOUxzjxYfFtdvvQ,727
|
|
22
22
|
together/legacy/complete.py,sha256=NRJX-vjnkg4HrgDo9LS3jFfhwfXpeGxcl24dcrLPK3A,2439
|
|
@@ -40,26 +40,26 @@ together/resources/embeddings.py,sha256=PTvLb82yjG_-iQOyuhsilp77Fr7gZ0o6WD2KeRnK
|
|
|
40
40
|
together/resources/endpoints.py,sha256=BP75wUEcOtpiUbfLAQH5GX2RL8_RnM522-D8Iz7_LUU,20378
|
|
41
41
|
together/resources/evaluation.py,sha256=eYSs9HUpW51XZjX-yNlFZlLapsuEDINJ8BjxJoYa4U0,31443
|
|
42
42
|
together/resources/files.py,sha256=_uK5xzriXNOGNw3tQGuTbCaxBRo6Az6_cXOUtBNFzDk,5434
|
|
43
|
-
together/resources/finetune.py,sha256=
|
|
43
|
+
together/resources/finetune.py,sha256=rOclrA4GCu1wrE-D0-hc0ac7lJksucbIW6OOxQT0q7I,52981
|
|
44
44
|
together/resources/images.py,sha256=FHXkcnzyj2JLw4YF1NH56hgISEeCO0Sg_SvTCcTJaOo,4831
|
|
45
45
|
together/resources/models.py,sha256=WpP-x25AXYpmu-VKu_X4Up-zHwpWBBvPRpbV4FsWQrU,8266
|
|
46
46
|
together/resources/rerank.py,sha256=3Ju_aRSyZ1s_3zCSNZnSnEJErUVmt2xa3M8z1nvejMA,3931
|
|
47
47
|
together/resources/videos.py,sha256=Dn7vslH1pZVw4WYvH-69fjzqLZdKHkTK-lIbFkxh0w0,11144
|
|
48
48
|
together/together_response.py,sha256=a3dgKMPDrlfKQwxYENfNt2T4l2vSZxRWMixhHSy-q3E,1308
|
|
49
|
-
together/types/__init__.py,sha256=
|
|
49
|
+
together/types/__init__.py,sha256=nh6yT1mmlmkLGQE3DYeJYNkSAIIIxNep15jwZWICz40,4492
|
|
50
50
|
together/types/abstract.py,sha256=1lFQI_3WjsR_t1128AeKW0aTk6EiM6Gh1J3ZuyLLPao,642
|
|
51
51
|
together/types/audio_speech.py,sha256=pUzqpx7NCjtPIq91xO2k0psetzLz29NTHHm6DS0k8Xg,9682
|
|
52
52
|
together/types/batch.py,sha256=KiI5i1En7cyIUxHhVIGoQk6Wlw19c0PXSqDWwc2KZ2c,1140
|
|
53
|
-
together/types/chat_completions.py,sha256=
|
|
53
|
+
together/types/chat_completions.py,sha256=OkEk4_Z5cf36Ae775epG_lIQ6dkKPSSKujc9wQ-tzQs,5504
|
|
54
54
|
together/types/code_interpreter.py,sha256=cjF8TKgRkJllHS4i24dWQZBGTRsG557eHSewOiip0Kk,1770
|
|
55
|
-
together/types/common.py,sha256=
|
|
55
|
+
together/types/common.py,sha256=c2_CeyjOBWbJ0RIAsWB13DG8j6N3ATU-6yH-CnFitVY,1564
|
|
56
56
|
together/types/completions.py,sha256=o3FR5ixsTUj-a3pmOUzbSQg-hESVhpqrC9UD__VCqr4,2971
|
|
57
57
|
together/types/embeddings.py,sha256=J7grkYYn7xhqeKaBO2T-8XQRtHhkzYzymovtGdIUK5A,751
|
|
58
58
|
together/types/endpoints.py,sha256=EzNhHOoQ_D9fUdNQtxQPeSWiFzdFLqpNodN0YLmv_h0,4393
|
|
59
59
|
together/types/error.py,sha256=OVlCs3cx_2WhZK4JzHT8SQyRIIqKOP1AZQ4y1PydjAE,370
|
|
60
60
|
together/types/evaluation.py,sha256=9gCAgzAwFD95MWnSgvxnSYFF27wKOTqIGn-wSOpFt2M,2385
|
|
61
|
-
together/types/files.py,sha256=
|
|
62
|
-
together/types/finetune.py,sha256=
|
|
61
|
+
together/types/files.py,sha256=_pB_q8kU5QH7WE3Y8Uro6LGsgK_5zrGYzJREZL9cRH0,2025
|
|
62
|
+
together/types/finetune.py,sha256=vpbmyRRV0gJryi0F7YUIbUk5Ya8CPmi0mJ95ZjpfpbE,11959
|
|
63
63
|
together/types/images.py,sha256=IsrmIM2FVeG-kP4vhZUx5fG5EhOJ-d8fefrAmOVKNDs,926
|
|
64
64
|
together/types/models.py,sha256=V8bcy1c3uTmqwnTVphbYLF2AJ6l2P2724njl36TzfHQ,2878
|
|
65
65
|
together/types/rerank.py,sha256=qZfuXOn7MZ6ly8hpJ_MZ7OU_Bi1-cgYNSB20Wja8Qkk,1061
|
|
@@ -67,11 +67,11 @@ together/types/videos.py,sha256=KCLk8CF0kbA_51qnHOzAWg5VA6HTlwnY-sTZ2lUR0Eo,1861
|
|
|
67
67
|
together/utils/__init__.py,sha256=5fqvj4KT2rHxKSQot2TSyV_HcvkvkGiqAiaYuJwqtm0,786
|
|
68
68
|
together/utils/_log.py,sha256=5IYNI-jYzxyIS-pUvhb0vE_Muo3MA7GgBhsu66TKP2w,1951
|
|
69
69
|
together/utils/api_helpers.py,sha256=2K0O6qeEQ2zVFvi5NBN5m2kjZJaS3-JfKFecQ7SmGaw,3746
|
|
70
|
-
together/utils/files.py,sha256=
|
|
70
|
+
together/utils/files.py,sha256=mWFFpsgVPDQg1ZCb-oTrDUFv3aXg1AItgtwXvDsFegI,25047
|
|
71
71
|
together/utils/tools.py,sha256=H2MTJhEqtBllaDvOyZehIO_IVNK3P17rSDeILtJIVag,2964
|
|
72
72
|
together/version.py,sha256=p03ivHyE0SyWU4jAnRTBi_sOwywVWoZPU4g2gzRgG-Y,126
|
|
73
|
-
together-1.5.
|
|
74
|
-
together-1.5.
|
|
75
|
-
together-1.5.
|
|
76
|
-
together-1.5.
|
|
77
|
-
together-1.5.
|
|
73
|
+
together-1.5.32.dist-info/METADATA,sha256=lQExfe_6VE3LiQDX6E3zbVVsNwlPZ2vzQMuxtTaV7M8,17415
|
|
74
|
+
together-1.5.32.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
75
|
+
together-1.5.32.dist-info/entry_points.txt,sha256=G-b5NKW6lUUf1V1fH8IPTBb7jXnK7lhbX9H1zTEJXPs,50
|
|
76
|
+
together-1.5.32.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
77
|
+
together-1.5.32.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|