autoglm-gui 1.0.2__py3-none-any.whl → 1.2.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/adb_plus/__init__.py +12 -1
- AutoGLM_GUI/adb_plus/mdns.py +192 -0
- AutoGLM_GUI/adb_plus/pair.py +60 -0
- AutoGLM_GUI/adb_plus/qr_pair.py +372 -0
- AutoGLM_GUI/adb_plus/serial.py +61 -2
- AutoGLM_GUI/adb_plus/version.py +81 -0
- AutoGLM_GUI/api/__init__.py +16 -1
- AutoGLM_GUI/api/agents.py +329 -94
- AutoGLM_GUI/api/devices.py +304 -100
- AutoGLM_GUI/api/workflows.py +70 -0
- AutoGLM_GUI/device_manager.py +760 -0
- AutoGLM_GUI/exceptions.py +18 -0
- AutoGLM_GUI/phone_agent_manager.py +549 -0
- AutoGLM_GUI/phone_agent_patches.py +146 -0
- AutoGLM_GUI/schemas.py +380 -2
- AutoGLM_GUI/state.py +21 -0
- AutoGLM_GUI/static/assets/{about-BOnRPlKQ.js → about-PcGX7dIG.js} +1 -1
- AutoGLM_GUI/static/assets/chat-B0FKL2ne.js +124 -0
- AutoGLM_GUI/static/assets/dialog-BSNX0L1i.js +45 -0
- AutoGLM_GUI/static/assets/index-BjYIY--m.css +1 -0
- AutoGLM_GUI/static/assets/index-CnEYDOXp.js +11 -0
- AutoGLM_GUI/static/assets/index-DOt5XNhh.js +1 -0
- AutoGLM_GUI/static/assets/logo-Cyfm06Ym.png +0 -0
- AutoGLM_GUI/static/assets/workflows-B1hgBC_O.js +1 -0
- AutoGLM_GUI/static/favicon.ico +0 -0
- AutoGLM_GUI/static/index.html +9 -2
- AutoGLM_GUI/static/logo-192.png +0 -0
- AutoGLM_GUI/static/logo-512.png +0 -0
- AutoGLM_GUI/workflow_manager.py +181 -0
- {autoglm_gui-1.0.2.dist-info → autoglm_gui-1.2.0.dist-info}/METADATA +80 -35
- {autoglm_gui-1.0.2.dist-info → autoglm_gui-1.2.0.dist-info}/RECORD +34 -19
- AutoGLM_GUI/static/assets/chat-CGW6uMKB.js +0 -149
- AutoGLM_GUI/static/assets/index-CRFVU0eu.js +0 -1
- AutoGLM_GUI/static/assets/index-DH-Dl4tK.js +0 -10
- AutoGLM_GUI/static/assets/index-DzUQ89YC.css +0 -1
- {autoglm_gui-1.0.2.dist-info → autoglm_gui-1.2.0.dist-info}/WHEEL +0 -0
- {autoglm_gui-1.0.2.dist-info → autoglm_gui-1.2.0.dist-info}/entry_points.txt +0 -0
- {autoglm_gui-1.0.2.dist-info → autoglm_gui-1.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a1 as o,r as s,j as t}from"./index-CnEYDOXp.js";function n(){const e=o();return s.useEffect(()=>{e({to:"/chat"})},[e]),t.jsx("div",{className:"p-2",children:t.jsx("h3",{children:"Welcome Home!"})})}export{n as component};
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{c as D,u as S,r as t,l as b,j as e,B as r,d as W,a as F,b as T}from"./index-CnEYDOXp.js";import{P as E,L as f,C as L,a as P,b as z,c as H,T as I,D as q,d as B,e as M,f as _,g as j,I as O,h as R,i as A}from"./dialog-BSNX0L1i.js";const G=[["path",{d:"M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7",key:"1m0v6g"}],["path",{d:"M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z",key:"ohrbg2"}]],J=D("square-pen",G);function U(){const s=S(),[m,g]=t.useState([]),[p,x]=t.useState(!0),[k,o]=t.useState(!1),[c,h]=t.useState(null),[l,i]=t.useState({name:"",text:""}),[w,u]=t.useState(!1);t.useEffect(()=>{d()},[]);const d=async()=>{try{x(!0);const a=await b();g(a.workflows)}catch(a){console.error("Failed to load workflows:",a)}finally{x(!1)}},v=()=>{h(null),i({name:"",text:""}),o(!0)},N=a=>{h(a),i({name:a.name,text:a.text}),o(!0)},C=async()=>{try{u(!0),c?await F(c.uuid,l):await T(l),o(!1),d()}catch(a){console.error("Failed to save workflow:",a)}finally{u(!1)}},y=async a=>{if(window.confirm(s.workflows.deleteConfirm))try{await W(a),d()}catch(n){console.error("Failed to delete workflow:",n)}};return e.jsxs("div",{className:"container mx-auto p-6 max-w-7xl",children:[e.jsxs("div",{className:"flex justify-between items-center mb-6",children:[e.jsx("h1",{className:"text-3xl font-bold",children:s.workflows.title}),e.jsxs(r,{onClick:v,children:[e.jsx(E,{className:"w-4 h-4 mr-2"}),s.workflows.createNew]})]}),p?e.jsx("div",{className:"flex justify-center items-center h-64",children:e.jsx(f,{className:"w-8 h-8 animate-spin text-slate-400"})}):m.length===0?e.jsx("div",{className:"text-center py-12",children:e.jsx("p",{className:"text-slate-500 dark:text-slate-400",children:s.workflows.empty})}):e.jsx("div",{className:"grid gap-4 md:grid-cols-2 lg:grid-cols-3",children:m.map(a=>e.jsxs(L,{className:"hover:shadow-md transition-shadow",children:[e.jsx(P,{children:e.jsx(z,{className:"text-lg",children:a.name})}),e.jsxs(H,{children:[e.jsx("p",{className:"text-sm text-slate-600 dark:text-slate-400 mb-4 line-clamp-3",children:a.text}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(r,{variant:"outline",size:"sm",onClick:()=>N(a),children:[e.jsx(J,{className:"w-3 h-3 mr-1"}),s.common.edit]}),e.jsxs(r,{variant:"destructive",size:"sm",onClick:()=>y(a.uuid),children:[e.jsx(I,{className:"w-3 h-3 mr-1"}),s.common.delete]})]})]})]},a.uuid))}),e.jsx(q,{open:k,onOpenChange:o,children:e.jsxs(B,{className:"sm:max-w-[600px]",children:[e.jsx(M,{children:e.jsx(_,{children:c?s.workflows.edit:s.workflows.create})}),e.jsxs("div",{className:"space-y-4 py-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(j,{htmlFor:"name",children:s.workflows.name}),e.jsx(O,{id:"name",value:l.name,onChange:a=>i(n=>({...n,name:a.target.value})),placeholder:s.workflows.namePlaceholder})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(j,{htmlFor:"text",children:s.workflows.text}),e.jsx(R,{id:"text",value:l.text,onChange:a=>i(n=>({...n,text:a.target.value})),placeholder:s.workflows.textPlaceholder,rows:6,className:"resize-none !rounded-lg"})]})]}),e.jsxs(A,{children:[e.jsx(r,{variant:"outline",onClick:()=>o(!1),children:s.common.cancel}),e.jsx(r,{onClick:C,disabled:!l.name.trim()||!l.text.trim()||w,children:w?e.jsxs(e.Fragment,{children:[e.jsx(f,{className:"w-4 h-4 mr-2 animate-spin"}),s.common.loading]}):s.common.save})]})]})})]})}export{U as component};
|
|
Binary file
|
AutoGLM_GUI/static/index.html
CHANGED
|
@@ -4,8 +4,15 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>AutoGLM GUI</title>
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
|
|
8
|
+
<!-- Favicons -->
|
|
9
|
+
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
|
10
|
+
<link rel="apple-touch-icon" sizes="180x180" href="/logo-192.png" />
|
|
11
|
+
<link rel="icon" type="image/png" sizes="192x192" href="/logo-192.png" />
|
|
12
|
+
<link rel="icon" type="image/png" sizes="512x512" href="/logo-512.png" />
|
|
13
|
+
<meta name="theme-color" content="#f5f1e8" />
|
|
14
|
+
<script type="module" crossorigin src="/assets/index-CnEYDOXp.js"></script>
|
|
15
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BjYIY--m.css">
|
|
9
16
|
</head>
|
|
10
17
|
<body>
|
|
11
18
|
<div id="app"></div>
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"""Workflow 管理模块.
|
|
2
|
+
|
|
3
|
+
Features:
|
|
4
|
+
- 单例模式
|
|
5
|
+
- JSON 文件持久化
|
|
6
|
+
- 基于 mtime 的缓存机制
|
|
7
|
+
- 原子文件写入
|
|
8
|
+
- UUID 生成
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import uuid as uuid_lib
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Optional
|
|
15
|
+
|
|
16
|
+
from AutoGLM_GUI.logger import logger
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class WorkflowManager:
|
|
20
|
+
"""Workflow 管理器(单例模式)."""
|
|
21
|
+
|
|
22
|
+
_instance: Optional["WorkflowManager"] = None
|
|
23
|
+
|
|
24
|
+
def __new__(cls):
|
|
25
|
+
"""单例模式:确保只有一个实例."""
|
|
26
|
+
if cls._instance is None:
|
|
27
|
+
cls._instance = super().__new__(cls)
|
|
28
|
+
return cls._instance
|
|
29
|
+
|
|
30
|
+
def __init__(self):
|
|
31
|
+
"""初始化管理器."""
|
|
32
|
+
if hasattr(self, "_initialized"):
|
|
33
|
+
return
|
|
34
|
+
self._initialized = True
|
|
35
|
+
self._workflows_path = Path.home() / ".config" / "autoglm" / "workflows.json"
|
|
36
|
+
self._file_cache: Optional[list[dict]] = None
|
|
37
|
+
self._file_mtime: Optional[float] = None
|
|
38
|
+
|
|
39
|
+
def list_workflows(self) -> list[dict]:
|
|
40
|
+
"""获取所有 workflows.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
list[dict]: Workflow 列表
|
|
44
|
+
"""
|
|
45
|
+
return self._load_workflows()
|
|
46
|
+
|
|
47
|
+
def get_workflow(self, uuid: str) -> dict | None:
|
|
48
|
+
"""根据 UUID 获取单个 workflow.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
uuid: Workflow UUID
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
dict | None: Workflow 数据,如果不存在则返回 None
|
|
55
|
+
"""
|
|
56
|
+
workflows = self._load_workflows()
|
|
57
|
+
return next((wf for wf in workflows if wf["uuid"] == uuid), None)
|
|
58
|
+
|
|
59
|
+
def create_workflow(self, name: str, text: str) -> dict:
|
|
60
|
+
"""创建新 workflow.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
name: Workflow 名称
|
|
64
|
+
text: Workflow 任务内容
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
dict: 新创建的 workflow
|
|
68
|
+
"""
|
|
69
|
+
workflows = self._load_workflows()
|
|
70
|
+
new_workflow = {
|
|
71
|
+
"uuid": str(uuid_lib.uuid4()),
|
|
72
|
+
"name": name,
|
|
73
|
+
"text": text,
|
|
74
|
+
}
|
|
75
|
+
workflows.append(new_workflow)
|
|
76
|
+
self._save_workflows(workflows)
|
|
77
|
+
logger.info(f"Created workflow: {name} (uuid={new_workflow['uuid']})")
|
|
78
|
+
return new_workflow
|
|
79
|
+
|
|
80
|
+
def update_workflow(self, uuid: str, name: str, text: str) -> dict | None:
|
|
81
|
+
"""更新 workflow.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
uuid: Workflow UUID
|
|
85
|
+
name: 新名称
|
|
86
|
+
text: 新任务内容
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
dict | None: 更新后的 workflow,如果不存在则返回 None
|
|
90
|
+
"""
|
|
91
|
+
workflows = self._load_workflows()
|
|
92
|
+
for wf in workflows:
|
|
93
|
+
if wf["uuid"] == uuid:
|
|
94
|
+
wf["name"] = name
|
|
95
|
+
wf["text"] = text
|
|
96
|
+
self._save_workflows(workflows)
|
|
97
|
+
logger.info(f"Updated workflow: {name} (uuid={uuid})")
|
|
98
|
+
return wf
|
|
99
|
+
logger.warning(f"Workflow not found for update: uuid={uuid}")
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
def delete_workflow(self, uuid: str) -> bool:
|
|
103
|
+
"""删除 workflow.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
uuid: Workflow UUID
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
bool: 删除成功返回 True,不存在返回 False
|
|
110
|
+
"""
|
|
111
|
+
workflows = self._load_workflows()
|
|
112
|
+
original_len = len(workflows)
|
|
113
|
+
workflows = [wf for wf in workflows if wf["uuid"] != uuid]
|
|
114
|
+
if len(workflows) < original_len:
|
|
115
|
+
self._save_workflows(workflows)
|
|
116
|
+
logger.info(f"Deleted workflow: uuid={uuid}")
|
|
117
|
+
return True
|
|
118
|
+
logger.warning(f"Workflow not found for deletion: uuid={uuid}")
|
|
119
|
+
return False
|
|
120
|
+
|
|
121
|
+
def _load_workflows(self) -> list[dict]:
|
|
122
|
+
"""从文件加载(带 mtime 缓存).
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
list[dict]: Workflow 列表
|
|
126
|
+
"""
|
|
127
|
+
if not self._workflows_path.exists():
|
|
128
|
+
return []
|
|
129
|
+
|
|
130
|
+
# 检查缓存
|
|
131
|
+
current_mtime = self._workflows_path.stat().st_mtime
|
|
132
|
+
if self._file_mtime == current_mtime and self._file_cache is not None:
|
|
133
|
+
return self._file_cache.copy()
|
|
134
|
+
|
|
135
|
+
# 重新加载
|
|
136
|
+
try:
|
|
137
|
+
with open(self._workflows_path, "r", encoding="utf-8") as f:
|
|
138
|
+
data = json.load(f)
|
|
139
|
+
workflows = data.get("workflows", [])
|
|
140
|
+
self._file_cache = workflows
|
|
141
|
+
self._file_mtime = current_mtime
|
|
142
|
+
logger.debug(f"Loaded {len(workflows)} workflows from file")
|
|
143
|
+
return workflows.copy()
|
|
144
|
+
except (json.JSONDecodeError, FileNotFoundError) as e:
|
|
145
|
+
logger.warning(f"Failed to load workflows: {e}")
|
|
146
|
+
return []
|
|
147
|
+
|
|
148
|
+
def _save_workflows(self, workflows: list[dict]) -> bool:
|
|
149
|
+
"""原子写入文件.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
workflows: Workflow 列表
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
bool: 保存成功返回 True
|
|
156
|
+
"""
|
|
157
|
+
self._workflows_path.parent.mkdir(parents=True, exist_ok=True)
|
|
158
|
+
|
|
159
|
+
data = {"workflows": workflows}
|
|
160
|
+
|
|
161
|
+
# 原子写入:临时文件 + rename
|
|
162
|
+
temp_path = self._workflows_path.with_suffix(".tmp")
|
|
163
|
+
try:
|
|
164
|
+
with open(temp_path, "w", encoding="utf-8") as f:
|
|
165
|
+
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
166
|
+
temp_path.replace(self._workflows_path)
|
|
167
|
+
|
|
168
|
+
# 更新缓存
|
|
169
|
+
self._file_cache = workflows.copy()
|
|
170
|
+
self._file_mtime = self._workflows_path.stat().st_mtime
|
|
171
|
+
logger.debug(f"Saved {len(workflows)} workflows to file")
|
|
172
|
+
return True
|
|
173
|
+
except Exception as e:
|
|
174
|
+
logger.error(f"Failed to save workflows: {e}")
|
|
175
|
+
if temp_path.exists():
|
|
176
|
+
temp_path.unlink()
|
|
177
|
+
return False
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
# 单例实例
|
|
181
|
+
workflow_manager = WorkflowManager()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: autoglm-gui
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Web GUI for AutoGLM Phone Agent - AI-powered Android automation
|
|
5
5
|
Project-URL: Homepage, https://github.com/suyiiyii/AutoGLM-GUI
|
|
6
6
|
Project-URL: Repository, https://github.com/suyiiyii/AutoGLM-GUI
|
|
@@ -27,12 +27,19 @@ Requires-Dist: openai>=2.9.0
|
|
|
27
27
|
Requires-Dist: pillow>=11.3.0
|
|
28
28
|
Requires-Dist: python-socketio>=5.11.0
|
|
29
29
|
Requires-Dist: uvicorn[standard]>=0.38.0
|
|
30
|
+
Requires-Dist: zeroconf>=0.148.0
|
|
30
31
|
Description-Content-Type: text/markdown
|
|
31
32
|
|
|
33
|
+
<div align="center">
|
|
34
|
+
|
|
35
|
+
<img src="https://github.com/user-attachments/assets/bbdaeb1c-b7f2-4a4b-a11a-34db4de0ba12" alt="autoglm-gui" width="150">
|
|
36
|
+
|
|
32
37
|
# AutoGLM-GUI
|
|
33
38
|
|
|
34
39
|
AutoGLM 手机助手的现代化 Web 图形界面 - 让 AI 自动化操作 Android 设备变得简单
|
|
35
40
|
|
|
41
|
+
**🎉 Android 11+ 设备现已支持完全无线连接,扫码即配对,无需数据线!🎉**
|
|
42
|
+
|
|
36
43
|

|
|
37
44
|

|
|
38
45
|
[](https://pypi.org/project/autoglm-gui/)
|
|
@@ -40,14 +47,21 @@ AutoGLM 手机助手的现代化 Web 图形界面 - 让 AI 自动化操作 Andro
|
|
|
40
47
|
<a href="https://qm.qq.com/q/J5eAs9tn0W" target="__blank">
|
|
41
48
|
<strong>欢迎加入讨论交流群</strong>
|
|
42
49
|
</a>
|
|
50
|
+
|
|
51
|
+
[English Documentation](README_EN.md)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
43
55
|
## ✨ 特性
|
|
44
56
|
|
|
57
|
+
- **完全无线配对** - 🆕 支持 Android 11+ 二维码扫码配对,无需数据线即可连接设备
|
|
45
58
|
- **多设备并发控制** - 同时管理和控制多个 Android 设备,设备间状态完全隔离
|
|
46
59
|
- **对话式任务管理** - 通过聊天界面控制 Android 设备
|
|
60
|
+
- **Workflow 工作流** - 🆕 预定义常用任务,一键快速执行,支持创建、编辑、删除和管理
|
|
47
61
|
- **实时屏幕预览** - 基于 scrcpy 的低延迟视频流,随时查看设备正在执行的操作
|
|
48
62
|
- **直接操控手机** - 在实时画面上直接点击、滑动操作,支持精准坐标转换和视觉反馈
|
|
49
63
|
- **零配置部署** - 支持任何 OpenAI 兼容的 LLM API
|
|
50
|
-
- **ADB 深度集成** - 通过 Android Debug Bridge
|
|
64
|
+
- **ADB 深度集成** - 通过 Android Debug Bridge 直接控制设备(支持 USB 和 WiFi)
|
|
51
65
|
- **模块化界面** - 清晰的侧边栏 + 设备面板设计,功能分离明确
|
|
52
66
|
|
|
53
67
|
## 📥 快速下载
|
|
@@ -58,9 +72,9 @@ AutoGLM 手机助手的现代化 Web 图形界面 - 让 AI 自动化操作 Andro
|
|
|
58
72
|
|
|
59
73
|
| 操作系统 | 下载链接 | 说明 |
|
|
60
74
|
|---------|---------|------|
|
|
61
|
-
| 🪟 **Windows** (x64) | [📦 下载便携版 EXE](https://github.com/suyiiyii/AutoGLM-GUI/releases/download/v1.0
|
|
62
|
-
| 🍎 **macOS** (Apple Silicon) | [📦 下载 DMG](https://github.com/suyiiyii/AutoGLM-GUI/releases/download/v1.0
|
|
63
|
-
| 🐧 **Linux** (x64) | [📦 下载 AppImage](https://github.com/suyiiyii/AutoGLM-GUI/releases/download/v1.0
|
|
75
|
+
| 🪟 **Windows** (x64) | [📦 下载便携版 EXE](https://github.com/suyiiyii/AutoGLM-GUI/releases/download/v1.2.0/AutoGLM.GUI.1.2.0.exe) | 适用于 Windows 10/11,免安装 |
|
|
76
|
+
| 🍎 **macOS** (Apple Silicon) | [📦 下载 DMG](https://github.com/suyiiyii/AutoGLM-GUI/releases/download/v1.2.0/AutoGLM.GUI-1.2.0-arm64.dmg) | 适用于 M 芯片 Mac |
|
|
77
|
+
| 🐧 **Linux** (x64) | [📦 下载 AppImage](https://github.com/suyiiyii/AutoGLM-GUI/releases/download/v1.2.0/AutoGLM.GUI-1.2.0.AppImage) \| [deb](https://github.com/suyiiyii/AutoGLM-GUI/releases/download/v1.2.0/autoglm-gui_1.2.0_amd64.deb) \| [tar.gz](https://github.com/suyiiyii/AutoGLM-GUI/releases/download/v1.2.0/autoglm-gui-1.2.0.tar.gz) | 通用格式,支持主流发行版 |
|
|
64
78
|
|
|
65
79
|
</div>
|
|
66
80
|
|
|
@@ -133,10 +147,14 @@ autoglm-gui --base-url http://localhost:8000/v1 --model autoglm-phone-9b
|
|
|
133
147
|
### 前置要求
|
|
134
148
|
|
|
135
149
|
- Python 3.10+
|
|
136
|
-
-
|
|
137
|
-
- 已安装 ADB 并添加到系统 PATH
|
|
150
|
+
- Android 设备(Android 11+ 支持完全无线配对,无需数据线)
|
|
151
|
+
- 已安装 ADB 并添加到系统 PATH(桌面版已内置)
|
|
138
152
|
- 一个 OpenAI 兼容的 API 端点
|
|
139
153
|
|
|
154
|
+
**关于设备连接**:
|
|
155
|
+
- **Android 11+**:支持二维码扫码配对,完全无需数据线即可连接和控制设备
|
|
156
|
+
- **Android 10 及更低版本**:需要先通过 USB 数据线连接并开启无线调试,之后可拔掉数据线无线使用
|
|
157
|
+
|
|
140
158
|
### 快捷运行(推荐)
|
|
141
159
|
|
|
142
160
|
**无需手动准备环境,直接安装运行:**
|
|
@@ -207,9 +225,33 @@ AutoGLM-GUI 支持同时控制多个 Android 设备:
|
|
|
207
225
|
- ⚪ 灰点:设备离线
|
|
208
226
|
- ✓ 标记:设备已初始化
|
|
209
227
|
|
|
228
|
+
#### 📱 二维码无线配对(Android 11+ 推荐)
|
|
229
|
+
|
|
230
|
+
**完全无需数据线**,手机和电脑只需在同一 WiFi 网络即可:
|
|
231
|
+
|
|
232
|
+
1. **手机端准备**:
|
|
233
|
+
- 打开「设置」→「开发者选项」→ 开启「无线调试」
|
|
234
|
+
- 保持手机和电脑连接到同一个 WiFi 网络
|
|
235
|
+
|
|
236
|
+
2. **电脑端操作**:
|
|
237
|
+
- 点击界面左下角的 ➕ 「添加无线设备」按钮
|
|
238
|
+
- 切换到「配对设备」标签页
|
|
239
|
+
- **二维码自动生成**,等待扫码
|
|
240
|
+
|
|
241
|
+
3. **手机端扫码**:
|
|
242
|
+
- 在「无线调试」页面,点击「使用二维码配对设备」
|
|
243
|
+
- 扫描电脑上显示的二维码
|
|
244
|
+
- 配对成功后,设备会自动出现在设备列表中
|
|
245
|
+
|
|
246
|
+
**特点**:
|
|
247
|
+
- ✅ 完全无需数据线
|
|
248
|
+
- ✅ 一键扫码即可配对
|
|
249
|
+
- ✅ 自动发现并连接设备
|
|
250
|
+
- ✅ 适用于 Android 11 及以上版本
|
|
251
|
+
|
|
210
252
|
### AI 自动化模式
|
|
211
253
|
|
|
212
|
-
1. **连接设备** -
|
|
254
|
+
1. **连接设备** - 使用上述任一方式连接设备(推荐 Android 11+ 的二维码配对)
|
|
213
255
|
2. **选择设备** - 在左侧边栏选择要控制的设备
|
|
214
256
|
3. **初始化** - 点击"初始化设备"按钮配置 Agent
|
|
215
257
|
4. **对话** - 描述你想要做什么(例如:"去美团点一杯霸王茶姬的伯牙绝弦")
|
|
@@ -226,38 +268,41 @@ AutoGLM-GUI 支持同时控制多个 Android 设备:
|
|
|
226
268
|
5. **精准转换** - 自动处理屏幕缩放和坐标转换,确保操作位置准确
|
|
227
269
|
6. **显示模式** - 支持自动、视频流、截图三种显示模式切换
|
|
228
270
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
271
|
+
### Workflow 工作流管理
|
|
272
|
+
|
|
273
|
+
将常用任务保存为 Workflow,实现一键快速执行:
|
|
274
|
+
|
|
275
|
+
#### 创建和管理 Workflow
|
|
276
|
+
|
|
277
|
+
1. **进入管理页面** - 点击左侧导航栏的 Workflows 图标(📋)
|
|
278
|
+
2. **新建 Workflow** - 点击右上角"新建 Workflow"按钮
|
|
279
|
+
3. **填写信息**:
|
|
280
|
+
- **名称**:给 Workflow 起一个简短易记的名称(如:"订购霸王茶姬")
|
|
281
|
+
- **任务内容**:详细描述要执行的任务(如:"去美团点一杯霸王茶姬的伯牙绝弦,要去冰,加珍珠")
|
|
282
|
+
4. **保存** - 点击保存按钮即可
|
|
283
|
+
|
|
284
|
+
**管理操作**:
|
|
285
|
+
- **编辑** - 点击 Workflow 卡片上的"编辑"按钮修改内容
|
|
286
|
+
- **删除** - 点击"删除"按钮移除不需要的 Workflow
|
|
287
|
+
- **预览** - Workflow 卡片显示任务内容的前几行预览
|
|
235
288
|
|
|
236
|
-
|
|
289
|
+
#### 快速执行 Workflow
|
|
237
290
|
|
|
238
|
-
|
|
291
|
+
在 Chat 界面执行已保存的 Workflow:
|
|
239
292
|
|
|
240
|
-
|
|
293
|
+
1. **选择设备** - 确保已选择并初始化目标设备
|
|
294
|
+
2. **打开 Workflow 选择器** - 点击输入框旁边的 Workflow 按钮(📋 图标)
|
|
295
|
+
3. **选择要执行的任务** - 从列表中点击你想执行的 Workflow
|
|
296
|
+
4. **自动填充** - 任务内容会自动填入输入框
|
|
297
|
+
5. **发送执行** - 点击发送按钮开始执行
|
|
241
298
|
|
|
242
|
-
|
|
243
|
-
-
|
|
244
|
-
-
|
|
245
|
-
-
|
|
246
|
-
-
|
|
299
|
+
**使用场景示例**:
|
|
300
|
+
- 📱 **日常任务**:订外卖、打车、查快递
|
|
301
|
+
- 🎮 **游戏操作**:每日签到、领取奖励
|
|
302
|
+
- 📧 **消息发送**:固定内容的消息群发
|
|
303
|
+
- 🔄 **重复操作**:定期执行的维护任务
|
|
247
304
|
|
|
248
|
-
**前端设计**:
|
|
249
|
-
- 使用 `Map<string, DeviceState>` 管理每个设备的独立状态
|
|
250
|
-
- 组件化设计,功能职责清晰分离:
|
|
251
|
-
- `DeviceCard` - 单个设备信息卡片
|
|
252
|
-
- `DeviceSidebar` - 设备列表侧边栏
|
|
253
|
-
- `DevicePanel` - 设备操作面板(ChatBox + Screen Monitor)
|
|
254
|
-
- 设备状态完全隔离,互不影响
|
|
255
305
|
|
|
256
|
-
**核心特点**:
|
|
257
|
-
- ✅ 无任务队列,简化设计
|
|
258
|
-
- ✅ 无复杂调度,每个设备独立运行
|
|
259
|
-
- ✅ 实时 WebSocket 通信,支持流式响应
|
|
260
|
-
- ✅ 自动设备发现和状态同步(每 3 秒刷新)
|
|
261
306
|
|
|
262
307
|
## 🛠️ 开发指南
|
|
263
308
|
|
|
@@ -287,7 +332,7 @@ Apache License 2.0
|
|
|
287
332
|
|
|
288
333
|
### 许可证说明
|
|
289
334
|
|
|
290
|
-
AutoGLM-GUI
|
|
335
|
+
AutoGLM-GUI 打包了 ADB Keyboard APK (`com.android.adbkeyboard`),该组件使用 GPL-2.0 许可证。ADB Keyboard 组件作为独立工具使用,不影响 AutoGLM-GUI 本身的 MIT 许可。
|
|
291
336
|
|
|
292
337
|
详见:`AutoGLM_GUI/resources/apks/ADBKeyBoard.LICENSE.txt`
|
|
293
338
|
|
|
@@ -2,36 +2,51 @@ AutoGLM_GUI/__init__.py,sha256=ic002QIj6sw9cyhh7e_60DFIb7omtPcF01-L6M4lllM,2176
|
|
|
2
2
|
AutoGLM_GUI/__main__.py,sha256=ogFi2KO9kCn47ZvT5jqBzoBTnqG191TFKfEM9lcal1w,6390
|
|
3
3
|
AutoGLM_GUI/config.py,sha256=SRBPcIKqR5HxrxiiwpOUAPxHvp-36igtFhDEptG_Zz4,619
|
|
4
4
|
AutoGLM_GUI/config_manager.py,sha256=xbiwKbg6XuXps21pstVRPlGzRbVEzSx5p0-ElnEP8hg,17625
|
|
5
|
-
AutoGLM_GUI/
|
|
5
|
+
AutoGLM_GUI/device_manager.py,sha256=dAHP29a63H6GY43f715dOlJdwOz1eWa2XnPf2_SbIiY,26923
|
|
6
|
+
AutoGLM_GUI/exceptions.py,sha256=YnN1qJdWgC8LholEGd3nman2G-ylXgcUdZJdilsHf8A,499
|
|
6
7
|
AutoGLM_GUI/logger.py,sha256=wLzjbRqsHAsOtI9yB0bcUZFVzgGK6qM8330std6FjVw,2553
|
|
8
|
+
AutoGLM_GUI/phone_agent_manager.py,sha256=bun1DUqCRGwIKsTVeBKI6U09nHtWZRuSTYhCWlLfTnI,18104
|
|
9
|
+
AutoGLM_GUI/phone_agent_patches.py,sha256=-RfpL9RHxOI2GyC2v8L49S0gXiK8l1cldEX3Ysrpl5c,4887
|
|
7
10
|
AutoGLM_GUI/platform_utils.py,sha256=bYlQGAYYpU1ZqOUD-F-fIzpEA5z53dMFfaErsFhAvYk,2357
|
|
8
|
-
AutoGLM_GUI/schemas.py,sha256=
|
|
11
|
+
AutoGLM_GUI/schemas.py,sha256=BPXf4XhzTfKqFKA8jZklQ2XFGQA7n4uJPx70omfxn8c,15432
|
|
9
12
|
AutoGLM_GUI/scrcpy_protocol.py,sha256=h6AtAGq3zMM30FWM7EYiYKJz7BDikpNCOjcKtFcRx3s,997
|
|
10
13
|
AutoGLM_GUI/scrcpy_stream.py,sha256=-tGyDNaML1TnZLzTNiVUgxMTv_7TQS0CKZ35G2RuPfg,16595
|
|
11
14
|
AutoGLM_GUI/server.py,sha256=GGGz7llG5rflIpO61nil8Zde12PLkv6OIzghuxwSkoI,249
|
|
12
15
|
AutoGLM_GUI/socketio_server.py,sha256=__fWLlqBYFFl1YXanm8Vls-_Wr8pQ68kU7N_3q4WZfY,3535
|
|
13
|
-
AutoGLM_GUI/state.py,sha256=
|
|
16
|
+
AutoGLM_GUI/state.py,sha256=ziw-t69JrojUOfzuNmVrZPc6J3-adBFpN4J3Xhq1sdU,1825
|
|
14
17
|
AutoGLM_GUI/version.py,sha256=z0MPXu-k9UO7RXxVGcAwim2M3yklrRqLwgOq66zSdzo,178
|
|
15
|
-
AutoGLM_GUI/
|
|
18
|
+
AutoGLM_GUI/workflow_manager.py,sha256=AZ_zrhSeEvtlF1HTNMNS3f4qBwRuX-bzImdZEVZVXV8,5552
|
|
19
|
+
AutoGLM_GUI/adb_plus/__init__.py,sha256=4F4IIRejvrNArMi1xoyMmSLpsQcC3iy-frBEPXkNR5w,945
|
|
16
20
|
AutoGLM_GUI/adb_plus/device.py,sha256=nCMDUd18LPfl5CsJeDjKd9HSt6FFOy2jS1muOSeLO08,1683
|
|
17
21
|
AutoGLM_GUI/adb_plus/ip.py,sha256=dt6ffIjiW_jGoEqUKUDi9fRGbWN1W9LxfT8rWIqgS-0,2200
|
|
18
22
|
AutoGLM_GUI/adb_plus/keyboard_installer.py,sha256=dsQqLgWd2kkTeljdTTT77mFwJpcM-IJecMcJJEutbHo,13541
|
|
23
|
+
AutoGLM_GUI/adb_plus/mdns.py,sha256=AwQ4MQsPKVW1tPjIUpOWvBQGlJxvVrO9eTvxoqsgPUo,5862
|
|
24
|
+
AutoGLM_GUI/adb_plus/pair.py,sha256=3UElG0yjylhmZBtPpDER2BNMZs9CwDeavjuQOwOC4sw,1945
|
|
25
|
+
AutoGLM_GUI/adb_plus/qr_pair.py,sha256=K0Jnn5FcuQVU7cM74BTi7WdKh3UF9H85qyua9YPwIEE,13574
|
|
19
26
|
AutoGLM_GUI/adb_plus/screenshot.py,sha256=pr7BpmUcGZO9rthpDeMRn4D1oAGX9aEEVL3ZnTQzrIo,3211
|
|
20
|
-
AutoGLM_GUI/adb_plus/serial.py,sha256=
|
|
27
|
+
AutoGLM_GUI/adb_plus/serial.py,sha256=lDbBXTIoOJ5lbFj50K5X7PZnfpKt1vRpFiWVjolfEhQ,3142
|
|
21
28
|
AutoGLM_GUI/adb_plus/touch.py,sha256=7cyMon9nOd6zQvZdHK7BHWoRLLWkdK-qWfTuSFfFzJA,2301
|
|
22
|
-
AutoGLM_GUI/
|
|
23
|
-
AutoGLM_GUI/api/
|
|
29
|
+
AutoGLM_GUI/adb_plus/version.py,sha256=u5u1N40izJceeORN9kFhyz0wq_hZtlwBXaiytfA3px8,2428
|
|
30
|
+
AutoGLM_GUI/api/__init__.py,sha256=q9cF2jHvAvJu-Sme1Edf8K3EP9CpYNCOSkaSCvevS5k,2844
|
|
31
|
+
AutoGLM_GUI/api/agents.py,sha256=co7Viu6iqg9-TXxMUCkxy-O0CrXnf0HmZiT-l3_Q6eo,21541
|
|
24
32
|
AutoGLM_GUI/api/control.py,sha256=G-7hfdqTl5fq-UXOwE2CI_HMbfmRH1Vd589t2FTNZyY,3155
|
|
25
|
-
AutoGLM_GUI/api/devices.py,sha256=
|
|
33
|
+
AutoGLM_GUI/api/devices.py,sha256=AzHUwFGjaj5xaHMmDylyNy0CUGZQHwlCdE3t41azqQk,11186
|
|
26
34
|
AutoGLM_GUI/api/media.py,sha256=Ioncwd68CNkYvqmeTJJ3P5I1rjWfw6PM4WPz5Ixx8vI,1631
|
|
27
35
|
AutoGLM_GUI/api/version.py,sha256=ZN99iH2PA_qx5A1fnSEO-Yihh4K7Bc4r1jOnP6IcXZo,5861
|
|
28
|
-
AutoGLM_GUI/
|
|
29
|
-
AutoGLM_GUI/static/
|
|
30
|
-
AutoGLM_GUI/static/
|
|
31
|
-
AutoGLM_GUI/static/
|
|
32
|
-
AutoGLM_GUI/static/
|
|
33
|
-
AutoGLM_GUI/static/assets/
|
|
36
|
+
AutoGLM_GUI/api/workflows.py,sha256=dis4k8b-xTYL99qlSYev-Qo5a7z9XdwA1xyC8fRJGLE,2360
|
|
37
|
+
AutoGLM_GUI/static/favicon.ico,sha256=uB4wrcENiFaF-K4V-FzNp51XLW8GC4-ujpBDHgISfGM,781
|
|
38
|
+
AutoGLM_GUI/static/index.html,sha256=r9j_w8jMNg1lonFuSWcAizyt2paPp6eQhxrfa5-NF94,761
|
|
39
|
+
AutoGLM_GUI/static/logo-192.png,sha256=FOXgZxFrN0ZleO0VjlCnvD5cDkd1okJPkwPDZqsflNs,35243
|
|
40
|
+
AutoGLM_GUI/static/logo-512.png,sha256=HlwSg09dQ3_Jtb09Ght4l2VK3YNLZlP_941LCdpDkWk,251598
|
|
41
|
+
AutoGLM_GUI/static/assets/about-PcGX7dIG.js,sha256=161N6amC89mHQ20_n3CnP3tVEllFHuxW-2TQYuY8u_A,155
|
|
42
|
+
AutoGLM_GUI/static/assets/chat-B0FKL2ne.js,sha256=Nag9CL0f8h9LuZgWm0HjwhzqktIPpm_auOAD0H_TpzY,270658
|
|
43
|
+
AutoGLM_GUI/static/assets/dialog-BSNX0L1i.js,sha256=3qF7evfcz9DgCt7X6z-sdti08Q07ZuFZHLLsA7sjoqM,27348
|
|
44
|
+
AutoGLM_GUI/static/assets/index-BjYIY--m.css,sha256=VOiK2srNO8IUiVRALg1ew8UvkNQH7GvaR-pTltZlSDw,74549
|
|
45
|
+
AutoGLM_GUI/static/assets/index-CnEYDOXp.js,sha256=VrISJRc0U1fFPnvnjKxdyqQOhoXAjE60B2YMjWRoKko,380923
|
|
46
|
+
AutoGLM_GUI/static/assets/index-DOt5XNhh.js,sha256=F7m5yI5zjW-iE8cVikyg_eHQL3AMSstRbI0Nxor8mVg,229
|
|
47
|
+
AutoGLM_GUI/static/assets/logo-Cyfm06Ym.png,sha256=6GRUFH2KNmB4ZmnrmJ1wxpoIYEmOW-__XlmKImyAMKM,4955675
|
|
34
48
|
AutoGLM_GUI/static/assets/worker-D6BRitjy.js,sha256=RL1NIRIks9dXdDhXOHK1cCg-OELT0uv9a6u_UEHfQ0Q,173494
|
|
49
|
+
AutoGLM_GUI/static/assets/workflows-B1hgBC_O.js,sha256=RWOePaljNY8UFnn_V37p7x8rU2bm9D-HTWm5S9kWrHY,3459
|
|
35
50
|
phone_agent/__init__.py,sha256=7sCmGiY-ePdb6L08MGG6DkOiu8goop6wq-v2SiM62tE,360
|
|
36
51
|
phone_agent/agent.py,sha256=1SgHpv70_XbujG1ElYRZbvRO5-d4l7gBgiFRBz_FIH8,8157
|
|
37
52
|
phone_agent/agent_ios.py,sha256=R7EBsoHVghEUBtI5TB7M0_btpFcb4NHquMNxktrqrJE,9338
|
|
@@ -66,8 +81,8 @@ phone_agent/xctest/device.py,sha256=sOAPMoliMIabcrtsmzuGDKnZXtitqlc0lo8RSjQta7A,
|
|
|
66
81
|
phone_agent/xctest/input.py,sha256=aMp1YCRGBtGsRMKhA9rrjxuLkri0_k3n6hisi0EBJ2o,8164
|
|
67
82
|
phone_agent/xctest/screenshot.py,sha256=H6dsQGgf38h8dvuSeigiR2Qr8NucPanIgTK8kjlV9hA,6027
|
|
68
83
|
scrcpy-server-v3.3.3,sha256=fnAyO6fyWWSd1KzOl6xP77roECssbZHi575hP9U1S-A,90164
|
|
69
|
-
autoglm_gui-1.0.
|
|
70
|
-
autoglm_gui-1.0.
|
|
71
|
-
autoglm_gui-1.0.
|
|
72
|
-
autoglm_gui-1.0.
|
|
73
|
-
autoglm_gui-1.0.
|
|
84
|
+
autoglm_gui-1.2.0.dist-info/METADATA,sha256=j4fQlaQmNuPSzFfj9_-u8jDrxqvIVMGRkPY7arrSBWM,12453
|
|
85
|
+
autoglm_gui-1.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
86
|
+
autoglm_gui-1.2.0.dist-info/entry_points.txt,sha256=sz4rBO_kgrYmOiT0QnhCCv0b9QqBdWyCjugJgY8AEOI,58
|
|
87
|
+
autoglm_gui-1.2.0.dist-info/licenses/LICENSE,sha256=0IkSHDewdtmXnmYzTNq4U47EJYjTuhjQNpT0bZKuqWc,11342
|
|
88
|
+
autoglm_gui-1.2.0.dist-info/RECORD,,
|