simplex 1.2.1__tar.gz → 1.2.3__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
1
  Metadata-Version: 2.2
2
2
  Name: simplex
3
- Version: 1.2.1
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.
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="simplex",
5
- version="1.2.1",
5
+ version="1.2.3",
6
6
  packages=find_packages(),
7
7
  install_requires=[
8
8
  "openai>=1.0.0",
@@ -26,12 +26,11 @@ class Simplex:
26
26
  self.driver = self.browser.new_page()
27
27
  else:
28
28
  self.playwright = None
29
- if len(self.browser.contexts) > 0 and len(self.browser.contexts[0].pages) > 0:
30
- self.driver = self.browser.contexts[0].pages[0]
31
- else:
32
- self.driver = self.browser.new_page()
29
+ self.driver = self.browser.contexts[0].pages[0]
30
+ self.driver.set_default_navigation_timeout(0)
31
+ self.driver.set_default_timeout(0)
33
32
 
34
- def find_element(self, element_description: str, state: Image.Image | None = None, annotate: bool = True) -> List[int]:
33
+ def extract_bbox(self, element_description: str, state: Image.Image | None = None, annotate: bool = True) -> List[int]:
35
34
  """
36
35
  Find an element in the screenshot using the element description
37
36
 
@@ -42,6 +41,7 @@ class Simplex:
42
41
  Returns:
43
42
  bounding_box (tuple): [x1, y1, x2, y2] bounding box of the found element
44
43
  """
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
-
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(74, 144, 226, 1)';
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';
@@ -124,7 +123,7 @@ class Simplex:
124
123
  self.driver.wait_for_selector('#simplex-bbox-overlay')
125
124
  return bbox
126
125
  else:
127
- print("Error:", response.text)
126
+ print("[SIMPLEX] Error:", response.text)
128
127
 
129
128
  def step_to_action(self, step_description: str, state: Image.Image | None = None) -> List[List[str]]:
130
129
  """
@@ -168,7 +167,7 @@ class Simplex:
168
167
  actions = [[action.strip() for action in action_pair] for action_pair in actions]
169
168
  return actions
170
169
  else:
171
- print(f"Error: {response.status_code}")
170
+ print(f"[SIMPLEX] Error: {response.status_code}")
172
171
  print(response.text)
173
172
  return []
174
173
 
@@ -182,8 +181,40 @@ class Simplex:
182
181
  """
183
182
  if new_tab:
184
183
  self.driver = self.browser.new_page()
184
+ self.driver.wait_for_load_state()
185
+ print(f"[SIMPLEX] Navigating to URL {url}...")
185
186
  self.driver.goto(url)
186
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
+
187
218
  def execute_action(self, action: List[List[str]], state: Image.Image | None = None, annotate: bool = True) -> None:
188
219
  """
189
220
  Execute an action with playwright driver
@@ -192,34 +223,30 @@ class Simplex:
192
223
  action (List[List[str]]): List of actions to perform
193
224
  """
194
225
  action_type, description = action
195
- if state is None:
196
- state = self.take_stable_screenshot()
197
-
198
226
  try:
199
227
  if action_type == "CLICK":
200
- bbox = self.find_element(description, state, annotate=annotate)
228
+ bbox = self.extract_bbox(description, state, annotate=annotate)
201
229
  center_x, center_y = center_bbox(bbox)
202
230
  self.driver.mouse.click(center_x, center_y)
203
-
204
- elif action_type == "HOVER":
205
- bbox = self.find_element(description, state, annotate=annotate)
206
- center_x, center_y = center_bbox(bbox)
207
- self.driver.mouse.move(center_x, center_y)
208
-
231
+ print(f"[SIMPLEX] Clicked on element \"{description}\"")
209
232
  elif action_type == "TYPE":
210
233
  self.driver.keyboard.type(description)
234
+ print(f"[SIMPLEX] Typed \"{description}\"")
211
235
 
212
236
  elif action_type == "ENTER":
213
237
  self.driver.keyboard.press("Enter")
238
+ print(f"[SIMPLEX] Pressed enter")
214
239
 
215
240
  elif action_type == "SCROLL":
216
241
  self.driver.mouse.wheel(0, int(description))
242
+ print(f"[SIMPLEX] Scrolled {description} pixels")
217
243
 
218
244
  elif action_type == "WAIT":
219
245
  self.driver.wait_for_timeout(int(description))
246
+ print(f"[SIMPLEX] Waited {description} seconds")
220
247
 
221
248
  except Exception as e:
222
- print(f"Error executing action: {e}")
249
+ print(f"[SIMPLEX] Error executing action: {e}")
223
250
  return None
224
251
 
225
252
  def do(self, step_description: str, annotate: bool = True) -> None:
@@ -230,6 +257,57 @@ class Simplex:
230
257
  actions = self.step_to_action(step_description, state)
231
258
  for action in actions:
232
259
  self.execute_action(action, annotate=annotate)
260
+
261
+ def extract_text(self, element_description: str, state: Image.Image | None = None) -> List[str] | None:
262
+ """
263
+ Extract an element text from the page
264
+ """
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
+
310
+
233
311
 
234
312
  def take_stable_screenshot(self) -> Image.Image:
235
313
  """
@@ -238,6 +316,7 @@ class Simplex:
238
316
  Returns:
239
317
  PIL.Image.Image: Screenshot of the current page
240
318
  """
319
+ print("[SIMPLEX] Taking screenshot of the page...")
241
320
  self.driver.wait_for_load_state('networkidle')
242
321
  return screenshot_to_image(self.driver.screenshot())
243
322
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: simplex
3
- Version: 1.2.1
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.
@@ -9,6 +9,7 @@ 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
13
14
  from hyperbrowser.models.session import CreateSessionParams
14
15
 
@@ -153,14 +154,32 @@ def test_find_element():
153
154
  def test_find_element_2():
154
155
 
155
156
  simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"))
156
- simplex.goto("https://www.cgtrader.com/")
157
- simplex.find_element("search bar")
157
+ # simplex.goto("https://www.cgtrader.com/")
158
+ state = Image.open("nvidia-stock.png")
159
+ bbox = simplex.extract_bbox("nvidia stock graph", state)
160
+ print(bbox)
161
+
162
+ state.crop(bbox)
163
+ state.save("cropped_state.png")
164
+
165
+
166
+
158
167
 
168
+
169
+ import requests
159
170
  def test_hyperbrowser_integration():
160
171
  """Test Simplex integration with Hyperbrowser"""
172
+ import time
173
+ start_time = time.time()
174
+
175
+ bb = Browserbase(api_key=os.getenv("BROWSERBASE_API_KEY"))
176
+ session_start = time.time()
177
+ session = bb.sessions.create(project_id=os.getenv("BROWSERBASE_PROJECT_ID"))
178
+ print(session.id)
179
+ print(f"Session creation took {time.time() - session_start:.2f}s")
161
180
 
162
181
  # Initialize Hyperbrowser client
163
- client = Hyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))
182
+ # client = Hyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))
164
183
 
