midscene 0.1.0__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.
- midscene-0.1.0/LICENSE +21 -0
- midscene-0.1.0/PKG-INFO +574 -0
- midscene-0.1.0/README.md +518 -0
- midscene-0.1.0/pyproject.toml +97 -0
- midscene-0.1.0/setup.cfg +4 -0
- midscene-0.1.0/src/midscene/__init__.py +73 -0
- midscene-0.1.0/src/midscene/_node_driver/android/service/package.json +13 -0
- midscene-0.1.0/src/midscene/_node_driver/android/service/service.js +470 -0
- midscene-0.1.0/src/midscene/_node_driver/web/service/package.json +14 -0
- midscene-0.1.0/src/midscene/_node_driver/web/service/service.js +405 -0
- midscene-0.1.0/src/midscene/_pytest_plugin.py +168 -0
- midscene-0.1.0/src/midscene/_pytest_support.py +98 -0
- midscene-0.1.0/src/midscene/agent_android.py +103 -0
- midscene-0.1.0/src/midscene/agent_web.py +60 -0
- midscene-0.1.0/src/midscene/base_agent.py +212 -0
- midscene-0.1.0/src/midscene/config.py +86 -0
- midscene-0.1.0/src/midscene/drivers.py +70 -0
- midscene-0.1.0/src/midscene/exceptions.py +34 -0
- midscene-0.1.0/src/midscene/node_bootstrap.py +322 -0
- midscene-0.1.0/src/midscene/node_service.py +266 -0
- midscene-0.1.0/src/midscene/py.typed +0 -0
- midscene-0.1.0/src/midscene/runtime.py +373 -0
- midscene-0.1.0/src/midscene.egg-info/PKG-INFO +574 -0
- midscene-0.1.0/src/midscene.egg-info/SOURCES.txt +30 -0
- midscene-0.1.0/src/midscene.egg-info/dependency_links.txt +1 -0
- midscene-0.1.0/src/midscene.egg-info/entry_points.txt +2 -0
- midscene-0.1.0/src/midscene.egg-info/requires.txt +10 -0
- midscene-0.1.0/src/midscene.egg-info/top_level.txt +1 -0
- midscene-0.1.0/tests/test_agent_integration.py +563 -0
- midscene-0.1.0/tests/test_example_integration.py +89 -0
- midscene-0.1.0/tests/test_node_service.py +215 -0
- midscene-0.1.0/tests/test_web_service.py +105 -0
midscene-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 zypdominate
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
midscene-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: midscene
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: AI-powered Android & web UI automation via Midscene.js, bridged into Python
|
|
5
|
+
Author: zypdominate
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 zypdominate
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/zypdominate/midscene-python
|
|
29
|
+
Project-URL: Repository, https://github.com/zypdominate/midscene-python
|
|
30
|
+
Project-URL: Issues, https://github.com/zypdominate/midscene-python/issues
|
|
31
|
+
Project-URL: Changelog, https://github.com/zypdominate/midscene-python/blob/master/CHANGELOG.md
|
|
32
|
+
Keywords: android,web,browser,puppeteer,automation,testing,ai,midscene
|
|
33
|
+
Classifier: Development Status :: 3 - Alpha
|
|
34
|
+
Classifier: Intended Audience :: Developers
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Operating System :: OS Independent
|
|
37
|
+
Classifier: Programming Language :: Python :: 3
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
42
|
+
Classifier: Topic :: Software Development :: Testing
|
|
43
|
+
Requires-Python: >=3.9
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
License-File: LICENSE
|
|
46
|
+
Requires-Dist: python-dotenv>=1.2.1
|
|
47
|
+
Requires-Dist: requests>=2.28
|
|
48
|
+
Requires-Dist: pytest>=8.4.2
|
|
49
|
+
Provides-Extra: dev
|
|
50
|
+
Requires-Dist: build; extra == "dev"
|
|
51
|
+
Requires-Dist: twine; extra == "dev"
|
|
52
|
+
Requires-Dist: ruff; extra == "dev"
|
|
53
|
+
Requires-Dist: mypy; extra == "dev"
|
|
54
|
+
Requires-Dist: types-requests; extra == "dev"
|
|
55
|
+
Dynamic: license-file
|
|
56
|
+
|
|
57
|
+
# Midscene Python
|
|
58
|
+
|
|
59
|
+
[](https://pypi.org/project/midscene/)
|
|
60
|
+
[](https://pypi.org/project/midscene/)
|
|
61
|
+
[](https://github.com/zypdominate/midscene-python/actions/workflows/ci.yml)
|
|
62
|
+
[](LICENSE)
|
|
63
|
+
|
|
64
|
+
将 [Midscene.js](https://github.com/web-infra-dev/midscene) AI 驱动的 UI 自动化能力桥接到 Python 测试框架。
|
|
65
|
+
|
|
66
|
+
无需自行安装 Node.js;无需维护 UI 选择器——用自然语言描述操作,AI 负责定位和执行。
|
|
67
|
+
|
|
68
|
+
单一 `midscene` 包,工程代码按模块划分,同时支持:
|
|
69
|
+
|
|
70
|
+
| 模块 | 能力 | 入口 |
|
|
71
|
+
|------|------|------|
|
|
72
|
+
| `agent_android` | Android 自动化(ADB + `@midscene/android`) | `from midscene import MidsceneAgent` |
|
|
73
|
+
| `agent_web` / `drivers` | 网页自动化(Puppeteer + `@midscene/web`,预留 Playwright/Bridge) | `from midscene import MidsceneWebAgent` |
|
|
74
|
+
| 共享底层 | 配置、异常、Node 运行时桥接、RPC 服务管理、`BaseAgent` | `from midscene import MidsceneConfig, BaseAgent` |
|
|
75
|
+
|
|
76
|
+
> 本 README 以 Android 为主线说明;网页用法见 [网页自动化](#网页自动化)。
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 目录
|
|
81
|
+
|
|
82
|
+
- [架构](#架构)
|
|
83
|
+
- [安装](#安装)
|
|
84
|
+
- [快速开始](#快速开始)
|
|
85
|
+
- [网页自动化](#网页自动化)
|
|
86
|
+
- [pytest 插件](#pytest-插件)
|
|
87
|
+
- [配置](#配置)
|
|
88
|
+
- [API 参考](#api-参考)
|
|
89
|
+
- [异常处理](#异常处理)
|
|
90
|
+
- [开发者指南](#开发者指南)
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 架构
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
Python 测试代码
|
|
98
|
+
└── agent.ai_action("点击登录按钮")
|
|
99
|
+
│
|
|
100
|
+
│ JSON-RPC 2.0(本地回环,无网络开销)
|
|
101
|
+
▼
|
|
102
|
+
midscene(共享底层)
|
|
103
|
+
├── Node 运行时(首次使用自动下载到 ~/.midscene/node_runtime/,android/web 共享)
|
|
104
|
+
├── NodeServiceManager(按平台 ServiceSpec 多实例:android / web 各一个 Node 进程)
|
|
105
|
+
└── BaseAgent(跨平台 ai_action / ai_tap / ai_query / ai_assert …)
|
|
106
|
+
│
|
|
107
|
+
├── MidsceneAgent → @midscene/android → ADB → Android 设备 / 模拟器
|
|
108
|
+
└── MidsceneWebAgent → @midscene/web → Puppeteer → Chromium 浏览器
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**关键特性:**
|
|
112
|
+
|
|
113
|
+
- 每个平台的 Python 进程与其 Node 进程 1:1;同平台多个 Agent 共享一个 Node 进程(通过 sessionId 隔离)
|
|
114
|
+
- android 与 web 各自拥有独立的 Node 服务与缓存命名空间,可并存
|
|
115
|
+
- Python 进程退出时 Node 子进程自动清理
|
|
116
|
+
- 无需系统已安装 `node` 或 `npm`
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 安装
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
pip install midscene
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
> **首次使用**:会按需自动执行 `npm install`(Android 用 `@midscene/android`,Web 用 `@midscene/web` + puppeteer),需要访问 npm registry。只有实际使用的平台才会触发对应安装。
|
|
127
|
+
|
|
128
|
+
**系统要求:**
|
|
129
|
+
|
|
130
|
+
| 条件 | 说明 |
|
|
131
|
+
|------|------|
|
|
132
|
+
| Python | 3.9 及以上 |
|
|
133
|
+
| ADB | 已安装并在 PATH 中(`adb devices` 能看到目标设备) |
|
|
134
|
+
| AI API | 支持 OpenAI 兼容接口的视觉模型(如 qwen-vl-max、GPT-4o) |
|
|
135
|
+
| Node.js | **无需安装**,wheel 内已内置 |
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## 快速开始
|
|
140
|
+
|
|
141
|
+
### 1. 配置 AI 模型
|
|
142
|
+
|
|
143
|
+
推荐使用 `.env` 文件(自动加载,无需 `export`):
|
|
144
|
+
|
|
145
|
+
```ini
|
|
146
|
+
# .env
|
|
147
|
+
MIDSCENE_MODEL_BASE_URL=https://ark.cn-beijing.volces.com/api/v3/
|
|
148
|
+
MIDSCENE_MODEL_API_KEY=ark-your-api-key
|
|
149
|
+
MIDSCENE_MODEL_NAME=doubao-seed-1-6-vision-250815
|
|
150
|
+
MIDSCENE_MODEL_FAMILY=doubao-seed
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 2. 编写测试
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
from midscene import MidsceneAgent
|
|
157
|
+
|
|
158
|
+
# 从 .env 或环境变量自动读取配置
|
|
159
|
+
agent = MidsceneAgent("emulator-5556")
|
|
160
|
+
|
|
161
|
+
with MidsceneAgent("emulator-5556") as agent:
|
|
162
|
+
agent.ai_action("等待应用首页加载完成")
|
|
163
|
+
agent.ai_tap("登录按钮")
|
|
164
|
+
agent.ai_input("用户名输入框", "testuser")
|
|
165
|
+
agent.ai_input("密码输入框", "Test@123456")
|
|
166
|
+
agent.ai_tap("确认登录")
|
|
167
|
+
agent.ai_wait_for("登录成功,显示用户首页", timeout_ms=10000)
|
|
168
|
+
agent.ai_assert("当前页面是用户首页")
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### 3. 在 pytest 中使用
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
# conftest.py
|
|
175
|
+
import pytest
|
|
176
|
+
from midscene import MidsceneAgent
|
|
177
|
+
|
|
178
|
+
@pytest.fixture
|
|
179
|
+
def agent():
|
|
180
|
+
ag = MidsceneAgent("emulator-5556")
|
|
181
|
+
yield ag
|
|
182
|
+
ag.destroy()
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
# test_login.py
|
|
186
|
+
def test_login(agent: MidsceneAgent):
|
|
187
|
+
agent.ai_action("打开登录页面")
|
|
188
|
+
agent.ai_input("用户名", "testuser")
|
|
189
|
+
agent.ai_input("密码", "password")
|
|
190
|
+
agent.ai_tap("登录")
|
|
191
|
+
agent.ai_assert("登录成功,显示用户名 testuser")
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## 网页自动化
|
|
197
|
+
|
|
198
|
+
网页自动化由 `MidsceneWebAgent` 提供,默认使用 Puppeteer 驱动(首次使用会自动安装 `@midscene/web` 与 puppeteer,并下载 Chromium)。
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
from midscene import MidsceneWebAgent
|
|
202
|
+
|
|
203
|
+
agent = MidsceneWebAgent("https://example.com")
|
|
204
|
+
agent.ai_action("在搜索框输入 midscene 并回车")
|
|
205
|
+
agent.ai_assert("搜索结果已展示")
|
|
206
|
+
agent.destroy()
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
选择 / 配置驱动:
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
from midscene import MidsceneWebAgent, PuppeteerDriver
|
|
213
|
+
|
|
214
|
+
# 有头模式 + 指定视口
|
|
215
|
+
agent = MidsceneWebAgent(
|
|
216
|
+
"https://example.com",
|
|
217
|
+
driver=PuppeteerDriver(headless=False, viewport={"width": 1440, "height": 900}),
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# 连接已运行的 Chrome(chrome --remote-debugging-port=9222)
|
|
221
|
+
agent = MidsceneWebAgent(driver=PuppeteerDriver(cdp_endpoint="http://127.0.0.1:9222"))
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
网页专有方法:`goto(url)`、`new_tab(url=None)`、`set_viewport(width, height)`、`ai_hover(locate)`,以及全部跨平台 `ai_*` 方法。`PlaywrightDriver` / `BridgeDriver` 为占位,后续接入。
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## pytest 插件
|
|
229
|
+
|
|
230
|
+
安装 `midscene` 后,pytest 会**自动加载**内置插件,无需额外配置。提供 `midscene_agent`(Android)与 `midscene_web_agent`(Web)两个 fixture。
|
|
231
|
+
|
|
232
|
+
### 内置 fixture:`midscene_agent`
|
|
233
|
+
|
|
234
|
+
无需在 `conftest.py` 中自行声明 fixture,直接在测试函数参数中使用即可:
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
# test_my_app.py
|
|
238
|
+
import pytest
|
|
239
|
+
|
|
240
|
+
@pytest.mark.device
|
|
241
|
+
def test_login(midscene_agent):
|
|
242
|
+
midscene_agent.ai_action("点击登录按钮")
|
|
243
|
+
midscene_agent.ai_input("用户名", "testuser")
|
|
244
|
+
midscene_agent.ai_input("密码", "Test@123456")
|
|
245
|
+
midscene_agent.ai_assert("登录成功,显示用户首页")
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
设备 ID 解析顺序:
|
|
249
|
+
|
|
250
|
+
| 优先级 | 来源 |
|
|
251
|
+
|--------|------|
|
|
252
|
+
| 1 | `--midscene-device` CLI 参数 |
|
|
253
|
+
| 2 | `MIDSCENE_DEVICE_ID` 环境变量 |
|
|
254
|
+
| 3 | `ANDROID_DEVICE_ID` 环境变量 |
|
|
255
|
+
| 4 | 自动选取第一台已连接设备 |
|
|
256
|
+
|
|
257
|
+
### 失败自动截图与报告
|
|
258
|
+
|
|
259
|
+
使用 `midscene_agent` 的测试用例失败时,插件会自动:
|
|
260
|
+
|
|
261
|
+
1. 调用 `get_screenshot()` 将当前屏幕保存为 PNG。
|
|
262
|
+
2. 调用 `get_report_file()` 获取 Midscene HTML 报告路径。
|
|
263
|
+
3. 将上述路径附加到 pytest 报告的 sections(终端 `-v` 输出和 pytest-html 均可见)。
|
|
264
|
+
|
|
265
|
+
截图保存路径示例:
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
midscene_artifacts/tests__test_login__test_login.png
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### CLI 选项
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
# 指定设备
|
|
275
|
+
pytest --midscene-device emulator-5556 tests/ -m device
|
|
276
|
+
|
|
277
|
+
# 自定义截图保存目录
|
|
278
|
+
pytest --midscene-artifact-dir /tmp/ci_artifacts tests/ -m device
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
| 选项 | 默认值 | 说明 |
|
|
282
|
+
|------|--------|------|
|
|
283
|
+
| `--midscene-device` | 自动检测 | `midscene_agent` 使用的 Android 设备 ID |
|
|
284
|
+
| `--midscene-url` | 无 | `midscene_web_agent` 的起始页面 URL(或 `MIDSCENE_WEB_URL`) |
|
|
285
|
+
| `--midscene-headed` | 关闭 | `midscene_web_agent` 以有头模式启动浏览器 |
|
|
286
|
+
| `--midscene-artifact-dir` | `midscene_artifacts/` | 失败截图与报告的保存目录 |
|
|
287
|
+
|
|
288
|
+
`midscene_web_agent` 用法:
|
|
289
|
+
|
|
290
|
+
```python
|
|
291
|
+
def test_search(midscene_web_agent):
|
|
292
|
+
midscene_web_agent.goto("https://example.com")
|
|
293
|
+
midscene_web_agent.ai_action("点击更多信息链接")
|
|
294
|
+
midscene_web_agent.ai_assert("页面已跳转")
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## 配置
|
|
300
|
+
|
|
301
|
+
### MidsceneConfig
|
|
302
|
+
|
|
303
|
+
可以通过环境变量、`.env` 文件或代码直接传入配置:
|
|
304
|
+
|
|
305
|
+
```python
|
|
306
|
+
from midscene import MidsceneAgent, MidsceneConfig
|
|
307
|
+
|
|
308
|
+
# 方式一:从 .env / 环境变量自动读取(推荐)
|
|
309
|
+
agent = MidsceneAgent("emulator-5556")
|
|
310
|
+
|
|
311
|
+
# 方式二:代码直接传入
|
|
312
|
+
config = MidsceneConfig(
|
|
313
|
+
base_url="https://ark.cn-beijing.volces.com/api/v3/",
|
|
314
|
+
api_key="ark-your-api-key",
|
|
315
|
+
model_name="doubao-seed-1-6-vision-250815",
|
|
316
|
+
model_family="doubao-seed",
|
|
317
|
+
)
|
|
318
|
+
agent = MidsceneAgent("emulator-5556", config)
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### 支持的模型家族
|
|
322
|
+
|
|
323
|
+
| `model_family` | 适用模型 | 示例 `model_name` |
|
|
324
|
+
|---|---|---|
|
|
325
|
+
| `openai` | OpenAI GPT 系列 | `gpt-4o` |
|
|
326
|
+
| `qwen` | 阿里通义千问 | `qwen-vl-max` |
|
|
327
|
+
| `doubao` | 字节豆包 | `doubao-vision-pro-32k` |
|
|
328
|
+
| `gemini` | Google Gemini | `gemini-2.0-flash` |
|
|
329
|
+
| `claude` | Anthropic Claude | `claude-opus-4-5` |
|
|
330
|
+
|
|
331
|
+
### 环境变量说明
|
|
332
|
+
|
|
333
|
+
| 变量 | 必填 | 说明 |
|
|
334
|
+
|------|------|------|
|
|
335
|
+
| `MIDSCENE_MODEL_BASE_URL` | ✅ | AI API 的 base URL |
|
|
336
|
+
| `MIDSCENE_MODEL_API_KEY` | ✅ | API Key |
|
|
337
|
+
| `MIDSCENE_MODEL_NAME` | ✅ | 模型名称 |
|
|
338
|
+
| `MIDSCENE_MODEL_FAMILY` | ❌ | 模型家族 |
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## API 参考
|
|
343
|
+
|
|
344
|
+
所有方法均为同步调用,内部通过 JSON-RPC 与 Node.js 微服务通信。
|
|
345
|
+
|
|
346
|
+
### 初始化与销毁
|
|
347
|
+
|
|
348
|
+
```python
|
|
349
|
+
agent = MidsceneAgent(device_id, config=None)
|
|
350
|
+
# device_id : ADB 设备 ID,如 "emulator-5556" 或 "192.168.1.100:5555"
|
|
351
|
+
# config : MidsceneConfig 实例,可选,默认从环境变量读取
|
|
352
|
+
|
|
353
|
+
agent.destroy() # 释放 session,进程退出时自动调用
|
|
354
|
+
agent.is_closed() # 返回 True/False
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Auto Planning
|
|
358
|
+
|
|
359
|
+
```python
|
|
360
|
+
agent.ai_action(prompt: str) -> None
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
AI 自动规划并执行多步操作。适合描述复合目标:
|
|
364
|
+
|
|
365
|
+
```python
|
|
366
|
+
agent.ai_action("打开设置,找到蓝牙选项并开启")
|
|
367
|
+
agent.ai_action("滑动到页面底部,点击'加载更多'")
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### Instant Actions — 精确单步操作
|
|
371
|
+
|
|
372
|
+
比 `ai_action` 更快、更稳定,适合已知元素的直接操作:
|
|
373
|
+
|
|
374
|
+
```python
|
|
375
|
+
agent.ai_tap(locate: str) -> None
|
|
376
|
+
# 点击元素
|
|
377
|
+
agent.ai_tap("屏幕右上角的关闭按钮")
|
|
378
|
+
agent.ai_tap("文字为'立即购买'的按钮")
|
|
379
|
+
|
|
380
|
+
agent.ai_input(locate: str, value: str) -> None
|
|
381
|
+
# 在指定输入框中输入文本(先清空再输入)
|
|
382
|
+
agent.ai_input("搜索框", "midscene python")
|
|
383
|
+
|
|
384
|
+
agent.ai_clear_input(locate: str) -> None
|
|
385
|
+
# 清空输入框内容
|
|
386
|
+
agent.ai_clear_input("用户名输入框")
|
|
387
|
+
|
|
388
|
+
agent.ai_scroll(
|
|
389
|
+
locate: str = None,
|
|
390
|
+
direction: str = "down", # "up" | "down" | "left" | "right"
|
|
391
|
+
scroll_type: str = None,
|
|
392
|
+
distance: int = None,
|
|
393
|
+
) -> None
|
|
394
|
+
# 滚动操作
|
|
395
|
+
agent.ai_scroll("商品列表", direction="down", distance=3)
|
|
396
|
+
|
|
397
|
+
agent.ai_long_press(locate: str, duration: int = None) -> None
|
|
398
|
+
# 长按,duration 单位毫秒
|
|
399
|
+
agent.ai_long_press("消息列表第一条")
|
|
400
|
+
|
|
401
|
+
agent.ai_double_click(locate: str) -> None
|
|
402
|
+
# 双击
|
|
403
|
+
agent.ai_double_click("图片预览区域")
|
|
404
|
+
|
|
405
|
+
agent.ai_keyboard_press(key_name: str, locate: str = None) -> None
|
|
406
|
+
# 模拟按键,如 "Enter"、"Back"、"Home"
|
|
407
|
+
agent.ai_keyboard_press("Enter")
|
|
408
|
+
agent.ai_keyboard_press("Back")
|
|
409
|
+
|
|
410
|
+
agent.ai_pinch(
|
|
411
|
+
direction: str, # "in"(缩小)| "out"(放大)
|
|
412
|
+
locate: str = None,
|
|
413
|
+
distance: int = None,
|
|
414
|
+
duration: int = None,
|
|
415
|
+
) -> None
|
|
416
|
+
# 捏合/张开手势
|
|
417
|
+
agent.ai_pinch("out", locate="地图区域")
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Utility — 断言与数据提取
|
|
421
|
+
|
|
422
|
+
```python
|
|
423
|
+
agent.ai_assert(assertion: str) -> None
|
|
424
|
+
# AI 视觉断言,失败时抛出 AssertionError
|
|
425
|
+
agent.ai_assert("当前页面显示用户名 testuser")
|
|
426
|
+
agent.ai_assert("购物车商品数量为 3")
|
|
427
|
+
|
|
428
|
+
agent.ai_wait_for(assertion: str, timeout_ms: int = 15000) -> None
|
|
429
|
+
# 等待条件满足,超时抛出异常
|
|
430
|
+
agent.ai_wait_for("加载动画消失", timeout_ms=10000)
|
|
431
|
+
agent.ai_wait_for("弹窗出现", timeout_ms=5000)
|
|
432
|
+
|
|
433
|
+
agent.ai_query(data_demand) -> Any
|
|
434
|
+
# 从当前屏幕提取结构化数据
|
|
435
|
+
products = agent.ai_query({"name": "string", "price": "number", "in_stock": "boolean"})
|
|
436
|
+
title = agent.ai_query("页面标题文字")
|
|
437
|
+
|
|
438
|
+
agent.ai_ask(prompt: str) -> Any
|
|
439
|
+
# 自由问答,返回 AI 对当前屏幕的理解
|
|
440
|
+
answer = agent.ai_ask("当前页面的主要功能是什么?")
|
|
441
|
+
|
|
442
|
+
agent.ai_boolean(prompt: str) -> bool
|
|
443
|
+
# 返回布尔值
|
|
444
|
+
is_logged_in = agent.ai_boolean("用户是否已登录?")
|
|
445
|
+
|
|
446
|
+
agent.ai_number(prompt: str) -> Any
|
|
447
|
+
# 返回数字
|
|
448
|
+
count = agent.ai_number("购物车中的商品数量")
|
|
449
|
+
|
|
450
|
+
agent.ai_string(prompt: str) -> str
|
|
451
|
+
# 返回字符串
|
|
452
|
+
username = agent.ai_string("当前登录的用户名")
|
|
453
|
+
|
|
454
|
+
agent.ai_locate(locate_prompt: str) -> Any
|
|
455
|
+
# 定位元素,返回位置信息(坐标等)
|
|
456
|
+
pos = agent.ai_locate("确认按钮")
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### 原生 ADB
|
|
460
|
+
|
|
461
|
+
```python
|
|
462
|
+
agent.run_adb_shell(command: str, timeout_ms: int = None) -> str
|
|
463
|
+
# 执行 adb shell 命令,返回输出文本;timeout_ms 单位为毫秒
|
|
464
|
+
output = agent.run_adb_shell("dumpsys activity top | grep 'ACTIVITY'")
|
|
465
|
+
output = agent.run_adb_shell("pm list packages | grep com.example", timeout_ms=5000)
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
## 异常处理
|
|
471
|
+
|
|
472
|
+
```python
|
|
473
|
+
from midscene import MidsceneRPCError
|
|
474
|
+
|
|
475
|
+
try:
|
|
476
|
+
agent.ai_assert("某个不存在的条件")
|
|
477
|
+
except AssertionError as e:
|
|
478
|
+
# AI 断言失败(pass=False),包含失败原因
|
|
479
|
+
print(f"断言失败: {e}")
|
|
480
|
+
|
|
481
|
+
try:
|
|
482
|
+
agent.ai_action("点击某个按钮")
|
|
483
|
+
except MidsceneRPCError as e:
|
|
484
|
+
# Node.js 侧报错(如设备断开、ADB 错误)
|
|
485
|
+
print(f"RPC 错误 [code={e.code}]: {e}")
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
| 异常 | 触发场景 |
|
|
489
|
+
|------|---------|
|
|
490
|
+
| `AssertionError` | `ai_assert()` 条件不满足 |
|
|
491
|
+
| `MidsceneRPCError` | Node.js 侧业务错误(ADB 断开、元素找不到等) |
|
|
492
|
+
| `MidsceneSetupError` | Node 二进制缺失、npm install 失败、环境变量未配置 |
|
|
493
|
+
| `MidsceneNodeServiceError` | Node.js 服务启动失败或意外退出 |
|
|
494
|
+
| `MidsceneError` | 使用已 `destroy()` 的 Agent |
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
## 开发者指南
|
|
499
|
+
|
|
500
|
+
### 本地开发
|
|
501
|
+
|
|
502
|
+
```bash
|
|
503
|
+
git clone https://github.com/zypdominate/midscene-python
|
|
504
|
+
cd midscene_python
|
|
505
|
+
|
|
506
|
+
# 以可编辑方式安装(含开发工具)
|
|
507
|
+
pip install -e ".[dev]"
|
|
508
|
+
|
|
509
|
+
# 首次运行测试会自动下载 Node 到 ~/.midscene/node_runtime/
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
根目录 `pyproject.toml` 同时承载打包元数据与 ruff / pytest / mypy 配置,并把 `src` 加入 `pythonpath`,因此在根目录直接执行 `pytest` / `ruff check .` / `mypy` 即可。
|
|
513
|
+
|
|
514
|
+
### 运行测试
|
|
515
|
+
|
|
516
|
+
```bash
|
|
517
|
+
# 全部非真机/非浏览器测试(首次需联网下载 Node + npm 依赖)
|
|
518
|
+
pytest -m "not device and not web" -v
|
|
519
|
+
|
|
520
|
+
# 需要真实 Android 设备的测试(需配置好 .env 并连接设备)
|
|
521
|
+
pytest tests/ -m device -v -s
|
|
522
|
+
|
|
523
|
+
# 需要真实浏览器 + AI Key 的网页测试
|
|
524
|
+
pytest tests/ -m web -v -s
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### 构建与发布
|
|
528
|
+
|
|
529
|
+
```bash
|
|
530
|
+
# 构建 py3-none-any wheel + sdist
|
|
531
|
+
python tools/build_wheel.py --clean
|
|
532
|
+
|
|
533
|
+
# 检查并上传 PyPI
|
|
534
|
+
python tools/upload_pypi.py --dry-run
|
|
535
|
+
python tools/upload_pypi.py --require-all --yes
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
### 项目结构
|
|
539
|
+
|
|
540
|
+
```
|
|
541
|
+
src/midscene/
|
|
542
|
+
├── __init__.py # 顶层导出(MidsceneAgent / MidsceneWebAgent / 驱动 / 异常 …)
|
|
543
|
+
├── config.py # MidsceneConfig(环境变量 / .env 支持)
|
|
544
|
+
├── exceptions.py
|
|
545
|
+
├── node_bootstrap.py # 首次运行从 nodejs.org 下载 Node/npm
|
|
546
|
+
├── runtime.py # ServiceSpec + 按平台参数化的 npm install / 缓存
|
|
547
|
+
├── node_service.py # NodeServiceManager(按 spec 名称多实例)
|
|
548
|
+
├── base_agent.py # BaseAgent(跨平台 ai_* 方法 + RPC)
|
|
549
|
+
├── agent_android.py # MidsceneAgent(BaseAgent) + 设备/系统方法
|
|
550
|
+
├── agent_web.py # MidsceneWebAgent(BaseAgent) + goto/new_tab/set_viewport
|
|
551
|
+
├── drivers.py # PuppeteerDriver(实现)+ Playwright/Bridge(占位)
|
|
552
|
+
├── _pytest_plugin.py # midscene_agent / midscene_web_agent fixture + pytest11 入口
|
|
553
|
+
├── _pytest_support.py # pytest 插件共享逻辑(失败截图/报告)
|
|
554
|
+
├── py.typed
|
|
555
|
+
└── _node_driver/
|
|
556
|
+
├── android/service/ # package.json(@midscene/android) + service.js
|
|
557
|
+
└── web/service/ # package.json(@midscene/web + puppeteer) + service.js
|
|
558
|
+
|
|
559
|
+
# 运行时缓存(不在 pip 包内,android/web 共享 Node 运行时):
|
|
560
|
+
# ~/.midscene/node_runtime/ ← Node + npm
|
|
561
|
+
# ~/.midscene/android/node_service/ ← npm install @midscene/android
|
|
562
|
+
# ~/.midscene/web/node_service/ ← npm install @midscene/web + puppeteer
|
|
563
|
+
|
|
564
|
+
tests/ # Android + Web 测试集中在根目录
|
|
565
|
+
tools/
|
|
566
|
+
├── build_wheel.py # 构建 py3-none-any wheel + sdist
|
|
567
|
+
└── upload_pypi.py # 检查 dist/ 并上传 PyPI
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## License
|
|
573
|
+
|
|
574
|
+
MIT
|