Skip to content

Commit f24ea4a

Browse files
authored
Add support for Batch API (#325)
1 parent e3215ad commit f24ea4a

File tree

7 files changed

+202
-2
lines changed

7 files changed

+202
-2
lines changed

src/together/client.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class Together:
2323
fine_tuning: resources.FineTuning
2424
rerank: resources.Rerank
2525
audio: resources.Audio
26+
batches: resources.Batches
2627
code_interpreter: CodeInterpreter
2728

2829
# client options
@@ -90,6 +91,7 @@ def __init__(
9091
self.audio = resources.Audio(self.client)
9192
self.endpoints = resources.Endpoints(self.client)
9293
self.code_interpreter = CodeInterpreter(self.client)
94+
self.batches = resources.Batches(self.client)
9395

9496

9597
class AsyncTogether:
@@ -102,7 +104,7 @@ class AsyncTogether:
102104
fine_tuning: resources.AsyncFineTuning
103105
rerank: resources.AsyncRerank
104106
code_interpreter: CodeInterpreter
105-
107+
batches: resources.AsyncBatches
106108
# client options
107109
client: TogetherClient
108110

@@ -166,6 +168,7 @@ def __init__(
166168
self.fine_tuning = resources.AsyncFineTuning(self.client)
167169
self.rerank = resources.AsyncRerank(self.client)
168170
self.code_interpreter = CodeInterpreter(self.client)
171+
self.batches = resources.AsyncBatches(self.client)
169172

170173

171174
Client = Together

src/together/resources/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from together.resources.images import AsyncImages, Images
99
from together.resources.models import AsyncModels, Models
1010
from together.resources.rerank import AsyncRerank, Rerank
11+
from together.resources.batch import Batches, AsyncBatches
1112

1213

1314
__all__ = [
@@ -31,4 +32,6 @@
3132
"Audio",
3233
"AsyncEndpoints",
3334
"Endpoints",
35+
"Batches",
36+
"AsyncBatches",
3437
]

src/together/resources/batch.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
from __future__ import annotations
2+
3+
from typing import List
4+
5+
from together.abstract import api_requestor
6+
from together.together_response import TogetherResponse
7+
from together.types import (
8+
TogetherClient,
9+
TogetherRequest,
10+
BatchJob,
11+
)
12+
13+
14+
class Batches:
15+
def __init__(self, client: TogetherClient) -> None:
16+
self._client = client
17+
18+
def create_batch(self, file_id: str, endpoint: str) -> BatchJob:
19+
20+
requestor = api_requestor.APIRequestor(
21+
client=self._client,
22+
)
23+
24+
parameter_payload = {
25+
"input_file_id": file_id,
26+
"endpoint": endpoint,
27+
"completion_window": "24h",
28+
}
29+
30+
response, _, _ = requestor.request(
31+
options=TogetherRequest(
32+
method="POST",
33+
url=f"batches",
34+
params=parameter_payload,
35+
),
36+
stream=False,
37+
)
38+
39+
assert isinstance(response, TogetherResponse)
40+
response_body = response.data.get("job", {})
41+
return BatchJob(**response_body)
42+
43+
def get_batch(self, batch_job_id: str) -> BatchJob:
44+
requestor = api_requestor.APIRequestor(
45+
client=self._client,
46+
)
47+
48+
response, _, _ = requestor.request(
49+
options=TogetherRequest(
50+
method="GET",
51+
url=f"batches/{batch_job_id}",
52+
),
53+
stream=False,
54+
)
55+
56+
assert isinstance(response, TogetherResponse)
57+
return BatchJob(**response.data)
58+
59+
def list_batches(self) -> List[BatchJob]:
60+
requestor = api_requestor.APIRequestor(
61+
client=self._client,
62+
)
63+
64+
response, _, _ = requestor.request(
65+
options=TogetherRequest(
66+
method="GET",
67+
url="batches",
68+
),
69+
stream=False,
70+
)
71+
72+
assert isinstance(response, TogetherResponse)
73+
jobs = response.data or []
74+
return [BatchJob(**job) for job in jobs]
75+
76+
77+
class AsyncBatches:
78+
def __init__(self, client: TogetherClient) -> None:
79+
self._client = client
80+
81+
async def create_batch(self, file_id: str, endpoint: str) -> BatchJob:
82+
requestor = api_requestor.APIRequestor(
83+
client=self._client,
84+
)
85+
86+
parameter_payload = {
87+
"input_file_id": file_id,
88+
"endpoint": endpoint,
89+
"completion_window": "24h",
90+
}
91+
92+
response, _, _ = await requestor.arequest(
93+
options=TogetherRequest(
94+
method="POST",
95+
url=f"batches",
96+
params=parameter_payload,
97+
),
98+
stream=False,
99+
)
100+
101+
assert isinstance(response, TogetherResponse)
102+
response_body = response.data.get("job", {})
103+
return BatchJob(**response_body)
104+
105+
async def get_batch(self, batch_job_id: str) -> BatchJob:
106+
requestor = api_requestor.APIRequestor(
107+
client=self._client,
108+
)
109+
110+
response, _, _ = await requestor.arequest(
111+
options=TogetherRequest(
112+
method="GET",
113+
url=f"batches/{batch_job_id}",
114+
),
115+
stream=False,
116+
)
117+
118+
assert isinstance(response, TogetherResponse)
119+
return BatchJob(**response.data)
120+
121+
async def list_batches(self) -> List[BatchJob]:
122+
requestor = api_requestor.APIRequestor(
123+
client=self._client,
124+
)
125+
126+
response, _, _ = await requestor.arequest(
127+
options=TogetherRequest(
128+
method="GET",
129+
url="batches",
130+
),
131+
stream=False,
132+
)
133+
134+
assert isinstance(response, TogetherResponse)
135+
jobs = response.data or []
136+
return [BatchJob(**job) for job in jobs]

src/together/resources/files.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def upload(
3232
) -> FileResponse:
3333
upload_manager = UploadManager(self._client)
3434

35-
if check:
35+
if check and purpose == FilePurpose.FineTune:
3636
report_dict = check_file(file)
3737
if not report_dict["is_check_passed"]:
3838
raise FileTypeError(

src/together/types/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
from together.types.images import ImageRequest, ImageResponse
5353
from together.types.models import ModelObject
5454
from together.types.rerank import RerankRequest, RerankResponse
55+
from together.types.batch import BatchJob, BatchJobStatus, BatchEndpoint
5556

5657

5758
__all__ = [
@@ -104,4 +105,7 @@
104105
"DedicatedEndpoint",
105106
"ListEndpoint",
106107
"Autoscaling",
108+
"BatchJob",
109+
"BatchJobStatus",
110+
"BatchEndpoint",
107111
]

src/together/types/batch.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from __future__ import annotations
2+
3+
from enum import Enum
4+
from typing import Optional
5+
from datetime import datetime
6+
7+
from pydantic import Field
8+
9+
from together.types.abstract import BaseModel
10+
11+
12+
class BatchJobStatus(str, Enum):
13+
"""
14+
The status of a batch job
15+
"""
16+
17+
VALIDATING = "VALIDATING"
18+
IN_PROGRESS = "IN_PROGRESS"
19+
COMPLETED = "COMPLETED"
20+
FAILED = "FAILED"
21+
EXPIRED = "EXPIRED"
22+
CANCELLED = "CANCELLED"
23+
24+
25+
class BatchEndpoint(str, Enum):
26+
"""
27+
The endpoint of a batch job
28+
"""
29+
30+
COMPLETIONS = "/v1/completions"
31+
CHAT_COMPLETIONS = "/v1/chat/completions"
32+
# More endpoints can be added here as needed
33+
34+
35+
class BatchJob(BaseModel):
36+
"""
37+
A batch job object
38+
"""
39+
40+
id: str
41+
user_id: str
42+
input_file_id: str
43+
file_size_bytes: int
44+
status: BatchJobStatus
45+
job_deadline: datetime
46+
created_at: datetime
47+
endpoint: str
48+
progress: float = 0.0
49+
model_id: Optional[str] = None
50+
output_file_id: Optional[str] = None
51+
error_file_id: Optional[str] = None
52+
error: Optional[str] = None
53+
completed_at: Optional[datetime] = None

src/together/types/files.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
class FilePurpose(str, Enum):
1515
FineTune = "fine-tune"
16+
BatchAPI = "batch-api"
1617

1718

1819
class FileType(str, Enum):

0 commit comments

Comments
 (0)