165
184
  # Create session params with CAPTCHA solving enabled
166
185
  session_params = CreateSessionParams(
@@ -169,28 +188,45 @@ def test_hyperbrowser_integration():
169
188
  )
170
189
 
171
190
  # Create a new session with params
172
- session = client.sessions.create(session_params)
173
- ws_endpoint = session.ws_endpoint
191
+ # session = client.sessions.create(session_params)
192
+ ws_endpoint = session.connect_url
174
193
 
175
194
  try:
176
195
  with sync_playwright() as p:
177
196
  # Connect browser to Hyperbrowser session
197
+ browser_start = time.time()
178
198
  browser = p.chromium.connect_over_cdp(ws_endpoint)
179
-
199
+ print(f"Browser connection took {time.time() - browser_start:.2f}s")
200
+ url = f"https://api.browserbase.com/v1/sessions/{session.id}/debug"
201
+ headers = {"X-BB-API-Key": os.getenv("BROWSERBASE_API_KEY")}
202
+ response = requests.get(url, headers=headers)
203
+ print(response.text)
204
+ print(response.json()["pages"][0]["debuggerUrl"])
205
+
180
206
  # Initialize Simplex with the Hyperbrowser-connected page
181
207
  simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"), browser=browser)
182
208
 
183
209
  # Test basic functionality
210
+ nav_start = time.time()
184
211
  simplex.goto("https://www.turbosquid.com/")
185
- simplex.do("search for iphone")
212
+ print(f"Navigation took {time.time() - nav_start:.2f}s")
213
+
214
+ # search_start = time.time()
215
+ # simplex.do("search for iphone")
216
+ # print(f"Search action took {time.time() - search_start:.2f}s")
186
217
 
187
218
  # Verify the search worked by finding the search results
188
- bbox = simplex.find_element("search results")
219
+ find_start = time.time()
220
+ bbox = simplex.find_element("search results", annotate=True)
221
+ print(f"Finding results took {time.time() - find_start:.2f}s")
189
222
  assert bbox is not None, "Search results not found"
190
223
 
191
224
  finally:
192
225
  # Always stop the Hyperbrowser session
193
- client.sessions.stop(session.id)
226
+ # client.sessions.stop(session.id)
227
+ browser.close()
228
+ print(f"Total test time: {time.time() - start_time:.2f}s")
229
+
194
230
 
195
231
 
196
232
  def execute_action_test():
@@ -216,7 +252,28 @@ def execute_action_test():
216
252
  browser.close()
217
253
  playwright.stop()
218
254
 
255
+
256
+ def test_extract_text():
257
+ simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"))
258
+ simplex.goto("https://www.cgtrader.com/3d-models/electronics/other/apple-watch-ultra-2022-hq-3d-model")
259
+ time.sleep(2)
260
+ start = time.time()
261
+ text = simplex.extract_text("type of license")
262
+ end = time.time()
263
+ print(f"Time taken: {end - start:.2f}s")
264
+ print(text)
265
+
266
+
267
+ def test_extract_image():
268
+ simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"))
269
+ state = Image.open("nvidia-stock.png")
270
+ image = simplex.extract_image("stock trends and market summary", state)
271
+ image.save("cropped_image.png")
272
+
273
+ print(type(simplex.driver))
274
+
275
+
219
276
  if __name__ == "__main__":
220
- execute_action_test()
277
+ test_extract_image()
221
278
 
222
279
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes