simplex 1.2.0__tar.gz → 1.2.2__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 simplex might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.1
2
2
  Name: simplex
3
- Version: 1.2.0
3
+ Version: 1.2.2
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.
@@ -21,15 +21,6 @@ Requires-Dist: rich>=13.0.0
21
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
33
24
 
34
25
  # Simplex AI Python SDK
35
26
 
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="simplex",
5
- version="1.2.0",
5
+ version="1.2.2",
6
6
  packages=find_packages(),
7
7
  install_requires=[
8
8
  "openai>=1.0.0",
@@ -3,7 +3,6 @@ from PIL import Image
3
3
  import requests
4
4
  from typing import List
5
5
  import io
6
- import time
7
6
 
8
7
  from .utils import center_bbox, screenshot_to_image
9
8
 
@@ -24,10 +23,12 @@ class Simplex:
24
23
  if browser is None:
25
24
  self.playwright = sync_playwright().start()
26
25
  self.browser = self.playwright.chromium.launch(headless=True)
26
+ self.driver = self.browser.new_page()
27
27
  else:
28
28
  self.playwright = None
29
-
30
- self.driver = self.browser.new_page(viewport={"width": 1280, "height": 720})
29
+ self.driver = self.browser.contexts[0].pages[0]
30
+ self.driver.set_default_navigation_timeout(0)
31
+ self.driver.set_default_timeout(0)
31
32
 
32
33
  def find_element(self, element_description: str, state: Image.Image | None = None, annotate: bool = True) -> List[int]:
33
34
  """
@@ -40,6 +41,7 @@ class Simplex:
40
41
  Returns:
41
42
  bounding_box (tuple): [x1, y1, x2, y2] bounding box of the found element
42
43
  """
44
+ print(f"Finding element \"{element_description}\"...")
43
45
  if state is None:
44
46
  state = self.take_stable_screenshot()
45
47
 
@@ -56,6 +58,7 @@ class Simplex:
56
58
  'element_description': (None, element_description),
57
59
  'api_key': (None, self.api_key)
58
60
  }
61
+ print("Sending screenshot to server...")
59
62
  # Make the request
60
63
  response = requests.post(
61
64
  endpoint,
@@ -83,20 +86,43 @@ class Simplex:
83
86
  // Create new overlay
84
87
  const overlay = document.createElement('div');
85
88
  overlay.id = 'simplex-bbox-overlay';
86
- overlay.style.position = 'absolute';
87
- overlay.style.border = '2px solid red';
89
+ overlay.style.position = 'fixed';
90
+ overlay.style.border = '2px dashed rgba(74, 144, 226, 1)';
91
+ overlay.style.background = 'rgba(74, 144, 226, 0.1)';
92
+ overlay.style.animation = 'marching-ants 0.5s linear infinite';
88
93
  overlay.style.left = bbox[0] + 'px';
89
94
  overlay.style.top = bbox[1] + 'px';
90
95
  overlay.style.width = (bbox[2] - bbox[0]) + 'px';
91
96
  overlay.style.height = (bbox[3] - bbox[1]) + 'px';
92
97
  overlay.style.pointerEvents = 'none';
93
98
  overlay.style.zIndex = '10000';
99
+ overlay.style.margin = '0';
100
+ overlay.style.padding = '0';
101
+
102
+ // Add marching ants animation keyframes
103
+ if (!document.querySelector('#marching-ants-keyframes')) {
104
+ const style = document.createElement('style');
105
+ style.id = 'marching-ants-keyframes';
106
+ style.textContent = `
107
+ @keyframes marching-ants {
108
+ 0% { border-style: dashed; }
109
+ 50% { border-style: solid; }
110
+ 100% { border-style: dashed; }
111
+ }
112
+ `;
113
+ document.head.appendChild(style);
114
+ }
94
115
 
95
116
  document.body.appendChild(overlay);
117
+
118
+ // Remove overlay after 3 second
119
+ setTimeout(() => {
120
+ overlay.remove();
121
+ }, 2000);
96
122
  }
97
123
  """, bbox)
98
124
  self.driver.wait_for_selector('#simplex-bbox-overlay')
99
- time.sleep(5)
125
+ print(f"Found element \"{element_description}\" at pixel coordinates {bbox}.")
100
126
  return bbox
101
127
  else:
102
128
  print("Error:", response.text)
@@ -147,10 +173,18 @@ class Simplex:
147
173
  print(response.text)
148
174
  return []
149
175
 
150
- def goto(self, url: str) -> None:
176
+ def goto(self, url: str, new_tab: bool = False) -> None:
151
177
  """
152
178
  Navigate to a URL
