simplex 1.2.0__tar.gz → 1.2.1__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.
- {simplex-1.2.0 → simplex-1.2.1}/PKG-INFO +1 -1
- {simplex-1.2.0 → simplex-1.2.1}/setup.py +1 -1
- {simplex-1.2.0 → simplex-1.2.1}/simplex/simplex.py +41 -7
- {simplex-1.2.0 → simplex-1.2.1}/simplex.egg-info/PKG-INFO +1 -1
- {simplex-1.2.0 → simplex-1.2.1}/tests/test_local.py +42 -26
- {simplex-1.2.0 → simplex-1.2.1}/LICENSE +0 -0
- {simplex-1.2.0 → simplex-1.2.1}/README.md +0 -0
- {simplex-1.2.0 → simplex-1.2.1}/pyproject.toml +0 -0
- {simplex-1.2.0 → simplex-1.2.1}/setup.cfg +0 -0
- {simplex-1.2.0 → simplex-1.2.1}/simplex/__init__.py +0 -0
- {simplex-1.2.0 → simplex-1.2.1}/simplex/constants.py +0 -0
- {simplex-1.2.0 → simplex-1.2.1}/simplex/utils.py +0 -0
- {simplex-1.2.0 → simplex-1.2.1}/simplex.egg-info/SOURCES.txt +0 -0
- {simplex-1.2.0 → simplex-1.2.1}/simplex.egg-info/dependency_links.txt +0 -0
- {simplex-1.2.0 → simplex-1.2.1}/simplex.egg-info/entry_points.txt +0 -0
- {simplex-1.2.0 → simplex-1.2.1}/simplex.egg-info/requires.txt +0 -0
- {simplex-1.2.0 → simplex-1.2.1}/simplex.egg-info/top_level.txt +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,13 @@ 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
|
-
|
|
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()
|
|
31
33
|
|
|
32
34
|
def find_element(self, element_description: str, state: Image.Image | None = None, annotate: bool = True) -> List[int]:
|
|
33
35
|
"""
|
|
@@ -56,6 +58,7 @@ class Simplex:
|
|
|
56
58
|
'element_description': (None, element_description),
|
|
57
59
|
'api_key': (None, self.api_key)
|
|
58
60
|
}
|
|
61
|
+
|
|
59
62
|
# Make the request
|
|
60
63
|
response = requests.post(
|
|
61
64
|
endpoint,
|
|
@@ -83,20 +86,42 @@ 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 = '
|
|
87
|
-
overlay.style.border = '2px
|
|
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)
|
|
100
125
|
return bbox
|
|
101
126
|
else:
|
|
102
127
|
print("Error:", response.text)
|
|
@@ -147,10 +172,16 @@ class Simplex:
|
|
|
147
172
|
print(response.text)
|
|
148
173
|
return []
|
|
149
174
|
|
|
150
|
-
def goto(self, url: str) -> None:
|
|
175
|
+
def goto(self, url: str, new_tab: bool = False) -> None:
|
|
151
176
|
"""
|
|
152
177
|
Navigate to a URL
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
url (str): URL to navigate to
|
|
181
|
+
new_tab (bool): Whether to open a new tab or use the current tab
|
|
153
182
|
"""
|
|
183
|
+
if new_tab:
|
|
184
|
+
self.driver = self.browser.new_page()
|
|
154
185
|
self.driver.goto(url)
|
|
155
186
|
|
|
156
187
|
def execute_action(self, action: List[List[str]], state: Image.Image | None = None, annotate: bool = True) -> None:
|
|
@@ -178,6 +209,9 @@ class Simplex:
|
|
|
178
209
|
elif action_type == "TYPE":
|
|
179
210
|
self.driver.keyboard.type(description)
|
|
180
211
|
|
|
212
|
+
elif action_type == "ENTER":
|
|
213
|
+
self.driver.keyboard.press("Enter")
|
|
214
|
+
|
|
181
215
|
elif action_type == "SCROLL":
|
|
182
216
|
self.driver.mouse.wheel(0, int(description))
|
|
183
217
|
|
|
@@ -10,6 +10,7 @@ from PIL import Image
|
|
|
10
10
|
import time
|
|
11
11
|
import os
|
|
12
12
|
from hyperbrowser import Hyperbrowser
|
|
13
|
+
from hyperbrowser.models.session import CreateSessionParams
|
|
13
14
|
|
|
14
15
|
from dotenv import load_dotenv
|
|
15
16
|
|
|
@@ -35,15 +36,7 @@ def screenshot_tests():
|
|
|
35
36
|
print(action)
|
|
36
37
|
|
|
37
38
|
|
|
38
|
-
|
|
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])
|
|
39
|
+
|
|
47
40
|
|
|
48
41
|
|
|
49
42
|
def cgtrader_test():
|
|
@@ -51,8 +44,8 @@ def cgtrader_test():
|
|
|
51
44
|
urls = []
|
|
52
45
|
|
|
53
46
|
with sync_playwright() as p:
|
|
54
|
-
|
|
55
|
-
simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"),
|
|
47
|
+
browser = p.chromium.launch(headless=False)
|
|
48
|
+
simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"), browser=browser)
|
|
56
49
|
simplex.goto("https://www.cgtrader.com/")
|
|
57
50
|
|
|
58
51
|
for asset in assets:
|
|
@@ -60,7 +53,7 @@ def cgtrader_test():
|
|
|
60
53
|
simplex.do(f"search for {asset}")
|
|
61
54
|
simplex.do("click on search button")
|
|
62
55
|
simplex.do(f"click on the first product")
|
|
63
|
-
driver.wait_for_timeout(3000)
|
|
56
|
+
simplex.driver.wait_for_timeout(3000)
|
|
64
57
|
|
|
65
58
|
urls.append(simplex.driver.url)
|
|
66
59
|
|
|
@@ -158,15 +151,10 @@ def test_find_element():
|
|
|
158
151
|
|
|
159
152
|
|
|
160
153
|
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
154
|
|
|
169
|
-
|
|
155
|
+
simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"))
|
|
156
|
+
simplex.goto("https://www.cgtrader.com/")
|
|
157
|
+
simplex.find_element("search bar")
|
|
170
158
|
|
|
171
159
|
def test_hyperbrowser_integration():
|
|
172
160
|
"""Test Simplex integration with Hyperbrowser"""
|
|
@@ -174,22 +162,26 @@ def test_hyperbrowser_integration():
|
|
|
174
162
|
# Initialize Hyperbrowser client
|
|
175
163
|
client = Hyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))
|
|
176
164
|
|
|
177
|
-
# Create
|
|
178
|
-
|
|
165
|
+
# Create session params with CAPTCHA solving enabled
|
|
166
|
+
session_params = CreateSessionParams(
|
|
167
|
+
solve_captchas=True,
|
|
168
|
+
use_stealth=True # Recommended when solving CAPTCHAs
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Create a new session with params
|
|
172
|
+
session = client.sessions.create(session_params)
|
|
179
173
|
ws_endpoint = session.ws_endpoint
|
|
180
174
|
|
|
181
175
|
try:
|
|
182
176
|
with sync_playwright() as p:
|
|
183
177
|
# Connect browser to Hyperbrowser session
|
|
184
178
|
browser = p.chromium.connect_over_cdp(ws_endpoint)
|
|
185
|
-
context = browser.new_context()
|
|
186
|
-
page = context.new_page()
|
|
187
179
|
|
|
188
180
|
# Initialize Simplex with the Hyperbrowser-connected page
|
|
189
181
|
simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"), browser=browser)
|
|
190
182
|
|
|
191
183
|
# Test basic functionality
|
|
192
|
-
simplex.goto("https://www.
|
|
184
|
+
simplex.goto("https://www.turbosquid.com/")
|
|
193
185
|
simplex.do("search for iphone")
|
|
194
186
|
|
|
195
187
|
# Verify the search worked by finding the search results
|
|
@@ -200,7 +192,31 @@ def test_hyperbrowser_integration():
|
|
|
200
192
|
# Always stop the Hyperbrowser session
|
|
201
193
|
client.sessions.stop(session.id)
|
|
202
194
|
|
|
195
|
+
|
|
196
|
+
def execute_action_test():
|
|
197
|
+
playwright = sync_playwright().start()
|
|
198
|
+
browser = playwright.chromium.launch(headless=False)
|
|
199
|
+
simplex = Simplex(api_key=os.getenv("SIMPLEX_API_KEY"), browser=browser)
|
|
200
|
+
simplex.goto("https://www.mit.edu/")
|
|
201
|
+
simplex.find_element('search bar')
|
|
202
|
+
|
|
203
|
+
time.sleep(3)
|
|
204
|
+
|
|
205
|
+
# Save HTML content
|
|
206
|
+
html_content = simplex.driver.content()
|
|
207
|
+
with open('page.html', 'w', encoding='utf-8') as f:
|
|
208
|
+
f.write(html_content)
|
|
209
|
+
|
|
210
|
+
# Keep browser open until user interrupts with Ctrl+C
|
|
211
|
+
try:
|
|
212
|
+
print("Browser is kept open. Press Ctrl+C to exit...")
|
|
213
|
+
while True:
|
|
214
|
+
time.sleep(1)
|
|
215
|
+
except KeyboardInterrupt:
|
|
216
|
+
browser.close()
|
|
217
|
+
playwright.stop()
|
|
218
|
+
|
|
203
219
|
if __name__ == "__main__":
|
|
204
|
-
|
|
220
|
+
execute_action_test()
|
|
205
221
|
|
|
206
222
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|