smooth-py 0.1.2__py3-none-any.whl → 0.1.3__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.
Potentially problematic release.
This version of smooth-py might be problematic. Click here for more details.
smooth/__init__.py
CHANGED
|
@@ -8,6 +8,7 @@ from typing import (
|
|
|
8
8
|
Any,
|
|
9
9
|
Literal,
|
|
10
10
|
)
|
|
11
|
+
from urllib.parse import urlencode
|
|
11
12
|
|
|
12
13
|
import httpx
|
|
13
14
|
import requests
|
|
@@ -40,9 +41,9 @@ class TaskRequest(BaseModel):
|
|
|
40
41
|
|
|
41
42
|
task: str = Field(description="The task to run.")
|
|
42
43
|
agent: Literal["smooth"] = Field(default="smooth", description="The agent to use for the task.")
|
|
43
|
-
max_steps: int = Field(default=32, ge=2, le=
|
|
44
|
+
max_steps: int = Field(default=32, ge=2, le=128, description="Maximum number of steps the agent can take (min 2, max 128).")
|
|
44
45
|
device: Literal["desktop", "mobile"] = Field(default="mobile", description="Device type for the task. Default is mobile.")
|
|
45
|
-
enable_recording: bool = Field(default=
|
|
46
|
+
enable_recording: bool = Field(default=True, description="Enable video recording of the task execution. Default is True")
|
|
46
47
|
session_id: str | None = Field(
|
|
47
48
|
default=None,
|
|
48
49
|
description="Browser session ID to use. Each session maintains its own state, such as login credentials.",
|
|
@@ -51,7 +52,7 @@ class TaskRequest(BaseModel):
|
|
|
51
52
|
proxy_server: str | None = Field(
|
|
52
53
|
default=None,
|
|
53
54
|
description=(
|
|
54
|
-
"Proxy server url to route browser traffic through.
|
|
55
|
+
"Proxy server url to route browser traffic through. Must include the protocol to use (e.g. http:// or https://)"
|
|
55
56
|
),
|
|
56
57
|
)
|
|
57
58
|
proxy_username: str | None = Field(default=None, description="Proxy server username.")
|
|
@@ -159,9 +160,9 @@ class TaskHandle:
|
|
|
159
160
|
self._poll_interval = poll_interval
|
|
160
161
|
self._timeout = timeout
|
|
161
162
|
self._task_response: TaskResponse | None = None
|
|
163
|
+
self._live_url = live_url
|
|
162
164
|
|
|
163
165
|
self.id = task_id
|
|
164
|
-
self.live_url = live_url
|
|
165
166
|
|
|
166
167
|
def result(self) -> TaskResponse:
|
|
167
168
|
"""Waits for the task to complete and returns the result."""
|
|
@@ -177,6 +178,28 @@ class TaskHandle:
|
|
|
177
178
|
time.sleep(self._poll_interval)
|
|
178
179
|
raise TimeoutError(f"Task {self.id} did not complete within {self._timeout} seconds.")
|
|
179
180
|
|
|
181
|
+
def live_url(self, interactive: bool = True, embed: bool = False) -> str:
|
|
182
|
+
"""Returns the live URL for the task."""
|
|
183
|
+
params = {
|
|
184
|
+
"interactive": interactive,
|
|
185
|
+
"embed": embed
|
|
186
|
+
}
|
|
187
|
+
return f"{self._live_url}?{urlencode(params)}"
|
|
188
|
+
|
|
189
|
+
def recording_url(self) -> str:
|
|
190
|
+
"""Returns the recording URL for the task."""
|
|
191
|
+
if self._task_response and self._task_response.recording_url is not None:
|
|
192
|
+
return self._task_response.recording_url
|
|
193
|
+
|
|
194
|
+
start_time = time.time()
|
|
195
|
+
while (time.time() - start_time) < 8:
|
|
196
|
+
task_response = self._client._get_task(self.id) # pyright: ignore [reportPrivateUsage]
|
|
197
|
+
self._task_response = task_response
|
|
198
|
+
if task_response.recording_url is not None:
|
|
199
|
+
return task_response.recording_url
|
|
200
|
+
time.sleep(1)
|
|
201
|
+
raise TimeoutError(f"Recording not available for task {self.id}.")
|
|
202
|
+
|
|
180
203
|
|
|
181
204
|
class SmoothClient(BaseClient):
|
|
182
205
|
"""A synchronous client for the API."""
|
|
@@ -349,10 +372,10 @@ class AsyncTaskHandle:
|
|
|
349
372
|
self._client = client
|
|
350
373
|
self._poll_interval = poll_interval
|
|
351
374
|
self._timeout = timeout
|
|
375
|
+
self._live_url = live_url
|
|
352
376
|
self._task_response: TaskResponse | None = None
|
|
353
377
|
|
|
354
378
|
self.id = task_id
|
|
355
|
-
self.live_url = live_url
|
|
356
379
|
|
|
357
380
|
async def result(self) -> TaskResponse:
|
|
358
381
|
"""Waits for the task to complete and returns the result."""
|
|
@@ -362,12 +385,33 @@ class AsyncTaskHandle:
|
|
|
362
385
|
start_time = time.time()
|
|
363
386
|
while self._timeout is None or (time.time() - start_time) < self._timeout:
|
|
364
387
|
task_response = await self._client._get_task(self.id) # pyright: ignore [reportPrivateUsage]
|
|
388
|
+
self._task_response = task_response
|
|
365
389
|
if task_response.status not in ["running", "waiting"]:
|
|
366
|
-
self._task_response = task_response
|
|
367
390
|
return task_response
|
|
368
391
|
await asyncio.sleep(self._poll_interval)
|
|
369
392
|
raise TimeoutError(f"Task {self.id} did not complete within {self._timeout} seconds.")
|
|
370
393
|
|
|
394
|
+
def live_url(self, interactive: bool = True, embed: bool = False) -> str:
|
|
395
|
+
"""Returns the live URL for the task."""
|
|
396
|
+
params = {
|
|
397
|
+
"interactive": interactive,
|
|
398
|
+
"embed": embed
|
|
399
|
+
}
|
|
400
|
+
return f"{self._live_url}?{urlencode(params)}"
|
|
401
|
+
|
|
402
|
+
async def recording_url(self) -> str:
|
|
403
|
+
"""Returns the recording URL for the task."""
|
|
404
|
+
if self._task_response and self._task_response.recording_url is not None:
|
|
405
|
+
return self._task_response.recording_url
|
|
406
|
+
|
|
407
|
+
start_time = time.time()
|
|
408
|
+
while (time.time() - start_time) < 8:
|
|
409
|
+
task_response = await self._client._get_task(self.id) # pyright: ignore [reportPrivateUsage]
|
|
410
|
+
self._task_response = task_response
|
|
411
|
+
if task_response.recording_url is not None:
|
|
412
|
+
return task_response.recording_url
|
|
413
|
+
await asyncio.sleep(1)
|
|
414
|
+
raise TimeoutError(f"Recording not available for task {self.id}.")
|
|
371
415
|
|
|
372
416
|
class SmoothAsyncClient(BaseClient):
|
|
373
417
|
"""An asynchronous client for the API."""
|
|
@@ -411,8 +455,6 @@ class SmoothAsyncClient(BaseClient):
|
|
|
411
455
|
async def run(
|
|
412
456
|
self,
|
|
413
457
|
task: str,
|
|
414
|
-
poll_interval: int = 1,
|
|
415
|
-
timeout: int = 60 * 15,
|
|
416
458
|
agent: Literal["smooth"] = "smooth",
|
|
417
459
|
max_steps: int = 32,
|
|
418
460
|
device: Literal["desktop", "mobile"] = "mobile",
|
|
@@ -422,6 +464,8 @@ class SmoothAsyncClient(BaseClient):
|
|
|
422
464
|
proxy_server: str | None = None,
|
|
423
465
|
proxy_username: str | None = None,
|
|
424
466
|
proxy_password: str | None = None,
|
|
467
|
+
poll_interval: int = 1,
|
|
468
|
+
timeout: int = 60 * 15,
|
|
425
469
|
) -> AsyncTaskHandle:
|
|
426
470
|
"""Runs a task and returns a handle to the task asynchronously.
|
|
427
471
|
|
|
@@ -430,8 +474,6 @@ class SmoothAsyncClient(BaseClient):
|
|
|
430
474
|
|
|
431
475
|
Args:
|
|
432
476
|
task: The task to run.
|
|
433
|
-
poll_interval: The time in seconds to wait between polling for status.
|
|
434
|
-
timeout: The maximum time in seconds to wait for the task to complete.
|
|
435
477
|
agent: The agent to use for the task.
|
|
436
478
|
max_steps: Maximum number of steps the agent can take (max 64).
|
|
437
479
|
device: Device type for the task. Default is mobile.
|
|
@@ -441,6 +483,8 @@ class SmoothAsyncClient(BaseClient):
|
|
|
441
483
|
proxy_server: Proxy server url to route browser traffic through.
|
|
442
484
|
proxy_username: Proxy server username.
|
|
443
485
|
proxy_password: Proxy server password.
|
|
486
|
+
poll_interval: The time in seconds to wait between polling for status.
|
|
487
|
+
timeout: The maximum time in seconds to wait for the task to complete.
|
|
444
488
|
|
|
445
489
|
Returns:
|
|
446
490
|
A handle to the running task.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
smooth/__init__.py,sha256=dmofDTp_gE9sHBG3ZrCgApWQKtJn7a4MTOWuzxG6f_A,21078
|
|
2
|
+
smooth_py-0.1.3.dist-info/METADATA,sha256=DiTe2Cg4TNmJGCGX_qHOhrKYzwHzvKWIxYIq3Yrqi9w,5388
|
|
3
|
+
smooth_py-0.1.3.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
4
|
+
smooth_py-0.1.3.dist-info/RECORD,,
|
smooth_py-0.1.2.dist-info/RECORD
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
smooth/__init__.py,sha256=23X7aQVAVzYcwh2KCZ8RfWL1rPzpE6W8IWWwVSDPzIo,19324
|
|
2
|
-
smooth_py-0.1.2.dist-info/METADATA,sha256=x-k813clxo_ET7pl-MBv4CJojFxYRSIBwoWokN091ak,5388
|
|
3
|
-
smooth_py-0.1.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
4
|
-
smooth_py-0.1.2.dist-info/RECORD,,
|
|
File without changes
|