simplex 1.2.2__py3-none-any.whl → 1.2.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 simplex might be problematic. Click here for more details.
- simplex/constants.py +1 -0
- simplex/simplex.py +92 -25
- {simplex-1.2.2.dist-info → simplex-1.2.3.dist-info}/METADATA +12 -3
- simplex-1.2.3.dist-info/RECORD +10 -0
- {simplex-1.2.2.dist-info → simplex-1.2.3.dist-info}/WHEEL +1 -1
- simplex-1.2.2.dist-info/RECORD +0 -9
- {simplex-1.2.2.dist-info → simplex-1.2.3.dist-info}/LICENSE +0 -0
- {simplex-1.2.2.dist-info → simplex-1.2.3.dist-info}/entry_points.txt +0 -0
- {simplex-1.2.2.dist-info → simplex-1.2.3.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,6 @@ class Simplex:
|
|
|
67
67
|
|
|
68
68
|
|
|
69
69
|
# Print the results
|
|
70
|
-
print(f"Status Code: {response.status_code}")
|
|
71
70
|
if response.status_code == 200:
|
|
72
71
|
res = response.json()
|
|
73
72
|
bbox = [int(res['x1']), int(res['y1']), int(res['x2']), int(res['y2'])]
|
|
@@ -87,7 +86,7 @@ class Simplex:
|
|
|
87
86
|
const overlay = document.createElement('div');
|
|
88
87
|
overlay.id = 'simplex-bbox-overlay';
|
|
89
88
|
overlay.style.position = 'fixed';
|
|
90
|
-
overlay.style.border = '2px dashed rgba(
|
|
89
|
+
overlay.style.border = '2px dashed rgba(0, 255, 0, 1)';
|
|
91
90
|
overlay.style.background = 'rgba(74, 144, 226, 0.1)';
|
|
92
91
|
overlay.style.animation = 'marching-ants 0.5s linear infinite';
|
|
93
92
|
overlay.style.left = bbox[0] + 'px';
|
|
@@ -122,10 +121,9 @@ class Simplex:
|
|
|
122
121
|
}
|
|
123
122
|
""", bbox)
|
|
124
123
|
self.driver.wait_for_selector('#simplex-bbox-overlay')
|
|
125
|
-
print(f"Found element \"{element_description}\" at pixel coordinates {bbox}.")
|
|
126
124
|
return bbox
|
|
127
125
|
else:
|
|
128
|
-
print("Error:", response.text)
|
|
126
|
+
print("[SIMPLEX] Error:", response.text)
|
|
129
127
|
|
|
130
128
|
def step_to_action(self, step_description: str, state: Image.Image | None = None) -> List[List[str]]:
|
|
131
129
|
"""
|
|
@@ -169,7 +167,7 @@ class Simplex:
|
|
|
169
167
|
actions = [[action.strip() for action in action_pair] for action_pair in actions]
|
|
170
168
|
return actions
|
|
171
169
|
else:
|
|
172
|
-
print(f"Error: {response.status_code}")
|
|
170
|
+
print(f"[SIMPLEX] Error: {response.status_code}")
|
|
173
171
|
print(response.text)
|
|
174
172
|
return []
|
|
175
173
|
|
|
@@ -184,9 +182,39 @@ class Simplex:
|
|
|
184
182
|
if new_tab:
|
|
185
183
|
self.driver = self.browser.new_page()
|
|
186
184
|
self.driver.wait_for_load_state()
|
|
187
|
-
print(f"Navigating to URL {url}...")
|
|
185
|
+
print(f"[SIMPLEX] Navigating to URL {url}...")
|
|
188
186
|
self.driver.goto(url)
|
|
189
187
|
|
|
188
|
+
def click(self, element_description: str, annotate: bool = True) -> None:
|
|
189
|
+
"""
|
|
190
|
+
Click on an element
|
|
191
|
+
"""
|
|
192
|
+
self.execute_action(["CLICK", element_description], annotate=annotate)
|
|
193
|
+
|
|
194
|
+
def type(self, text: str) -> None:
|
|
195
|
+
"""
|
|
196
|
+
Type text into an element
|
|
197
|
+
"""
|
|
198
|
+
self.execute_action(["TYPE", text])
|
|
199
|
+
|
|
200
|
+
def press_enter(self, annotate: bool = True) -> None:
|
|
201
|
+
"""
|
|
202
|
+
Press enter
|
|
203
|
+
"""
|
|
204
|
+
self.execute_action(["ENTER", ""], annotate=annotate)
|
|
205
|
+
|
|
206
|
+
def scroll(self, scroll_amount: int, annotate: bool = True) -> None:
|
|
207
|
+
"""
|
|
208
|
+
Scroll the page
|
|
209
|
+
"""
|
|
210
|
+
self.execute_action(["SCROLL", scroll_amount], annotate=annotate)
|
|
211
|
+
|
|
212
|
+
def wait(self, wait_time: int, annotate: bool = True) -> None:
|
|
213
|
+
"""
|
|
214
|
+
Wait for a given amount of time
|
|
215
|
+
"""
|
|
216
|
+
self.execute_action(["WAIT", wait_time], annotate=annotate)
|
|
217
|
+
|
|
190
218
|
def execute_action(self, action: List[List[str]], state: Image.Image | None = None, annotate: bool = True) -> None:
|
|
191
219
|
"""
|
|
192
220
|
Execute an action with playwright driver
|
|
@@ -194,35 +222,31 @@ class Simplex:
|
|
|
194
222
|
Args:
|
|
195
223
|
action (List[List[str]]): List of actions to perform
|
|
196
224
|
"""
|
|
197
|
-
print(f"Executing action {action}...")
|
|
198
225
|
action_type, description = action
|
|
199
226
|
try:
|
|
200
227
|
if action_type == "CLICK":
|
|
201
|
-
bbox = self.
|
|
228
|
+
bbox = self.extract_bbox(description, state, annotate=annotate)
|
|
202
229
|
center_x, center_y = center_bbox(bbox)
|
|
203
230
|
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
|
-
|
|
231
|
+
print(f"[SIMPLEX] Clicked on element \"{description}\"")
|
|
210
232
|
elif action_type == "TYPE":
|
|
211
|
-
print(f"Typing \"{description}\"...")
|
|
212
233
|
self.driver.keyboard.type(description)
|
|
234
|
+
print(f"[SIMPLEX] Typed \"{description}\"")
|
|
213
235
|
|
|
214
236
|
elif action_type == "ENTER":
|
|
215
237
|
self.driver.keyboard.press("Enter")
|
|
238
|
+
print(f"[SIMPLEX] Pressed enter")
|
|
216
239
|
|
|
217
240
|
elif action_type == "SCROLL":
|
|
218
241
|
self.driver.mouse.wheel(0, int(description))
|
|
242
|
+
print(f"[SIMPLEX] Scrolled {description} pixels")
|
|
219
243
|
|
|
220
244
|
elif action_type == "WAIT":
|
|
221
245
|
self.driver.wait_for_timeout(int(description))
|
|
222
|
-
|
|
246
|
+
print(f"[SIMPLEX] Waited {description} seconds")
|
|
223
247
|
|
|
224
248
|
except Exception as e:
|
|
225
|
-
print(f"Error executing action: {e}")
|
|
249
|
+
print(f"[SIMPLEX] Error executing action: {e}")
|
|
226
250
|
return None
|
|
227
251
|
|
|
228
252
|
def do(self, step_description: str, annotate: bool = True) -> None:
|
|
@@ -234,13 +258,56 @@ class Simplex:
|
|
|
234
258
|
for action in actions:
|
|
235
259
|
self.execute_action(action, annotate=annotate)
|
|
236
260
|
|
|
237
|
-
def
|
|
261
|
+
def extract_text(self, element_description: str, state: Image.Image | None = None) -> List[str] | None:
|
|
238
262
|
"""
|
|
239
|
-
Extract an element from the page
|
|
263
|
+
Extract an element text from the page
|
|
240
264
|
"""
|
|
241
|
-
|
|
265
|
+
print(f"[SIMPLEX] Finding element \"{element_description}\"...")
|
|
266
|
+
if state is None:
|
|
267
|
+
state = self.take_stable_screenshot()
|
|
268
|
+
|
|
269
|
+
endpoint = f"{BASE_URL}/extract-text"
|
|
270
|
+
|
|
271
|
+
# Convert PIL Image to bytes
|
|
272
|
+
img_byte_arr = io.BytesIO()
|
|
273
|
+
state.save(img_byte_arr, format='PNG')
|
|
274
|
+
img_byte_arr = img_byte_arr.getvalue()
|
|
275
|
+
|
|
276
|
+
# Prepare multipart form data
|
|
277
|
+
files = {
|
|
278
|
+
'image_data': ('screenshot.png', img_byte_arr, 'image/png'),
|
|
279
|
+
'element_description': (None, element_description),
|
|
280
|
+
'api_key': (None, self.api_key)
|
|
281
|
+
}
|
|
282
|
+
print("[SIMPLEX] Sending screenshot to server...")
|
|
283
|
+
|
|
284
|
+
# Make the request
|
|
285
|
+
response = requests.post(
|
|
286
|
+
endpoint,
|
|
287
|
+
files=files
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
# Print the results
|
|
291
|
+
if response.status_code == 200:
|
|
292
|
+
res = response.json()
|
|
293
|
+
text = res['text']
|
|
294
|
+
return text
|
|
295
|
+
else:
|
|
296
|
+
print("[SIMPLEX] Error:", response.text)
|
|
297
|
+
return None
|
|
298
|
+
|
|
299
|
+
def extract_image(self, element_description: str, state: Image.Image | None = None) -> Image.Image | None:
|
|
300
|
+
"""
|
|
301
|
+
Extract an element image from the page
|
|
302
|
+
"""
|
|
303
|
+
if state is None:
|
|
304
|
+
state = self.take_stable_screenshot()
|
|
305
|
+
|
|
306
|
+
bbox = self.extract_bbox(element_description, state)
|
|
307
|
+
cropped_state = state.crop((bbox[0], bbox[1], bbox[2], bbox[3]))
|
|
308
|
+
return cropped_state
|
|
309
|
+
|
|
242
310
|
|
|
243
|
-
# self.execute_action(action, annotate=annotate)
|
|
244
311
|
|
|
245
312
|
def take_stable_screenshot(self) -> Image.Image:
|
|
246
313
|
"""
|
|
@@ -249,7 +316,7 @@ class Simplex:
|
|
|
249
316
|
Returns:
|
|
250
317
|
PIL.Image.Image: Screenshot of the current page
|
|
251
318
|
"""
|
|
252
|
-
print("Taking screenshot of the page...")
|
|
319
|
+
print("[SIMPLEX] Taking screenshot of the page...")
|
|
253
320
|
self.driver.wait_for_load_state('networkidle')
|
|
254
321
|
return screenshot_to_image(self.driver.screenshot())
|
|
255
322
|
|
|
@@ -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.3
|
|
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=c1kWt8KvOIu-vhVmQga1BH-sRNFHvmWBrfP9t-93iBE,12101
|
|
4
|
+
simplex/utils.py,sha256=UrD4Ena3yk0POmxxyiqMszzPbTscTCJpMP4xZFDAuOc,339
|
|
5
|
+
simplex-1.2.3.dist-info/LICENSE,sha256=Xh0SJjYZfNI71pCNMB40aKlBLLuOB0blx5xkTtufFNQ,1075
|
|
6
|
+
simplex-1.2.3.dist-info/METADATA,sha256=HM_H6qRoBXMEtKsO6Ish0NU5V62a7JnugRZmSvGYNMs,1114
|
|
7
|
+
simplex-1.2.3.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
8
|
+
simplex-1.2.3.dist-info/entry_points.txt,sha256=3veL2w3c5vxb3dm8I_M8Fs-370n1ZnvD8uu1nSsL7z8,45
|
|
9
|
+
simplex-1.2.3.dist-info/top_level.txt,sha256=cbMH1bYpN0A3gP-ecibPRHasHoqB-01T_2BUFS8p0CE,8
|
|
10
|
+
simplex-1.2.3.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
|