sutro 0.1.23__tar.gz → 0.1.25__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.
Potentially problematic release.
This version of sutro might be problematic. Click here for more details.
- {sutro-0.1.23 → sutro-0.1.25}/PKG-INFO +1 -1
- {sutro-0.1.23 → sutro-0.1.25}/pyproject.toml +1 -1
- {sutro-0.1.23 → sutro-0.1.25}/sutro/sdk.py +38 -42
- {sutro-0.1.23 → sutro-0.1.25}/.gitignore +0 -0
- {sutro-0.1.23 → sutro-0.1.25}/LICENSE +0 -0
- {sutro-0.1.23 → sutro-0.1.25}/README.md +0 -0
- {sutro-0.1.23 → sutro-0.1.25}/sutro/__init__.py +0 -0
- {sutro-0.1.23 → sutro-0.1.25}/sutro/cli.py +0 -0
|
@@ -215,7 +215,7 @@ class Sutro:
|
|
|
215
215
|
json_schema: Dict[str, Any],
|
|
216
216
|
sampling_params: dict,
|
|
217
217
|
system_prompt: str,
|
|
218
|
-
|
|
218
|
+
cost_estimate: bool,
|
|
219
219
|
stay_attached: Optional[bool],
|
|
220
220
|
random_seed_per_input: bool,
|
|
221
221
|
truncate_rows: bool
|
|
@@ -232,7 +232,7 @@ class Sutro:
|
|
|
232
232
|
"job_priority": job_priority,
|
|
233
233
|
"json_schema": json_schema,
|
|
234
234
|
"system_prompt": system_prompt,
|
|
235
|
-
"
|
|
235
|
+
"cost_estimate": cost_estimate,
|
|
236
236
|
"sampling_params": sampling_params,
|
|
237
237
|
"random_seed_per_input": random_seed_per_input,
|
|
238
238
|
"truncate_rows": truncate_rows
|
|
@@ -245,7 +245,7 @@ class Sutro:
|
|
|
245
245
|
# Terminal size {self._terminal_width} is too small to display spinner with the given settings.
|
|
246
246
|
# https://github.com/pavdmyt/yaspin/blob/9c7430b499ab4611888ece39783a870e4a05fa45/yaspin/core.py#L568-L571
|
|
247
247
|
job_id = None
|
|
248
|
-
t = f"Creating {'[
|
|
248
|
+
t = f"Creating {'[cost estimate] ' if cost_estimate else ''}priority {job_priority} job"
|
|
249
249
|
spinner_text = to_colored_text(t)
|
|
250
250
|
try:
|
|
251
251
|
with yaspin(SPINNER, text=spinner_text, color=YASPIN_COLOR) as spinner:
|
|
@@ -262,12 +262,12 @@ class Sutro:
|
|
|
262
262
|
return None
|
|
263
263
|
else:
|
|
264
264
|
job_id = response_data["results"]
|
|
265
|
-
if
|
|
265
|
+
if cost_estimate:
|
|
266
266
|
spinner.write(
|
|
267
|
-
to_colored_text(f"Awaiting cost estimates with job ID: {job_id}. You can safely detach and retrieve the cost estimates later."
|
|
267
|
+
to_colored_text(f"Awaiting cost estimates with job ID: {job_id}. You can safely detach and retrieve the cost estimates later.")
|
|
268
268
|
)
|
|
269
269
|
spinner.stop()
|
|
270
|
-
self.await_job_completion(job_id, obtain_results=False)
|
|
270
|
+
self.await_job_completion(job_id, obtain_results=False, is_cost_estimate=True)
|
|
271
271
|
cost_estimate = self._get_job_cost_estimate(job_id)
|
|
272
272
|
spinner.write(
|
|
273
273
|
to_colored_text(f"✔ Cost estimates retrieved for job {job_id}: ${cost_estimate}", state="success")
|
|
@@ -410,7 +410,7 @@ class Sutro:
|
|
|
410
410
|
spinner.stop()
|
|
411
411
|
return None
|
|
412
412
|
|
|
413
|
-
results = job_results_response.json()["results"]
|
|
413
|
+
results = job_results_response.json()["results"]["outputs"]
|
|
414
414
|
|
|
415
415
|
spinner.write(
|
|
416
416
|
to_colored_text(
|
|
@@ -421,12 +421,6 @@ class Sutro:
|
|
|
421
421
|
spinner.stop()
|
|
422
422
|
|
|
423
423
|
if isinstance(data, (pd.DataFrame, pl.DataFrame)):
|
|
424
|
-
sample_n = 1 if sampling_params is None else sampling_params["n"]
|
|
425
|
-
if sample_n > 1:
|
|
426
|
-
results = [
|
|
427
|
-
results[i : i + sample_n]
|
|
428
|
-
for i in range(0, len(results), sample_n)
|
|
429
|
-
]
|
|
430
424
|
if isinstance(data, pd.DataFrame):
|
|
431
425
|
data[output_column] = results
|
|
432
426
|
elif isinstance(data, pl.DataFrame):
|
|
@@ -538,20 +532,8 @@ class Sutro:
|
|
|
538
532
|
text=to_colored_text("Looking for job..."),
|
|
539
533
|
color=YASPIN_COLOR,
|
|
540
534
|
) as spinner:
|
|
541
|
-
#
|
|
542
|
-
|
|
543
|
-
# GET /jobs/{job_id}
|
|
544
|
-
jobs_response = s.get(
|
|
545
|
-
f"{self.base_url}/list-jobs",
|
|
546
|
-
headers=headers
|
|
547
|
-
)
|
|
548
|
-
jobs_response.raise_for_status()
|
|
549
|
-
|
|
550
|
-
# Find the specific job we want to attach to
|
|
551
|
-
job = next(
|
|
552
|
-
(job for job in jobs_response.json()["jobs"] if job["job_id"] == job_id),
|
|
553
|
-
None
|
|
554
|
-
)
|
|
535
|
+
# Fetch the specific job we want to attach to
|
|
536
|
+
job = self._fetch_job(job_id)
|
|
555
537
|
|
|
556
538
|
if not job:
|
|
557
539
|
spinner.write(to_colored_text(f"Job {job_id} not found", state="fail"))
|
|
@@ -732,7 +714,7 @@ class Sutro:
|
|
|
732
714
|
"""
|
|
733
715
|
Helper function to list jobs.
|
|
734
716
|
"""
|
|
735
|
-
endpoint = f"{self.base_url}/list-jobs"
|
|
717
|
+
endpoint = f"{self.base_url}/list-jobs˚"
|
|
736
718
|
headers = {
|
|
737
719
|
"Authorization": f"Key {self.api_key}",
|
|
738
720
|
"Content-Type": "application/json",
|
|
@@ -742,25 +724,38 @@ class Sutro:
|
|
|
742
724
|
return None
|
|
743
725
|
return response.json()["jobs"]
|
|
744
726
|
|
|
727
|
+
def _fetch_job(self, job_id):
|
|
728
|
+
"""
|
|
729
|
+
Helper function to fetch a single job.
|
|
730
|
+
"""
|
|
731
|
+
endpoint = f"{self.base_url}/jobs/{job_id}"
|
|
732
|
+
headers = {
|
|
733
|
+
"Authorization": f"Key {self.api_key}",
|
|
734
|
+
"Content-Type": "application/json",
|
|
735
|
+
}
|
|
736
|
+
response = requests.get(endpoint, headers=headers)
|
|
737
|
+
if response.status_code != 200:
|
|
738
|
+
return None
|
|
739
|
+
return response.json().get('job')
|
|
740
|
+
|
|
745
741
|
def _get_job_cost_estimate(self, job_id: str):
|
|
746
742
|
"""
|
|
747
743
|
Get the cost estimate for a job.
|
|
748
744
|
"""
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
return
|
|
745
|
+
job = self._fetch_job(job_id)
|
|
746
|
+
if not job:
|
|
747
|
+
return None
|
|
748
|
+
|
|
749
|
+
return job.get('cost_estimate')
|
|
754
750
|
|
|
755
751
|
def _get_failure_reason(self, job_id: str):
|
|
756
752
|
"""
|
|
757
753
|
Get the failure reason for a job.
|
|
758
754
|
"""
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
return None
|
|
755
|
+
job = self._fetch_job(job_id)
|
|
756
|
+
if not job:
|
|
757
|
+
return None
|
|
758
|
+
return job.get('failure_reason')
|
|
764
759
|
|
|
765
760
|
def _fetch_job_status(self, job_id: str):
|
|
766
761
|
"""
|
|
@@ -1245,7 +1240,7 @@ class Sutro:
|
|
|
1245
1240
|
return
|
|
1246
1241
|
return response.json()["quotas"]
|
|
1247
1242
|
|
|
1248
|
-
def await_job_completion(self, job_id: str, timeout: Optional[int] = 7200, obtain_results: bool = True) -> list | None:
|
|
1243
|
+
def await_job_completion(self, job_id: str, timeout: Optional[int] = 7200, obtain_results: bool = True, is_cost_estimate: bool=False) -> list | None:
|
|
1249
1244
|
"""
|
|
1250
1245
|
Waits for job completion to occur and then returns the results upon
|
|
1251
1246
|
a successful completion.
|
|
@@ -1266,8 +1261,9 @@ class Sutro:
|
|
|
1266
1261
|
with yaspin(
|
|
1267
1262
|
SPINNER, text=to_colored_text("Awaiting job completion"), color=YASPIN_COLOR
|
|
1268
1263
|
) as spinner:
|
|
1269
|
-
|
|
1270
|
-
|
|
1264
|
+
if not is_cost_estimate:
|
|
1265
|
+
clickable_link = make_clickable_link(f'https://app.sutro.sh/jobs/{job_id}')
|
|
1266
|
+
spinner.write(to_colored_text(f'Progress can also be monitored at: {clickable_link}'))
|
|
1271
1267
|
while (time.time() - start_time) < timeout:
|
|
1272
1268
|
try:
|
|
1273
1269
|
status = self._fetch_job_status(job_id)
|
|
@@ -1284,9 +1280,9 @@ class Sutro:
|
|
|
1284
1280
|
spinner.text = to_colored_text(f"Job status is {status} for {job_id}")
|
|
1285
1281
|
|
|
1286
1282
|
if status == JobStatus.SUCCEEDED:
|
|
1287
|
-
spinner.write(to_colored_text("Job completed! Retrieving results...", "success"))
|
|
1288
1283
|
spinner.stop() # Stop this spinner as `get_job_results` has its own spinner text
|
|
1289
1284
|
if obtain_results:
|
|
1285
|
+
spinner.write(to_colored_text("Job completed! Retrieving results...", "success"))
|
|
1290
1286
|
results = self.get_job_results(job_id)
|
|
1291
1287
|
break
|
|
1292
1288
|
if status == JobStatus.FAILED:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|