autoglm-gui 1.4.1__py3-none-any.whl → 1.5.1__py3-none-any.whl
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.
- AutoGLM_GUI/__init__.py +11 -0
- AutoGLM_GUI/__main__.py +26 -4
- AutoGLM_GUI/actions/__init__.py +6 -0
- phone_agent/actions/handler_ios.py → AutoGLM_GUI/actions/handler.py +30 -112
- AutoGLM_GUI/actions/types.py +15 -0
- {phone_agent → AutoGLM_GUI}/adb/__init__.py +25 -23
- {phone_agent → AutoGLM_GUI}/adb/connection.py +5 -40
- {phone_agent → AutoGLM_GUI}/adb/device.py +12 -94
- {phone_agent → AutoGLM_GUI}/adb/input.py +6 -47
- AutoGLM_GUI/adb/screenshot.py +11 -0
- {phone_agent/config → AutoGLM_GUI/adb}/timing.py +1 -1
- AutoGLM_GUI/adb_plus/keyboard_installer.py +4 -2
- AutoGLM_GUI/adb_plus/screenshot.py +22 -1
- AutoGLM_GUI/adb_plus/serial.py +38 -20
- AutoGLM_GUI/adb_plus/touch.py +4 -9
- AutoGLM_GUI/agents/__init__.py +43 -12
- AutoGLM_GUI/agents/events.py +19 -0
- AutoGLM_GUI/agents/factory.py +31 -38
- AutoGLM_GUI/agents/glm/__init__.py +7 -0
- AutoGLM_GUI/agents/glm/agent.py +297 -0
- AutoGLM_GUI/agents/glm/message_builder.py +81 -0
- AutoGLM_GUI/agents/glm/parser.py +110 -0
- {phone_agent/config → AutoGLM_GUI/agents/glm}/prompts_en.py +7 -9
- {phone_agent/config → AutoGLM_GUI/agents/glm}/prompts_zh.py +18 -25
- AutoGLM_GUI/agents/mai/__init__.py +28 -0
- AutoGLM_GUI/agents/mai/agent.py +408 -0
- AutoGLM_GUI/agents/mai/parser.py +254 -0
- AutoGLM_GUI/agents/mai/prompts.py +103 -0
- AutoGLM_GUI/agents/mai/traj_memory.py +91 -0
- AutoGLM_GUI/agents/protocols.py +12 -8
- AutoGLM_GUI/agents/stream_runner.py +193 -0
- AutoGLM_GUI/api/__init__.py +40 -21
- AutoGLM_GUI/api/agents.py +181 -239
- AutoGLM_GUI/api/control.py +9 -6
- AutoGLM_GUI/api/devices.py +102 -12
- AutoGLM_GUI/api/history.py +104 -0
- AutoGLM_GUI/api/layered_agent.py +67 -15
- AutoGLM_GUI/api/media.py +64 -1
- AutoGLM_GUI/api/scheduled_tasks.py +98 -0
- AutoGLM_GUI/config.py +81 -0
- AutoGLM_GUI/config_manager.py +68 -51
- AutoGLM_GUI/device_manager.py +248 -29
- AutoGLM_GUI/device_protocol.py +1 -1
- AutoGLM_GUI/devices/adb_device.py +5 -10
- AutoGLM_GUI/devices/mock_device.py +4 -2
- AutoGLM_GUI/devices/remote_device.py +8 -3
- AutoGLM_GUI/history_manager.py +164 -0
- AutoGLM_GUI/model/__init__.py +5 -0
- AutoGLM_GUI/model/message_builder.py +69 -0
- AutoGLM_GUI/model/types.py +24 -0
- AutoGLM_GUI/models/__init__.py +10 -0
- AutoGLM_GUI/models/history.py +140 -0
- AutoGLM_GUI/models/scheduled_task.py +71 -0
- AutoGLM_GUI/parsers/__init__.py +22 -0
- AutoGLM_GUI/parsers/base.py +50 -0
- AutoGLM_GUI/parsers/phone_parser.py +58 -0
- AutoGLM_GUI/phone_agent_manager.py +62 -396
- AutoGLM_GUI/platform_utils.py +26 -0
- AutoGLM_GUI/prompt_config.py +15 -0
- AutoGLM_GUI/prompts/__init__.py +32 -0
- AutoGLM_GUI/scheduler_manager.py +350 -0
- AutoGLM_GUI/schemas.py +246 -72
- AutoGLM_GUI/scrcpy_stream.py +142 -24
- AutoGLM_GUI/socketio_server.py +100 -27
- AutoGLM_GUI/static/assets/{about-_XNhzQZX.js → about-CfwX1Cmc.js} +1 -1
- AutoGLM_GUI/static/assets/alert-dialog-CtGlN2IJ.js +1 -0
- AutoGLM_GUI/static/assets/chat-BYa-foUI.js +129 -0
- AutoGLM_GUI/static/assets/circle-alert-t08bEMPO.js +1 -0
- AutoGLM_GUI/static/assets/dialog-FNwZJFwk.js +45 -0
- AutoGLM_GUI/static/assets/eye-D0UPWCWC.js +1 -0
- AutoGLM_GUI/static/assets/history-CRo95B7i.js +1 -0
- AutoGLM_GUI/static/assets/{index-Cy8TmmHV.js → index-BaLMSqd3.js} +1 -1
- AutoGLM_GUI/static/assets/index-CTHbFvKl.js +11 -0
- AutoGLM_GUI/static/assets/index-CV7jGxGm.css +1 -0
- AutoGLM_GUI/static/assets/label-DJFevVmr.js +1 -0
- AutoGLM_GUI/static/assets/logs-RW09DyYY.js +1 -0
- AutoGLM_GUI/static/assets/popover--JTJrE5v.js +1 -0
- AutoGLM_GUI/static/assets/scheduled-tasks-DTRKsQXF.js +1 -0
- AutoGLM_GUI/static/assets/square-pen-CPK_K680.js +1 -0
- AutoGLM_GUI/static/assets/textarea-PRmVnWq5.js +1 -0
- AutoGLM_GUI/static/assets/workflows-CdcsAoaT.js +1 -0
- AutoGLM_GUI/static/index.html +2 -2
- AutoGLM_GUI/types.py +17 -0
- {autoglm_gui-1.4.1.dist-info → autoglm_gui-1.5.1.dist-info}/METADATA +179 -130
- autoglm_gui-1.5.1.dist-info/RECORD +118 -0
- AutoGLM_GUI/agents/mai_adapter.py +0 -627
- AutoGLM_GUI/api/dual_model.py +0 -317
- AutoGLM_GUI/device_adapter.py +0 -263
- AutoGLM_GUI/dual_model/__init__.py +0 -53
- AutoGLM_GUI/dual_model/decision_model.py +0 -664
- AutoGLM_GUI/dual_model/dual_agent.py +0 -917
- AutoGLM_GUI/dual_model/protocols.py +0 -354
- AutoGLM_GUI/dual_model/vision_model.py +0 -442
- AutoGLM_GUI/mai_ui_adapter/agent_wrapper.py +0 -291
- AutoGLM_GUI/phone_agent_patches.py +0 -147
- AutoGLM_GUI/static/assets/chat-DwJpiAWf.js +0 -126
- AutoGLM_GUI/static/assets/dialog-B3uW4T8V.js +0 -45
- AutoGLM_GUI/static/assets/index-Cpv2gSF1.css +0 -1
- AutoGLM_GUI/static/assets/index-UYYauTly.js +0 -12
- AutoGLM_GUI/static/assets/workflows-Du_de-dt.js +0 -1
- autoglm_gui-1.4.1.dist-info/RECORD +0 -117
- mai_agent/base.py +0 -137
- mai_agent/mai_grounding_agent.py +0 -263
- mai_agent/mai_naivigation_agent.py +0 -526
- mai_agent/prompt.py +0 -148
- mai_agent/unified_memory.py +0 -67
- mai_agent/utils.py +0 -73
- phone_agent/__init__.py +0 -12
- phone_agent/actions/__init__.py +0 -5
- phone_agent/actions/handler.py +0 -400
- phone_agent/adb/screenshot.py +0 -108
- phone_agent/agent.py +0 -253
- phone_agent/agent_ios.py +0 -277
- phone_agent/config/__init__.py +0 -53
- phone_agent/config/apps_harmonyos.py +0 -256
- phone_agent/config/apps_ios.py +0 -339
- phone_agent/config/prompts.py +0 -80
- phone_agent/device_factory.py +0 -166
- phone_agent/hdc/__init__.py +0 -53
- phone_agent/hdc/connection.py +0 -384
- phone_agent/hdc/device.py +0 -269
- phone_agent/hdc/input.py +0 -145
- phone_agent/hdc/screenshot.py +0 -127
- phone_agent/model/__init__.py +0 -5
- phone_agent/model/client.py +0 -290
- phone_agent/xctest/__init__.py +0 -47
- phone_agent/xctest/connection.py +0 -379
- phone_agent/xctest/device.py +0 -472
- phone_agent/xctest/input.py +0 -311
- phone_agent/xctest/screenshot.py +0 -226
- {phone_agent/config → AutoGLM_GUI/adb}/apps.py +0 -0
- {phone_agent/config → AutoGLM_GUI}/i18n.py +0 -0
- {autoglm_gui-1.4.1.dist-info → autoglm_gui-1.5.1.dist-info}/WHEEL +0 -0
- {autoglm_gui-1.4.1.dist-info → autoglm_gui-1.5.1.dist-info}/entry_points.txt +0 -0
- {autoglm_gui-1.4.1.dist-info → autoglm_gui-1.5.1.dist-info}/licenses/LICENSE +0 -0
AutoGLM_GUI/__init__.py
CHANGED
|
@@ -5,6 +5,9 @@ import sys
|
|
|
5
5
|
from functools import wraps
|
|
6
6
|
from importlib import metadata
|
|
7
7
|
|
|
8
|
+
from AutoGLM_GUI.config import AgentConfig, ModelConfig, StepResult
|
|
9
|
+
from AutoGLM_GUI.logger import logger
|
|
10
|
+
|
|
8
11
|
# 修复 Windows 编码问题 - 必须在所有其他导入之前
|
|
9
12
|
if sys.platform == "win32":
|
|
10
13
|
import codecs
|
|
@@ -58,3 +61,11 @@ try:
|
|
|
58
61
|
__version__ = metadata.version("autoglm-gui")
|
|
59
62
|
except metadata.PackageNotFoundError:
|
|
60
63
|
__version__ = "unknown"
|
|
64
|
+
|
|
65
|
+
__all__ = [
|
|
66
|
+
"__version__",
|
|
67
|
+
"ModelConfig",
|
|
68
|
+
"AgentConfig",
|
|
69
|
+
"StepResult",
|
|
70
|
+
"logger",
|
|
71
|
+
]
|
AutoGLM_GUI/__main__.py
CHANGED
|
@@ -44,19 +44,25 @@ def find_available_port(
|
|
|
44
44
|
)
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
def open_browser(
|
|
47
|
+
def open_browser(
|
|
48
|
+
host: str, port: int, use_ssl: bool = False, delay: float = 1.5
|
|
49
|
+
) -> None:
|
|
48
50
|
"""Open browser after a delay to ensure server is ready.
|
|
49
51
|
|
|
50
52
|
Args:
|
|
51
53
|
host: Server host
|
|
52
54
|
port: Server port
|
|
55
|
+
use_ssl: Whether to use HTTPS
|
|
53
56
|
delay: Delay in seconds before opening browser
|
|
54
57
|
"""
|
|
55
58
|
|
|
56
59
|
def _open():
|
|
57
60
|
time.sleep(delay)
|
|
61
|
+
protocol = "https" if use_ssl else "http"
|
|
58
62
|
url = (
|
|
59
|
-
f"
|
|
63
|
+
f"{protocol}://127.0.0.1:{port}"
|
|
64
|
+
if host == "0.0.0.0"
|
|
65
|
+
else f"{protocol}://{host}:{port}"
|
|
60
66
|
)
|
|
61
67
|
try:
|
|
62
68
|
webbrowser.open(url)
|
|
@@ -125,6 +131,16 @@ def main() -> None:
|
|
|
125
131
|
action="store_true",
|
|
126
132
|
help="Disable file logging",
|
|
127
133
|
)
|
|
134
|
+
parser.add_argument(
|
|
135
|
+
"--ssl-keyfile",
|
|
136
|
+
default=None,
|
|
137
|
+
help="SSL key file path (for HTTPS)",
|
|
138
|
+
)
|
|
139
|
+
parser.add_argument(
|
|
140
|
+
"--ssl-certfile",
|
|
141
|
+
default=None,
|
|
142
|
+
help="SSL certificate file path (for HTTPS)",
|
|
143
|
+
)
|
|
128
144
|
|
|
129
145
|
args = parser.parse_args()
|
|
130
146
|
|
|
@@ -172,6 +188,9 @@ def main() -> None:
|
|
|
172
188
|
# 获取配置来源
|
|
173
189
|
config_source = config_manager.get_config_source()
|
|
174
190
|
|
|
191
|
+
# Determine if SSL is enabled
|
|
192
|
+
use_ssl = args.ssl_keyfile is not None and args.ssl_certfile is not None
|
|
193
|
+
|
|
175
194
|
# Display startup banner
|
|
176
195
|
print()
|
|
177
196
|
print("=" * 50)
|
|
@@ -179,7 +198,8 @@ def main() -> None:
|
|
|
179
198
|
print("=" * 50)
|
|
180
199
|
print(f" Version: {__version__}")
|
|
181
200
|
print()
|
|
182
|
-
|
|
201
|
+
protocol = "https" if use_ssl else "http"
|
|
202
|
+
print(f" Server: {protocol}://{args.host}:{args.port}")
|
|
183
203
|
print()
|
|
184
204
|
print(" Model Configuration:")
|
|
185
205
|
print(f" Source: {config_source.value}")
|
|
@@ -202,13 +222,15 @@ def main() -> None:
|
|
|
202
222
|
|
|
203
223
|
# Open browser automatically unless disabled
|
|
204
224
|
if not args.no_browser:
|
|
205
|
-
open_browser(args.host, args.port)
|
|
225
|
+
open_browser(args.host, args.port, use_ssl=use_ssl)
|
|
206
226
|
|
|
207
227
|
uvicorn.run(
|
|
208
228
|
server.app if not args.reload else "AutoGLM_GUI.server:app",
|
|
209
229
|
host=args.host,
|
|
210
230
|
port=args.port,
|
|
211
231
|
reload=args.reload,
|
|
232
|
+
ssl_keyfile=args.ssl_keyfile,
|
|
233
|
+
ssl_certfile=args.ssl_certfile,
|
|
212
234
|
)
|
|
213
235
|
|
|
214
236
|
|
|
@@ -1,69 +1,27 @@
|
|
|
1
|
-
"""Action handler for
|
|
1
|
+
"""Action handler for executing phone operations."""
|
|
2
2
|
|
|
3
3
|
import time
|
|
4
|
-
from dataclasses import dataclass
|
|
5
4
|
from typing import Any, Callable
|
|
6
5
|
|
|
7
|
-
from
|
|
8
|
-
back,
|
|
9
|
-
double_tap,
|
|
10
|
-
home,
|
|
11
|
-
launch_app,
|
|
12
|
-
long_press,
|
|
13
|
-
swipe,
|
|
14
|
-
tap,
|
|
15
|
-
)
|
|
16
|
-
from phone_agent.xctest.input import clear_text, hide_keyboard, type_text
|
|
6
|
+
from AutoGLM_GUI.device_protocol import DeviceProtocol
|
|
17
7
|
|
|
8
|
+
from .types import ActionResult
|
|
18
9
|
|
|
19
|
-
@dataclass
|
|
20
|
-
class ActionResult:
|
|
21
|
-
"""Result of an action execution."""
|
|
22
|
-
|
|
23
|
-
success: bool
|
|
24
|
-
should_finish: bool
|
|
25
|
-
message: str | None = None
|
|
26
|
-
requires_confirmation: bool = False
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class IOSActionHandler:
|
|
30
|
-
"""
|
|
31
|
-
Handles execution of actions from AI model output for iOS devices.
|
|
32
|
-
|
|
33
|
-
Args:
|
|
34
|
-
wda_url: WebDriverAgent URL.
|
|
35
|
-
session_id: Optional WDA session ID.
|
|
36
|
-
confirmation_callback: Optional callback for sensitive action confirmation.
|
|
37
|
-
Should return True to proceed, False to cancel.
|
|
38
|
-
takeover_callback: Optional callback for takeover requests (login, captcha).
|
|
39
|
-
"""
|
|
40
10
|
|
|
11
|
+
class ActionHandler:
|
|
41
12
|
def __init__(
|
|
42
13
|
self,
|
|
43
|
-
|
|
44
|
-
session_id: str | None = None,
|
|
14
|
+
device: DeviceProtocol,
|
|
45
15
|
confirmation_callback: Callable[[str], bool] | None = None,
|
|
46
16
|
takeover_callback: Callable[[str], None] | None = None,
|
|
47
17
|
):
|
|
48
|
-
self.
|
|
49
|
-
self.session_id = session_id
|
|
18
|
+
self.device = device
|
|
50
19
|
self.confirmation_callback = confirmation_callback or self._default_confirmation
|
|
51
20
|
self.takeover_callback = takeover_callback or self._default_takeover
|
|
52
21
|
|
|
53
22
|
def execute(
|
|
54
23
|
self, action: dict[str, Any], screen_width: int, screen_height: int
|
|
55
24
|
) -> ActionResult:
|
|
56
|
-
"""
|
|
57
|
-
Execute an action from the AI model.
|
|
58
|
-
|
|
59
|
-
Args:
|
|
60
|
-
action: The action dictionary from the model.
|
|
61
|
-
screen_width: Current screen width in pixels.
|
|
62
|
-
screen_height: Current screen height in pixels.
|
|
63
|
-
|
|
64
|
-
Returns:
|
|
65
|
-
ActionResult indicating success and whether to finish.
|
|
66
|
-
"""
|
|
67
25
|
action_type = action.get("_metadata")
|
|
68
26
|
|
|
69
27
|
if action_type == "finish":
|
|
@@ -79,6 +37,13 @@ class IOSActionHandler:
|
|
|
79
37
|
)
|
|
80
38
|
|
|
81
39
|
action_name = action.get("action")
|
|
40
|
+
if not isinstance(action_name, str) or not action_name:
|
|
41
|
+
return ActionResult(
|
|
42
|
+
success=False,
|
|
43
|
+
should_finish=False,
|
|
44
|
+
message=f"Unknown action: {action_name}",
|
|
45
|
+
)
|
|
46
|
+
|
|
82
47
|
handler_method = self._get_handler(action_name)
|
|
83
48
|
|
|
84
49
|
if handler_method is None:
|
|
@@ -96,7 +61,6 @@ class IOSActionHandler:
|
|
|
96
61
|
)
|
|
97
62
|
|
|
98
63
|
def _get_handler(self, action_name: str) -> Callable | None:
|
|
99
|
-
"""Get the handler method for an action."""
|
|
100
64
|
handlers = {
|
|
101
65
|
"Launch": self._handle_launch,
|
|
102
66
|
"Tap": self._handle_tap,
|
|
@@ -110,41 +74,33 @@ class IOSActionHandler:
|
|
|
110
74
|
"Wait": self._handle_wait,
|
|
111
75
|
"Take_over": self._handle_takeover,
|
|
112
76
|
"Note": self._handle_note,
|
|
113
|
-
"Call_API": self._handle_call_api,
|
|
114
|
-
"Interact": self._handle_interact,
|
|
115
77
|
}
|
|
116
78
|
return handlers.get(action_name)
|
|
117
79
|
|
|
118
80
|
def _convert_relative_to_absolute(
|
|
119
81
|
self, element: list[int], screen_width: int, screen_height: int
|
|
120
82
|
) -> tuple[int, int]:
|
|
121
|
-
"""Convert relative coordinates (0-1000) to absolute pixels."""
|
|
122
83
|
x = int(element[0] / 1000 * screen_width)
|
|
123
84
|
y = int(element[1] / 1000 * screen_height)
|
|
124
85
|
return x, y
|
|
125
86
|
|
|
126
87
|
def _handle_launch(self, action: dict, width: int, height: int) -> ActionResult:
|
|
127
|
-
"""Handle app launch action."""
|
|
128
88
|
app_name = action.get("app")
|
|
129
89
|
if not app_name:
|
|
130
90
|
return ActionResult(False, False, "No app name specified")
|
|
131
91
|
|
|
132
|
-
success = launch_app(app_name
|
|
92
|
+
success = self.device.launch_app(app_name)
|
|
133
93
|
if success:
|
|
134
94
|
return ActionResult(True, False)
|
|
135
95
|
return ActionResult(False, False, f"App not found: {app_name}")
|
|
136
96
|
|
|
137
97
|
def _handle_tap(self, action: dict, width: int, height: int) -> ActionResult:
|
|
138
|
-
"""Handle tap action."""
|
|
139
98
|
element = action.get("element")
|
|
140
99
|
if not element:
|
|
141
100
|
return ActionResult(False, False, "No element coordinates")
|
|
142
101
|
|
|
143
102
|
x, y = self._convert_relative_to_absolute(element, width, height)
|
|
144
103
|
|
|
145
|
-
print(f"Physically tap on ({x}, {y})")
|
|
146
|
-
|
|
147
|
-
# Check for sensitive operation
|
|
148
104
|
if "message" in action:
|
|
149
105
|
if not self.confirmation_callback(action["message"]):
|
|
150
106
|
return ActionResult(
|
|
@@ -153,28 +109,27 @@ class IOSActionHandler:
|
|
|
153
109
|
message="User cancelled sensitive operation",
|
|
154
110
|
)
|
|
155
111
|
|
|
156
|
-
tap(x, y
|
|
112
|
+
self.device.tap(x, y)
|
|
157
113
|
return ActionResult(True, False)
|
|
158
114
|
|
|
159
115
|
def _handle_type(self, action: dict, width: int, height: int) -> ActionResult:
|
|
160
|
-
"""Handle text input action."""
|
|
161
116
|
text = action.get("text", "")
|
|
162
117
|
|
|
163
|
-
|
|
164
|
-
clear_text(wda_url=self.wda_url, session_id=self.session_id)
|
|
118
|
+
original_ime = self.device.detect_and_set_adb_keyboard()
|
|
165
119
|
time.sleep(0.5)
|
|
166
120
|
|
|
167
|
-
|
|
168
|
-
time.sleep(0.
|
|
121
|
+
self.device.clear_text()
|
|
122
|
+
time.sleep(0.3)
|
|
169
123
|
|
|
170
|
-
|
|
171
|
-
hide_keyboard(wda_url=self.wda_url, session_id=self.session_id)
|
|
124
|
+
self.device.type_text(text)
|
|
172
125
|
time.sleep(0.5)
|
|
173
126
|
|
|
127
|
+
self.device.restore_keyboard(original_ime)
|
|
128
|
+
time.sleep(0.3)
|
|
129
|
+
|
|
174
130
|
return ActionResult(True, False)
|
|
175
131
|
|
|
176
132
|
def _handle_swipe(self, action: dict, width: int, height: int) -> ActionResult:
|
|
177
|
-
"""Handle swipe action."""
|
|
178
133
|
start = action.get("start")
|
|
179
134
|
end = action.get("end")
|
|
180
135
|
|
|
@@ -184,56 +139,36 @@ class IOSActionHandler:
|
|
|
184
139
|
start_x, start_y = self._convert_relative_to_absolute(start, width, height)
|
|
185
140
|
end_x, end_y = self._convert_relative_to_absolute(end, width, height)
|
|
186
141
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
swipe(
|
|
190
|
-
start_x,
|
|
191
|
-
start_y,
|
|
192
|
-
end_x,
|
|
193
|
-
end_y,
|
|
194
|
-
wda_url=self.wda_url,
|
|
195
|
-
session_id=self.session_id,
|
|
196
|
-
)
|
|
142
|
+
self.device.swipe(start_x, start_y, end_x, end_y)
|
|
197
143
|
return ActionResult(True, False)
|
|
198
144
|
|
|
199
145
|
def _handle_back(self, action: dict, width: int, height: int) -> ActionResult:
|
|
200
|
-
|
|
201
|
-
back(wda_url=self.wda_url, session_id=self.session_id)
|
|
146
|
+
self.device.back()
|
|
202
147
|
return ActionResult(True, False)
|
|
203
148
|
|
|
204
149
|
def _handle_home(self, action: dict, width: int, height: int) -> ActionResult:
|
|
205
|
-
|
|
206
|
-
home(wda_url=self.wda_url, session_id=self.session_id)
|
|
150
|
+
self.device.home()
|
|
207
151
|
return ActionResult(True, False)
|
|
208
152
|
|
|
209
153
|
def _handle_double_tap(self, action: dict, width: int, height: int) -> ActionResult:
|
|
210
|
-
"""Handle double tap action."""
|
|
211
154
|
element = action.get("element")
|
|
212
155
|
if not element:
|
|
213
156
|
return ActionResult(False, False, "No element coordinates")
|
|
214
157
|
|
|
215
158
|
x, y = self._convert_relative_to_absolute(element, width, height)
|
|
216
|
-
double_tap(x, y
|
|
159
|
+
self.device.double_tap(x, y)
|
|
217
160
|
return ActionResult(True, False)
|
|
218
161
|
|
|
219
162
|
def _handle_long_press(self, action: dict, width: int, height: int) -> ActionResult:
|
|
220
|
-
"""Handle long press action."""
|
|
221
163
|
element = action.get("element")
|
|
222
164
|
if not element:
|
|
223
165
|
return ActionResult(False, False, "No element coordinates")
|
|
224
166
|
|
|
225
167
|
x, y = self._convert_relative_to_absolute(element, width, height)
|
|
226
|
-
long_press(
|
|
227
|
-
x,
|
|
228
|
-
y,
|
|
229
|
-
duration=3.0,
|
|
230
|
-
wda_url=self.wda_url,
|
|
231
|
-
session_id=self.session_id,
|
|
232
|
-
)
|
|
168
|
+
self.device.long_press(x, y)
|
|
233
169
|
return ActionResult(True, False)
|
|
234
170
|
|
|
235
171
|
def _handle_wait(self, action: dict, width: int, height: int) -> ActionResult:
|
|
236
|
-
"""Handle wait action."""
|
|
237
172
|
duration_str = action.get("duration", "1 seconds")
|
|
238
173
|
try:
|
|
239
174
|
duration = float(duration_str.replace("seconds", "").strip())
|
|
@@ -244,35 +179,18 @@ class IOSActionHandler:
|
|
|
244
179
|
return ActionResult(True, False)
|
|
245
180
|
|
|
246
181
|
def _handle_takeover(self, action: dict, width: int, height: int) -> ActionResult:
|
|
247
|
-
"""Handle takeover request (login, captcha, etc.)."""
|
|
248
182
|
message = action.get("message", "User intervention required")
|
|
249
183
|
self.takeover_callback(message)
|
|
250
184
|
return ActionResult(True, False)
|
|
251
185
|
|
|
252
186
|
def _handle_note(self, action: dict, width: int, height: int) -> ActionResult:
|
|
253
|
-
"""Handle note action (placeholder for content recording)."""
|
|
254
|
-
# This action is typically used for recording page content
|
|
255
|
-
# Implementation depends on specific requirements
|
|
256
|
-
return ActionResult(True, False)
|
|
257
|
-
|
|
258
|
-
def _handle_call_api(self, action: dict, width: int, height: int) -> ActionResult:
|
|
259
|
-
"""Handle API call action (placeholder for summarization)."""
|
|
260
|
-
# This action is typically used for content summarization
|
|
261
|
-
# Implementation depends on specific requirements
|
|
262
187
|
return ActionResult(True, False)
|
|
263
188
|
|
|
264
|
-
def _handle_interact(self, action: dict, width: int, height: int) -> ActionResult:
|
|
265
|
-
"""Handle interaction request (user choice needed)."""
|
|
266
|
-
# This action signals that user input is needed
|
|
267
|
-
return ActionResult(True, False, message="User interaction required")
|
|
268
|
-
|
|
269
189
|
@staticmethod
|
|
270
190
|
def _default_confirmation(message: str) -> bool:
|
|
271
|
-
"
|
|
272
|
-
response
|
|
273
|
-
return response.upper() == "Y"
|
|
191
|
+
response = input(f"\n⚠️ Confirm action: {message} (y/n): ")
|
|
192
|
+
return response.lower() in ("y", "yes")
|
|
274
193
|
|
|
275
194
|
@staticmethod
|
|
276
195
|
def _default_takeover(message: str) -> None:
|
|
277
|
-
"
|
|
278
|
-
input(f"{message}\nPress Enter after completing manual operation...")
|
|
196
|
+
input(f"\n🤚 {message}. Press Enter to continue...")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Type definitions for actions."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class ActionResult:
|
|
9
|
+
success: bool
|
|
10
|
+
should_finish: bool
|
|
11
|
+
message: str | None = None
|
|
12
|
+
requires_confirmation: bool = False
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
Action = dict[str, Any]
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
from phone_agent.adb.connection import (
|
|
1
|
+
from AutoGLM_GUI.adb.apps import APP_PACKAGES, get_app_name, get_package_name
|
|
2
|
+
from AutoGLM_GUI.adb.connection import (
|
|
4
3
|
ADBConnection,
|
|
5
4
|
ConnectionType,
|
|
6
5
|
DeviceInfo,
|
|
7
6
|
list_devices,
|
|
8
7
|
quick_connect,
|
|
9
8
|
)
|
|
10
|
-
from
|
|
9
|
+
from AutoGLM_GUI.adb.device import (
|
|
11
10
|
back,
|
|
12
11
|
double_tap,
|
|
13
12
|
get_current_app,
|
|
@@ -17,35 +16,38 @@ from phone_agent.adb.device import (
|
|
|
17
16
|
swipe,
|
|
18
17
|
tap,
|
|
19
18
|
)
|
|
20
|
-
from
|
|
19
|
+
from AutoGLM_GUI.adb.input import (
|
|
21
20
|
clear_text,
|
|
22
21
|
detect_and_set_adb_keyboard,
|
|
23
22
|
restore_keyboard,
|
|
24
23
|
type_text,
|
|
25
24
|
)
|
|
26
|
-
from
|
|
25
|
+
from AutoGLM_GUI.adb.screenshot import Screenshot, get_screenshot
|
|
26
|
+
from AutoGLM_GUI.adb.timing import TIMING_CONFIG, TimingConfig
|
|
27
27
|
|
|
28
28
|
__all__ = [
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
"
|
|
29
|
+
"ADBConnection",
|
|
30
|
+
"ConnectionType",
|
|
31
|
+
"DeviceInfo",
|
|
32
|
+
"list_devices",
|
|
33
|
+
"quick_connect",
|
|
34
|
+
"TIMING_CONFIG",
|
|
35
|
+
"TimingConfig",
|
|
36
|
+
"APP_PACKAGES",
|
|
37
|
+
"get_package_name",
|
|
38
|
+
"get_app_name",
|
|
38
39
|
"tap",
|
|
40
|
+
"double_tap",
|
|
41
|
+
"long_press",
|
|
39
42
|
"swipe",
|
|
40
43
|
"back",
|
|
41
44
|
"home",
|
|
42
|
-
"double_tap",
|
|
43
|
-
"long_press",
|
|
44
45
|
"launch_app",
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
46
|
+
"get_current_app",
|
|
47
|
+
"type_text",
|
|
48
|
+
"clear_text",
|
|
49
|
+
"detect_and_set_adb_keyboard",
|
|
50
|
+
"restore_keyboard",
|
|
51
|
+
"Screenshot",
|
|
52
|
+
"get_screenshot",
|
|
51
53
|
]
|
|
@@ -5,7 +5,8 @@ import time
|
|
|
5
5
|
from dataclasses import dataclass
|
|
6
6
|
from enum import Enum
|
|
7
7
|
|
|
8
|
-
from
|
|
8
|
+
from AutoGLM_GUI.adb.timing import TIMING_CONFIG
|
|
9
|
+
from AutoGLM_GUI.adb_plus.ip import get_wifi_ip
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class ConnectionType(Enum):
|
|
@@ -261,51 +262,15 @@ class ADBConnection:
|
|
|
261
262
|
"""
|
|
262
263
|
Get the IP address of a connected device.
|
|
263
264
|
|
|
265
|
+
Delegates to adb_plus.ip.get_wifi_ip() for better WiFi interface detection.
|
|
266
|
+
|
|
264
267
|
Args:
|
|
265
268
|
device_id: Device ID. If None, uses first available device.
|
|
266
269
|
|
|
267
270
|
Returns:
|
|
268
271
|
IP address string or None if not found.
|
|
269
272
|
"""
|
|
270
|
-
|
|
271
|
-
cmd = [self.adb_path]
|
|
272
|
-
if device_id:
|
|
273
|
-
cmd.extend(["-s", device_id])
|
|
274
|
-
cmd.extend(["shell", "ip", "route"])
|
|
275
|
-
|
|
276
|
-
result = subprocess.run(
|
|
277
|
-
cmd, capture_output=True, text=True, encoding="utf-8", timeout=5
|
|
278
|
-
)
|
|
279
|
-
|
|
280
|
-
# Parse IP from route output
|
|
281
|
-
for line in result.stdout.split("\n"):
|
|
282
|
-
if "src" in line:
|
|
283
|
-
parts = line.split()
|
|
284
|
-
for i, part in enumerate(parts):
|
|
285
|
-
if part == "src" and i + 1 < len(parts):
|
|
286
|
-
return parts[i + 1]
|
|
287
|
-
|
|
288
|
-
# Alternative: try wlan0 interface
|
|
289
|
-
cmd[-1] = "ip addr show wlan0"
|
|
290
|
-
result = subprocess.run(
|
|
291
|
-
cmd[:-1] + ["shell", "ip", "addr", "show", "wlan0"],
|
|
292
|
-
capture_output=True,
|
|
293
|
-
text=True,
|
|
294
|
-
encoding="utf-8",
|
|
295
|
-
timeout=5,
|
|
296
|
-
)
|
|
297
|
-
|
|
298
|
-
for line in result.stdout.split("\n"):
|
|
299
|
-
if "inet " in line:
|
|
300
|
-
parts = line.strip().split()
|
|
301
|
-
if len(parts) >= 2:
|
|
302
|
-
return parts[1].split("/")[0]
|
|
303
|
-
|
|
304
|
-
return None
|
|
305
|
-
|
|
306
|
-
except Exception as e:
|
|
307
|
-
print(f"Error getting device IP: {e}")
|
|
308
|
-
return None
|
|
273
|
+
return get_wifi_ip(adb_path=self.adb_path, device_id=device_id)
|
|
309
274
|
|
|
310
275
|
def restart_server(self) -> tuple[bool, str]:
|
|
311
276
|
"""
|