simplex 1.0.0__tar.gz → 1.2.0__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.1
1
+ Metadata-Version: 2.2
2
2
  Name: simplex
3
- Version: 1.0.0
3
+ Version: 1.2.0
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,6 +21,15 @@ 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
24
33
 
25
34
  # Simplex AI Python SDK
26
35
 
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="simplex",
5
- version="1.0.0",
5
+ version="1.2.0",
6
6
  packages=find_packages(),
7
7
  install_requires=[
8
8
  "openai>=1.0.0",
@@ -1,42 +1,35 @@
1
- from playwright.sync_api import Page, sync_playwright
1
+ from playwright.sync_api import Page, sync_playwright, Browser
2
2
  from PIL import Image
3
3
  import requests
4
4
  from typing import List
5
5
  import io
6
+ import time
6
7
 
7
8
  from .utils import center_bbox, screenshot_to_image
8
9
 
9
10
  BASE_URL = "https://u3mvtbirxf.us-east-1.awsapprunner.com"
10
11
 
11
12
  class Simplex:
12
- def __init__(self, api_key: str, driver: Page = None):
13
+ def __init__(self, api_key: str, browser: Browser = None):
13
14
  """
14
15
  Initialize Simplex instance
15
16
 
16
17
  Args:
17
18
  api_key (str): API key for authentication
18
- driver (playwright.sync_api.Page, optional): Playwright page object. If not provided,
19
- a new headless browser instance will be created.
19
+ browser (optional): Browser instance (for Hyperbrowser integration)
20
20
  """
21
21
  self.api_key = api_key
22
+ self.browser = browser
22
23
 
23
- if driver is None:
24
+ if browser is None:
24
25
  self.playwright = sync_playwright().start()
25
26
  self.browser = self.playwright.chromium.launch(headless=True)
26
- self.driver = self.browser.new_page()
27
27
  else:
28
- self.driver = driver
29
- self.browser = None
30
28
  self.playwright = None
29
+
30
+ self.driver = self.browser.new_page(viewport={"width": 1280, "height": 720})
31
31
 
32
- def __del__(self):
33
- """Cleanup Playwright resources"""
34
- if self.browser:
35
- self.browser.close()
36
- if self.playwright:
37
- self.playwright.stop()
38
-
39
- def find_element(self, element_description: str, state: Image.Image | None = None) -> List[int]:
32
+ def find_element(self, element_description: str, state: Image.Image | None = None, annotate: bool = True) -> List[int]:
40
33
  """
41
34
  Find an element in the screenshot using the element description
42
35
 
@@ -69,11 +62,41 @@ class Simplex:
69
62
  files=files
70
63
  )
71
64
 
65
+
72
66
  # Print the results
73
67
  print(f"Status Code: {response.status_code}")
74
68
  if response.status_code == 200:
75
69
  res = response.json()
76
70
  bbox = [int(res['x1']), int(res['y1']), int(res['x2']), int(res['y2'])]
71
+
72
+ # Add overlay directly to the page if driver exists
73
+ if hasattr(self, 'driver') and annotate:
74
+ # Create and inject overlay element
75
+ self.driver.evaluate("""
76
+ (bbox) => {
77
+ // Remove any existing overlay
78
+ const existingOverlay = document.getElementById('simplex-bbox-overlay');
79
+ if (existingOverlay) {
80
+ existingOverlay.remove();
81
+ }
82
+
83
+ // Create new overlay
84
+ const overlay = document.createElement('div');
85
+ overlay.id = 'simplex-bbox-overlay';
86
+ overlay.style.position = 'absolute';
87
+ overlay.style.border = '2px solid red';
88
+ overlay.style.left = bbox[0] + 'px';
89
+ overlay.style.top = bbox[1] + 'px';
90
+ overlay.style.width = (bbox[2] - bbox[0]) + 'px';
91
+ overlay.style.height = (bbox[3] - bbox[1]) + 'px';
92
+ overlay.style.pointerEvents = 'none';
93
+ overlay.style.zIndex = '10000';
94
+
95
+ document.body.appendChild(overlay);
96
+ }
97
+ """, bbox)
98
+ self.driver.wait_for_selector('#simplex-bbox-overlay')
99
+ time.sleep(5)
77
100
  return bbox
78
101
  else:
79
102
  print("Error:", response.text)
@@ -130,7 +153,7 @@ class Simplex:
130
153
  """
131
154
  self.driver.goto(url)
132
155
 
133
- def execute_action(self, action: List[List[str]], state: Image.Image | None = None) -> None:
156
+ def execute_action(self, action: List[List[str]], state: Image.Image | None = None, annotate: bool = True) -> None:
134
157
  """
135
158
  Execute an action with playwright driver
136
159
 
@@ -143,12 +166,12 @@ class Simplex:
143
166
 
144
167
  try:
145
168
  if action_type == "CLICK":
146
- bbox = self.find_element(description, state)
169
+ bbox = self.find_element(description, state, annotate=annotate)
147
170
  center_x, center_y = center_bbox(bbox)
148
171
  self.driver.mouse.click(center_x, center_y)
149
172
 
150
173
  elif action_type == "HOVER":
151
- bbox = self.find_element(description, state)
174
+ bbox = self.find_element(description, state, annotate=annotate)
152
175
  center_x, center_y = center_bbox(bbox)
153
176
  self.driver.mouse.move(center_x, center_y)
154
177
 
@@ -165,14 +188,14 @@ class Simplex:
165
188
  print(f"Error executing action: {e}")
166
189
  return None
167
190
 
168
- def do(self, step_description: str) -> None:
191
+ def do(self, step_description: str, annotate: bool = True) -> None:
169
192
  """
170
193
  Execute a step description
171
194
  """
172
195
  state = self.take_stable_screenshot()
173
196
  actions = self.step_to_action(step_description, state)
174
197
  for action in actions:
175
- self.execute_action(action)
198
+ self.execute_action(action, annotate=annotate)
176
199
 
177
200
  def take_stable_screenshot(self) -> Image.Image:
178
201
  """
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: simplex
3
- Version: 1.0.0
3
+ Version: 1.2.0
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,6 +21,15 @@ 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
24
33
 
25
34
  # Simplex AI Python SDK
26
35
 
@@ -0,0 +1,206 @@
1
+ import sys
2
+ import os
3
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
4
+ from simplex import Simplex
5
+
6
+ from PIL import ImageDraw
7
+
8
+ from playwright.sync_api import sync_playwright
9
+ from PIL import Image
10
+ import time
11
+ import os
12
+ from hyperbrowser import Hyperbrowser
13
+
14
+ from dotenv import load_dotenv
15
+
16
+
17
+ load_dotenv()
18
+
19
+
20
+ def screenshot_tests():
21
+ simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"))
22
+ image = "/home/ubuntu/supreme-waffle/images/netflix.png"
23
+ screenshot = Image.open(image)
24
+
25
+ start_time = time.time()
26
+ bbox = simplex.find_element("dark mode icon", screenshot)
27
+ end_time = time.time()
28
+ print(f"Time taken: {end_time - start_time} seconds")
29
+ print(bbox)
30
+
31
+ start_time = time.time()
32
+ action = simplex.step_to_action("click and enter email address", screenshot)
33
+ end_time = time.time()
34
+ print(f"Time taken: {end_time - start_time} seconds")
35
+ print(action)
36
+
37
+
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])
47
+
48
+
49
+ def cgtrader_test():
50
+ assets = ["apple watch"]
51
+ urls = []
52
+
53
+ 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)
56
+ simplex.goto("https://www.cgtrader.com/")
57
+
58
+ for asset in assets:
59
+ simplex.goto("https://www.cgtrader.com")
60
+ simplex.do(f"search for {asset}")
61
+ simplex.do("click on search button")
62
+ simplex.do(f"click on the first product")
63
+ driver.wait_for_timeout(3000)
64
+
65
+ urls.append(simplex.driver.url)
66
+
67
+ print(urls)
68
+
69
+
70
+ def test_find_element():
71
+ simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"))
72
+ simplex.goto("https://www.cgtrader.com/")
73
+
74
+ state = simplex.take_stable_screenshot()
75
+ bbox = simplex.find_element("search bar")
76
+
77
+ copy_image = state.copy()
78
+ draw = ImageDraw.Draw(copy_image)
79
+ draw.rectangle(bbox, outline='red', width=2)
80
+ copy_image.save("annotated_state.png")
81
+
82
+
83
+ # Get the page HTML and device scale factor
84
+ html = simplex.driver.content()
85
+ scale_factor = simplex.driver.evaluate("window.devicePixelRatio")
86
+
87
+ # Get viewport dimensions and other relevant settings
88
+ viewport_size = simplex.driver.viewport_size
89
+ zoom_level = simplex.driver.evaluate("document.documentElement.style.zoom || 1")
90
+
91
+ # Debug print
92
+ print(f"Original bbox: {bbox}")
93
+ print(f"Scale factor: {scale_factor}")
94
+ print(f"Viewport size: {viewport_size}")
95
+ print(f"Zoom level: {zoom_level}")
96
+
97
+ # Transform coordinates from screenshot to HTML
98
+ html_bbox = [
99
+ bbox[0] / scale_factor,
100
+ bbox[1] / scale_factor,
101
+ bbox[2] / scale_factor,
102
+ bbox[3] / scale_factor
103
+ ]
104
+ print(f"Transformed bbox: {html_bbox}")
105
+
106
+ # Create HTML wrapper with matching viewport settings and scaled overlay
107
+ html_with_settings = f"""
108
+ <!DOCTYPE html>
109
+ <html>
110
+ <head>
111
+ <meta name="viewport" content="width=device-width, initial-scale=1">
112
+ <style>
113
+ body {{
114
+ margin: 0;
115
+ width: {viewport_size['width']}px;
116
+ height: {viewport_size['height']}px;
117
+ zoom: {zoom_level};
118
+ }}
119
+ .viewport-container {{
120
+ width: 100%;
121
+ height: 100%;
122
+ overflow: hidden;
123
+ position: relative;
124
+ transform-origin: top left;
125
+ transform: scale({1/scale_factor});
126
+ }}
127
+ #page-content {{
128
+ width: {viewport_size['width'] * scale_factor}px;
129
+ height: {viewport_size['height'] * scale_factor}px;
130
+ transform-origin: top left;
131
+ }}
132
+ #bbox-overlay {{
133
+ position: absolute;
134
+ border: 2px solid red;
135
+ left: {bbox[0]}px;
136
+ top: {bbox[1]}px;
137
+ width: {bbox[2] - bbox[0]}px;
138
+ height: {bbox[3] - bbox[1]}px;
139
+ pointer-events: none;
140
+ z-index: 10000;
141
+ }}
142
+ </style>
143
+ </head>
144
+ <body>
145
+ <div class="viewport-container">
146
+ <div id="page-content">
147
+ {html}
148
+ </div>
149
+ <div id="bbox-overlay"></div>
150
+ </div>
151
+ </body>
152
+ </html>
153
+ """
154
+
155
+ # Save the HTML with viewport settings
156
+ with open('screenshot_with_viewport.html', 'w') as f:
157
+ f.write(html_with_settings)
158
+
159
+
160
+ 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
+
171
+ def test_hyperbrowser_integration():
172
+ """Test Simplex integration with Hyperbrowser"""
173
+
174
+ # Initialize Hyperbrowser client
175
+ client = Hyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))
176
+
177
+ # Create a new session
178
+ session = client.sessions.create()
179
+ ws_endpoint = session.ws_endpoint
180
+
181
+ try:
182
+ with sync_playwright() as p:
183
+ # Connect browser to Hyperbrowser session
184
+ browser = p.chromium.connect_over_cdp(ws_endpoint)
185
+ context = browser.new_context()
186
+ page = context.new_page()
187
+
188
+ # Initialize Simplex with the Hyperbrowser-connected page
189
+ simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"), browser=browser)
190
+
191
+ # Test basic functionality
192
+ simplex.goto("https://www.cgtrader.com/")
193
+ simplex.do("search for iphone")
194
+
195
+ # Verify the search worked by finding the search results
196
+ bbox = simplex.find_element("search results")
197
+ assert bbox is not None, "Search results not found"
198
+
199
+ finally:
200
+ # Always stop the Hyperbrowser session
201
+ client.sessions.stop(session.id)
202
+
203
+ if __name__ == "__main__":
204
+ test_hyperbrowser_integration()
205
+
206
+
@@ -1,111 +0,0 @@
1
- import sys
2
- import os
3
- sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
4
- from simplex import Simplex
5
-
6
- from PIL import ImageDraw
7
-
8
- from playwright.sync_api import sync_playwright
9
- from PIL import Image
10
- import time
11
- import tempfile
12
- import webbrowser
13
-
14
- from dotenv import load_dotenv
15
-
16
- import io
17
-
18
-
19
- load_dotenv()
20
-
21
-
22
- def screenshot_tests():
23
- simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"))
24
- image = "/home/ubuntu/supreme-waffle/images/netflix.png"
25
- screenshot = Image.open(image)
26
-
27
- start_time = time.time()
28
- bbox = simplex.find_element("dark mode icon", screenshot)
29
- end_time = time.time()
30
- print(f"Time taken: {end_time - start_time} seconds")
31
- print(bbox)
32
-
33
- start_time = time.time()
34
- action = simplex.step_to_action("click and enter email address", screenshot)
35
- end_time = time.time()
36
- print(f"Time taken: {end_time - start_time} seconds")
37
- print(action)
38
-
39
-
40
- def execute_action_test():
41
- playwright = sync_playwright().start()
42
- browser = playwright.chromium.launch(headless=False)
43
- driver = browser.new_page()
44
-
45
- simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"), driver=driver)
46
- simplex.goto("https://www.netflix.com/")
47
- actions = [['CLICK', 'email field'], ['TYPE', 'email address']]
48
- simplex.execute_action(actions[0])
49
-
50
-
51
- def cgtrader_test():
52
- assets = ["apple watch"]
53
- urls = []
54
-
55
- with sync_playwright() as p:
56
- driver = p.chromium.launch(headless=False).new_page()
57
- simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"), driver=driver)
58
- simplex.goto("https://www.cgtrader.com/")
59
-
60
- for asset in assets:
61
- simplex.goto("https://www.cgtrader.com")
62
- simplex.do(f"search for {asset}")
63
- simplex.do("click on search button")
64
- simplex.do(f"click on the first product")
65
- driver.wait_for_timeout(3000)
66
-
67
- urls.append(simplex.driver.url)
68
-
69
- print(urls)
70
-
71
-
72
- def test_find_element():
73
- simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"))
74
- simplex.goto("https://www.cgtrader.com/")
75
-
76
- state = simplex.take_stable_screenshot()
77
- bbox = simplex.find_element("cart")
78
-
79
- # Save the screenshot without annotation
80
- state.save('screenshot_with_bbox.png')
81
-
82
- # Create a minimal HTML file with just the visualization and bbox
83
- with open('screenshot_with_bbox.html', 'w') as f:
84
- f.write(f"""
85
- <div style="position: relative; display: inline-block;">
86
- <img src="screenshot_with_bbox.png">
87
- <div style="
88
- position: absolute;
89
- border: 2px solid red;
90
- left: {bbox[0]}px;
91
- top: {bbox[1]}px;
92
- width: {bbox[2] - bbox[0]}px;
93
- height: {bbox[3] - bbox[1]}px;
94
- pointer-events: none;
95
- "></div>
96
- </div>
97
- """)
98
-
99
- # Create a second HTML file with just the screenshot
100
- with open('screenshot.html', 'w') as f:
101
- f.write("""
102
- <div style="position: relative; display: inline-block;">
103
- <img src="screenshot_with_bbox.png">
104
- </div>
105
- """)
106
-
107
-
108
- if __name__ == "__main__":
109
- cgtrader_test()
110
-
111
-
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes