optexity 0.1.5.1__tar.gz → 0.1.5.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.
- {optexity-0.1.5.1 → optexity-0.1.5.3}/PKG-INFO +1 -1
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/interaction/handle_click.py +4 -1
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/interaction/handle_command.py +24 -3
- optexity-0.1.5.3/optexity/inference/core/interaction/handle_hover.py +83 -0
- optexity-0.1.5.3/optexity/inference/core/interaction/handle_keypress.py +42 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/interaction/handle_select_utils.py +11 -1
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/logging.py +8 -1
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/run_automation.py +6 -3
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/run_extraction.py +37 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/run_interaction.py +10 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/run_two_fa.py +12 -7
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/infra/browser.py +187 -52
- optexity-0.1.5.3/optexity/inference/infra/utils.py +98 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/schema/actions/extraction_action.py +9 -3
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/schema/actions/interaction_action.py +38 -4
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/schema/actions/two_fa_action.py +1 -1
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/schema/automation.py +2 -7
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/schema/task.py +7 -2
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/utils/utils.py +14 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity.egg-info/PKG-INFO +1 -1
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity.egg-info/SOURCES.txt +2 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/pyproject.toml +1 -1
- optexity-0.1.5.1/optexity/inference/core/interaction/handle_keypress.py +0 -16
- {optexity-0.1.5.1 → optexity-0.1.5.3}/LICENSE +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/README.md +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/__init__.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/cli.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/examples/__init__.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/examples/add_example.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/examples/download_pdf_url.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/examples/extract_price_stockanalysis.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/examples/file_upload.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/examples/i94.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/examples/i94_travel_history.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/examples/peachstate_medicaid.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/examples/supabase_login.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/exceptions.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/__init__.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/agents/__init__.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/agents/error_handler/__init__.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/agents/error_handler/error_handler.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/agents/error_handler/prompt.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/agents/index_prediction/__init__.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/agents/index_prediction/action_prediction_locator_axtree.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/agents/index_prediction/prompt.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/agents/select_value_prediction/__init__.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/agents/select_value_prediction/prompt.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/agents/select_value_prediction/select_value_prediction.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/agents/two_fa_extraction/__init__.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/agents/two_fa_extraction/prompt.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/agents/two_fa_extraction/two_fa_extraction.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/child_process.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/__init__.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/interaction/__init__.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/interaction/handle_agentic_task.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/interaction/handle_check.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/interaction/handle_input.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/interaction/handle_select.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/interaction/handle_upload.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/interaction/utils.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/run_assertion.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/run_python_script.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/two_factor_auth/__init__.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/infra/__init__.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/infra/browser_extension.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/models/__init__.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/models/gemini.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/models/human.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/models/llm_model.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/run_local.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/onepassword_integration.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/schema/__init__.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/schema/actions/__init__.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/schema/actions/assertion_action.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/schema/actions/misc_action.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/schema/actions/prompts.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/schema/callback.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/schema/inference.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/schema/memory.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/schema/token_usage.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/test.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/utils/__init__.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/utils/settings.py +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity.egg-info/dependency_links.txt +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity.egg-info/entry_points.txt +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity.egg-info/requires.txt +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/optexity.egg-info/top_level.txt +0 -0
- {optexity-0.1.5.1 → optexity-0.1.5.3}/setup.cfg +0 -0
|
@@ -59,8 +59,11 @@ async def click_element_index(
|
|
|
59
59
|
return
|
|
60
60
|
|
|
61
61
|
async def _actual_click_element():
|
|
62
|
+
print(
|
|
63
|
+
f"Clicking element with index: {index} and button: {click_element_action.button}"
|
|
64
|
+
)
|
|
62
65
|
action_model = browser.backend_agent.ActionModel(
|
|
63
|
-
**{"click": {"index": index}}
|
|
66
|
+
**{"click": {"index": index, "button": click_element_action.button}}
|
|
64
67
|
)
|
|
65
68
|
await browser.backend_agent.multi_act([action_model])
|
|
66
69
|
|
|
@@ -13,6 +13,7 @@ from optexity.inference.infra.browser import Browser
|
|
|
13
13
|
from optexity.schema.actions.interaction_action import (
|
|
14
14
|
CheckAction,
|
|
15
15
|
ClickElementAction,
|
|
16
|
+
HoverAction,
|
|
16
17
|
InputTextAction,
|
|
17
18
|
SelectOptionAction,
|
|
18
19
|
UncheckAction,
|
|
@@ -32,6 +33,7 @@ async def command_based_action_with_retry(
|
|
|
32
33
|
| CheckAction
|
|
33
34
|
| UploadFileAction
|
|
34
35
|
| UncheckAction
|
|
36
|
+
| HoverAction
|
|
35
37
|
),
|
|
36
38
|
browser: Browser,
|
|
37
39
|
memory: Memory,
|
|
@@ -83,7 +85,7 @@ async def command_based_action_with_retry(
|
|
|
83
85
|
)
|
|
84
86
|
elif isinstance(action, InputTextAction):
|
|
85
87
|
await input_text_locator(
|
|
86
|
-
action, locator, max_timeout_seconds_per_try
|
|
88
|
+
action, locator, browser, max_timeout_seconds_per_try
|
|
87
89
|
)
|
|
88
90
|
elif isinstance(action, SelectOptionAction):
|
|
89
91
|
await select_option_locator(
|
|
@@ -102,6 +104,8 @@ async def command_based_action_with_retry(
|
|
|
102
104
|
await uncheck_locator(
|
|
103
105
|
action, locator, max_timeout_seconds_per_try, browser
|
|
104
106
|
)
|
|
107
|
+
elif isinstance(action, HoverAction):
|
|
108
|
+
await hover_locator(locator, max_timeout_seconds_per_try)
|
|
105
109
|
elif isinstance(action, UploadFileAction):
|
|
106
110
|
await upload_file_locator(action, locator)
|
|
107
111
|
logger.debug(
|
|
@@ -149,7 +153,9 @@ async def click_locator(
|
|
|
149
153
|
)
|
|
150
154
|
else:
|
|
151
155
|
await locator.click(
|
|
152
|
-
|
|
156
|
+
button=click_element_action.button,
|
|
157
|
+
no_wait_after=True,
|
|
158
|
+
timeout=max_timeout_seconds_per_try * 1000,
|
|
153
159
|
)
|
|
154
160
|
|
|
155
161
|
if click_element_action.expect_download:
|
|
@@ -163,6 +169,7 @@ async def click_locator(
|
|
|
163
169
|
async def input_text_locator(
|
|
164
170
|
input_text_action: InputTextAction,
|
|
165
171
|
locator: Locator,
|
|
172
|
+
browser: Browser,
|
|
166
173
|
max_timeout_seconds_per_try: float,
|
|
167
174
|
):
|
|
168
175
|
|
|
@@ -172,12 +179,19 @@ async def input_text_locator(
|
|
|
172
179
|
no_wait_after=True,
|
|
173
180
|
timeout=max_timeout_seconds_per_try * 1000,
|
|
174
181
|
)
|
|
175
|
-
|
|
182
|
+
elif input_text_action.fill_or_type == "type":
|
|
176
183
|
await locator.type(
|
|
177
184
|
input_text_action.input_text,
|
|
178
185
|
no_wait_after=True,
|
|
179
186
|
timeout=max_timeout_seconds_per_try * 1000,
|
|
180
187
|
)
|
|
188
|
+
else:
|
|
189
|
+
page = await browser.get_current_page()
|
|
190
|
+
if page is None:
|
|
191
|
+
return
|
|
192
|
+
for char in input_text_action.input_text:
|
|
193
|
+
await page.keyboard.press(char)
|
|
194
|
+
await asyncio.sleep(0.1)
|
|
181
195
|
|
|
182
196
|
if input_text_action.press_enter:
|
|
183
197
|
await locator.press("Enter")
|
|
@@ -211,6 +225,13 @@ async def uncheck_locator(
|
|
|
211
225
|
)
|
|
212
226
|
|
|
213
227
|
|
|
228
|
+
async def hover_locator(
|
|
229
|
+
locator: Locator,
|
|
230
|
+
max_timeout_seconds_per_try: float,
|
|
231
|
+
):
|
|
232
|
+
await locator.hover(no_wait_after=True, timeout=max_timeout_seconds_per_try * 1000)
|
|
233
|
+
|
|
234
|
+
|
|
214
235
|
async def upload_file_locator(upload_file_action: UploadFileAction, locator: Locator):
|
|
215
236
|
await locator.set_input_files(upload_file_action.file_path)
|
|
216
237
|
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from optexity.inference.core.interaction.handle_command import (
|
|
4
|
+
command_based_action_with_retry,
|
|
5
|
+
)
|
|
6
|
+
from optexity.inference.core.interaction.utils import get_index_from_prompt
|
|
7
|
+
from optexity.inference.infra.browser import Browser
|
|
8
|
+
from optexity.schema.actions.interaction_action import HoverAction
|
|
9
|
+
from optexity.schema.memory import Memory
|
|
10
|
+
from optexity.schema.task import Task
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
async def handle_hover_element(
|
|
16
|
+
hover_element_action: HoverAction,
|
|
17
|
+
task: Task,
|
|
18
|
+
memory: Memory,
|
|
19
|
+
browser: Browser,
|
|
20
|
+
max_timeout_seconds_per_try: float,
|
|
21
|
+
max_tries: int,
|
|
22
|
+
):
|
|
23
|
+
|
|
24
|
+
if hover_element_action.command and not hover_element_action.skip_command:
|
|
25
|
+
last_error = await command_based_action_with_retry(
|
|
26
|
+
hover_element_action,
|
|
27
|
+
browser,
|
|
28
|
+
memory,
|
|
29
|
+
task,
|
|
30
|
+
max_tries,
|
|
31
|
+
max_timeout_seconds_per_try,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
if last_error is None:
|
|
35
|
+
return
|
|
36
|
+
|
|
37
|
+
if not hover_element_action.skip_prompt:
|
|
38
|
+
logger.debug(
|
|
39
|
+
f"Executing prompt-based action: {hover_element_action.__class__.__name__}"
|
|
40
|
+
)
|
|
41
|
+
await hover_element_index(hover_element_action, browser, memory, task)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
async def hover_element_index(
|
|
45
|
+
hover_element_action: HoverAction,
|
|
46
|
+
browser: Browser,
|
|
47
|
+
memory: Memory,
|
|
48
|
+
task: Task,
|
|
49
|
+
):
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
index = await get_index_from_prompt(
|
|
53
|
+
memory, hover_element_action.prompt_instructions, browser, task
|
|
54
|
+
)
|
|
55
|
+
if index is None:
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
print(f"Hovering element with index: {index}")
|
|
59
|
+
|
|
60
|
+
async def _actual_hover_element():
|
|
61
|
+
try:
|
|
62
|
+
action_model = browser.backend_agent.ActionModel(
|
|
63
|
+
**{"hover": {"index": index}}
|
|
64
|
+
)
|
|
65
|
+
await browser.backend_agent.multi_act([action_model])
|
|
66
|
+
except Exception as e:
|
|
67
|
+
logger.error(f"Error in hover_element_index: {e} trying right click")
|
|
68
|
+
node = await browser.backend_agent.browser_session.get_element_by_index(
|
|
69
|
+
index
|
|
70
|
+
)
|
|
71
|
+
if node is None:
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
backend_page = (
|
|
75
|
+
await browser.backend_agent.browser_session.get_current_page()
|
|
76
|
+
)
|
|
77
|
+
element = await backend_page.get_element(node.backend_node_id)
|
|
78
|
+
await element.click(button="right")
|
|
79
|
+
|
|
80
|
+
await _actual_hover_element()
|
|
81
|
+
except Exception as e:
|
|
82
|
+
logger.error(f"Error in hover_element_index: {e}")
|
|
83
|
+
return
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from optexity.inference.infra.browser import Browser
|
|
2
|
+
from optexity.schema.actions.interaction_action import KeyPressAction, KeyPressType
|
|
3
|
+
from optexity.schema.memory import Memory
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
async def handle_key_press(
|
|
7
|
+
keypress_action: KeyPressAction,
|
|
8
|
+
memory: Memory,
|
|
9
|
+
browser: Browser,
|
|
10
|
+
):
|
|
11
|
+
page = await browser.get_current_page()
|
|
12
|
+
if page is None:
|
|
13
|
+
return
|
|
14
|
+
|
|
15
|
+
if keypress_action.type == KeyPressType.ENTER:
|
|
16
|
+
await page.keyboard.press("Enter")
|
|
17
|
+
if keypress_action.type == KeyPressType.TAB:
|
|
18
|
+
await page.keyboard.press("Tab")
|
|
19
|
+
if keypress_action.type == KeyPressType.ZERO:
|
|
20
|
+
await page.keyboard.press("0")
|
|
21
|
+
if keypress_action.type == KeyPressType.ONE:
|
|
22
|
+
await page.keyboard.press("1")
|
|
23
|
+
if keypress_action.type == KeyPressType.TWO:
|
|
24
|
+
await page.keyboard.press("2")
|
|
25
|
+
if keypress_action.type == KeyPressType.THREE:
|
|
26
|
+
await page.keyboard.press("3")
|
|
27
|
+
if keypress_action.type == KeyPressType.FOUR:
|
|
28
|
+
await page.keyboard.press("4")
|
|
29
|
+
if keypress_action.type == KeyPressType.FIVE:
|
|
30
|
+
await page.keyboard.press("5")
|
|
31
|
+
if keypress_action.type == KeyPressType.SIX:
|
|
32
|
+
await page.keyboard.press("6")
|
|
33
|
+
if keypress_action.type == KeyPressType.SEVEN:
|
|
34
|
+
await page.keyboard.press("7")
|
|
35
|
+
if keypress_action.type == KeyPressType.EIGHT:
|
|
36
|
+
await page.keyboard.press("8")
|
|
37
|
+
if keypress_action.type == KeyPressType.NINE:
|
|
38
|
+
await page.keyboard.press("9")
|
|
39
|
+
if keypress_action.type == KeyPressType.SLASH:
|
|
40
|
+
await page.keyboard.press("/")
|
|
41
|
+
if keypress_action.type == KeyPressType.SPACE:
|
|
42
|
+
await page.keyboard.press("Space")
|
{optexity-0.1.5.1 → optexity-0.1.5.3}/optexity/inference/core/interaction/handle_select_utils.py
RENAMED
|
@@ -57,9 +57,19 @@ async def smart_select(
|
|
|
57
57
|
options: list[SelectOptionValue], patterns: list[str], memory: Memory
|
|
58
58
|
):
|
|
59
59
|
# Get all options from the <select>
|
|
60
|
-
|
|
60
|
+
## TODO: remove this once we have a better way to handle select one
|
|
61
61
|
matched_values = []
|
|
62
62
|
|
|
63
|
+
if len(options) == 0:
|
|
64
|
+
return []
|
|
65
|
+
if len(options) == 1:
|
|
66
|
+
return [options[0].value]
|
|
67
|
+
if len(options) == 2 and "Select One" in [o.value for o in options]:
|
|
68
|
+
if options[0].value == "Select One":
|
|
69
|
+
return [options[1].value]
|
|
70
|
+
else:
|
|
71
|
+
return [options[0].value]
|
|
72
|
+
|
|
63
73
|
for p in patterns:
|
|
64
74
|
# If pattern contains regex characters, treat as regex
|
|
65
75
|
is_regex = p.startswith("^") or p.endswith("$") or ".*" in p
|
|
@@ -364,7 +364,14 @@ async def save_latest_memory_state_locally(
|
|
|
364
364
|
await f.write(json.dumps(task.input_parameters, indent=4))
|
|
365
365
|
|
|
366
366
|
async with aiofiles.open(step_directory / "secure_parameters.json", "w") as f:
|
|
367
|
-
|
|
367
|
+
secure_parameters = {
|
|
368
|
+
key: [
|
|
369
|
+
a.model_dump(exclude_none=True, exclude_defaults=True)
|
|
370
|
+
for a in value
|
|
371
|
+
]
|
|
372
|
+
for key, value in task.secure_parameters.items()
|
|
373
|
+
}
|
|
374
|
+
await f.write(json.dumps(secure_parameters, indent=4))
|
|
368
375
|
|
|
369
376
|
async with aiofiles.open(step_directory / "generated_variables.json", "w") as f:
|
|
370
377
|
await f.write(json.dumps(memory.variables.generated_variables, indent=4))
|
|
@@ -25,7 +25,6 @@ from optexity.inference.core.run_interaction import (
|
|
|
25
25
|
run_interaction_action,
|
|
26
26
|
)
|
|
27
27
|
from optexity.inference.core.run_python_script import run_python_script_action
|
|
28
|
-
from optexity.inference.core.run_two_fa import run_two_fa_action
|
|
29
28
|
from optexity.inference.infra.browser import Browser
|
|
30
29
|
from optexity.schema.actions.interaction_action import DownloadUrlAsPdfAction
|
|
31
30
|
from optexity.schema.automation import ActionNode, ForLoopNode, IfElseNode
|
|
@@ -55,11 +54,14 @@ async def run_automation(task: Task, child_process_id: int):
|
|
|
55
54
|
logger.info(f"Task {task.task_id} started running")
|
|
56
55
|
memory = None
|
|
57
56
|
browser = None
|
|
57
|
+
|
|
58
58
|
try:
|
|
59
59
|
await start_task_in_server(task)
|
|
60
60
|
memory = Memory()
|
|
61
|
+
|
|
61
62
|
browser = Browser(
|
|
62
63
|
memory=memory,
|
|
64
|
+
user_data_dir=f"/tmp/userdata_{task.task_id}",
|
|
63
65
|
headless=False,
|
|
64
66
|
channel=task.automation.browser_channel,
|
|
65
67
|
debug_port=9222 + child_process_id,
|
|
@@ -67,9 +69,12 @@ async def run_automation(task: Task, child_process_id: int):
|
|
|
67
69
|
proxy_session_id=task.proxy_session_id(
|
|
68
70
|
settings.PROXY_PROVIDER if task.use_proxy else None
|
|
69
71
|
),
|
|
72
|
+
is_dedicated=task.is_dedicated,
|
|
70
73
|
)
|
|
71
74
|
await browser.start()
|
|
72
75
|
|
|
76
|
+
browser.memory = memory
|
|
77
|
+
|
|
73
78
|
automation = task.automation
|
|
74
79
|
|
|
75
80
|
memory.automation_state.step_index = -1
|
|
@@ -274,8 +279,6 @@ async def run_action_node(
|
|
|
274
279
|
await run_extraction_action(
|
|
275
280
|
action_node.extraction_action, memory, browser, task
|
|
276
281
|
)
|
|
277
|
-
elif action_node.two_fa_action:
|
|
278
|
-
await run_two_fa_action(action_node.two_fa_action, memory)
|
|
279
282
|
elif action_node.python_script_action:
|
|
280
283
|
await run_python_script_action(
|
|
281
284
|
action_node.python_script_action, memory, browser
|
|
@@ -4,12 +4,14 @@ import traceback
|
|
|
4
4
|
import aiofiles
|
|
5
5
|
import httpx
|
|
6
6
|
|
|
7
|
+
from optexity.inference.core.run_two_fa import run_two_fa_action
|
|
7
8
|
from optexity.inference.infra.browser import Browser
|
|
8
9
|
from optexity.inference.models import GeminiModels, get_llm_model
|
|
9
10
|
from optexity.schema.actions.extraction_action import (
|
|
10
11
|
ExtractionAction,
|
|
11
12
|
LLMExtraction,
|
|
12
13
|
NetworkCallExtraction,
|
|
14
|
+
PythonScriptExtraction,
|
|
13
15
|
ScreenshotExtraction,
|
|
14
16
|
StateExtraction,
|
|
15
17
|
)
|
|
@@ -51,6 +53,14 @@ async def run_extraction_action(
|
|
|
51
53
|
task,
|
|
52
54
|
extraction_action.unique_identifier,
|
|
53
55
|
)
|
|
56
|
+
elif extraction_action.python_script:
|
|
57
|
+
await handle_python_script_extraction(
|
|
58
|
+
extraction_action.python_script,
|
|
59
|
+
memory,
|
|
60
|
+
browser,
|
|
61
|
+
task,
|
|
62
|
+
extraction_action.unique_identifier,
|
|
63
|
+
)
|
|
54
64
|
elif extraction_action.screenshot:
|
|
55
65
|
await handle_screenshot_extraction(
|
|
56
66
|
extraction_action.screenshot,
|
|
@@ -65,6 +75,8 @@ async def run_extraction_action(
|
|
|
65
75
|
browser,
|
|
66
76
|
extraction_action.unique_identifier,
|
|
67
77
|
)
|
|
78
|
+
elif extraction_action.two_fa_action:
|
|
79
|
+
await run_two_fa_action(extraction_action.two_fa_action, memory)
|
|
68
80
|
|
|
69
81
|
|
|
70
82
|
async def handle_state_extraction(
|
|
@@ -225,6 +237,31 @@ async def handle_network_call_extraction(
|
|
|
225
237
|
)
|
|
226
238
|
|
|
227
239
|
|
|
240
|
+
async def handle_python_script_extraction(
|
|
241
|
+
python_script_extraction: PythonScriptExtraction,
|
|
242
|
+
memory: Memory,
|
|
243
|
+
browser: Browser,
|
|
244
|
+
task: Task,
|
|
245
|
+
unique_identifier: str | None = None,
|
|
246
|
+
):
|
|
247
|
+
local_vars = {}
|
|
248
|
+
exec(python_script_extraction.script, {}, local_vars)
|
|
249
|
+
code_fn = local_vars["code_fn"]
|
|
250
|
+
axtree = memory.browser_states[-1].axtree
|
|
251
|
+
result = await code_fn(axtree)
|
|
252
|
+
if result is not None:
|
|
253
|
+
memory.variables.output_data.append(
|
|
254
|
+
OutputData(
|
|
255
|
+
unique_identifier=unique_identifier,
|
|
256
|
+
json_data=result,
|
|
257
|
+
)
|
|
258
|
+
)
|
|
259
|
+
else:
|
|
260
|
+
logger.warning(
|
|
261
|
+
f"No result from Python script extraction: {python_script_extraction.script}"
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
|
|
228
265
|
async def download_request(
|
|
229
266
|
network_call: NetworkRequest, download_filename: str, task: Task, memory: Memory
|
|
230
267
|
):
|
|
@@ -12,6 +12,7 @@ from optexity.inference.core.interaction.handle_check import (
|
|
|
12
12
|
handle_uncheck_element,
|
|
13
13
|
)
|
|
14
14
|
from optexity.inference.core.interaction.handle_click import handle_click_element
|
|
15
|
+
from optexity.inference.core.interaction.handle_hover import handle_hover_element
|
|
15
16
|
from optexity.inference.core.interaction.handle_input import handle_input_text
|
|
16
17
|
from optexity.inference.core.interaction.handle_keypress import handle_key_press
|
|
17
18
|
from optexity.inference.core.interaction.handle_select import handle_select_option
|
|
@@ -95,6 +96,15 @@ async def run_interaction_action(
|
|
|
95
96
|
interaction_action.max_timeout_seconds_per_try,
|
|
96
97
|
interaction_action.max_tries,
|
|
97
98
|
)
|
|
99
|
+
elif interaction_action.hover:
|
|
100
|
+
await handle_hover_element(
|
|
101
|
+
interaction_action.hover,
|
|
102
|
+
task,
|
|
103
|
+
memory,
|
|
104
|
+
browser,
|
|
105
|
+
interaction_action.max_timeout_seconds_per_try,
|
|
106
|
+
interaction_action.max_tries,
|
|
107
|
+
)
|
|
98
108
|
elif interaction_action.go_back:
|
|
99
109
|
await handle_go_back(interaction_action.go_back, memory, browser)
|
|
100
110
|
elif interaction_action.download_url_as_pdf:
|
|
@@ -33,6 +33,7 @@ async def run_two_fa_action(two_fa_action: TwoFAAction, memory: Memory):
|
|
|
33
33
|
|
|
34
34
|
elapsed = 0
|
|
35
35
|
messages = None
|
|
36
|
+
code = None
|
|
36
37
|
|
|
37
38
|
while elapsed < two_fa_action.max_wait_time:
|
|
38
39
|
messages = await fetch_messages(
|
|
@@ -109,12 +110,16 @@ async def fetch_messages(
|
|
|
109
110
|
end_2fa_time=end_2fa_time,
|
|
110
111
|
)
|
|
111
112
|
|
|
112
|
-
|
|
113
|
+
try:
|
|
114
|
+
async with httpx.AsyncClient(timeout=30.0) as client:
|
|
113
115
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
response = await client.post(
|
|
117
|
+
url, json=body.model_dump(mode="json"), headers=headers
|
|
118
|
+
)
|
|
119
|
+
response.raise_for_status()
|
|
120
|
+
response_data = FetchMessagesResponse.model_validate(response.json())
|
|
119
121
|
|
|
120
|
-
|
|
122
|
+
return response_data.messages
|
|
123
|
+
except Exception as e:
|
|
124
|
+
logger.error(f"Error fetching messages: {e}")
|
|
125
|
+
return []
|