autoglm-gui 1.4.0__py3-none-any.whl → 1.5.0__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 -8
- AutoGLM_GUI/actions/__init__.py +6 -0
- AutoGLM_GUI/actions/handler.py +196 -0
- AutoGLM_GUI/actions/types.py +15 -0
- AutoGLM_GUI/adb/__init__.py +53 -0
- AutoGLM_GUI/adb/apps.py +227 -0
- AutoGLM_GUI/adb/connection.py +323 -0
- AutoGLM_GUI/adb/device.py +171 -0
- AutoGLM_GUI/adb/input.py +67 -0
- AutoGLM_GUI/adb/screenshot.py +11 -0
- AutoGLM_GUI/adb/timing.py +167 -0
- AutoGLM_GUI/adb_plus/keyboard_installer.py +4 -2
- AutoGLM_GUI/adb_plus/qr_pair.py +8 -8
- 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 +51 -0
- AutoGLM_GUI/agents/events.py +19 -0
- AutoGLM_GUI/agents/factory.py +153 -0
- AutoGLM_GUI/agents/glm/__init__.py +7 -0
- AutoGLM_GUI/agents/glm/agent.py +292 -0
- AutoGLM_GUI/agents/glm/message_builder.py +81 -0
- AutoGLM_GUI/agents/glm/parser.py +110 -0
- AutoGLM_GUI/agents/glm/prompts_en.py +77 -0
- AutoGLM_GUI/agents/glm/prompts_zh.py +75 -0
- AutoGLM_GUI/agents/mai/__init__.py +28 -0
- AutoGLM_GUI/agents/mai/agent.py +405 -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 +27 -0
- AutoGLM_GUI/agents/stream_runner.py +188 -0
- AutoGLM_GUI/api/__init__.py +71 -11
- AutoGLM_GUI/api/agents.py +190 -229
- AutoGLM_GUI/api/control.py +9 -6
- AutoGLM_GUI/api/devices.py +112 -28
- AutoGLM_GUI/api/health.py +13 -0
- AutoGLM_GUI/api/history.py +78 -0
- AutoGLM_GUI/api/layered_agent.py +306 -181
- AutoGLM_GUI/api/mcp.py +11 -10
- AutoGLM_GUI/api/media.py +64 -1
- AutoGLM_GUI/api/scheduled_tasks.py +98 -0
- AutoGLM_GUI/api/version.py +23 -10
- AutoGLM_GUI/api/workflows.py +2 -1
- AutoGLM_GUI/config.py +72 -14
- AutoGLM_GUI/config_manager.py +98 -27
- AutoGLM_GUI/device_adapter.py +263 -0
- AutoGLM_GUI/device_manager.py +248 -29
- AutoGLM_GUI/device_protocol.py +266 -0
- AutoGLM_GUI/devices/__init__.py +49 -0
- AutoGLM_GUI/devices/adb_device.py +200 -0
- AutoGLM_GUI/devices/mock_device.py +185 -0
- AutoGLM_GUI/devices/remote_device.py +177 -0
- AutoGLM_GUI/exceptions.py +3 -3
- AutoGLM_GUI/history_manager.py +164 -0
- AutoGLM_GUI/i18n.py +81 -0
- AutoGLM_GUI/metrics.py +13 -20
- 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 +96 -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 +118 -367
- AutoGLM_GUI/platform_utils.py +31 -2
- AutoGLM_GUI/prompt_config.py +15 -0
- AutoGLM_GUI/prompts/__init__.py +32 -0
- AutoGLM_GUI/scheduler_manager.py +304 -0
- AutoGLM_GUI/schemas.py +272 -63
- AutoGLM_GUI/scrcpy_stream.py +159 -37
- AutoGLM_GUI/server.py +3 -1
- AutoGLM_GUI/socketio_server.py +114 -29
- AutoGLM_GUI/state.py +10 -30
- AutoGLM_GUI/static/assets/{about-DeclntHg.js → about-BQm96DAl.js} +1 -1
- AutoGLM_GUI/static/assets/alert-dialog-B42XxGPR.js +1 -0
- AutoGLM_GUI/static/assets/chat-C0L2gQYG.js +129 -0
- AutoGLM_GUI/static/assets/circle-alert-D4rSJh37.js +1 -0
- AutoGLM_GUI/static/assets/dialog-DZ78cEcj.js +45 -0
- AutoGLM_GUI/static/assets/history-DFBv7TGc.js +1 -0
- AutoGLM_GUI/static/assets/index-Bzyv2yQ2.css +1 -0
- AutoGLM_GUI/static/assets/{index-zQ4KKDHt.js → index-CmZSnDqc.js} +1 -1
- AutoGLM_GUI/static/assets/index-CssG-3TH.js +11 -0
- AutoGLM_GUI/static/assets/label-BCUzE_nm.js +1 -0
- AutoGLM_GUI/static/assets/logs-eoFxn5of.js +1 -0
- AutoGLM_GUI/static/assets/popover-DLsuV5Sx.js +1 -0
- AutoGLM_GUI/static/assets/scheduled-tasks-MyqGJvy_.js +1 -0
- AutoGLM_GUI/static/assets/square-pen-zGWYrdfj.js +1 -0
- AutoGLM_GUI/static/assets/textarea-BX6y7uM5.js +1 -0
- AutoGLM_GUI/static/assets/workflows-CYFs6ssC.js +1 -0
- AutoGLM_GUI/static/index.html +2 -2
- AutoGLM_GUI/types.py +142 -0
- {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.5.0.dist-info}/METADATA +178 -92
- autoglm_gui-1.5.0.dist-info/RECORD +157 -0
- mai_agent/base.py +137 -0
- mai_agent/mai_grounding_agent.py +263 -0
- mai_agent/mai_naivigation_agent.py +526 -0
- mai_agent/prompt.py +148 -0
- mai_agent/unified_memory.py +67 -0
- mai_agent/utils.py +73 -0
- AutoGLM_GUI/api/dual_model.py +0 -311
- 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 -146
- AutoGLM_GUI/static/assets/chat-Iut2yhSw.js +0 -125
- AutoGLM_GUI/static/assets/dialog-BfdcBs1x.js +0 -45
- AutoGLM_GUI/static/assets/index-5hCCwHA7.css +0 -1
- AutoGLM_GUI/static/assets/index-DHF1NZh0.js +0 -12
- AutoGLM_GUI/static/assets/workflows-xiplap-r.js +0 -1
- autoglm_gui-1.4.0.dist-info/RECORD +0 -100
- {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.5.0.dist-info}/WHEEL +0 -0
- {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.5.0.dist-info}/entry_points.txt +0 -0
- {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.5.0.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
|
|
|
@@ -140,7 +156,6 @@ def main() -> None:
|
|
|
140
156
|
import uvicorn
|
|
141
157
|
|
|
142
158
|
from AutoGLM_GUI import server
|
|
143
|
-
from AutoGLM_GUI.config import config
|
|
144
159
|
from AutoGLM_GUI.config_manager import config_manager
|
|
145
160
|
from AutoGLM_GUI.logger import configure_logger
|
|
146
161
|
|
|
@@ -170,12 +185,12 @@ def main() -> None:
|
|
|
170
185
|
# 5. 同步到环境变量(reload 模式需要)
|
|
171
186
|
config_manager.sync_to_env()
|
|
172
187
|
|
|
173
|
-
# 6. 刷新旧的 config 对象(保持现有代码兼容)
|
|
174
|
-
config.refresh_from_env()
|
|
175
|
-
|
|
176
188
|
# 获取配置来源
|
|
177
189
|
config_source = config_manager.get_config_source()
|
|
178
190
|
|
|
191
|
+
# Determine if SSL is enabled
|
|
192
|
+
use_ssl = args.ssl_keyfile is not None and args.ssl_certfile is not None
|
|
193
|
+
|
|
179
194
|
# Display startup banner
|
|
180
195
|
print()
|
|
181
196
|
print("=" * 50)
|
|
@@ -183,7 +198,8 @@ def main() -> None:
|
|
|
183
198
|
print("=" * 50)
|
|
184
199
|
print(f" Version: {__version__}")
|
|
185
200
|
print()
|
|
186
|
-
|
|
201
|
+
protocol = "https" if use_ssl else "http"
|
|
202
|
+
print(f" Server: {protocol}://{args.host}:{args.port}")
|
|
187
203
|
print()
|
|
188
204
|
print(" Model Configuration:")
|
|
189
205
|
print(f" Source: {config_source.value}")
|
|
@@ -206,13 +222,15 @@ def main() -> None:
|
|
|
206
222
|
|
|
207
223
|
# Open browser automatically unless disabled
|
|
208
224
|
if not args.no_browser:
|
|
209
|
-
open_browser(args.host, args.port)
|
|
225
|
+
open_browser(args.host, args.port, use_ssl=use_ssl)
|
|
210
226
|
|
|
211
227
|
uvicorn.run(
|
|
212
228
|
server.app if not args.reload else "AutoGLM_GUI.server:app",
|
|
213
229
|
host=args.host,
|
|
214
230
|
port=args.port,
|
|
215
231
|
reload=args.reload,
|
|
232
|
+
ssl_keyfile=args.ssl_keyfile,
|
|
233
|
+
ssl_certfile=args.ssl_certfile,
|
|
216
234
|
)
|
|
217
235
|
|
|
218
236
|
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"""Action handler for executing phone operations."""
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from typing import Any, Callable
|
|
5
|
+
|
|
6
|
+
from AutoGLM_GUI.device_protocol import DeviceProtocol
|
|
7
|
+
|
|
8
|
+
from .types import ActionResult
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ActionHandler:
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
device: DeviceProtocol,
|
|
15
|
+
confirmation_callback: Callable[[str], bool] | None = None,
|
|
16
|
+
takeover_callback: Callable[[str], None] | None = None,
|
|
17
|
+
):
|
|
18
|
+
self.device = device
|
|
19
|
+
self.confirmation_callback = confirmation_callback or self._default_confirmation
|
|
20
|
+
self.takeover_callback = takeover_callback or self._default_takeover
|
|
21
|
+
|
|
22
|
+
def execute(
|
|
23
|
+
self, action: dict[str, Any], screen_width: int, screen_height: int
|
|
24
|
+
) -> ActionResult:
|
|
25
|
+
action_type = action.get("_metadata")
|
|
26
|
+
|
|
27
|
+
if action_type == "finish":
|
|
28
|
+
return ActionResult(
|
|
29
|
+
success=True, should_finish=True, message=action.get("message")
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
if action_type != "do":
|
|
33
|
+
return ActionResult(
|
|
34
|
+
success=False,
|
|
35
|
+
should_finish=True,
|
|
36
|
+
message=f"Unknown action type: {action_type}",
|
|
37
|
+
)
|
|
38
|
+
|
|
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
|
+
|
|
47
|
+
handler_method = self._get_handler(action_name)
|
|
48
|
+
|
|
49
|
+
if handler_method is None:
|
|
50
|
+
return ActionResult(
|
|
51
|
+
success=False,
|
|
52
|
+
should_finish=False,
|
|
53
|
+
message=f"Unknown action: {action_name}",
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
return handler_method(action, screen_width, screen_height)
|
|
58
|
+
except Exception as e:
|
|
59
|
+
return ActionResult(
|
|
60
|
+
success=False, should_finish=False, message=f"Action failed: {e}"
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def _get_handler(self, action_name: str) -> Callable | None:
|
|
64
|
+
handlers = {
|
|
65
|
+
"Launch": self._handle_launch,
|
|
66
|
+
"Tap": self._handle_tap,
|
|
67
|
+
"Type": self._handle_type,
|
|
68
|
+
"Type_Name": self._handle_type,
|
|
69
|
+
"Swipe": self._handle_swipe,
|
|
70
|
+
"Back": self._handle_back,
|
|
71
|
+
"Home": self._handle_home,
|
|
72
|
+
"Double Tap": self._handle_double_tap,
|
|
73
|
+
"Long Press": self._handle_long_press,
|
|
74
|
+
"Wait": self._handle_wait,
|
|
75
|
+
"Take_over": self._handle_takeover,
|
|
76
|
+
"Note": self._handle_note,
|
|
77
|
+
}
|
|
78
|
+
return handlers.get(action_name)
|
|
79
|
+
|
|
80
|
+
def _convert_relative_to_absolute(
|
|
81
|
+
self, element: list[int], screen_width: int, screen_height: int
|
|
82
|
+
) -> tuple[int, int]:
|
|
83
|
+
x = int(element[0] / 1000 * screen_width)
|
|
84
|
+
y = int(element[1] / 1000 * screen_height)
|
|
85
|
+
return x, y
|
|
86
|
+
|
|
87
|
+
def _handle_launch(self, action: dict, width: int, height: int) -> ActionResult:
|
|
88
|
+
app_name = action.get("app")
|
|
89
|
+
if not app_name:
|
|
90
|
+
return ActionResult(False, False, "No app name specified")
|
|
91
|
+
|
|
92
|
+
success = self.device.launch_app(app_name)
|
|
93
|
+
if success:
|
|
94
|
+
return ActionResult(True, False)
|
|
95
|
+
return ActionResult(False, False, f"App not found: {app_name}")
|
|
96
|
+
|
|
97
|
+
def _handle_tap(self, action: dict, width: int, height: int) -> ActionResult:
|
|
98
|
+
element = action.get("element")
|
|
99
|
+
if not element:
|
|
100
|
+
return ActionResult(False, False, "No element coordinates")
|
|
101
|
+
|
|
102
|
+
x, y = self._convert_relative_to_absolute(element, width, height)
|
|
103
|
+
|
|
104
|
+
if "message" in action:
|
|
105
|
+
if not self.confirmation_callback(action["message"]):
|
|
106
|
+
return ActionResult(
|
|
107
|
+
success=False,
|
|
108
|
+
should_finish=True,
|
|
109
|
+
message="User cancelled sensitive operation",
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
self.device.tap(x, y)
|
|
113
|
+
return ActionResult(True, False)
|
|
114
|
+
|
|
115
|
+
def _handle_type(self, action: dict, width: int, height: int) -> ActionResult:
|
|
116
|
+
text = action.get("text", "")
|
|
117
|
+
|
|
118
|
+
original_ime = self.device.detect_and_set_adb_keyboard()
|
|
119
|
+
time.sleep(0.5)
|
|
120
|
+
|
|
121
|
+
self.device.clear_text()
|
|
122
|
+
time.sleep(0.3)
|
|
123
|
+
|
|
124
|
+
self.device.type_text(text)
|
|
125
|
+
time.sleep(0.5)
|
|
126
|
+
|
|
127
|
+
self.device.restore_keyboard(original_ime)
|
|
128
|
+
time.sleep(0.3)
|
|
129
|
+
|
|
130
|
+
return ActionResult(True, False)
|
|
131
|
+
|
|
132
|
+
def _handle_swipe(self, action: dict, width: int, height: int) -> ActionResult:
|
|
133
|
+
start = action.get("start")
|
|
134
|
+
end = action.get("end")
|
|
135
|
+
|
|
136
|
+
if not start or not end:
|
|
137
|
+
return ActionResult(False, False, "Missing swipe coordinates")
|
|
138
|
+
|
|
139
|
+
start_x, start_y = self._convert_relative_to_absolute(start, width, height)
|
|
140
|
+
end_x, end_y = self._convert_relative_to_absolute(end, width, height)
|
|
141
|
+
|
|
142
|
+
self.device.swipe(start_x, start_y, end_x, end_y)
|
|
143
|
+
return ActionResult(True, False)
|
|
144
|
+
|
|
145
|
+
def _handle_back(self, action: dict, width: int, height: int) -> ActionResult:
|
|
146
|
+
self.device.back()
|
|
147
|
+
return ActionResult(True, False)
|
|
148
|
+
|
|
149
|
+
def _handle_home(self, action: dict, width: int, height: int) -> ActionResult:
|
|
150
|
+
self.device.home()
|
|
151
|
+
return ActionResult(True, False)
|
|
152
|
+
|
|
153
|
+
def _handle_double_tap(self, action: dict, width: int, height: int) -> ActionResult:
|
|
154
|
+
element = action.get("element")
|
|
155
|
+
if not element:
|
|
156
|
+
return ActionResult(False, False, "No element coordinates")
|
|
157
|
+
|
|
158
|
+
x, y = self._convert_relative_to_absolute(element, width, height)
|
|
159
|
+
self.device.double_tap(x, y)
|
|
160
|
+
return ActionResult(True, False)
|
|
161
|
+
|
|
162
|
+
def _handle_long_press(self, action: dict, width: int, height: int) -> ActionResult:
|
|
163
|
+
element = action.get("element")
|
|
164
|
+
if not element:
|
|
165
|
+
return ActionResult(False, False, "No element coordinates")
|
|
166
|
+
|
|
167
|
+
x, y = self._convert_relative_to_absolute(element, width, height)
|
|
168
|
+
self.device.long_press(x, y)
|
|
169
|
+
return ActionResult(True, False)
|
|
170
|
+
|
|
171
|
+
def _handle_wait(self, action: dict, width: int, height: int) -> ActionResult:
|
|
172
|
+
duration_str = action.get("duration", "1 seconds")
|
|
173
|
+
try:
|
|
174
|
+
duration = float(duration_str.replace("seconds", "").strip())
|
|
175
|
+
except ValueError:
|
|
176
|
+
duration = 1.0
|
|
177
|
+
|
|
178
|
+
time.sleep(duration)
|
|
179
|
+
return ActionResult(True, False)
|
|
180
|
+
|
|
181
|
+
def _handle_takeover(self, action: dict, width: int, height: int) -> ActionResult:
|
|
182
|
+
message = action.get("message", "User intervention required")
|
|
183
|
+
self.takeover_callback(message)
|
|
184
|
+
return ActionResult(True, False)
|
|
185
|
+
|
|
186
|
+
def _handle_note(self, action: dict, width: int, height: int) -> ActionResult:
|
|
187
|
+
return ActionResult(True, False)
|
|
188
|
+
|
|
189
|
+
@staticmethod
|
|
190
|
+
def _default_confirmation(message: str) -> bool:
|
|
191
|
+
response = input(f"\n⚠️ Confirm action: {message} (y/n): ")
|
|
192
|
+
return response.lower() in ("y", "yes")
|
|
193
|
+
|
|
194
|
+
@staticmethod
|
|
195
|
+
def _default_takeover(message: str) -> None:
|
|
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]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from AutoGLM_GUI.adb.apps import APP_PACKAGES, get_app_name, get_package_name
|
|
2
|
+
from AutoGLM_GUI.adb.connection import (
|
|
3
|
+
ADBConnection,
|
|
4
|
+
ConnectionType,
|
|
5
|
+
DeviceInfo,
|
|
6
|
+
list_devices,
|
|
7
|
+
quick_connect,
|
|
8
|
+
)
|
|
9
|
+
from AutoGLM_GUI.adb.device import (
|
|
10
|
+
back,
|
|
11
|
+
double_tap,
|
|
12
|
+
get_current_app,
|
|
13
|
+
home,
|
|
14
|
+
launch_app,
|
|
15
|
+
long_press,
|
|
16
|
+
swipe,
|
|
17
|
+
tap,
|
|
18
|
+
)
|
|
19
|
+
from AutoGLM_GUI.adb.input import (
|
|
20
|
+
clear_text,
|
|
21
|
+
detect_and_set_adb_keyboard,
|
|
22
|
+
restore_keyboard,
|
|
23
|
+
type_text,
|
|
24
|
+
)
|
|
25
|
+
from AutoGLM_GUI.adb.screenshot import Screenshot, get_screenshot
|
|
26
|
+
from AutoGLM_GUI.adb.timing import TIMING_CONFIG, TimingConfig
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
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",
|
|
39
|
+
"tap",
|
|
40
|
+
"double_tap",
|
|
41
|
+
"long_press",
|
|
42
|
+
"swipe",
|
|
43
|
+
"back",
|
|
44
|
+
"home",
|
|
45
|
+
"launch_app",
|
|
46
|
+
"get_current_app",
|
|
47
|
+
"type_text",
|
|
48
|
+
"clear_text",
|
|
49
|
+
"detect_and_set_adb_keyboard",
|
|
50
|
+
"restore_keyboard",
|
|
51
|
+
"Screenshot",
|
|
52
|
+
"get_screenshot",
|
|
53
|
+
]
|
AutoGLM_GUI/adb/apps.py
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"""App name to package name mapping for supported applications."""
|
|
2
|
+
|
|
3
|
+
APP_PACKAGES: dict[str, str] = {
|
|
4
|
+
# Social & Messaging
|
|
5
|
+
"微信": "com.tencent.mm",
|
|
6
|
+
"QQ": "com.tencent.mobileqq",
|
|
7
|
+
"微博": "com.sina.weibo",
|
|
8
|
+
# E-commerce
|
|
9
|
+
"淘宝": "com.taobao.taobao",
|
|
10
|
+
"京东": "com.jingdong.app.mall",
|
|
11
|
+
"拼多多": "com.xunmeng.pinduoduo",
|
|
12
|
+
"淘宝闪购": "com.taobao.taobao",
|
|
13
|
+
"京东秒送": "com.jingdong.app.mall",
|
|
14
|
+
# Lifestyle & Social
|
|
15
|
+
"小红书": "com.xingin.xhs",
|
|
16
|
+
"豆瓣": "com.douban.frodo",
|
|
17
|
+
"知乎": "com.zhihu.android",
|
|
18
|
+
# Maps & Navigation
|
|
19
|
+
"高德地图": "com.autonavi.minimap",
|
|
20
|
+
"百度地图": "com.baidu.BaiduMap",
|
|
21
|
+
# Food & Services
|
|
22
|
+
"美团": "com.sankuai.meituan",
|
|
23
|
+
"大众点评": "com.dianping.v1",
|
|
24
|
+
"饿了么": "me.ele",
|
|
25
|
+
"肯德基": "com.yek.android.kfc.activitys",
|
|
26
|
+
# Travel
|
|
27
|
+
"携程": "ctrip.android.view",
|
|
28
|
+
"铁路12306": "com.MobileTicket",
|
|
29
|
+
"12306": "com.MobileTicket",
|
|
30
|
+
"去哪儿": "com.Qunar",
|
|
31
|
+
"去哪儿旅行": "com.Qunar",
|
|
32
|
+
"滴滴出行": "com.sdu.didi.psnger",
|
|
33
|
+
# Video & Entertainment
|
|
34
|
+
"bilibili": "tv.danmaku.bili",
|
|
35
|
+
"抖音": "com.ss.android.ugc.aweme",
|
|
36
|
+
"快手": "com.smile.gifmaker",
|
|
37
|
+
"腾讯视频": "com.tencent.qqlive",
|
|
38
|
+
"爱奇艺": "com.qiyi.video",
|
|
39
|
+
"优酷视频": "com.youku.phone",
|
|
40
|
+
"芒果TV": "com.hunantv.imgo.activity",
|
|
41
|
+
"红果短剧": "com.phoenix.read",
|
|
42
|
+
# Music & Audio
|
|
43
|
+
"网易云音乐": "com.netease.cloudmusic",
|
|
44
|
+
"QQ音乐": "com.tencent.qqmusic",
|
|
45
|
+
"汽水音乐": "com.luna.music",
|
|
46
|
+
"喜马拉雅": "com.ximalaya.ting.android",
|
|
47
|
+
# Reading
|
|
48
|
+
"番茄小说": "com.dragon.read",
|
|
49
|
+
"番茄免费小说": "com.dragon.read",
|
|
50
|
+
"七猫免费小说": "com.kmxs.reader",
|
|
51
|
+
# Productivity
|
|
52
|
+
"飞书": "com.ss.android.lark",
|
|
53
|
+
"QQ邮箱": "com.tencent.androidqqmail",
|
|
54
|
+
# AI & Tools
|
|
55
|
+
"豆包": "com.larus.nova",
|
|
56
|
+
# Health & Fitness
|
|
57
|
+
"keep": "com.gotokeep.keep",
|
|
58
|
+
"美柚": "com.lingan.seeyou",
|
|
59
|
+
# News & Information
|
|
60
|
+
"腾讯新闻": "com.tencent.news",
|
|
61
|
+
"今日头条": "com.ss.android.article.news",
|
|
62
|
+
# Real Estate
|
|
63
|
+
"贝壳找房": "com.lianjia.beike",
|
|
64
|
+
"安居客": "com.anjuke.android.app",
|
|
65
|
+
# Finance
|
|
66
|
+
"同花顺": "com.hexin.plat.android",
|
|
67
|
+
# Games
|
|
68
|
+
"星穹铁道": "com.miHoYo.hkrpg",
|
|
69
|
+
"崩坏:星穹铁道": "com.miHoYo.hkrpg",
|
|
70
|
+
"恋与深空": "com.papegames.lysk.cn",
|
|
71
|
+
"AndroidSystemSettings": "com.android.settings",
|
|
72
|
+
"Android System Settings": "com.android.settings",
|
|
73
|
+
"Android System Settings": "com.android.settings",
|
|
74
|
+
"Android-System-Settings": "com.android.settings",
|
|
75
|
+
"Settings": "com.android.settings",
|
|
76
|
+
"AudioRecorder": "com.android.soundrecorder",
|
|
77
|
+
"audiorecorder": "com.android.soundrecorder",
|
|
78
|
+
"Bluecoins": "com.rammigsoftware.bluecoins",
|
|
79
|
+
"bluecoins": "com.rammigsoftware.bluecoins",
|
|
80
|
+
"Broccoli": "com.flauschcode.broccoli",
|
|
81
|
+
"broccoli": "com.flauschcode.broccoli",
|
|
82
|
+
"Booking.com": "com.booking",
|
|
83
|
+
"Booking": "com.booking",
|
|
84
|
+
"booking.com": "com.booking",
|
|
85
|
+
"booking": "com.booking",
|
|
86
|
+
"BOOKING.COM": "com.booking",
|
|
87
|
+
"Chrome": "com.android.chrome",
|
|
88
|
+
"chrome": "com.android.chrome",
|
|
89
|
+
"Google Chrome": "com.android.chrome",
|
|
90
|
+
"Clock": "com.android.deskclock",
|
|
91
|
+
"clock": "com.android.deskclock",
|
|
92
|
+
"Contacts": "com.android.contacts",
|
|
93
|
+
"contacts": "com.android.contacts",
|
|
94
|
+
"Duolingo": "com.duolingo",
|
|
95
|
+
"duolingo": "com.duolingo",
|
|
96
|
+
"Expedia": "com.expedia.bookings",
|
|
97
|
+
"expedia": "com.expedia.bookings",
|
|
98
|
+
"Files": "com.android.fileexplorer",
|
|
99
|
+
"files": "com.android.fileexplorer",
|
|
100
|
+
"File Manager": "com.android.fileexplorer",
|
|
101
|
+
"file manager": "com.android.fileexplorer",
|
|
102
|
+
"gmail": "com.google.android.gm",
|
|
103
|
+
"Gmail": "com.google.android.gm",
|
|
104
|
+
"GoogleMail": "com.google.android.gm",
|
|
105
|
+
"Google Mail": "com.google.android.gm",
|
|
106
|
+
"GoogleFiles": "com.google.android.apps.nbu.files",
|
|
107
|
+
"googlefiles": "com.google.android.apps.nbu.files",
|
|
108
|
+
"FilesbyGoogle": "com.google.android.apps.nbu.files",
|
|
109
|
+
"GoogleCalendar": "com.google.android.calendar",
|
|
110
|
+
"Google-Calendar": "com.google.android.calendar",
|
|
111
|
+
"Google Calendar": "com.google.android.calendar",
|
|
112
|
+
"google-calendar": "com.google.android.calendar",
|
|
113
|
+
"google calendar": "com.google.android.calendar",
|
|
114
|
+
"GoogleChat": "com.google.android.apps.dynamite",
|
|
115
|
+
"Google Chat": "com.google.android.apps.dynamite",
|
|
116
|
+
"Google-Chat": "com.google.android.apps.dynamite",
|
|
117
|
+
"GoogleClock": "com.google.android.deskclock",
|
|
118
|
+
"Google Clock": "com.google.android.deskclock",
|
|
119
|
+
"Google-Clock": "com.google.android.deskclock",
|
|
120
|
+
"GoogleContacts": "com.google.android.contacts",
|
|
121
|
+
"Google-Contacts": "com.google.android.contacts",
|
|
122
|
+
"Google Contacts": "com.google.android.contacts",
|
|
123
|
+
"google-contacts": "com.google.android.contacts",
|
|
124
|
+
"google contacts": "com.google.android.contacts",
|
|
125
|
+
"GoogleDocs": "com.google.android.apps.docs.editors.docs",
|
|
126
|
+
"Google Docs": "com.google.android.apps.docs.editors.docs",
|
|
127
|
+
"googledocs": "com.google.android.apps.docs.editors.docs",
|
|
128
|
+
"google docs": "com.google.android.apps.docs.editors.docs",
|
|
129
|
+
"Google Drive": "com.google.android.apps.docs",
|
|
130
|
+
"Google-Drive": "com.google.android.apps.docs",
|
|
131
|
+
"google drive": "com.google.android.apps.docs",
|
|
132
|
+
"google-drive": "com.google.android.apps.docs",
|
|
133
|
+
"GoogleDrive": "com.google.android.apps.docs",
|
|
134
|
+
"Googledrive": "com.google.android.apps.docs",
|
|
135
|
+
"googledrive": "com.google.android.apps.docs",
|
|
136
|
+
"GoogleFit": "com.google.android.apps.fitness",
|
|
137
|
+
"googlefit": "com.google.android.apps.fitness",
|
|
138
|
+
"GoogleKeep": "com.google.android.keep",
|
|
139
|
+
"googlekeep": "com.google.android.keep",
|
|
140
|
+
"GoogleMaps": "com.google.android.apps.maps",
|
|
141
|
+
"Google Maps": "com.google.android.apps.maps",
|
|
142
|
+
"googlemaps": "com.google.android.apps.maps",
|
|
143
|
+
"google maps": "com.google.android.apps.maps",
|
|
144
|
+
"Google Play Books": "com.google.android.apps.books",
|
|
145
|
+
"Google-Play-Books": "com.google.android.apps.books",
|
|
146
|
+
"google play books": "com.google.android.apps.books",
|
|
147
|
+
"google-play-books": "com.google.android.apps.books",
|
|
148
|
+
"GooglePlayBooks": "com.google.android.apps.books",
|
|
149
|
+
"googleplaybooks": "com.google.android.apps.books",
|
|
150
|
+
"GooglePlayStore": "com.android.vending",
|
|
151
|
+
"Google Play Store": "com.android.vending",
|
|
152
|
+
"Google-Play-Store": "com.android.vending",
|
|
153
|
+
"GoogleSlides": "com.google.android.apps.docs.editors.slides",
|
|
154
|
+
"Google Slides": "com.google.android.apps.docs.editors.slides",
|
|
155
|
+
"Google-Slides": "com.google.android.apps.docs.editors.slides",
|
|
156
|
+
"GoogleTasks": "com.google.android.apps.tasks",
|
|
157
|
+
"Google Tasks": "com.google.android.apps.tasks",
|
|
158
|
+
"Google-Tasks": "com.google.android.apps.tasks",
|
|
159
|
+
"Joplin": "net.cozic.joplin",
|
|
160
|
+
"joplin": "net.cozic.joplin",
|
|
161
|
+
"McDonald": "com.mcdonalds.app",
|
|
162
|
+
"mcdonald": "com.mcdonalds.app",
|
|
163
|
+
"Osmand": "net.osmand",
|
|
164
|
+
"osmand": "net.osmand",
|
|
165
|
+
"PiMusicPlayer": "com.Project100Pi.themusicplayer",
|
|
166
|
+
"pimusicplayer": "com.Project100Pi.themusicplayer",
|
|
167
|
+
"Quora": "com.quora.android",
|
|
168
|
+
"quora": "com.quora.android",
|
|
169
|
+
"Reddit": "com.reddit.frontpage",
|
|
170
|
+
"reddit": "com.reddit.frontpage",
|
|
171
|
+
"RetroMusic": "code.name.monkey.retromusic",
|
|
172
|
+
"retromusic": "code.name.monkey.retromusic",
|
|
173
|
+
"SimpleCalendarPro": "com.scientificcalculatorplus.simplecalculator.basiccalculator.mathcalc",
|
|
174
|
+
"SimpleSMSMessenger": "com.simplemobiletools.smsmessenger",
|
|
175
|
+
"Telegram": "org.telegram.messenger",
|
|
176
|
+
"temu": "com.einnovation.temu",
|
|
177
|
+
"Temu": "com.einnovation.temu",
|
|
178
|
+
"Tiktok": "com.zhiliaoapp.musically",
|
|
179
|
+
"tiktok": "com.zhiliaoapp.musically",
|
|
180
|
+
"Twitter": "com.twitter.android",
|
|
181
|
+
"twitter": "com.twitter.android",
|
|
182
|
+
"X": "com.twitter.android",
|
|
183
|
+
"VLC": "org.videolan.vlc",
|
|
184
|
+
"WeChat": "com.tencent.mm",
|
|
185
|
+
"wechat": "com.tencent.mm",
|
|
186
|
+
"Whatsapp": "com.whatsapp",
|
|
187
|
+
"WhatsApp": "com.whatsapp",
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def get_package_name(app_name: str) -> str | None:
|
|
192
|
+
"""
|
|
193
|
+
Get the package name for an app.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
app_name: The display name of the app.
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
The Android package name, or None if not found.
|
|
200
|
+
"""
|
|
201
|
+
return APP_PACKAGES.get(app_name)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def get_app_name(package_name: str) -> str | None:
|
|
205
|
+
"""
|
|
206
|
+
Get the app name from a package name.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
package_name: The Android package name.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
The display name of the app, or None if not found.
|
|
213
|
+
"""
|
|
214
|
+
for name, package in APP_PACKAGES.items():
|
|
215
|
+
if package == package_name:
|
|
216
|
+
return name
|
|
217
|
+
return None
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def list_supported_apps() -> list[str]:
|
|
221
|
+
"""
|
|
222
|
+
Get a list of all supported app names.
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
List of app names.
|
|
226
|
+
"""
|
|
227
|
+
return list(APP_PACKAGES.keys())
|