seekrai 0.1.0__py3-none-any.whl → 0.2.0__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.
- seekrai/abstract/api_requestor.py +3 -0
- seekrai/client.py +4 -0
- seekrai/constants.py +1 -1
- seekrai/filemanager.py +11 -22
- seekrai/resources/__init__.py +3 -0
- seekrai/resources/alignment.py +175 -0
- seekrai/resources/files.py +64 -4
- seekrai/resources/models.py +5 -3
- seekrai/types/__init__.py +10 -0
- seekrai/types/alignment.py +39 -0
- seekrai/types/files.py +34 -5
- {seekrai-0.1.0.dist-info → seekrai-0.2.0.dist-info}/METADATA +5 -10
- {seekrai-0.1.0.dist-info → seekrai-0.2.0.dist-info}/RECORD +16 -14
- {seekrai-0.1.0.dist-info → seekrai-0.2.0.dist-info}/LICENSE +0 -0
- {seekrai-0.1.0.dist-info → seekrai-0.2.0.dist-info}/WHEEL +0 -0
- {seekrai-0.1.0.dist-info → seekrai-0.2.0.dist-info}/entry_points.txt +0 -0
|
@@ -519,6 +519,9 @@ class APIRequestor:
|
|
|
519
519
|
if "text/plain" in rheaders.get("Content-Type", ""):
|
|
520
520
|
data: Dict[str, Any] = {"message": rbody}
|
|
521
521
|
else:
|
|
522
|
+
if rbody.strip().endswith("[DONE]"):
|
|
523
|
+
# TODO
|
|
524
|
+
rbody = rbody.replace("data: [DONE]", "")
|
|
522
525
|
data = json.loads(rbody)
|
|
523
526
|
except (JSONDecodeError, UnicodeDecodeError) as e:
|
|
524
527
|
raise error.APIError(
|
seekrai/client.py
CHANGED
|
@@ -18,6 +18,7 @@ class SeekrFlow:
|
|
|
18
18
|
images: resources.Images
|
|
19
19
|
models: resources.Models
|
|
20
20
|
fine_tuning: resources.FineTuning
|
|
21
|
+
alignment: resources.Alignment
|
|
21
22
|
|
|
22
23
|
# client options
|
|
23
24
|
client: SeekrFlowClient
|
|
@@ -77,6 +78,7 @@ class SeekrFlow:
|
|
|
77
78
|
self.images = resources.Images(self.client)
|
|
78
79
|
self.models = resources.Models(self.client)
|
|
79
80
|
self.fine_tuning = resources.FineTuning(self.client)
|
|
81
|
+
self.alignment = resources.Alignment(self.client)
|
|
80
82
|
|
|
81
83
|
|
|
82
84
|
class AsyncSeekrFlow:
|
|
@@ -87,6 +89,7 @@ class AsyncSeekrFlow:
|
|
|
87
89
|
images: resources.AsyncImages
|
|
88
90
|
models: resources.AsyncModels
|
|
89
91
|
fine_tuning: resources.AsyncFineTuning
|
|
92
|
+
alignment: resources.AsyncAlignment
|
|
90
93
|
|
|
91
94
|
# client options
|
|
92
95
|
client: SeekrFlowClient
|
|
@@ -146,6 +149,7 @@ class AsyncSeekrFlow:
|
|
|
146
149
|
self.images = resources.AsyncImages(self.client)
|
|
147
150
|
self.models = resources.AsyncModels(self.client)
|
|
148
151
|
self.fine_tuning = resources.AsyncFineTuning(self.client)
|
|
152
|
+
self.alignment = resources.AsyncAlignment(self.client)
|
|
149
153
|
|
|
150
154
|
|
|
151
155
|
Client = SeekrFlow
|
seekrai/constants.py
CHANGED
|
@@ -19,7 +19,7 @@ INITIAL_RETRY_DELAY = float(env_or_default("INITIAL_RETRY_DELAY", 0.5))
|
|
|
19
19
|
MAX_RETRY_DELAY = float(env_or_default("MAX_RETRY_DELAY", 8.0))
|
|
20
20
|
|
|
21
21
|
# API defaults
|
|
22
|
-
BASE_URL = env_or_default("BASE_URL", "https://
|
|
22
|
+
BASE_URL = env_or_default("BASE_URL", "https://flow.seekr.com/v1")
|
|
23
23
|
|
|
24
24
|
# Download defaults
|
|
25
25
|
DOWNLOAD_BLOCK_SIZE = int(
|
seekrai/filemanager.py
CHANGED
|
@@ -12,6 +12,7 @@ import httpx
|
|
|
12
12
|
import requests
|
|
13
13
|
from requests.structures import CaseInsensitiveDict
|
|
14
14
|
from tqdm import tqdm
|
|
15
|
+
from tqdm.utils import CallbackIOWrapper
|
|
15
16
|
|
|
16
17
|
import seekrai.utils
|
|
17
18
|
from seekrai.abstract import api_requestor
|
|
@@ -42,15 +43,15 @@ def chmod_and_replace(src: Path, dst: Path) -> None:
|
|
|
42
43
|
# Get umask by creating a temporary file in the cache folder.
|
|
43
44
|
tmp_file = dst.parent / f"tmp_{uuid.uuid4()}"
|
|
44
45
|
|
|
45
|
-
try:
|
|
46
|
-
|
|
46
|
+
# try:
|
|
47
|
+
tmp_file.touch()
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
cache_dir_mode = Path(tmp_file).stat().st_mode
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
os.chmod(src.as_posix(), stat.S_IMODE(cache_dir_mode))
|
|
51
52
|
|
|
52
|
-
finally:
|
|
53
|
-
|
|
53
|
+
# finally:
|
|
54
|
+
# tmp_file.unlink()
|
|
54
55
|
|
|
55
56
|
shutil.move(src.as_posix(), dst.as_posix())
|
|
56
57
|
|
|
@@ -186,10 +187,7 @@ class DownloadManager:
|
|
|
186
187
|
url, output, remote_name, fetch_metadata
|
|
187
188
|
)
|
|
188
189
|
|
|
189
|
-
|
|
190
|
-
lock_path = Path(file_path.as_posix() + ".lock")
|
|
191
|
-
|
|
192
|
-
with tempfile.NamedTemporaryFile() as temp_file:
|
|
190
|
+
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
|
|
193
191
|
response = requestor.request_raw(
|
|
194
192
|
options=SeekrFlowRequest(
|
|
195
193
|
method="GET",
|
|
@@ -201,7 +199,6 @@ class DownloadManager:
|
|
|
201
199
|
try:
|
|
202
200
|
response.raise_for_status()
|
|
203
201
|
except Exception as e:
|
|
204
|
-
os.remove(lock_path)
|
|
205
202
|
raise APIError(
|
|
206
203
|
"Error downloading file", http_status=response.status_code
|
|
207
204
|
) from e
|
|
@@ -234,8 +231,6 @@ class DownloadManager:
|
|
|
234
231
|
# Moves temp file to output file path
|
|
235
232
|
chmod_and_replace(Path(temp_file.name), file_path)
|
|
236
233
|
|
|
237
|
-
os.remove(lock_path)
|
|
238
|
-
|
|
239
234
|
return str(file_path.resolve()), file_size
|
|
240
235
|
|
|
241
236
|
|
|
@@ -323,13 +318,6 @@ class UploadManager:
|
|
|
323
318
|
client=self._client,
|
|
324
319
|
)
|
|
325
320
|
|
|
326
|
-
if redirect:
|
|
327
|
-
if file.suffix not in [".jsonl", ".parquet", ".pt"]:
|
|
328
|
-
raise FileTypeError(
|
|
329
|
-
f"Unknown extension of file {file}. "
|
|
330
|
-
"Only files with extensions .jsonl, .parquet, and .pt are supported."
|
|
331
|
-
)
|
|
332
|
-
|
|
333
321
|
file_size = os.stat(file.as_posix()).st_size
|
|
334
322
|
|
|
335
323
|
with tqdm(
|
|
@@ -338,13 +326,14 @@ class UploadManager:
|
|
|
338
326
|
unit_scale=True,
|
|
339
327
|
desc=f"Uploading file {file.name}",
|
|
340
328
|
disable=bool(DISABLE_TQDM),
|
|
341
|
-
):
|
|
329
|
+
) as t:
|
|
342
330
|
with file.open("rb") as f:
|
|
331
|
+
reader_wrapper = CallbackIOWrapper(t.update, f, "read")
|
|
343
332
|
response, _, _ = requestor.request(
|
|
344
333
|
options=SeekrFlowRequest(
|
|
345
334
|
method="PUT",
|
|
346
335
|
url=url,
|
|
347
|
-
files={"files":
|
|
336
|
+
files={"files": reader_wrapper, "filename": file.name},
|
|
348
337
|
params={"purpose": purpose.value},
|
|
349
338
|
),
|
|
350
339
|
)
|
seekrai/resources/__init__.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from seekrai.resources.alignment import Alignment, AsyncAlignment
|
|
1
2
|
from seekrai.resources.chat import AsyncChat, Chat
|
|
2
3
|
from seekrai.resources.completions import AsyncCompletions, Completions
|
|
3
4
|
from seekrai.resources.embeddings import AsyncEmbeddings, Embeddings
|
|
@@ -8,6 +9,8 @@ from seekrai.resources.models import AsyncModels, Models
|
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
__all__ = [
|
|
12
|
+
"AsyncAlignment",
|
|
13
|
+
"Alignment",
|
|
11
14
|
"AsyncCompletions",
|
|
12
15
|
"Completions",
|
|
13
16
|
"AsyncChat",
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from seekrai.abstract import api_requestor
|
|
4
|
+
from seekrai.seekrflow_response import SeekrFlowResponse
|
|
5
|
+
from seekrai.types import (
|
|
6
|
+
AlignmentList,
|
|
7
|
+
AlignmentRequest,
|
|
8
|
+
AlignmentResponse,
|
|
9
|
+
SeekrFlowClient,
|
|
10
|
+
SeekrFlowRequest,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Alignment:
|
|
15
|
+
def __init__(self, client: SeekrFlowClient) -> None:
|
|
16
|
+
self._client = client
|
|
17
|
+
|
|
18
|
+
def generate(
|
|
19
|
+
self,
|
|
20
|
+
instructions: str,
|
|
21
|
+
files: List[str],
|
|
22
|
+
) -> AlignmentResponse:
|
|
23
|
+
requestor = api_requestor.APIRequestor(
|
|
24
|
+
client=self._client,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
parameter_payload = AlignmentRequest(
|
|
28
|
+
instructions=instructions,
|
|
29
|
+
files=files,
|
|
30
|
+
).model_dump()
|
|
31
|
+
|
|
32
|
+
response, _, _ = requestor.request(
|
|
33
|
+
options=SeekrFlowRequest(
|
|
34
|
+
method="POST",
|
|
35
|
+
url="flow/alignment/generate",
|
|
36
|
+
params=parameter_payload,
|
|
37
|
+
),
|
|
38
|
+
stream=False,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
assert isinstance(response, SeekrFlowResponse)
|
|
42
|
+
return AlignmentResponse(**response.data)
|
|
43
|
+
|
|
44
|
+
def list(self) -> AlignmentList:
|
|
45
|
+
"""
|
|
46
|
+
Lists alignment job history
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
AlignmentList: Object containing a list of alignment jobs
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
requestor = api_requestor.APIRequestor(
|
|
53
|
+
client=self._client,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
response, _, _ = requestor.request(
|
|
57
|
+
options=SeekrFlowRequest(
|
|
58
|
+
method="GET",
|
|
59
|
+
url="flow/alignment",
|
|
60
|
+
),
|
|
61
|
+
stream=False,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
assert isinstance(response, SeekrFlowResponse)
|
|
65
|
+
|
|
66
|
+
return AlignmentList(**response.data)
|
|
67
|
+
|
|
68
|
+
def retrieve(self, id: str) -> AlignmentResponse:
|
|
69
|
+
"""
|
|
70
|
+
Retrieves alignment job details
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
id (str): Alignment job ID to retrieve.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
AlignmentResponse: Object containing information about alignment job.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
requestor = api_requestor.APIRequestor(
|
|
80
|
+
client=self._client,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
response, _, _ = requestor.request(
|
|
84
|
+
options=SeekrFlowRequest(
|
|
85
|
+
method="GET",
|
|
86
|
+
url=f"flow/alignment/{id}",
|
|
87
|
+
),
|
|
88
|
+
stream=False,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
assert isinstance(response, SeekrFlowResponse)
|
|
92
|
+
|
|
93
|
+
return AlignmentResponse(**response.data)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class AsyncAlignment:
|
|
97
|
+
def __init__(self, client: SeekrFlowClient) -> None:
|
|
98
|
+
self._client = client
|
|
99
|
+
|
|
100
|
+
async def generate(
|
|
101
|
+
self,
|
|
102
|
+
instructions: str,
|
|
103
|
+
files: List[str],
|
|
104
|
+
) -> AlignmentResponse:
|
|
105
|
+
requestor = api_requestor.APIRequestor(
|
|
106
|
+
client=self._client,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
parameter_payload = AlignmentRequest(
|
|
110
|
+
instructions=instructions,
|
|
111
|
+
files=files,
|
|
112
|
+
).model_dump()
|
|
113
|
+
|
|
114
|
+
response, _, _ = await requestor.arequest(
|
|
115
|
+
options=SeekrFlowRequest(
|
|
116
|
+
method="POST",
|
|
117
|
+
url="flow/alignment/generate",
|
|
118
|
+
params=parameter_payload,
|
|
119
|
+
),
|
|
120
|
+
stream=False,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
assert isinstance(response, SeekrFlowResponse)
|
|
124
|
+
return AlignmentResponse(**response.data)
|
|
125
|
+
|
|
126
|
+
async def list(self) -> AlignmentList:
|
|
127
|
+
"""
|
|
128
|
+
Lists alignment job history
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
AlignmentList: Object containing a list of alignment jobs
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
requestor = api_requestor.APIRequestor(
|
|
135
|
+
client=self._client,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
response, _, _ = await requestor.arequest(
|
|
139
|
+
options=SeekrFlowRequest(
|
|
140
|
+
method="GET",
|
|
141
|
+
url="flow/alignment",
|
|
142
|
+
),
|
|
143
|
+
stream=False,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
assert isinstance(response, SeekrFlowResponse)
|
|
147
|
+
|
|
148
|
+
return AlignmentList(**response.data)
|
|
149
|
+
|
|
150
|
+
async def retrieve(self, id: str) -> AlignmentResponse:
|
|
151
|
+
"""
|
|
152
|
+
Retrieves alignment job details
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
id (str): Alignment job ID to retrieve.
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
AlignmentResponse: Object containing information about alignment job.
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
requestor = api_requestor.APIRequestor(
|
|
162
|
+
client=self._client,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
response, _, _ = await requestor.arequest(
|
|
166
|
+
options=SeekrFlowRequest(
|
|
167
|
+
method="GET",
|
|
168
|
+
url=f"flow/alignment/{id}",
|
|
169
|
+
),
|
|
170
|
+
stream=False,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
assert isinstance(response, SeekrFlowResponse)
|
|
174
|
+
|
|
175
|
+
return AlignmentResponse(**response.data)
|
seekrai/resources/files.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
|
+
from typing import Any, Dict
|
|
4
5
|
|
|
5
6
|
from seekrai.abstract import api_requestor
|
|
6
7
|
from seekrai.filemanager import DownloadManager, UploadManager
|
|
@@ -14,6 +15,10 @@ from seekrai.types import (
|
|
|
14
15
|
SeekrFlowClient,
|
|
15
16
|
SeekrFlowRequest,
|
|
16
17
|
)
|
|
18
|
+
from seekrai.types.files import (
|
|
19
|
+
AlignFileMetadataValidationReq,
|
|
20
|
+
AlignFileMetadataValidationResp,
|
|
21
|
+
)
|
|
17
22
|
from seekrai.utils import normalize_key
|
|
18
23
|
|
|
19
24
|
|
|
@@ -21,11 +26,18 @@ class Files:
|
|
|
21
26
|
def __init__(self, client: SeekrFlowClient) -> None:
|
|
22
27
|
self._client = client
|
|
23
28
|
|
|
29
|
+
def _get_local_file_metadata(self, file_path: Path) -> Dict[str, Any]:
|
|
30
|
+
suffix = file_path.suffix.lstrip(".")
|
|
31
|
+
size_bytes = int(file_path.stat().st_size)
|
|
32
|
+
return {
|
|
33
|
+
"suffix": suffix,
|
|
34
|
+
"size_bytes": size_bytes,
|
|
35
|
+
"filename": file_path.name,
|
|
36
|
+
}
|
|
37
|
+
|
|
24
38
|
def upload(
|
|
25
39
|
self, file: Path | str, *, purpose: FilePurpose | str = FilePurpose.FineTune
|
|
26
40
|
) -> FileResponse:
|
|
27
|
-
upload_manager = UploadManager(self._client)
|
|
28
|
-
|
|
29
41
|
if isinstance(file, str):
|
|
30
42
|
file = Path(file)
|
|
31
43
|
|
|
@@ -34,7 +46,30 @@ class Files:
|
|
|
34
46
|
|
|
35
47
|
assert isinstance(purpose, FilePurpose)
|
|
36
48
|
|
|
37
|
-
|
|
49
|
+
# Do the metadata validation (fail fast before uploading) for Alignment purpose
|
|
50
|
+
if purpose == FilePurpose.Alignment:
|
|
51
|
+
file_metadata = self._get_local_file_metadata(file)
|
|
52
|
+
suffix = file_metadata["suffix"]
|
|
53
|
+
size = file_metadata["size_bytes"]
|
|
54
|
+
metadata_validation = self.validate_align_file_metadata(
|
|
55
|
+
purpose,
|
|
56
|
+
suffix,
|
|
57
|
+
size,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
if not metadata_validation.is_valid:
|
|
61
|
+
assert metadata_validation.errors is not None # To appease linter
|
|
62
|
+
raise ValueError(
|
|
63
|
+
f"Alignment file metadata validation failed: {metadata_validation.errors}"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# Upload the file to s3
|
|
67
|
+
upload_manager = UploadManager(self._client)
|
|
68
|
+
file_response = upload_manager.upload(
|
|
69
|
+
"flow/files", file, purpose=purpose, redirect=True
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
return file_response
|
|
38
73
|
|
|
39
74
|
def list(self) -> FileList:
|
|
40
75
|
requestor = api_requestor.APIRequestor(
|
|
@@ -87,7 +122,7 @@ class Files:
|
|
|
87
122
|
output = Path(output)
|
|
88
123
|
|
|
89
124
|
downloaded_filename, file_size = download_manager.download(
|
|
90
|
-
f"flow/files/{id}/content", output, normalize_key(
|
|
125
|
+
f"flow/files/{id}/content", output, normalize_key(id)
|
|
91
126
|
)
|
|
92
127
|
|
|
93
128
|
return FileObject(
|
|
@@ -114,6 +149,31 @@ class Files:
|
|
|
114
149
|
|
|
115
150
|
return FileDeleteResponse(**response.data)
|
|
116
151
|
|
|
152
|
+
def validate_align_file_metadata(
|
|
153
|
+
self,
|
|
154
|
+
purpose: FilePurpose,
|
|
155
|
+
suffix: str,
|
|
156
|
+
size: int,
|
|
157
|
+
) -> AlignFileMetadataValidationResp:
|
|
158
|
+
requestor = api_requestor.APIRequestor(client=self._client)
|
|
159
|
+
|
|
160
|
+
request_body = AlignFileMetadataValidationReq(
|
|
161
|
+
purpose=purpose,
|
|
162
|
+
suffix=suffix,
|
|
163
|
+
size=size,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
response, _, _ = requestor.request(
|
|
167
|
+
options=SeekrFlowRequest(
|
|
168
|
+
method="POST",
|
|
169
|
+
url="flow/files/validate_metadata",
|
|
170
|
+
params=request_body.dict(),
|
|
171
|
+
),
|
|
172
|
+
stream=False,
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
return AlignFileMetadataValidationResp(**response.data)
|
|
176
|
+
|
|
117
177
|
|
|
118
178
|
class AsyncFiles:
|
|
119
179
|
def __init__(self, client: SeekrFlowClient) -> None:
|
seekrai/resources/models.py
CHANGED
|
@@ -5,6 +5,7 @@ from pathlib import Path
|
|
|
5
5
|
from typing import Any, List
|
|
6
6
|
|
|
7
7
|
from tqdm import tqdm
|
|
8
|
+
from tqdm.utils import CallbackIOWrapper
|
|
8
9
|
|
|
9
10
|
from seekrai.abstract import api_requestor
|
|
10
11
|
from seekrai.constants import DISABLE_TQDM
|
|
@@ -35,15 +36,16 @@ class Models:
|
|
|
35
36
|
total=file_size,
|
|
36
37
|
unit="B",
|
|
37
38
|
unit_scale=True,
|
|
38
|
-
desc=f"Uploading file {file.name}",
|
|
39
|
+
desc=f"Uploading model file {file.name}",
|
|
39
40
|
disable=bool(DISABLE_TQDM),
|
|
40
|
-
):
|
|
41
|
+
) as t:
|
|
41
42
|
with file.open("rb") as f:
|
|
43
|
+
reader_wrapper = CallbackIOWrapper(t.update, f, "read")
|
|
42
44
|
response, _, _ = requestor.request(
|
|
43
45
|
options=SeekrFlowRequest(
|
|
44
46
|
method="PUT",
|
|
45
47
|
url="flow/pt-models",
|
|
46
|
-
files={"files":
|
|
48
|
+
files={"files": reader_wrapper, "filename": file.name},
|
|
47
49
|
params={"purpose": model_type},
|
|
48
50
|
),
|
|
49
51
|
)
|
seekrai/types/__init__.py
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
from seekrai.types.abstract import SeekrFlowClient
|
|
2
|
+
from seekrai.types.alignment import (
|
|
3
|
+
AlignmentJobStatus,
|
|
4
|
+
AlignmentList,
|
|
5
|
+
AlignmentRequest,
|
|
6
|
+
AlignmentResponse,
|
|
7
|
+
)
|
|
2
8
|
from seekrai.types.chat_completions import (
|
|
3
9
|
ChatCompletionChunk,
|
|
4
10
|
ChatCompletionRequest,
|
|
@@ -65,4 +71,8 @@ __all__ = [
|
|
|
65
71
|
"ImageResponse",
|
|
66
72
|
"ModelResponse",
|
|
67
73
|
"ModelList",
|
|
74
|
+
"AlignmentRequest",
|
|
75
|
+
"AlignmentResponse",
|
|
76
|
+
"AlignmentJobStatus",
|
|
77
|
+
"AlignmentList",
|
|
68
78
|
]
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import List, Literal, Optional
|
|
4
|
+
|
|
5
|
+
from pydantic import Field
|
|
6
|
+
|
|
7
|
+
from seekrai.types.abstract import BaseModel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AlignmentRequest(BaseModel):
|
|
11
|
+
instructions: str = Field(
|
|
12
|
+
default=..., description="Task description/instructions for the alignment task"
|
|
13
|
+
)
|
|
14
|
+
files: List[str] = Field(
|
|
15
|
+
default=..., description="List of file ids to use for alignment"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AlignmentJobStatus(str, Enum):
|
|
20
|
+
STATUS_PENDING = "pending"
|
|
21
|
+
STATUS_QUEUED = "queued"
|
|
22
|
+
STATUS_RUNNING = "running"
|
|
23
|
+
STATUS_CANCEL_REQUESTED = "cancel_requested"
|
|
24
|
+
STATUS_CANCELLED = "cancelled"
|
|
25
|
+
STATUS_FAILED = "failed"
|
|
26
|
+
STATUS_COMPLETED = "completed"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AlignmentResponse(BaseModel):
|
|
30
|
+
id: Optional[str] = Field(default=..., description="Alignment job ID")
|
|
31
|
+
created_at: datetime | None = None
|
|
32
|
+
status: AlignmentJobStatus | None = None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class AlignmentList(BaseModel):
|
|
36
|
+
# object type
|
|
37
|
+
object: Literal["list"] | None = None
|
|
38
|
+
# list of fine-tune job objects
|
|
39
|
+
data: List[AlignmentResponse] | None = None
|
seekrai/types/files.py
CHANGED
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from datetime import datetime
|
|
4
4
|
from enum import Enum
|
|
5
|
-
from typing import List, Literal
|
|
5
|
+
from typing import List, Literal, Optional, Union
|
|
6
6
|
|
|
7
7
|
from seekrai.types.abstract import BaseModel
|
|
8
8
|
from seekrai.types.common import (
|
|
@@ -13,12 +13,42 @@ from seekrai.types.common import (
|
|
|
13
13
|
class FilePurpose(str, Enum):
|
|
14
14
|
FineTune = "fine-tune"
|
|
15
15
|
PreTrain = "pre-train"
|
|
16
|
+
Alignment = "alignment"
|
|
16
17
|
|
|
17
18
|
|
|
18
|
-
class
|
|
19
|
+
class TrainingFileType(str, Enum):
|
|
19
20
|
jsonl = "jsonl"
|
|
20
21
|
parquet = "parquet"
|
|
21
|
-
pytorch = "pt"
|
|
22
|
+
pytorch = "pt" # TODO - this doesnt belong here
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class AlignmentFileType(str, Enum):
|
|
26
|
+
HTML = "html"
|
|
27
|
+
MD = "md"
|
|
28
|
+
RST = "rst"
|
|
29
|
+
RTF = "rtf"
|
|
30
|
+
TXT = "txt"
|
|
31
|
+
XML = "xml"
|
|
32
|
+
JSON = "json"
|
|
33
|
+
JSONL = "jsonl"
|
|
34
|
+
CSV = "csv"
|
|
35
|
+
DOC = "doc"
|
|
36
|
+
DOCX = "docx"
|
|
37
|
+
PDF = "pdf"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
FileType = Union[TrainingFileType, AlignmentFileType]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class AlignFileMetadataValidationReq(BaseModel):
|
|
44
|
+
purpose: str
|
|
45
|
+
suffix: str
|
|
46
|
+
size: int
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class AlignFileMetadataValidationResp(BaseModel):
|
|
50
|
+
is_valid: bool
|
|
51
|
+
errors: Optional[str] = None
|
|
22
52
|
|
|
23
53
|
|
|
24
54
|
class FileRequest(BaseModel):
|
|
@@ -61,8 +91,7 @@ class FileResponse(BaseModel):
|
|
|
61
91
|
filename: str | None = None
|
|
62
92
|
# file byte size
|
|
63
93
|
bytes: int | None = None
|
|
64
|
-
#
|
|
65
|
-
line_count: int | None = None
|
|
94
|
+
created_by: str | None = None # TODO - fix this later
|
|
66
95
|
|
|
67
96
|
|
|
68
97
|
class FileList(BaseModel):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: seekrai
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Python client for SeekrAI
|
|
5
5
|
Home-page: https://gitlab.cb.ntent.com/ml/seekr-py
|
|
6
6
|
License: Apache-2.0
|
|
@@ -17,7 +17,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
17
17
|
Requires-Dist: click (>=8.1.7,<9.0.0)
|
|
18
18
|
Requires-Dist: eval-type-backport (>=0.1.3,<0.3.0)
|
|
19
19
|
Requires-Dist: filelock (>=3.13.1,<4.0.0)
|
|
20
|
-
Requires-Dist: httpx (>=0.27.0,<0.28.0)
|
|
20
|
+
Requires-Dist: httpx[http2] (>=0.27.0,<0.28.0)
|
|
21
21
|
Requires-Dist: numpy (>=1.23.5) ; python_version < "3.12"
|
|
22
22
|
Requires-Dist: numpy (>=1.26.0) ; python_version >= "3.12"
|
|
23
23
|
Requires-Dist: pillow (>=10.3.0,<11.0.0)
|
|
@@ -59,8 +59,6 @@ from seekrai import SeekrFlow
|
|
|
59
59
|
client = SeekrFlow(api_key="xxxxx")
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
This library contains both a python library and a CLI. We'll demonstrate how to use both below.
|
|
63
|
-
|
|
64
62
|
# Usage – Python Client
|
|
65
63
|
|
|
66
64
|
## Chat Completions
|
|
@@ -128,7 +126,7 @@ asyncio.run(async_chat_completion(messages))
|
|
|
128
126
|
|
|
129
127
|
## Files
|
|
130
128
|
|
|
131
|
-
The files API is used for fine-tuning and allows developers to upload data to fine-tune on. It also has several methods to list all files,
|
|
129
|
+
The files API is used for fine-tuning and allows developers to upload data to fine-tune on. It also has several methods to list all files, retrieve files, and delete files
|
|
132
130
|
|
|
133
131
|
```python
|
|
134
132
|
import os
|
|
@@ -136,15 +134,14 @@ from seekrai import SeekrFlow
|
|
|
136
134
|
|
|
137
135
|
client = SeekrFlow(api_key=os.environ.get("SEEKR_API_KEY"))
|
|
138
136
|
|
|
139
|
-
client.files.upload(file="somedata.
|
|
137
|
+
client.files.upload(file="somedata.parquet") # uploads a file
|
|
140
138
|
client.files.list() # lists all uploaded files
|
|
141
|
-
client.files.retrieve(id="file-d0d318cb-b7d9-493a-bd70-1cfe089d3815") # retrieves a specific file
|
|
142
139
|
client.files.delete(id="file-d0d318cb-b7d9-493a-bd70-1cfe089d3815") # deletes a file
|
|
143
140
|
```
|
|
144
141
|
|
|
145
142
|
## Fine-tunes
|
|
146
143
|
|
|
147
|
-
The finetune API is used for fine-tuning and allows developers to create finetuning jobs. It also has several methods to list all jobs,
|
|
144
|
+
The finetune API is used for fine-tuning and allows developers to create finetuning jobs. It also has several methods to list all jobs, retrieve statuses and get checkpoints.
|
|
148
145
|
|
|
149
146
|
```python
|
|
150
147
|
import os
|
|
@@ -160,10 +157,8 @@ client.fine_tuning.create(
|
|
|
160
157
|
batch_size=4,
|
|
161
158
|
learning_rate=1e-5,
|
|
162
159
|
suffix='my-demo-finetune',
|
|
163
|
-
wandb_api_key='1a2b3c4d5e.......',
|
|
164
160
|
)
|
|
165
161
|
client.fine_tuning.list() # lists all fine-tuned jobs
|
|
166
162
|
client.fine_tuning.retrieve(id="ft-c66a5c18-1d6d-43c9-94bd-32d756425b4b") # retrieves information on finetune event
|
|
167
|
-
client.fine_tuning.list_events(id="ft-c66a5c18-1d6d-43c9-94bd-32d756425b4b") # Lists events of a fine-tune job
|
|
168
163
|
```
|
|
169
164
|
|
|
@@ -1,28 +1,30 @@
|
|
|
1
1
|
seekrai/__init__.py,sha256=HC6iy-IdwqecabH-6a80Lsy9qO2PBToAI0WqEErV41c,935
|
|
2
2
|
seekrai/abstract/__init__.py,sha256=wNiOTW9TJpUgfCJCG-wAbhhWWH2PtoVpAuL3nxvQGps,56
|
|
3
|
-
seekrai/abstract/api_requestor.py,sha256
|
|
4
|
-
seekrai/client.py,sha256=
|
|
5
|
-
seekrai/constants.py,sha256=
|
|
3
|
+
seekrai/abstract/api_requestor.py,sha256=Bij__JWVSmr4AYnrh6ugFYo-48_uYGQodcTDp38pnf4,18169
|
|
4
|
+
seekrai/client.py,sha256=Z7T7cc0_Ess8pchceNdhYyT5RvP9luAuGmTPDz5Y0ss,4976
|
|
5
|
+
seekrai/constants.py,sha256=hoR2iF5te5Ydjt_lxIOSGID4vESIakG4F-3xAWdwxaU,1854
|
|
6
6
|
seekrai/error.py,sha256=rAYL8qEd8INwYMMKvhS-HKeC3QkWL4Wq-zfazFU-zBg,4861
|
|
7
|
-
seekrai/filemanager.py,sha256=
|
|
8
|
-
seekrai/resources/__init__.py,sha256=
|
|
7
|
+
seekrai/filemanager.py,sha256=8RuSzJvELD-fCI2Wd_t0jSKeVrmFwF7E5AzXIgDFxNA,9572
|
|
8
|
+
seekrai/resources/__init__.py,sha256=QpK4dsJoXdMvlA_53fOS2S19Ua0OyLGFBZw_fQrOOvk,799
|
|
9
|
+
seekrai/resources/alignment.py,sha256=6qQm9w0Em0q3zVeOzs8cX3wulr-B-wh4Pcr3pboIeTE,4468
|
|
9
10
|
seekrai/resources/chat/__init__.py,sha256=KmtPupgECtEN80NyvcnSmieTAFXhwmVxhMHP0qhspA4,618
|
|
10
11
|
seekrai/resources/chat/completions.py,sha256=v0Nwr7lJk6d5fZ-s6ut2BLDr9Vay8qGL9ZQLRgyOve0,11047
|
|
11
12
|
seekrai/resources/completions.py,sha256=w3La3zPMlN00y-b-tJwLgvZVH-xK_dKC6ktI5Ggn1us,8564
|
|
12
13
|
seekrai/resources/embeddings.py,sha256=3lohUrkdFqzSg8FgS7p4r87jwjE0NXU1PilWv278quk,2705
|
|
13
|
-
seekrai/resources/files.py,sha256=
|
|
14
|
+
seekrai/resources/files.py,sha256=16FfJFZJjZ10Q38AHvTwE-CtIPpKA0d4zyB52YN14e4,6876
|
|
14
15
|
seekrai/resources/finetune.py,sha256=fXLkVCTnfoeq4TvjhEWQsdIwO247tcpfWCVTlWZczDw,11271
|
|
15
16
|
seekrai/resources/images.py,sha256=E48lAe7YsZ2WXBHR_qz4SF7P4Y-U7t61m_bWNS91pM0,4802
|
|
16
|
-
seekrai/resources/models.py,sha256=
|
|
17
|
+
seekrai/resources/models.py,sha256=Pdd0S0gZdratWcHJPKNb7LkEdUGjr3xNR06W6GDiyxk,5000
|
|
17
18
|
seekrai/seekrflow_response.py,sha256=5RFEQzamDy7sTSDkxSsZQThZ3biNmeCPeHWdrFId5Go,1320
|
|
18
|
-
seekrai/types/__init__.py,sha256=
|
|
19
|
+
seekrai/types/__init__.py,sha256=YUXzhcpwGGDeiV9LxKzwaYne7zI5vl99OMLmCtdSXwY,1779
|
|
19
20
|
seekrai/types/abstract.py,sha256=TqWFQV_6bPblywfCH-r8FCkXWvPkc9KlJ4QVgyrnaMc,642
|
|
21
|
+
seekrai/types/alignment.py,sha256=FCPrACbjDPZ02Q1-1hURehcz2Nu5kPiEFlS_CSbrWUw,1093
|
|
20
22
|
seekrai/types/chat_completions.py,sha256=GgqEcfdjkWecPVZEHRENctQ1SQ6KB4CculxyKhkvnHo,3571
|
|
21
23
|
seekrai/types/common.py,sha256=79fvG60otq-H4QL0OULgmxUAAOKKas4YSYycLDLl7To,1430
|
|
22
24
|
seekrai/types/completions.py,sha256=lm9AFdZR3Xg5AHPkV-qETHikkwMJmkHrLGr5GG-YR-M,2171
|
|
23
25
|
seekrai/types/embeddings.py,sha256=OANoLNOs0aceS8NppVvvcNYQbF7-pAOAmcr30pw64OU,749
|
|
24
26
|
seekrai/types/error.py,sha256=uTKISs9aRC4_6zwirtNkanxepN8KY-SqCq0kNbfZylQ,370
|
|
25
|
-
seekrai/types/files.py,sha256=
|
|
27
|
+
seekrai/types/files.py,sha256=XmtiM6d9i3tnYS-Kii3QpxZJRqemJi2rvLJ32GsECXQ,2602
|
|
26
28
|
seekrai/types/finetune.py,sha256=mMS_3vJnJG2bBGWHCo3t98iieglwe_kR9sOrxfnO3xY,5825
|
|
27
29
|
seekrai/types/images.py,sha256=Fusj8OhVYFsT8kz636lRGGivLbPXo_ZNgakKwmzJi3U,914
|
|
28
30
|
seekrai/types/models.py,sha256=1ZfW9WwayApkISRizDntjkWhYNv-wkbrRVIfHn2QuC4,1242
|
|
@@ -32,8 +34,8 @@ seekrai/utils/api_helpers.py,sha256=0Y8BblNIr9h_R12zdmhkxgTlxgoRkbq84QNi4nNWGu8,
|
|
|
32
34
|
seekrai/utils/files.py,sha256=B61Pwra49MVVWjPtdkx4hBtAuUe9UI63hdNus87Uq0o,7164
|
|
33
35
|
seekrai/utils/tools.py,sha256=jgJTL-dOIouDbEJLdQpQfpXhqaz_poQYS52adyUtBjo,1781
|
|
34
36
|
seekrai/version.py,sha256=q6iGQVFor8zXiPP5F-3vy9TndOxKv5JXbaNJ2kdOQws,125
|
|
35
|
-
seekrai-0.
|
|
36
|
-
seekrai-0.
|
|
37
|
-
seekrai-0.
|
|
38
|
-
seekrai-0.
|
|
39
|
-
seekrai-0.
|
|
37
|
+
seekrai-0.2.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
38
|
+
seekrai-0.2.0.dist-info/METADATA,sha256=wGsyXdJTGptBTkCWfieuu52aHVvuzZt-cjyy9M75FyY,4748
|
|
39
|
+
seekrai-0.2.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
40
|
+
seekrai-0.2.0.dist-info/entry_points.txt,sha256=N49yOEGi1sK7Xr13F_rkkcOxQ88suyiMoOmRhUHTZ_U,48
|
|
41
|
+
seekrai-0.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|