mobile-mcp-ai 2.1.2__py3-none-any.whl → 2.5.8__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.
- mobile_mcp/__init__.py +34 -0
- mobile_mcp/config.py +142 -0
- mobile_mcp/core/basic_tools_lite.py +3266 -0
- {core → mobile_mcp/core}/device_manager.py +2 -2
- mobile_mcp/core/dynamic_config.py +272 -0
- mobile_mcp/core/ios_client_wda.py +569 -0
- mobile_mcp/core/ios_device_manager_wda.py +306 -0
- {core → mobile_mcp/core}/mobile_client.py +279 -39
- mobile_mcp/core/template_matcher.py +429 -0
- mobile_mcp/core/templates/close_buttons/auto_x_0112_151217.png +0 -0
- mobile_mcp/core/templates/close_buttons/auto_x_0112_152037.png +0 -0
- mobile_mcp/core/templates/close_buttons/auto_x_0112_152840.png +0 -0
- mobile_mcp/core/templates/close_buttons/auto_x_0112_153256.png +0 -0
- mobile_mcp/core/templates/close_buttons/auto_x_0112_154847.png +0 -0
- mobile_mcp/core/templates/close_buttons/gray_x_stock_ad.png +0 -0
- {core → mobile_mcp/core}/utils/smart_wait.py +3 -3
- mobile_mcp/mcp_tools/__init__.py +10 -0
- mobile_mcp/mcp_tools/mcp_server.py +1071 -0
- mobile_mcp_ai-2.5.8.dist-info/METADATA +469 -0
- mobile_mcp_ai-2.5.8.dist-info/RECORD +32 -0
- mobile_mcp_ai-2.5.8.dist-info/entry_points.txt +2 -0
- mobile_mcp_ai-2.5.8.dist-info/licenses/LICENSE +201 -0
- mobile_mcp_ai-2.5.8.dist-info/top_level.txt +1 -0
- core/ai/__init__.py +0 -11
- core/ai/ai_analyzer.py +0 -197
- core/ai/ai_config.py +0 -116
- core/ai/ai_platform_adapter.py +0 -399
- core/ai/smart_test_executor.py +0 -520
- core/ai/test_generator.py +0 -365
- core/ai/test_generator_from_history.py +0 -391
- core/ai/test_generator_standalone.py +0 -293
- core/assertion/__init__.py +0 -9
- core/assertion/smart_assertion.py +0 -341
- core/basic_tools.py +0 -377
- core/h5/__init__.py +0 -10
- core/h5/h5_handler.py +0 -548
- core/ios_client.py +0 -219
- core/ios_device_manager.py +0 -252
- core/locator/__init__.py +0 -10
- core/locator/cursor_ai_auto_analyzer.py +0 -119
- core/locator/cursor_vision_helper.py +0 -414
- core/locator/mobile_smart_locator.py +0 -1640
- core/locator/position_analyzer.py +0 -813
- core/locator/script_updater.py +0 -157
- core/nl_test_runner.py +0 -585
- core/smart_app_launcher.py +0 -334
- core/smart_tools.py +0 -311
- mcp/__init__.py +0 -8
- mcp/mcp_server.py +0 -1919
- mcp/mcp_server_simple.py +0 -476
- mobile_mcp_ai-2.1.2.dist-info/METADATA +0 -567
- mobile_mcp_ai-2.1.2.dist-info/RECORD +0 -45
- mobile_mcp_ai-2.1.2.dist-info/entry_points.txt +0 -2
- mobile_mcp_ai-2.1.2.dist-info/top_level.txt +0 -4
- vision/__init__.py +0 -10
- vision/vision_locator.py +0 -404
- {core → mobile_mcp/core}/__init__.py +0 -0
- {core → mobile_mcp/core}/utils/__init__.py +0 -0
- {core → mobile_mcp/core}/utils/logger.py +0 -0
- {core → mobile_mcp/core}/utils/operation_history_manager.py +0 -0
- {utils → mobile_mcp/utils}/__init__.py +0 -0
- {utils → mobile_mcp/utils}/logger.py +0 -0
- {utils → mobile_mcp/utils}/xml_formatter.py +0 -0
- {utils → mobile_mcp/utils}/xml_parser.py +0 -0
- {mobile_mcp_ai-2.1.2.dist-info → mobile_mcp_ai-2.5.8.dist-info}/WHEEL +0 -0
|
@@ -1,414 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
"""
|
|
4
|
-
Cursor AI 视觉识别辅助工具
|
|
5
|
-
|
|
6
|
-
当定位失败时,自动截图并请求Cursor AI分析。
|
|
7
|
-
这个模块提供了与Cursor AI交互的接口。
|
|
8
|
-
"""
|
|
9
|
-
import asyncio
|
|
10
|
-
import json
|
|
11
|
-
import tempfile
|
|
12
|
-
import os
|
|
13
|
-
from datetime import datetime
|
|
14
|
-
from typing import Dict, Optional, Tuple
|
|
15
|
-
from pathlib import Path
|
|
16
|
-
import time
|
|
17
|
-
import inspect
|
|
18
|
-
import traceback
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class CursorVisionHelper:
|
|
22
|
-
"""
|
|
23
|
-
Cursor AI 视觉识别辅助工具
|
|
24
|
-
|
|
25
|
-
功能:
|
|
26
|
-
1. 截图并保存
|
|
27
|
-
2. 生成提示信息,让Cursor AI分析截图
|
|
28
|
-
3. 解析Cursor AI返回的坐标
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
def __init__(self, mobile_client):
|
|
32
|
-
"""
|
|
33
|
-
初始化Cursor视觉识别辅助工具
|
|
34
|
-
|
|
35
|
-
Args:
|
|
36
|
-
mobile_client: MobileClient实例
|
|
37
|
-
"""
|
|
38
|
-
self.mobile_client = mobile_client
|
|
39
|
-
# 🎯 使用项目内的screenshots目录,而不是临时目录
|
|
40
|
-
project_root = Path(__file__).parent.parent.parent
|
|
41
|
-
self.screenshot_dir = project_root / "screenshots"
|
|
42
|
-
self.screenshot_dir.mkdir(exist_ok=True)
|
|
43
|
-
self.request_dir = self.screenshot_dir / "requests"
|
|
44
|
-
self.request_dir.mkdir(exist_ok=True)
|
|
45
|
-
self.result_dir = self.screenshot_dir / "results"
|
|
46
|
-
self.result_dir.mkdir(exist_ok=True)
|
|
47
|
-
|
|
48
|
-
async def take_screenshot(self, element_desc: str = "", region: Optional[Dict] = None) -> str:
|
|
49
|
-
"""
|
|
50
|
-
截图并保存(支持区域截图)
|
|
51
|
-
|
|
52
|
-
Args:
|
|
53
|
-
element_desc: 元素描述(用于文件名)
|
|
54
|
-
region: 截图区域 {"x": int, "y": int, "width": int, "height": int},None表示全屏
|
|
55
|
-
|
|
56
|
-
Returns:
|
|
57
|
-
截图文件路径
|
|
58
|
-
"""
|
|
59
|
-
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")
|
|
60
|
-
safe_desc = "".join(c for c in element_desc if c.isalnum() or c in (' ', '-', '_')).strip()[:20]
|
|
61
|
-
if safe_desc:
|
|
62
|
-
filename = f"screenshot_{safe_desc}_{timestamp}.png"
|
|
63
|
-
else:
|
|
64
|
-
filename = f"screenshot_{timestamp}.png"
|
|
65
|
-
|
|
66
|
-
screenshot_path = self.screenshot_dir / filename
|
|
67
|
-
|
|
68
|
-
if region:
|
|
69
|
-
# 区域截图:先截全屏,再裁剪
|
|
70
|
-
try:
|
|
71
|
-
from PIL import Image # type: ignore
|
|
72
|
-
PIL_AVAILABLE = True
|
|
73
|
-
except ImportError:
|
|
74
|
-
PIL_AVAILABLE = False
|
|
75
|
-
|
|
76
|
-
if PIL_AVAILABLE:
|
|
77
|
-
# 先截全屏
|
|
78
|
-
temp_path = str(screenshot_path).replace('.png', '_full.png')
|
|
79
|
-
self.mobile_client.u2.screenshot(temp_path)
|
|
80
|
-
|
|
81
|
-
# 裁剪区域
|
|
82
|
-
img = Image.open(temp_path)
|
|
83
|
-
x = region.get('x', 0)
|
|
84
|
-
y = region.get('y', 0)
|
|
85
|
-
width = region.get('width', img.width)
|
|
86
|
-
height = region.get('height', img.height)
|
|
87
|
-
|
|
88
|
-
# 确保不越界
|
|
89
|
-
x = max(0, min(x, img.width))
|
|
90
|
-
y = max(0, min(y, img.height))
|
|
91
|
-
width = min(width, img.width - x)
|
|
92
|
-
height = min(height, img.height - y)
|
|
93
|
-
|
|
94
|
-
# 裁剪
|
|
95
|
-
cropped = img.crop((x, y, x + width, y + height))
|
|
96
|
-
cropped.save(str(screenshot_path))
|
|
97
|
-
|
|
98
|
-
# 删除临时文件
|
|
99
|
-
import os
|
|
100
|
-
if os.path.exists(temp_path):
|
|
101
|
-
os.remove(temp_path)
|
|
102
|
-
|
|
103
|
-
print(f" 📸 区域截图: ({x}, {y}) - ({x+width}, {y+height}), 尺寸: {width}x{height}")
|
|
104
|
-
else:
|
|
105
|
-
# PIL不可用时,使用全屏截图
|
|
106
|
-
self.mobile_client.u2.screenshot(str(screenshot_path))
|
|
107
|
-
print(f" ⚠️ PIL未安装,使用全屏截图")
|
|
108
|
-
else:
|
|
109
|
-
# 全屏截图
|
|
110
|
-
self.mobile_client.u2.screenshot(str(screenshot_path))
|
|
111
|
-
|
|
112
|
-
return str(screenshot_path)
|
|
113
|
-
|
|
114
|
-
def _smart_region_selection(self, element_desc: str) -> Optional[Dict]:
|
|
115
|
-
"""
|
|
116
|
-
智能选择截图区域(根据元素描述推断区域)
|
|
117
|
-
|
|
118
|
-
Args:
|
|
119
|
-
element_desc: 元素描述
|
|
120
|
-
|
|
121
|
-
Returns:
|
|
122
|
-
区域信息 或 None(全屏)
|
|
123
|
-
"""
|
|
124
|
-
# 获取屏幕尺寸
|
|
125
|
-
screen_info = self.mobile_client.u2.info
|
|
126
|
-
screen_width = screen_info.get('displayWidth', 1080)
|
|
127
|
-
screen_height = screen_info.get('displayHeight', 2400)
|
|
128
|
-
|
|
129
|
-
desc_lower = element_desc.lower()
|
|
130
|
-
|
|
131
|
-
# 🎯 角落区域(优先匹配,更精确)
|
|
132
|
-
# 右上角区域(右上角图标、搜索图标等)
|
|
133
|
-
if any(kw in desc_lower for kw in ['右上角', '上角', '搜索图标', 'search icon']):
|
|
134
|
-
return {
|
|
135
|
-
'x': int(screen_width * 0.7), # 右侧30%
|
|
136
|
-
'y': 0,
|
|
137
|
-
'width': int(screen_width * 0.3), # 宽度30%
|
|
138
|
-
'height': int(screen_height * 0.15) # 顶部15%
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
# 左上角区域
|
|
142
|
-
if '左上角' in desc_lower:
|
|
143
|
-
return {
|
|
144
|
-
'x': 0,
|
|
145
|
-
'y': 0,
|
|
146
|
-
'width': int(screen_width * 0.3), # 左侧30%
|
|
147
|
-
'height': int(screen_height * 0.15) # 顶部15%
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
# 右下角区域
|
|
151
|
-
if '右下角' in desc_lower:
|
|
152
|
-
return {
|
|
153
|
-
'x': int(screen_width * 0.7), # 右侧30%
|
|
154
|
-
'y': int(screen_height * 0.85), # 底部15%
|
|
155
|
-
'width': int(screen_width * 0.3), # 宽度30%
|
|
156
|
-
'height': int(screen_height * 0.15) # 高度15%
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
# 左下角区域
|
|
160
|
-
if '左下角' in desc_lower:
|
|
161
|
-
return {
|
|
162
|
-
'x': 0,
|
|
163
|
-
'y': int(screen_height * 0.85), # 底部15%
|
|
164
|
-
'width': int(screen_width * 0.3), # 左侧30%
|
|
165
|
-
'height': int(screen_height * 0.15) # 高度15%
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
# 底部区域(底部导航栏、底部按钮等)
|
|
169
|
-
if any(kw in desc_lower for kw in ['底部', 'bottom', '导航栏', 'tab']):
|
|
170
|
-
return {
|
|
171
|
-
'x': 0,
|
|
172
|
-
'y': int(screen_height * 0.8), # 底部20%
|
|
173
|
-
'width': screen_width,
|
|
174
|
-
'height': int(screen_height * 0.2)
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
# 顶部区域(标题栏、顶部导航、设置图标等)
|
|
178
|
-
if any(kw in desc_lower for kw in ['顶部', 'top', '标题', 'header', '设置', 'settings']):
|
|
179
|
-
return {
|
|
180
|
-
'x': 0,
|
|
181
|
-
'y': 0,
|
|
182
|
-
'width': screen_width,
|
|
183
|
-
'height': int(screen_height * 0.2) # 顶部20%
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
# 中间区域(登录按钮、表单等)
|
|
187
|
-
if any(kw in desc_lower for kw in ['登录', 'login', '按钮', 'button', '表单', 'form']):
|
|
188
|
-
return {
|
|
189
|
-
'x': 0,
|
|
190
|
-
'y': int(screen_height * 0.3),
|
|
191
|
-
'width': screen_width,
|
|
192
|
-
'height': int(screen_height * 0.4) # 中间40%
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
# 默认全屏
|
|
196
|
-
return None
|
|
197
|
-
|
|
198
|
-
def generate_analysis_prompt(self, screenshot_path: str, element_desc: str) -> str:
|
|
199
|
-
"""
|
|
200
|
-
生成分析提示信息
|
|
201
|
-
|
|
202
|
-
Args:
|
|
203
|
-
screenshot_path: 截图路径
|
|
204
|
-
element_desc: 元素描述
|
|
205
|
-
|
|
206
|
-
Returns:
|
|
207
|
-
提示信息
|
|
208
|
-
"""
|
|
209
|
-
prompt = f"""
|
|
210
|
-
🎯 需要分析移动端截图并定位元素
|
|
211
|
-
|
|
212
|
-
截图路径: {screenshot_path}
|
|
213
|
-
要查找的元素: {element_desc}
|
|
214
|
-
|
|
215
|
-
请执行以下步骤:
|
|
216
|
-
1. 查看截图文件: {screenshot_path}
|
|
217
|
-
2. 在截图中找到元素: {element_desc}
|
|
218
|
-
3. 返回元素的中心点坐标,格式为JSON:
|
|
219
|
-
{{"x": 100, "y": 200, "confidence": 90}}
|
|
220
|
-
|
|
221
|
-
注意:
|
|
222
|
-
- x, y 是元素中心点的像素坐标
|
|
223
|
-
- confidence 是置信度(0-100)
|
|
224
|
-
- 如果找不到元素,返回 {{"found": false}}
|
|
225
|
-
"""
|
|
226
|
-
return prompt
|
|
227
|
-
|
|
228
|
-
def parse_coordinate_response(self, response: str) -> Optional[Dict]:
|
|
229
|
-
"""
|
|
230
|
-
解析坐标响应
|
|
231
|
-
|
|
232
|
-
Args:
|
|
233
|
-
response: Cursor AI的响应文本
|
|
234
|
-
|
|
235
|
-
Returns:
|
|
236
|
-
坐标信息 {"x": int, "y": int, "confidence": int} 或 None
|
|
237
|
-
"""
|
|
238
|
-
try:
|
|
239
|
-
# 尝试从响应中提取JSON
|
|
240
|
-
import re
|
|
241
|
-
|
|
242
|
-
# 查找JSON对象
|
|
243
|
-
json_match = re.search(r'\{[^}]+\}', response)
|
|
244
|
-
if json_match:
|
|
245
|
-
json_str = json_match.group()
|
|
246
|
-
coord = json.loads(json_str)
|
|
247
|
-
|
|
248
|
-
if coord.get("found") is False:
|
|
249
|
-
return None
|
|
250
|
-
|
|
251
|
-
if "x" in coord and "y" in coord:
|
|
252
|
-
return {
|
|
253
|
-
"x": int(coord["x"]),
|
|
254
|
-
"y": int(coord["y"]),
|
|
255
|
-
"confidence": coord.get("confidence", 80)
|
|
256
|
-
}
|
|
257
|
-
except Exception as e:
|
|
258
|
-
print(f" ⚠️ 解析坐标响应失败: {e}")
|
|
259
|
-
|
|
260
|
-
return None
|
|
261
|
-
|
|
262
|
-
async def analyze_with_cursor(self, element_desc: str, auto_analyze: bool = False) -> Optional[Dict]:
|
|
263
|
-
"""
|
|
264
|
-
使用Cursor AI分析截图并返回坐标
|
|
265
|
-
|
|
266
|
-
Args:
|
|
267
|
-
element_desc: 元素描述
|
|
268
|
-
auto_analyze: 是否自动分析(通过MCP工具调用Cursor AI)
|
|
269
|
-
|
|
270
|
-
Returns:
|
|
271
|
-
坐标信息 或 None
|
|
272
|
-
"""
|
|
273
|
-
# 智能选择截图区域
|
|
274
|
-
region = self._smart_region_selection(element_desc)
|
|
275
|
-
|
|
276
|
-
# 截图
|
|
277
|
-
screenshot_path = await self.take_screenshot(element_desc, region=region)
|
|
278
|
-
|
|
279
|
-
if auto_analyze:
|
|
280
|
-
# 🎯 自动分析:通过MCP工具调用Cursor AI
|
|
281
|
-
# 这里需要调用MCP工具,让Cursor AI分析截图
|
|
282
|
-
# 由于是在测试脚本中调用,需要通过某种机制触发Cursor AI
|
|
283
|
-
print(f"\n📸 已截图: {screenshot_path}")
|
|
284
|
-
print(f"🎯 自动调用Cursor AI分析截图...")
|
|
285
|
-
|
|
286
|
-
# 返回截图路径,等待Cursor AI分析
|
|
287
|
-
# 实际的坐标需要通过MCP工具返回
|
|
288
|
-
# 🎯 创建分析请求文件,让Cursor AI自动处理
|
|
289
|
-
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")
|
|
290
|
-
request_id = f"{timestamp}_{hash(element_desc) % 10000}"
|
|
291
|
-
request_file = self.request_dir / f"request_{request_id}.json"
|
|
292
|
-
result_file = self.result_dir / f"result_{request_id}.json"
|
|
293
|
-
|
|
294
|
-
# 尝试获取测试脚本路径
|
|
295
|
-
script_path = None
|
|
296
|
-
try:
|
|
297
|
-
frame = inspect.currentframe()
|
|
298
|
-
while frame:
|
|
299
|
-
filename = frame.f_globals.get('__file__', '')
|
|
300
|
-
if filename and 'test_' in filename and filename.endswith('.py'):
|
|
301
|
-
script_path = filename
|
|
302
|
-
break
|
|
303
|
-
frame = frame.f_back
|
|
304
|
-
except:
|
|
305
|
-
pass
|
|
306
|
-
|
|
307
|
-
request_data = {
|
|
308
|
-
"request_id": request_id,
|
|
309
|
-
"screenshot_path": screenshot_path,
|
|
310
|
-
"element_desc": element_desc,
|
|
311
|
-
"region": region,
|
|
312
|
-
"timestamp": timestamp,
|
|
313
|
-
"script_path": script_path,
|
|
314
|
-
"status": "pending"
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
# 写入请求文件
|
|
318
|
-
with open(request_file, 'w', encoding='utf-8') as f:
|
|
319
|
-
json.dump(request_data, f, ensure_ascii=False, indent=2)
|
|
320
|
-
|
|
321
|
-
print(f"\n📸 已截图: {screenshot_path}")
|
|
322
|
-
print(f"📝 已创建分析请求: {request_file}")
|
|
323
|
-
print(f"🎯 等待Cursor AI分析...")
|
|
324
|
-
print(f"💡 Cursor AI会自动读取请求文件并分析截图")
|
|
325
|
-
|
|
326
|
-
# 等待Cursor AI分析(轮询结果文件)
|
|
327
|
-
# 🎯 优化:缩短等待时间,避免阻塞过久
|
|
328
|
-
max_wait = 10 # 最多等待10秒(原30秒太长)
|
|
329
|
-
wait_interval = 0.5 # 每0.5秒检查一次(提高响应速度)
|
|
330
|
-
waited = 0
|
|
331
|
-
|
|
332
|
-
while waited < max_wait:
|
|
333
|
-
if result_file.exists():
|
|
334
|
-
try:
|
|
335
|
-
with open(result_file, 'r', encoding='utf-8') as f:
|
|
336
|
-
result_data = json.load(f)
|
|
337
|
-
|
|
338
|
-
if result_data.get('status') == 'completed':
|
|
339
|
-
coord = result_data.get('coordinate')
|
|
340
|
-
if coord and 'x' in coord and 'y' in coord:
|
|
341
|
-
print(f"✅ Cursor AI分析完成,坐标: ({coord['x']}, {coord['y']})")
|
|
342
|
-
|
|
343
|
-
# 🎯 可选:更新测试脚本(重新读取请求文件获取脚本路径)
|
|
344
|
-
try:
|
|
345
|
-
with open(request_file, 'r', encoding='utf-8') as rf:
|
|
346
|
-
request_data = json.load(rf)
|
|
347
|
-
script_path = request_data.get('script_path')
|
|
348
|
-
self._update_test_script(element_desc, coord, script_path)
|
|
349
|
-
except Exception as e:
|
|
350
|
-
print(f" ⚠️ 更新脚本失败: {e}")
|
|
351
|
-
|
|
352
|
-
# 清理文件
|
|
353
|
-
request_file.unlink(missing_ok=True)
|
|
354
|
-
result_file.unlink(missing_ok=True)
|
|
355
|
-
return {
|
|
356
|
-
"screenshot_path": screenshot_path,
|
|
357
|
-
"coordinate": coord,
|
|
358
|
-
"confidence": coord.get('confidence', 80),
|
|
359
|
-
"status": "completed"
|
|
360
|
-
}
|
|
361
|
-
except Exception as e:
|
|
362
|
-
print(f" ⚠️ 读取结果文件失败: {e}")
|
|
363
|
-
|
|
364
|
-
await asyncio.sleep(wait_interval)
|
|
365
|
-
waited += wait_interval
|
|
366
|
-
if waited % 5 == 0:
|
|
367
|
-
print(f" ⏳ 等待中... ({waited}/{max_wait}秒)")
|
|
368
|
-
|
|
369
|
-
print(f" ⚠️ 超时:Cursor AI未在{max_wait}秒内返回结果")
|
|
370
|
-
return {
|
|
371
|
-
"screenshot_path": screenshot_path,
|
|
372
|
-
"status": "timeout",
|
|
373
|
-
"request_file": str(request_file),
|
|
374
|
-
"result_file": str(result_file)
|
|
375
|
-
}
|
|
376
|
-
else:
|
|
377
|
-
# 手动分析:生成提示信息
|
|
378
|
-
prompt = self.generate_analysis_prompt(screenshot_path, element_desc)
|
|
379
|
-
|
|
380
|
-
print(f"\n📸 已截图: {screenshot_path}")
|
|
381
|
-
print(f"🎯 请Cursor AI分析截图,查找元素: {element_desc}")
|
|
382
|
-
print(f"\n{prompt}\n")
|
|
383
|
-
|
|
384
|
-
return {
|
|
385
|
-
"screenshot_path": screenshot_path,
|
|
386
|
-
"prompt": prompt,
|
|
387
|
-
"status": "waiting_for_ai_analysis"
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
def _update_test_script(self, element_desc: str, coordinate: Dict, script_path: Optional[str] = None):
|
|
391
|
-
"""
|
|
392
|
-
更新测试脚本,添加坐标信息
|
|
393
|
-
|
|
394
|
-
Args:
|
|
395
|
-
element_desc: 元素描述
|
|
396
|
-
coordinate: 坐标信息 {"x": int, "y": int, "confidence": int}
|
|
397
|
-
script_path: 脚本路径(如果为None,尝试自动查找)
|
|
398
|
-
"""
|
|
399
|
-
if not script_path:
|
|
400
|
-
return
|
|
401
|
-
|
|
402
|
-
try:
|
|
403
|
-
from mobile_mcp.core.locator.script_updater import ScriptUpdater
|
|
404
|
-
updater = ScriptUpdater(script_path)
|
|
405
|
-
success = updater.update_with_coordinate(element_desc, coordinate, method='comment')
|
|
406
|
-
if success:
|
|
407
|
-
print(f" ✅ 测试脚本已更新: {script_path}")
|
|
408
|
-
else:
|
|
409
|
-
print(f" ⚠️ 更新测试脚本失败")
|
|
410
|
-
except Exception as e:
|
|
411
|
-
print(f" ⚠️ 更新测试脚本异常: {e}")
|
|
412
|
-
import traceback
|
|
413
|
-
traceback.print_exc()
|
|
414
|
-
|