together 1.5.30__tar.gz → 1.5.31__tar.gz
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-1.5.30 → together-1.5.31}/PKG-INFO +1 -1
- {together-1.5.30 → together-1.5.31}/pyproject.toml +1 -1
- {together-1.5.30 → together-1.5.31}/src/together/cli/api/chat.py +24 -2
- {together-1.5.30 → together-1.5.31}/src/together/cli/api/endpoints.py +7 -4
- {together-1.5.30 → together-1.5.31}/src/together/constants.py +3 -3
- {together-1.5.30 → together-1.5.31}/src/together/filemanager.py +45 -22
- {together-1.5.30 → together-1.5.31}/src/together/types/chat_completions.py +6 -0
- {together-1.5.30 → together-1.5.31}/src/together/types/common.py +1 -0
- {together-1.5.30 → together-1.5.31}/src/together/types/files.py +1 -0
- {together-1.5.30 → together-1.5.31}/src/together/utils/files.py +8 -2
- {together-1.5.30 → together-1.5.31}/LICENSE +0 -0
- {together-1.5.30 → together-1.5.31}/README.md +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/__init__.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/abstract/__init__.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/abstract/api_requestor.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/cli/__init__.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/cli/api/__init__.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/cli/api/completions.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/cli/api/evaluation.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/cli/api/files.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/cli/api/finetune.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/cli/api/images.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/cli/api/models.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/cli/api/utils.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/cli/cli.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/client.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/error.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/legacy/__init__.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/legacy/base.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/legacy/complete.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/legacy/embeddings.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/legacy/files.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/legacy/finetune.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/legacy/images.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/legacy/models.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/__init__.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/audio/__init__.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/audio/speech.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/audio/transcriptions.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/audio/translations.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/audio/voices.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/batch.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/chat/__init__.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/chat/completions.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/code_interpreter.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/completions.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/embeddings.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/endpoints.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/evaluation.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/files.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/finetune.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/images.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/models.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/rerank.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/resources/videos.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/together_response.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/types/__init__.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/types/abstract.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/types/audio_speech.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/types/batch.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/types/code_interpreter.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/types/completions.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/types/embeddings.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/types/endpoints.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/types/error.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/types/evaluation.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/types/finetune.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/types/images.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/types/models.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/types/rerank.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/types/videos.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/utils/__init__.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/utils/_log.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/utils/api_helpers.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/utils/tools.py +0 -0
- {together-1.5.30 → together-1.5.31}/src/together/version.py +0 -0
|
@@ -12,7 +12,7 @@ build-backend = "poetry.masonry.api"
|
|
|
12
12
|
|
|
13
13
|
[tool.poetry]
|
|
14
14
|
name = "together"
|
|
15
|
-
version = "1.5.
|
|
15
|
+
version = "1.5.31"
|
|
16
16
|
authors = ["Together AI <support@together.ai>"]
|
|
17
17
|
description = "Python client for Together's Cloud Platform!"
|
|
18
18
|
readme = "README.md"
|
|
@@ -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,
|
|
@@ -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
|
|
@@ -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
|
|
@@ -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
|
|
@@ -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):
|
|
@@ -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):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|