seekrai 0.0.1__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.
Files changed (56) hide show
  1. seekrai/__init__.py +64 -0
  2. seekrai/abstract/__init__.py +1 -0
  3. seekrai/abstract/api_requestor.py +710 -0
  4. seekrai/cli/__init__.py +0 -0
  5. seekrai/cli/api/__init__.py +0 -0
  6. seekrai/cli/api/chat.py +245 -0
  7. seekrai/cli/api/completions.py +107 -0
  8. seekrai/cli/api/files.py +125 -0
  9. seekrai/cli/api/finetune.py +175 -0
  10. seekrai/cli/api/images.py +82 -0
  11. seekrai/cli/api/models.py +42 -0
  12. seekrai/cli/cli.py +77 -0
  13. seekrai/client.py +154 -0
  14. seekrai/constants.py +32 -0
  15. seekrai/error.py +188 -0
  16. seekrai/filemanager.py +393 -0
  17. seekrai/legacy/__init__.py +0 -0
  18. seekrai/legacy/base.py +27 -0
  19. seekrai/legacy/complete.py +91 -0
  20. seekrai/legacy/embeddings.py +25 -0
  21. seekrai/legacy/files.py +140 -0
  22. seekrai/legacy/finetune.py +173 -0
  23. seekrai/legacy/images.py +25 -0
  24. seekrai/legacy/models.py +44 -0
  25. seekrai/resources/__init__.py +25 -0
  26. seekrai/resources/chat/__init__.py +24 -0
  27. seekrai/resources/chat/completions.py +241 -0
  28. seekrai/resources/completions.py +205 -0
  29. seekrai/resources/embeddings.py +100 -0
  30. seekrai/resources/files.py +173 -0
  31. seekrai/resources/finetune.py +425 -0
  32. seekrai/resources/images.py +156 -0
  33. seekrai/resources/models.py +75 -0
  34. seekrai/seekrflow_response.py +50 -0
  35. seekrai/types/__init__.py +67 -0
  36. seekrai/types/abstract.py +26 -0
  37. seekrai/types/chat_completions.py +151 -0
  38. seekrai/types/common.py +64 -0
  39. seekrai/types/completions.py +86 -0
  40. seekrai/types/embeddings.py +35 -0
  41. seekrai/types/error.py +16 -0
  42. seekrai/types/files.py +88 -0
  43. seekrai/types/finetune.py +218 -0
  44. seekrai/types/images.py +42 -0
  45. seekrai/types/models.py +43 -0
  46. seekrai/utils/__init__.py +28 -0
  47. seekrai/utils/_log.py +61 -0
  48. seekrai/utils/api_helpers.py +84 -0
  49. seekrai/utils/files.py +204 -0
  50. seekrai/utils/tools.py +75 -0
  51. seekrai/version.py +6 -0
  52. seekrai-0.0.1.dist-info/LICENSE +201 -0
  53. seekrai-0.0.1.dist-info/METADATA +401 -0
  54. seekrai-0.0.1.dist-info/RECORD +56 -0
  55. seekrai-0.0.1.dist-info/WHEEL +4 -0
  56. seekrai-0.0.1.dist-info/entry_points.txt +3 -0
