simplex 1.2.2__py3-none-any.whl → 1.2.4__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 simplex might be problematic. Click here for more details.
- simplex/constants.py +1 -0
- simplex/simplex.py +93 -25
- {simplex-1.2.2.dist-info → simplex-1.2.4.dist-info}/METADATA +12 -3
- simplex-1.2.4.dist-info/RECORD +10 -0
- {simplex-1.2.2.dist-info → simplex-1.2.4.dist-info}/WHEEL +1 -1
- simplex-1.2.2.dist-info/RECORD +0 -9
- {simplex-1.2.2.dist-info → simplex-1.2.4.dist-info}/LICENSE +0 -0
- {simplex-1.2.2.dist-info → simplex-1.2.4.dist-info}/entry_points.txt +0 -0
- {simplex-1.2.2.dist-info → simplex-1.2.4.dist-info}/top_level.txt +0 -0
simplex/constants.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
BASE_URL = "https://u3mvtbirxf.us-east-1.awsapprunner.com"
|
simplex/simplex.py
CHANGED
|
@@ -30,7 +30,7 @@ class Simplex:
|
|
|
30
30
|
self.driver.set_default_navigation_timeout(0)
|
|
31
31
|
self.driver.set_default_timeout(0)
|
|
32
32
|
|
|
33
|
-
def
|
|
33
|
+
def extract_bbox(self, element_description: str, state: Image.Image | None = None, annotate: bool = True) -> List[int]:
|
|
34
34
|
"""
|
|
35
35
|
Find an element in the screenshot using the element description
|
|
36
36
|
|
|
@@ -41,7 +41,7 @@ class Simplex:
|
|
|
41
41
|
Returns:
|
|
42
42
|
bounding_box (tuple): [x1, y1, x2, y2] bounding box of the found element
|
|
43
43
|
"""
|
|
44
|
-
print(f"Finding element \"{element_description}\"...")
|
|
44
|
+
print(f"[SIMPLEX] Finding element \"{element_description}\"...")
|
|
45
45
|
if state is None:
|
|
46
46
|
state = self.take_stable_screenshot()
|
|
47
47
|
|
|
@@ -58,7 +58,7 @@ class Simplex:
|
|
|
58
58
|
'element_description': (None, element_description),
|
|
59
59
|
'api_key': (None, self.api_key)
|
|
60
60
|
}
|
|
61
|
-
print("Sending screenshot to server...")
|
|
61
|
+
print("[SIMPLEX] Sending screenshot to server...")
|
|
62
62
|
# Make the request
|
|
63
63
|
response = requests.post(
|
|
64
64
|
endpoint,
|
|
@@ -67,7 +67,7 @@ class Simplex:
|
|
|
67
67
|
|
|
68
68
|
|
|
69
69
|
# Print the results
|
|
70
|
-
print(
|
|
70
|
+
print(response.status_code)
|
|
71
71
|
if response.status_code == 200:
|
|
72
72
|
res = response.json()
|
|
73
73
|
bbox = [int(res['x1']), int(res['y1']), int(res['x2']), int(res['y2'])]
|
|
@@ -87,7 +87,7 @@ class Simplex:
|
|
|
87
87
|
const overlay = document.createElement('div');
|
|
88
88
|
overlay.id = 'simplex-bbox-overlay';
|
|
89
89
|
overlay.style.position = 'fixed';
|
|
90
|
-
overlay.style.border = '2px dashed rgba(
|
|
90
|
+
overlay.style.border = '2px dashed rgba(0, 255, 0, 1)';
|
|
91
91
|
overlay.style.background = 'rgba(74, 144, 226, 0.1)';
|
|
92
92
|
overlay.style.animation = 'marching-ants 0.5s linear infinite';
|
|
93
93
|
overlay.style.left = bbox[0] + 'px';
|
|
@@ -122,10 +122,9 @@ class Simplex:
|
|
|
122
122
|
}
|
|
123
123
|
""", bbox)
|
|
124
124
|
self.driver.wait_for_selector('#simplex-bbox-overlay')
|
|
125
|
-
print(f"Found element \"{element_description}\" at pixel coordinates {bbox}.")
|
|
126
125
|
return bbox
|
|
127
126
|
else:
|
|
128
|
-
print("Error:", response.text)
|
|
127
|
+
print("[SIMPLEX] Error:", response.text)
|
|
129
128
|
|
|
130
129
|
def step_to_action(self, step_description: str, state: Image.Image | None = None) -> List[List[str]]:
|
|
131
130
|
"""
|
|
@@ -169,7 +168,7 @@ class Simplex:
|
|
|
169
168
|
actions = [[action.strip() for action in action_pair] for action_pair in actions]
|
|
170
169
|
return actions
|
|
171
170
|
else:
|
|
172
|
-
print(f"Error: {response.status_code}")
|
|
171
|
+
print(f"[SIMPLEX] Error: {response.status_code}")
|
|
173
172
|
print(response.text)
|
|
174
173
|
return []
|
|
175
174
|
|
|
@@ -184,9 +183,39 @@ class Simplex:
|
|
|
184
183
|
if new_tab:
|
|
185
184
|
self.driver = self.browser.new_page()
|
|
186
185
|
self.driver.wait_for_load_state()
|
|
187
|
-
print(f"Navigating to URL {url}...")
|
|
186
|
+
print(f"[SIMPLEX] Navigating to URL {url}...")
|
|
188
187
|
self.driver.goto(url)
|
|
189
188
|
|
|
189
|
+
def click(self, element_description: str, annotate: bool = True) -> None:
|
|
190
|
+
"""
|
|
191
|
+
Click on an element
|
|
192
|
+
"""
|
|
193
|
+
self.execute_action(["CLICK", element_description], annotate=annotate)
|
|
194
|
+
|
|
195
|
+
def type(self, text: str) -> None:
|
|
196
|
+
"""
|
|
197
|
+
Type text into an element
|
|
198
|
+
"""
|
|
199
|
+
self.execute_action(["TYPE", text])
|
|
200
|
+
|
|
201
|
+
def press_enter(self, annotate: bool = True) -> None:
|
|
202
|
+
"""
|
|
203
|
+
Press enter
|
|
204
|
+
"""
|
|
205
|
+
self.execute_action(["ENTER", ""], annotate=annotate)
|
|
206
|
+
|
|
207
|
+
def scroll(self, scroll_amount: int, annotate: bool = True) -> None:
|
|
208
|
+
"""
|
|
209
|
+
Scroll the page
|
|
210
|
+
"""
|
|
211
|
+
self.execute_action(["SCROLL", scroll_amount], annotate=annotate)
|
|
212
|
+
|
|
213
|
+
def wait(self, wait_time: int, annotate: bool = True) -> None:
|
|
214
|
+
"""
|
|
215
|
+
Wait for a given amount of time
|
|
216
|
+
"""
|
|
217
|
+
self.execute_action(["WAIT", wait_time], annotate=annotate)
|
|
218
|
+
|
|
190
219
|
def execute_action(self, action: List[List[str]], state: Image.Image | None = None, annotate: bool = True) -> None:
|
|
191
220
|
"""
|
|
192
221
|
Execute an action with playwright driver
|
|
@@ -194,35 +223,31 @@ class Simplex:
|
|
|
194
223
|
Args:
|
|
195
224
|
action (List[List[str]]): List of actions to perform
|
|
196
225
|
"""
|
|
197
|
-
print(f"Executing action {action}...")
|
|
198
226
|
action_type, description = action
|
|
199
227
|
try:
|
|
200
228
|
if action_type == "CLICK":
|
|
201
|
-
bbox = self.
|
|
229
|
+
bbox = self.extract_bbox(description, state, annotate=annotate)
|
|
202
230
|
center_x, center_y = center_bbox(bbox)
|
|
203
231
|
self.driver.mouse.click(center_x, center_y)
|
|
204
|
-
|
|
205
|
-
elif action_type == "HOVER":
|
|
206
|
-
bbox = self.find_element(description, state, annotate=annotate)
|
|
207
|
-
center_x, center_y = center_bbox(bbox)
|
|
208
|
-
self.driver.mouse.move(center_x, center_y)
|
|
209
|
-
|
|
232
|
+
print(f"[SIMPLEX] Clicked on element \"{description}\"")
|
|
210
233
|
elif action_type == "TYPE":
|
|
211
|
-
print(f"Typing \"{description}\"...")
|
|
212
234
|
self.driver.keyboard.type(description)
|
|
235
|
+
print(f"[SIMPLEX] Typed \"{description}\"")
|
|
213
236
|
|
|
214
237
|
elif action_type == "ENTER":
|
|
215
238
|
self.driver.keyboard.press("Enter")
|
|
239
|
+
print(f"[SIMPLEX] Pressed enter")
|
|
216
240
|
|
|
217
241
|
elif action_type == "SCROLL":
|
|
218
242
|
self.driver.mouse.wheel(0, int(description))
|
|
243
|
+
print(f"[SIMPLEX] Scrolled {description} pixels")
|
|
219
244
|
|
|
220
245
|
elif action_type == "WAIT":
|
|
221
246
|
self.driver.wait_for_timeout(int(description))
|
|
222
|
-
|
|
247
|
+
print(f"[SIMPLEX] Waited {description} seconds")
|
|
223
248
|
|
|
224
249
|
except Exception as e:
|
|
225
|
-
print(f"Error executing action: {e}")
|
|
250
|
+
print(f"[SIMPLEX] Error executing action: {e}")
|
|
226
251
|
return None
|
|
227
252
|
|
|
228
253
|
def do(self, step_description: str, annotate: bool = True) -> None:
|
|
@@ -234,13 +259,56 @@ class Simplex:
|
|
|
234
259
|
for action in actions:
|
|
235
260
|
self.execute_action(action, annotate=annotate)
|
|
236
261
|
|
|
237
|
-
def
|
|
262
|
+
def extract_text(self, element_description: str, state: Image.Image | None = None) -> List[str] | None:
|
|
238
263
|
"""
|
|
239
|
-
Extract an element from the page
|
|
264
|
+
Extract an element text from the page
|
|
240
265
|
"""
|
|
241
|
-
|
|
266
|
+
print(f"[SIMPLEX] Finding element \"{element_description}\"...")
|
|
267
|
+
if state is None:
|
|
268
|
+
state = self.take_stable_screenshot()
|
|
269
|
+
|
|
270
|
+
endpoint = f"{BASE_URL}/extract-text"
|
|
271
|
+
|
|
272
|
+
# Convert PIL Image to bytes
|
|
273
|
+
img_byte_arr = io.BytesIO()
|
|
274
|
+
state.save(img_byte_arr, format='PNG')
|
|
275
|
+
img_byte_arr = img_byte_arr.getvalue()
|
|
276
|
+
|
|
277
|
+
# Prepare multipart form data
|
|
278
|
+
files = {
|
|
279
|
+
'image_data': ('screenshot.png', img_byte_arr, 'image/png'),
|
|
280
|
+
'element_description': (None, element_description),
|
|
281
|
+
'api_key': (None, self.api_key)
|
|
282
|
+
}
|
|
283
|
+
print("[SIMPLEX] Sending screenshot to server...")
|
|
284
|
+
|
|
285
|
+
# Make the request
|
|
286
|
+
response = requests.post(
|
|
287
|
+
endpoint,
|
|
288
|
+
files=files
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
# Print the results
|
|
292
|
+
if response.status_code == 200:
|
|
293
|
+
res = response.json()
|
|
294
|
+
text = res['text']
|
|
295
|
+
return text
|
|
296
|
+
else:
|
|
297
|
+
print("[SIMPLEX] Error:", response.text)
|
|
298
|
+
return None
|
|
299
|
+
|
|
300
|
+
def extract_image(self, element_description: str, state: Image.Image | None = None) -> Image.Image | None:
|
|
301
|
+
"""
|
|
302
|
+
Extract an element image from the page
|
|
303
|
+
"""
|
|
304
|
+
if state is None:
|
|
305
|
+
state = self.take_stable_screenshot()
|
|
306
|
+
|
|
307
|
+
bbox = self.extract_bbox(element_description, state)
|
|
308
|
+
cropped_state = state.crop((bbox[0], bbox[1], bbox[2], bbox[3]))
|
|
309
|
+
return cropped_state
|
|
310
|
+
|
|
242
311
|
|
|
243
|
-
# self.execute_action(action, annotate=annotate)
|
|
244
312
|
|
|
245
313
|
def take_stable_screenshot(self) -> Image.Image:
|
|
246
314
|
"""
|
|
@@ -249,7 +317,7 @@ class Simplex:
|
|
|
249
317
|
Returns:
|
|
250
318
|
PIL.Image.Image: Screenshot of the current page
|
|
251
319
|
"""
|
|
252
|
-
print("Taking screenshot of the page...")
|
|
320
|
+
print("[SIMPLEX] Taking screenshot of the page...")
|
|
253
321
|
self.driver.wait_for_load_state('networkidle')
|
|
254
322
|
return screenshot_to_image(self.driver.screenshot())
|
|
255
323
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: simplex
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.4
|
|
4
4
|
Summary: Official Python SDK for Simplex API
|
|
5
5
|
Home-page: https://github.com/shreyka/simplex-python
|
|
6
6
|
Author: Simplex Labs, Inc.
|
|
@@ -18,9 +18,18 @@ Requires-Dist: python-dotenv>=0.19.0
|
|
|
18
18
|
Requires-Dist: tiktoken>=0.5.0
|
|
19
19
|
Requires-Dist: click>=8.0.0
|
|
20
20
|
Requires-Dist: rich>=13.0.0
|
|
21
|
-
Requires-Dist:
|
|
21
|
+
Requires-Dist: prompt_toolkit>=3.0.0
|
|
22
22
|
Requires-Dist: playwright>=1.0.0
|
|
23
23
|
Requires-Dist: Pillow>=9.0.0
|
|
24
|
+
Dynamic: author
|
|
25
|
+
Dynamic: author-email
|
|
26
|
+
Dynamic: classifier
|
|
27
|
+
Dynamic: description
|
|
28
|
+
Dynamic: description-content-type
|
|
29
|
+
Dynamic: home-page
|
|
30
|
+
Dynamic: requires-dist
|
|
31
|
+
Dynamic: requires-python
|
|
32
|
+
Dynamic: summary
|
|
24
33
|
|
|
25
34
|
# Simplex AI Python SDK
|
|
26
35
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
simplex/__init__.py,sha256=1mbM4XUk0FNW161WOkM4ayC1s_QSsaBEls6PZ0iBScY,74
|
|
2
|
+
simplex/constants.py,sha256=nIXF2oVNNNknXweXAlmE-KBM9QjJtYw9osXVYjvloN0,59
|
|
3
|
+
simplex/simplex.py,sha256=m5vQxhVCyeU-h-cOVmpaAMoTATPJKdecfp1Fv51uaL0,12137
|
|
4
|
+
simplex/utils.py,sha256=UrD4Ena3yk0POmxxyiqMszzPbTscTCJpMP4xZFDAuOc,339
|
|
5
|
+
simplex-1.2.4.dist-info/LICENSE,sha256=Xh0SJjYZfNI71pCNMB40aKlBLLuOB0blx5xkTtufFNQ,1075
|
|
6
|
+
simplex-1.2.4.dist-info/METADATA,sha256=YyDn-TaMU_3JQO9ZWFbRA214_Lak1zKmA8beIHl0zPI,1114
|
|
7
|
+
simplex-1.2.4.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
8
|
+
simplex-1.2.4.dist-info/entry_points.txt,sha256=3veL2w3c5vxb3dm8I_M8Fs-370n1ZnvD8uu1nSsL7z8,45
|
|
9
|
+
simplex-1.2.4.dist-info/top_level.txt,sha256=cbMH1bYpN0A3gP-ecibPRHasHoqB-01T_2BUFS8p0CE,8
|
|
10
|
+
simplex-1.2.4.dist-info/RECORD,,
|
simplex-1.2.2.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
simplex/__init__.py,sha256=1mbM4XUk0FNW161WOkM4ayC1s_QSsaBEls6PZ0iBScY,74
|
|
2
|
-
simplex/simplex.py,sha256=___oQuVrlTYR3BJDxb0INKHQO74aSqeNZyCkj8NzdYQ,9856
|
|
3
|
-
simplex/utils.py,sha256=UrD4Ena3yk0POmxxyiqMszzPbTscTCJpMP4xZFDAuOc,339
|
|
4
|
-
simplex-1.2.2.dist-info/LICENSE,sha256=Xh0SJjYZfNI71pCNMB40aKlBLLuOB0blx5xkTtufFNQ,1075
|
|
5
|
-
simplex-1.2.2.dist-info/METADATA,sha256=cRRdYjOEPq-fkUDokBgx8Sas49liFjB6BLo4Ypv1dG0,917
|
|
6
|
-
simplex-1.2.2.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
7
|
-
simplex-1.2.2.dist-info/entry_points.txt,sha256=3veL2w3c5vxb3dm8I_M8Fs-370n1ZnvD8uu1nSsL7z8,45
|
|
8
|
-
simplex-1.2.2.dist-info/top_level.txt,sha256=cbMH1bYpN0A3gP-ecibPRHasHoqB-01T_2BUFS8p0CE,8
|
|
9
|
-
simplex-1.2.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|