179
+
180
+ Args:
181
+ url (str): URL to navigate to
182
+ new_tab (bool): Whether to open a new tab or use the current tab
153
183
  """
184
+ if new_tab:
185
+ self.driver = self.browser.new_page()
186
+ self.driver.wait_for_load_state()
187
+ print(f"Navigating to URL {url}...")
154
188
  self.driver.goto(url)
155
189
 
156
190
  def execute_action(self, action: List[List[str]], state: Image.Image | None = None, annotate: bool = True) -> None:
@@ -160,10 +194,8 @@ class Simplex:
160
194
  Args:
161
195
  action (List[List[str]]): List of actions to perform
162
196
  """
197
+ print(f"Executing action {action}...")
163
198
  action_type, description = action
164
- if state is None:
165
- state = self.take_stable_screenshot()
166
-
167
199
  try:
168
200
  if action_type == "CLICK":
169
201
  bbox = self.find_element(description, state, annotate=annotate)
@@ -176,13 +208,18 @@ class Simplex:
176
208
  self.driver.mouse.move(center_x, center_y)
177
209
 
178
210
  elif action_type == "TYPE":
211
+ print(f"Typing \"{description}\"...")
179
212
  self.driver.keyboard.type(description)
180
213
 
214
+ elif action_type == "ENTER":
215
+ self.driver.keyboard.press("Enter")
216
+
181
217
  elif action_type == "SCROLL":
182
218
  self.driver.mouse.wheel(0, int(description))
183
219
 
184
220
  elif action_type == "WAIT":
185
221
  self.driver.wait_for_timeout(int(description))
222
+
186
223
 
187
224
  except Exception as e:
188
225
  print(f"Error executing action: {e}")
@@ -196,6 +233,14 @@ class Simplex:
196
233
  actions = self.step_to_action(step_description, state)
197
234
  for action in actions:
198
235
  self.execute_action(action, annotate=annotate)
236
+
237
+ def extract(self, step_description: str, annotate: bool = True) -> None:
238
+ """
239
+ Extract an element from the page
240
+ """
241
+ state = self.take_stable_screenshot()
242
+
243
+ # self.execute_action(action, annotate=annotate)
199
244
 
200
245
  def take_stable_screenshot(self) -> Image.Image:
201
246
  """
@@ -204,6 +249,7 @@ class Simplex:
204
249
  Returns:
205
250
  PIL.Image.Image: Screenshot of the current page
206
251
  """
252
+ print("Taking screenshot of the page...")
207
253
  self.driver.wait_for_load_state('networkidle')
208
254
  return screenshot_to_image(self.driver.screenshot())
209
255
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.1
2
2
  Name: simplex
3
- Version: 1.2.0
3
+ Version: 1.2.2
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.
@@ -21,15 +21,6 @@ Requires-Dist: rich>=13.0.0
21
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
33
24
 
34
25
  # Simplex AI Python SDK
35
26
 
@@ -3,7 +3,6 @@ README.md
3
3
  pyproject.toml
4
4
  setup.py
5
5
  simplex/__init__.py
6
- simplex/constants.py
7
6
  simplex/simplex.py
8
7
  simplex/utils.py
9
8
  simplex.egg-info/PKG-INFO
@@ -9,7 +9,9 @@ from playwright.sync_api import sync_playwright
9
9
  from PIL import Image
10
10
  import time
11
11
  import os
12
+ from browserbase import Browserbase
12
13
  from hyperbrowser import Hyperbrowser
14
+ from hyperbrowser.models.session import CreateSessionParams
13
15
 
14
16
  from dotenv import load_dotenv
15
17
 
@@ -35,15 +37,7 @@ def screenshot_tests():
35
37
  print(action)
36
38
 
37
39
 
38
- def execute_action_test():
39
- playwright = sync_playwright().start()
40
- browser = playwright.chromium.launch(headless=False)
41
- driver = browser.new_page()
42
-
43
- simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"), driver=driver)
44
- simplex.goto("https://www.netflix.com/")
45
- actions = [['CLICK', 'email field'], ['TYPE', 'email address']]
46
- simplex.execute_action(actions[0])
40
+
47
41
 
48
42
 
49
43
  def cgtrader_test():
@@ -51,8 +45,8 @@ def cgtrader_test():
51
45
  urls = []
52
46
 
53
47
  with sync_playwright() as p:
54
- driver = p.chromium.launch(headless=False).new_page()
55
- simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"), driver=driver)
48
+ browser = p.chromium.launch(headless=False)
49
+ simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"), browser=browser)
56
50
  simplex.goto("https://www.cgtrader.com/")
57
51
 
58
52
  for asset in assets:
@@ -60,7 +54,7 @@ def cgtrader_test():
60
54
  simplex.do(f"search for {asset}")
61
55
  simplex.do("click on search button")
62
56
  simplex.do(f"click on the first product")
63
- driver.wait_for_timeout(3000)
57
+ simplex.driver.wait_for_timeout(3000)
64
58
 
65
59
  urls.append(simplex.driver.url)
66
60
 
@@ -158,47 +152,95 @@ def test_find_element():
158
152
 