seekrai/filemanager.py ADDED
@@ -0,0 +1,393 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import shutil
5
+ import stat
6
+ import tempfile
7
+ import uuid
8
+ from functools import partial
9
+ from pathlib import Path
10
+ from typing import Tuple
11
+
12
+ import requests
13
+ from filelock import FileLock
14
+ from requests.structures import CaseInsensitiveDict
15
+ from tqdm import tqdm
16
+ from tqdm.utils import CallbackIOWrapper
17
+
18
+ import seekrai.utils
19
+ from seekrai.abstract import api_requestor
20
+ from seekrai.constants import DISABLE_TQDM, DOWNLOAD_BLOCK_SIZE, MAX_RETRIES
21
+ from seekrai.error import (
22
+ APIError,
23
+ AuthenticationError,
24
+ DownloadError,
25
+ FileTypeError,
26
+ )
27
+ from seekrai.seekrflow_response import SeekrFlowResponse
28
+ from seekrai.types import (
29
+ FilePurpose,
30
+ FileResponse,
31
+ FileType,
32
+ SeekrFlowClient,
33
+ SeekrFlowRequest,
34
+ )
35
+
36
+
37
+ def chmod_and_replace(src: Path, dst: Path) -> None:
38
+ """Set correct permission before moving a blob from tmp directory to cache dir.
39
+
40
+ Do not take into account the `umask` from the process as there is no convenient way
41
+ to get it that is thread-safe.
42
+ """
43
+
44
+ # Get umask by creating a temporary file in the cache folder.
45
+ tmp_file = dst.parent / f"tmp_{uuid.uuid4()}"
46
+
47
+ try:
48
+ tmp_file.touch()
49
+
50
+ cache_dir_mode = Path(tmp_file).stat().st_mode
51
+
52
+ os.chmod(src.as_posix(), stat.S_IMODE(cache_dir_mode))
53
+
54
+ finally:
55
+ tmp_file.unlink()
56
+
57
+ shutil.move(src.as_posix(), dst.as_posix())
58
+
59
+
60
+ def _get_file_size(
61
+ headers: CaseInsensitiveDict[str],
62
+ ) -> int:
63
+ """
64
+ Extracts file size from header
65
+ """
66
+ total_size_in_bytes = 0
67
+
68
+ parts = headers.get("Content-Range", "").split(" ")
69
+
70
+ if len(parts) == 2:
71
+ range_parts = parts[1].split("/")
72
+
73
+ if len(range_parts) == 2:
74
+ total_size_in_bytes = int(range_parts[1])
75
+
76
+ assert total_size_in_bytes != 0, "Unable to retrieve remote file."
77
+
78
+ return total_size_in_bytes
79
+
80
+
81
+ def _prepare_output(
82
+ headers: CaseInsensitiveDict[str],
83
+ step: int = -1,
84
+ output: Path | None = None,
85
+ remote_name: str | None = None,
86
+ ) -> Path:
87
+ """
88
+ Generates output file name from remote name and headers
89
+ """
90
+ if output:
91
+ return output
92
+
93
+ content_type = str(headers.get("content-type"))
94
+
95
+ assert remote_name, (
96
+ "No model name found in fine_tune object. "
97
+ "Please specify an `output` file name."
98
+ )
99
+
100
+ if step > 0:
101
+ remote_name += f"-checkpoint-{step}"
102
+
103
+ if "x-tar" in content_type.lower():
104
+ remote_name += ".tar.gz"
105
+
106
+ elif "zstd" in content_type.lower() or step != -1:
107
+ remote_name += ".tar.zst"
108
+
109
+ else:
110
+ raise FileTypeError(
111
+ f"Unknown file type {content_type} found. Aborting download."
112
+ )
113
+
114
+ return Path(remote_name)
115
+
116
+
117
+ class DownloadManager:
118
+ def __init__(self, client: SeekrFlowClient) -> None:
119
+ self._client = client
120
+
121
+ def get_file_metadata(
122
+ self,
123
+ url: str,
124
+ output: Path | None = None,
125
+ remote_name: str | None = None,
126
+ fetch_metadata: bool = False,
127
+ ) -> Tuple[Path, int]:
128
+ """
129
+ gets remote file head and parses out file name and file size
130
+ """
131
+
132
+ if not fetch_metadata:
133
+ if isinstance(output, Path):
134
+ file_path = output
135
+ else:
136
+ assert isinstance(remote_name, str)
137
+ file_path = Path(remote_name)
138
+
139
+ return file_path, 0
140
+
141
+ requestor = api_requestor.APIRequestor(
142
+ client=self._client,
143
+ )
144
+
145
+ response = requestor.request_raw(
146
+ options=SeekrFlowRequest(
147
+ method="GET",
148
+ url=url,
149
+ headers={"Range": "bytes=0-1"},
150
+ ),
151
+ remaining_retries=MAX_RETRIES,
152
+ stream=False,
153
+ )
154
+
155
+ try:
156
+ response.raise_for_status()
157
+ except requests.exceptions.HTTPError as e:
158
+ raise APIError(
159
+ "Error fetching file metadata", http_status=response.status_code
160
+ ) from e
161
+
162
+ headers = response.headers
163
+
164
+ assert isinstance(headers, CaseInsensitiveDict)
165
+
166
+ file_path = _prepare_output(
167
+ headers=headers,
168
+ output=output,
169
+ remote_name=remote_name,
170
+ )
171
+
172
+ file_size = _get_file_size(headers)
173
+
174
+ return file_path, file_size
175
+
176
+ def download(
177
+ self,
178
+ url: str,
179
+ output: Path | None = None,
180
+ remote_name: str | None = None,
181
+ fetch_metadata: bool = False,
182
+ ) -> Tuple[str, int]:
183
+ requestor = api_requestor.APIRequestor(
184
+ client=self._client,
185
+ )
186
+
187
+ # pre-fetch remote file name and file size
188
+ file_path, file_size = self.get_file_metadata(
189
+ url, output, remote_name, fetch_metadata
190
+ )
191
+
192
+ temp_file_manager = partial(
193
+ tempfile.NamedTemporaryFile, mode="wb", dir=file_path.parent, delete=False
194
+ )
195
+
196
+ # Prevent parallel downloads of the same file with a lock.
197
+ lock_path = Path(file_path.as_posix() + ".lock")
198
+
199
+ with FileLock(lock_path.as_posix()):
200
+ with temp_file_manager() as temp_file:
201
+ response = requestor.request_raw(
202
+ options=SeekrFlowRequest(
203
+ method="GET",
204
+ url=url,
205
+ ),
206
+ remaining_retries=MAX_RETRIES,
207
+ stream=True,
208
+ )
209
+
210
+ try:
211
+ response.raise_for_status()
212
+ except Exception as e:
213
+ os.remove(lock_path)
214
+ raise APIError(
215
+ "Error downloading file", http_status=response.status_code
216
+ ) from e
217
+
218
+ if not fetch_metadata:
219
+ file_size = int(response.headers.get("content-length", 0))
220
+
221
+ assert file_size != 0, "Unable to retrieve remote file."
222
+
223
+ with tqdm(
224
+ total=file_size,
225
+ unit="B",
226
+ unit_scale=True,
227
+ desc=f"Downloading file {file_path.name}",
228
+ disable=bool(DISABLE_TQDM),
229
+ ) as pbar:
230
+ for chunk in response.iter_content(DOWNLOAD_BLOCK_SIZE):
231
+ pbar.update(len(chunk))
232
+ temp_file.write(chunk)
233
+
234
+ # Raise exception if remote file size does not match downloaded file size
235
+ if os.stat(temp_file.name).st_size != file_size:
236
+ DownloadError(
237
+ f"Downloaded file size `{pbar.n}` bytes does not match "
238
+ f"remote file size `{file_size}` bytes."
239
+ )
240
+
241
+ # Moves temp file to output file path
242
+ chmod_and_replace(Path(temp_file.name), file_path)
243
+
244
+ os.remove(lock_path)
245
+
246
+ return str(file_path.resolve()), file_size
247
+
248
+
249
+ class UploadManager:
250
+ def __init__(self, client: SeekrFlowClient) -> None:
251
+ self._client = client
252
+
253
+ @classmethod
254
+ def _redirect_error_handler(
255
+ cls, requestor: api_requestor.APIRequestor, response: requests.Response
256
+ ) -> None:
257
+ if response.status_code == 401:
258
+ raise AuthenticationError(
259
+ "This job would exceed your free trial credits. "
260
+ "Please upgrade to a paid account through "
261
+ "Settings -> Billing on api.seekrai.ai to continue.",
262
+ )
263
+ elif response.status_code != 302:
264
+ raise APIError(
265
+ f"Unexpected error raised by endpoint: {response.content.decode()}, headers: {response.headers}",
266
+ http_status=response.status_code,
267
+ )
268
+
269
+ def get_upload_url(
270
+ self,
271
+ url: str,
272
+ file: Path,
273
+ purpose: FilePurpose,
274
+ filetype: FileType,
275
+ ) -> Tuple[str, str]:
276
+ data = {
277
+ "purpose": purpose.value,
278
+ "file_name": file.name,
279
+ "file_type": filetype.value,
280
+ }
281
+
282
+ requestor = api_requestor.APIRequestor(
283
+ client=self._client,
284
+ )
285
+
286
+ method = "POST"
287
+
288
+ headers = seekrai.utils.get_headers(method, requestor.api_key)
289
+
290
+ response = requestor.request_raw(
291
+ options=SeekrFlowRequest(
292
+ method=method,
293
+ url=url,
294
+ params=data,
295
+ allow_redirects=False,
296
+ override_headers=True,
297
+ headers=headers,
298
+ ),
299
+ remaining_retries=MAX_RETRIES,
300
+ )
301
+
302
+ self._redirect_error_handler(requestor, response)
303
+
304
+ redirect_url = response.headers["Location"]
305
+ file_id = response.headers["X-SeekrFlow-File-Id"]
306
+
307
+ return redirect_url, file_id
308
+
309
+ def callback(self, url: str) -> SeekrFlowResponse:
310
+ requestor = api_requestor.APIRequestor(
311
+ client=self._client,
312
+ )
313
+
314
+ response, _, _ = requestor.request(
315
+ options=SeekrFlowRequest(
316
+ method="POST",
317
+ url=url,
318
+ ),
319
+ )
320
+
321
+ return response
322
+
323
+ def upload(
324
+ self,
325
+ url: str,
326
+ file: Path,
327
+ purpose: FilePurpose,
328
+ redirect: bool = False,
329
+ ) -> FileResponse:
330
+ file_id = None
331
+
332
+ requestor = api_requestor.APIRequestor(
333
+ client=self._client,
334
+ )
335
+
336
+ redirect_url = None
337
+ if redirect:
338
+ if file.suffix == ".jsonl":
339
+ filetype = FileType.jsonl
340
+ elif file.suffix == ".parquet":
341
+ filetype = FileType.parquet
342
+ else:
343
+ raise FileTypeError(
344
+ f"Unknown extension of file {file}. "
345
+ "Only files with extensions .jsonl and .parquet are supported."
346
+ )
347
+ # redirect_url, file_id = self.get_upload_url(url, file, purpose, filetype)
348
+
349
+ file_size = os.stat(file.as_posix()).st_size
350
+
351
+ with tqdm(
352
+ total=file_size,
353
+ unit="B",
354
+ unit_scale=True,
355
+ desc=f"Uploading file {file.name}",
356
+ disable=bool(DISABLE_TQDM),
357
+ ) as pbar:
358
+ with file.open("rb") as f:
359
+ # wrapped_file = CallbackIOWrapper(pbar.update, f, "read")
360
+
361
+ # if redirect:
362
+ # callback_response = requestor.request_raw(
363
+ # options=SeekrFlowRequest(
364
+ # method="PUT",
365
+ # url=redirect_url,
366
+ # params=wrapped_file,
367
+ # override_headers=True,
368
+ # ),
369
+ # absolute=True,
370
+ # remaining_retries=MAX_RETRIES,
371
+ # )
372
+ # else:
373
+ response, _, _ = requestor.request(
374
+ options=SeekrFlowRequest(
375
+ method="PUT",
376
+ url=url,
377
+ files={"files": f, "filename": file.name},
378
+ ),
379
+ )
380
+
381
+ # if redirect:
382
+ # assert isinstance(callback_response, requests.Response)
383
+ #
384
+ # if not callback_response.status_code == 200:
385
+ # raise APIError(
386
+ # f"Error code: {callback_response.status_code} - Failed to process uploaded file"
387
+ # )
388
+ #
389
+ # response = self.callback(f"{url}/{file_id}/preprocess")
390
+
391
+ assert isinstance(response, SeekrFlowResponse)
392
+
393
+ return FileResponse(**response.data)
File without changes
seekrai/legacy/base.py ADDED
@@ -0,0 +1,27 @@
1
+ import functools
2
+ import warnings
3
+
4
+
5
+ API_KEY_WARNING = (
6
+ "The use of seekrai.api_key is deprecated and will be removed in the next major release. "
7
+ "Please set the SEEKRFLOW_API_KEY environment variable instead."
8
+ )
9
+
10
+
11
+ def deprecated(func): # type: ignore
12
+ """
13
+ This is a decorator which can be used to mark functions
14
+ as deprecated. It will result in a warning being emitted
15
+ when the function is used.
16
+ """
17
+
18
+ @functools.wraps(func)
19
+ def new_func(*args, **kwargs): # type: ignore
20
+ warnings.warn(
21
+ f"Call to deprecated function {func.__name__}.",
22
+ category=DeprecationWarning,
23
+ stacklevel=2,
24
+ )
25
+ return func(*args, **kwargs)
26
+
27
+ return new_func
@@ -0,0 +1,91 @@
1
+ from __future__ import annotations
2
+
3
+ import warnings
4
+ from typing import Any, AsyncGenerator, Dict, Iterator
5
+
6
+ import seekrai
7
+ from seekrai.legacy.base import API_KEY_WARNING, deprecated
8
+ from seekrai.types import CompletionChunk, CompletionResponse
9
+
10
+
11
+ class Complete:
12
+ @classmethod
13
+ @deprecated # type: ignore
14
+ def create(
15
+ cls,
16
+ prompt: str,
17
+ **kwargs,
18
+ ) -> Dict[str, Any]:
19
+ """Legacy completion function."""
20
+
21
+ api_key = None
22
+ if seekrai.api_key:
23
+ warnings.warn(API_KEY_WARNING)
24
+ api_key = seekrai.api_key
25
+
26
+ client = seekrai.SeekrFlow(api_key=api_key)
27
+
28
+ return client.completions.create(
29
+ prompt=prompt, stream=False, **kwargs
30
+ ).model_dump() # type: ignore
31
+
32
+ @classmethod
33
+ @deprecated # type: ignore
34
+ def create_streaming(
35
+ cls,
36
+ prompt: str,
37
+ **kwargs,
38
+ ) -> Iterator[Dict[str, Any]]:
39
+ """Legacy streaming completion function."""
40
+
41
+ api_key = None
42
+ if seekrai.api_key:
43
+ warnings.warn(API_KEY_WARNING)
44
+ api_key = seekrai.api_key
45
+
46
+ client = seekrai.SeekrFlow(api_key=api_key)
47
+
48
+ return (
49
+ token.model_dump() # type: ignore
50
+ for token in client.completions.create(prompt=prompt, stream=True, **kwargs)
51
+ )
52
+
53
+
54
+ class Completion:
55
+ @classmethod
56
+ @deprecated # type: ignore
57
+ def create(
58
+ cls,
59
+ prompt: str,
60
+ **kwargs,
61
+ ) -> CompletionResponse | Iterator[CompletionChunk]:
62
+ """Completion function."""
63
+
64
+ api_key = None
65
+ if seekrai.api_key:
66
+ warnings.warn(API_KEY_WARNING)
67
+ api_key = seekrai.api_key
68
+
69
+ client = seekrai.SeekrFlow(api_key=api_key)
70
+
71
+ return client.completions.create(prompt=prompt, **kwargs)
72
+
73
+
74
+ class AsyncComplete:
75
+ @classmethod
76
+ @deprecated # type: ignore
77
+ async def create(
78
+ cls,
79
+ prompt: str,
80
+ **kwargs,
81
+ ) -> CompletionResponse | AsyncGenerator[CompletionChunk, None]:
82
+ """Async completion function."""
83
+
84
+ api_key = None
85
+ if seekrai.api_key:
86
+ warnings.warn(API_KEY_WARNING)
87
+ api_key = seekrai.api_key
88
+
89
+ client = seekrai.AsyncSeekrFlow(api_key=api_key)
90
+
91
+ return await client.completions.create(prompt=prompt, **kwargs)
@@ -0,0 +1,25 @@
1
+ import warnings
2
+ from typing import Any, Dict
3
+
4
+ import seekrai
5
+ from seekrai.legacy.base import API_KEY_WARNING, deprecated
6
+
7
+
8
+ class Embeddings:
9
+ @classmethod
10
+ @deprecated # type: ignore
11
+ def create(
12
+ cls,
13
+ input: str,
14
+ **kwargs,
15
+ ) -> Dict[str, Any]:
16
+ """Legacy embeddings function."""
17
+
18
+ api_key = None
19
+ if seekrai.api_key:
20
+ warnings.warn(API_KEY_WARNING)
21
+ api_key = seekrai.api_key
22
+
23
+ client = seekrai.SeekrFlow(api_key=api_key)
24
+
25
+ return client.embeddings.create(input=input, **kwargs).model_dump()
@@ -0,0 +1,140 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import warnings
5
+ from typing import Any, Dict, List
6
+
7
+ import seekrai
8
+ from seekrai.legacy.base import API_KEY_WARNING, deprecated
9
+ from seekrai.utils.files import check_file as check_json
10
+
11
+
12
+ class Files:
13
+ @classmethod
14
+ @deprecated # type: ignore
15
+ def list(
16
+ cls,
17
+ ) -> Dict[str, Any]:
18
+ """Legacy file list function."""
19
+
20
+ api_key = None
21
+ if seekrai.api_key:
22
+ warnings.warn(API_KEY_WARNING)
23
+ api_key = seekrai.api_key
24
+
25
+ client = seekrai.SeekrFlow(api_key=api_key)
26
+
27
+ return client.files.list().model_dump()
28
+
29
+ @classmethod
30
+ def check(self, file: str) -> Dict[str, object]:
31
+ return check_json(file)
32
+
33
+ @classmethod
34
+ @deprecated # type: ignore
35
+ def upload(
36
+ cls,
37
+ file: str,
38
+ check: bool = True,
39
+ ) -> Dict[str, Any]:
40
+ """Legacy file upload function."""
41
+
42
+ api_key = None
43
+ if seekrai.api_key:
44
+ warnings.warn(API_KEY_WARNING)
45
+ api_key = seekrai.api_key
46
+
47
+ if check:
48
+ report_dict = check_json(file)
49
+ if not report_dict["is_check_passed"]:
50
+ raise seekrai.error.FileTypeError(
51
+ f"Invalid file supplied. Failed to upload.\nReport:\n {report_dict}"
52
+ )
53
+
54
+ client = seekrai.SeekrFlow(api_key=api_key)
55
+
56
+ response = client.files.upload(file=file).model_dump()
57
+
58
+ response["report_dict"] = report_dict
59
+
60
+ return response
61
+
62
+ @classmethod
63
+ @deprecated # type: ignore
64
+ def delete(
65
+ cls,
66
+ file_id: str,
67
+ ) -> Dict[str, Any]:
68
+ """Legacy file delete function."""
69
+
70
+ api_key = None
71
+ if seekrai.api_key:
72
+ warnings.warn(API_KEY_WARNING)
73
+ api_key = seekrai.api_key
74
+
75
+ client = seekrai.SeekrFlow(api_key=api_key)
76
+
77
+ return client.files.delete(id=file_id).model_dump()
78
+
79
+ @classmethod
80
+ @deprecated # type: ignore
81
+ def retrieve(
82
+ cls,
83
+ file_id: str,
84
+ ) -> Dict[str, Any]:
85
+ """Legacy file retrieve function."""
86
+
87
+ api_key = None
88
+ if seekrai.api_key:
89
+ warnings.warn(API_KEY_WARNING)
90
+ api_key = seekrai.api_key
91
+
92
+ client = seekrai.SeekrFlow(api_key=api_key)
93
+
94
+ return client.files.retrieve(id=file_id).model_dump()
95
+
96
+ @classmethod
97
+ @deprecated # type: ignore
98
+ def retrieve_content(
99
+ cls,
100
+ file_id: str,
101
+ output: str | None = None,
102
+ ) -> Dict[str, Any]:
103
+ """Legacy file retrieve content function."""
104
+
105
+ api_key = None
106
+ if seekrai.api_key:
107
+ warnings.warn(API_KEY_WARNING)
108
+ api_key = seekrai.api_key
109
+
110
+ client = seekrai.SeekrFlow(api_key=api_key)
111
+
112
+ return client.files.retrieve_content(id=file_id, output=output).model_dump()
113
+
114
+ @classmethod
115
+ @deprecated # type: ignore
116
+ def save_jsonl(
117
+ self, data: Dict[str, str], output_path: str, append: bool = False
118
+ ) -> None:
119
+ """
120
+ Write list of objects to a JSON lines file.
121
+ """
122
+ mode = "a+" if append else "w"
123
+ with open(output_path, mode, encoding="utf-8") as f:
124
+ for line in data:
125
+ json_record = json.dumps(line, ensure_ascii=False)
126
+ f.write(json_record + "\n")
127
+ print("Wrote {} records to {}".format(len(data), output_path))
128
+
129
+ @classmethod
130
+ @deprecated # type: ignore
131
+ def load_jsonl(self, input_path: str) -> List[Dict[str, str]]:
132
+ """
133
+ Read list of objects from a JSON lines file.
134
+ """
135
+ data = []
136
+ with open(input_path, "r", encoding="utf-8") as f:
137
+ for line in f:
138
+ data.append(json.loads(line.rstrip("\n|\r")))
139
+ print("Loaded {} records from {}".format(len(data), input_path))
140
+ return data