159
153
 
160
154
  def test_find_element_2():
161
- with sync_playwright() as p:
162
- driver = p.chromium.launch(headless=False).new_page(viewport={"width": 1920, "height": 1080})
163
- simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"), driver=driver)
164
- simplex.goto("https://www.cgtrader.com/")
165
-
166
- state = simplex.take_stable_screenshot()
167
- bbox = simplex.find_element("search bar")
168
-
169
- print(bbox)
170
155
 
156
+ simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"))
157
+ simplex.goto("https://www.cgtrader.com/")
158
+ simplex.find_element("search bar")
159
+ import requests
171
160
  def test_hyperbrowser_integration():
172
161
  """Test Simplex integration with Hyperbrowser"""
162
+ import time
163
+ start_time = time.time()
164
+
165
+ bb = Browserbase(api_key=os.getenv("BROWSERBASE_API_KEY"))
166
+ session_start = time.time()
167
+ session = bb.sessions.create(project_id=os.getenv("BROWSERBASE_PROJECT_ID"))
168
+ print(session.id)
169
+ print(f"Session creation took {time.time() - session_start:.2f}s")
173
170
 
174
171
  # Initialize Hyperbrowser client
175
- client = Hyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))
172
+ # client = Hyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))
176
173
 
177
- # Create a new session
178
- session = client.sessions.create()
179
- ws_endpoint = session.ws_endpoint
174
+ # Create session params with CAPTCHA solving enabled
175
+ session_params = CreateSessionParams(
176
+ solve_captchas=True,
177
+ use_stealth=True # Recommended when solving CAPTCHAs
178
+ )
179
+
180
+ # Create a new session with params
181
+ # session = client.sessions.create(session_params)
182
+ ws_endpoint = session.connect_url
180
183
 
181
184
  try:
182
185
  with sync_playwright() as p:
183
186
  # Connect browser to Hyperbrowser session
187
+ browser_start = time.time()
184
188
  browser = p.chromium.connect_over_cdp(ws_endpoint)
185
- context = browser.new_context()
186
- page = context.new_page()
187
-
189
+ print(f"Browser connection took {time.time() - browser_start:.2f}s")
190
+ url = f"https://api.browserbase.com/v1/sessions/{session.id}/debug"
191
+ headers = {"X-BB-API-Key": os.getenv("BROWSERBASE_API_KEY")}
192
+ response = requests.get(url, headers=headers)
193
+ print(response.text)
194
+ print(response.json()["pages"][0]["debuggerUrl"])
195
+
188
196
  # Initialize Simplex with the Hyperbrowser-connected page
189
197
  simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"), browser=browser)
190
198
 
191
199
  # Test basic functionality
192
- simplex.goto("https://www.cgtrader.com/")
193
- simplex.do("search for iphone")
200
+ nav_start = time.time()
201
+ simplex.goto("https://www.turbosquid.com/")
202
+ print(f"Navigation took {time.time() - nav_start:.2f}s")
203
+
204
+ # search_start = time.time()
205
+ # simplex.do("search for iphone")
206
+ # print(f"Search action took {time.time() - search_start:.2f}s")
194
207
 
195
208
  # Verify the search worked by finding the search results
196
- bbox = simplex.find_element("search results")
209
+ find_start = time.time()
210
+ bbox = simplex.find_element("search results", annotate=True)
211
+ print(f"Finding results took {time.time() - find_start:.2f}s")
197
212
  assert bbox is not None, "Search results not found"
198
213
 
199
214
  finally:
200
215
  # Always stop the Hyperbrowser session
201
- client.sessions.stop(session.id)
216
+ # client.sessions.stop(session.id)
217
+ browser.close()
218
+ print(f"Total test time: {time.time() - start_time:.2f}s")
219
+
220
+
221
+
222
+ def execute_action_test():
223
+ playwright = sync_playwright().start()
224
+ browser = playwright.chromium.launch(headless=False)
225
+ simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"), browser=browser)
226
+ simplex.goto("https://www.mit.edu/")
227
+ simplex.find_element('search bar')
228
+
229
+ time.sleep(3)
230
+
231
+ # Save HTML content
232
+ html_content = simplex.driver.content()
233
+ with open('page.html', 'w', encoding='utf-8') as f:
234
+ f.write(html_content)
235
+
236
+ # Keep browser open until user interrupts with Ctrl+C
237
+ try:
238
+ print("Browser is kept open. Press Ctrl+C to exit...")
239
+ while True:
240
+ time.sleep(1)
241
+ except KeyboardInterrupt:
242
+ browser.close()
243
+ playwright.stop()
202
244
 
203
245
  if __name__ == "__main__":
204
246
  test_hyperbrowser_integration()
@@ -1 +0,0 @@
1
- BASE_URL = "https://u3mvtbirxf.us-east-1.awsapprunner.com"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes