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.
Files changed (65) hide show
  1. mobile_mcp/__init__.py +34 -0
  2. mobile_mcp/config.py +142 -0
  3. mobile_mcp/core/basic_tools_lite.py +3266 -0
  4. {core → mobile_mcp/core}/device_manager.py +2 -2
  5. mobile_mcp/core/dynamic_config.py +272 -0
  6. mobile_mcp/core/ios_client_wda.py +569 -0
  7. mobile_mcp/core/ios_device_manager_wda.py +306 -0
  8. {core → mobile_mcp/core}/mobile_client.py +279 -39
  9. mobile_mcp/core/template_matcher.py +429 -0
  10. mobile_mcp/core/templates/close_buttons/auto_x_0112_151217.png +0 -0
  11. mobile_mcp/core/templates/close_buttons/auto_x_0112_152037.png +0 -0
  12. mobile_mcp/core/templates/close_buttons/auto_x_0112_152840.png +0 -0
  13. mobile_mcp/core/templates/close_buttons/auto_x_0112_153256.png +0 -0
  14. mobile_mcp/core/templates/close_buttons/auto_x_0112_154847.png +0 -0
  15. mobile_mcp/core/templates/close_buttons/gray_x_stock_ad.png +0 -0
  16. {core → mobile_mcp/core}/utils/smart_wait.py +3 -3
  17. mobile_mcp/mcp_tools/__init__.py +10 -0
  18. mobile_mcp/mcp_tools/mcp_server.py +1071 -0
  19. mobile_mcp_ai-2.5.8.dist-info/METADATA +469 -0
  20. mobile_mcp_ai-2.5.8.dist-info/RECORD +32 -0
  21. mobile_mcp_ai-2.5.8.dist-info/entry_points.txt +2 -0
  22. mobile_mcp_ai-2.5.8.dist-info/licenses/LICENSE +201 -0
  23. mobile_mcp_ai-2.5.8.dist-info/top_level.txt +1 -0
  24. core/ai/__init__.py +0 -11
  25. core/ai/ai_analyzer.py +0 -197
  26. core/ai/ai_config.py +0 -116
  27. core/ai/ai_platform_adapter.py +0 -399
  28. core/ai/smart_test_executor.py +0 -520
  29. core/ai/test_generator.py +0 -365
  30. core/ai/test_generator_from_history.py +0 -391
  31. core/ai/test_generator_standalone.py +0 -293
  32. core/assertion/__init__.py +0 -9
  33. core/assertion/smart_assertion.py +0 -341
  34. core/basic_tools.py +0 -377
  35. core/h5/__init__.py +0 -10
  36. core/h5/h5_handler.py +0 -548
  37. core/ios_client.py +0 -219
  38. core/ios_device_manager.py +0 -252
  39. core/locator/__init__.py +0 -10
  40. core/locator/cursor_ai_auto_analyzer.py +0 -119
  41. core/locator/cursor_vision_helper.py +0 -414
  42. core/locator/mobile_smart_locator.py +0 -1640
  43. core/locator/position_analyzer.py +0 -813
  44. core/locator/script_updater.py +0 -157
  45. core/nl_test_runner.py +0 -585
  46. core/smart_app_launcher.py +0 -334
  47. core/smart_tools.py +0 -311
  48. mcp/__init__.py +0 -8
  49. mcp/mcp_server.py +0 -1919
  50. mcp/mcp_server_simple.py +0 -476
  51. mobile_mcp_ai-2.1.2.dist-info/METADATA +0 -567
  52. mobile_mcp_ai-2.1.2.dist-info/RECORD +0 -45
  53. mobile_mcp_ai-2.1.2.dist-info/entry_points.txt +0 -2
  54. mobile_mcp_ai-2.1.2.dist-info/top_level.txt +0 -4
  55. vision/__init__.py +0 -10
  56. vision/vision_locator.py +0 -404
  57. {core → mobile_mcp/core}/__init__.py +0 -0
  58. {core → mobile_mcp/core}/utils/__init__.py +0 -0
  59. {core → mobile_mcp/core}/utils/logger.py +0 -0
  60. {core → mobile_mcp/core}/utils/operation_history_manager.py +0 -0
  61. {utils → mobile_mcp/utils}/__init__.py +0 -0
  62. {utils → mobile_mcp/utils}/logger.py +0 -0
  63. {utils → mobile_mcp/utils}/xml_formatter.py +0 -0
  64. {utils → mobile_mcp/utils}/xml_parser.py +0 -0
  65. {mobile_mcp_ai-2.1.2.dist-info → mobile_mcp_ai-2.5.8.dist-info}/WHEEL +0 -0
@@ -1,399 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- AI平台适配器 - 支持多种AI平台的可选增强功能
5
-
6
- 支持的平台:
7
- 1. Cursor AI - 多模态视觉识别
8
- 2. Claude (Anthropic) - 通用AI能力
9
- 3. OpenAI GPT-4V - 视觉识别
10
- 4. 其他支持MCP的AI平台
11
-
12
- 设计理念:
13
- - 基础功能不依赖AI平台(通用)
14
- - AI增强功能作为可选插件
15
- - 自动检测可用的AI平台
16
- - 优雅降级(AI不可用时使用基础功能)
17
- """
18
- import os
19
- from typing import Optional, Dict, Any, List
20
- from enum import Enum
21
- from pathlib import Path
22
-
23
-
24
- class AIPlatform(Enum):
25
- """支持的AI平台"""
26
- CURSOR = "cursor"
27
- CLAUDE = "claude"
28
- OPENAI = "openai"
29
- GEMINI = "gemini"
30
- NONE = "none" # 无AI平台(仅基础功能)
31
-
32
-
33
- class AIPlatformAdapter:
34
- """
35
- AI平台适配器
36
-
37
- 功能:
38
- 1. 自动检测可用的AI平台
39
- 2. 提供统一的AI能力接口
40
- 3. 支持多平台切换
41
- 4. 优雅降级
42
- """
43
-
44
- def __init__(self):
45
- """初始化AI平台适配器"""
46
- self.detected_platform: AIPlatform = self._detect_platform()
47
- self.platform_config: Dict[str, Any] = {}
48
- self._initialize_platform()
49
-
50
- def _detect_platform(self) -> AIPlatform:
51
- """
52
- 自动检测可用的AI平台
53
-
54
- 检测顺序:
55
- 1. Cursor AI (通过环境变量或MCP上下文)
56
- 2. Claude (通过环境变量)
57
- 3. OpenAI (通过环境变量)
58
- 4. 其他平台
59
- """
60
- # 检测 Cursor AI
61
- if self._is_cursor_available():
62
- return AIPlatform.CURSOR
63
-
64
- # 检测 Claude
65
- if os.getenv("ANTHROPIC_API_KEY"):
66
- return AIPlatform.CLAUDE
67
-
68
- # 检测 OpenAI
69
- if os.getenv("OPENAI_API_KEY"):
70
- return AIPlatform.OPENAI
71
-
72
- # 检测 Gemini
73
- if os.getenv("GOOGLE_API_KEY"):
74
- return AIPlatform.GEMINI
75
-
76
- return AIPlatform.NONE
77
-
78
- def _is_cursor_available(self) -> bool:
79
- """检测 Cursor AI 是否可用"""
80
- # 方法1: 检查环境变量
81
- if os.getenv("CURSOR_AI_ENABLED", "").lower() == "true":
82
- return True
83
-
84
- # 方法2: 检查MCP上下文(在MCP Server中)
85
- # 如果是在MCP Server中运行,Cursor AI通常可用
86
- try:
87
- # 检查是否有MCP相关的环境
88
- mcp_server = os.getenv("MCP_SERVER_NAME", "")
89
- if "cursor" in mcp_server.lower():
90
- return True
91
- except:
92
- pass
93
-
94
- # 方法3: 🎯 在 MCP Server 环境中默认启用 Cursor AI
95
- # 如果没有配置其他 AI 平台,且在 MCP 环境中,默认使用 Cursor
96
- if self._is_running_in_mcp() and not self._has_other_ai_platform():
97
- return True
98
-
99
- return False
100
-
101
- def _is_running_in_mcp(self) -> bool:
102
- """检测是否在 MCP Server 环境中运行"""
103
- # 检查是否通过 MCP 协议运行(stdin/stdout)
104
- import sys
105
- return not sys.stdin.isatty() or os.getenv("MCP_MODE") == "1"
106
-
107
- def _has_other_ai_platform(self) -> bool:
108
- """检测是否配置了其他 AI 平台"""
109
- return bool(
110
- os.getenv("AI_PROVIDER") or
111
- os.getenv("ANTHROPIC_API_KEY") or
112
- os.getenv("OPENAI_API_KEY") or
113
- os.getenv("GOOGLE_API_KEY") or
114
- os.getenv("QWEN_API_KEY")
115
- )
116
-
117
- def _initialize_platform(self):
118
- """初始化检测到的平台"""
119
- if self.detected_platform == AIPlatform.CURSOR:
120
- self.platform_config = {
121
- "name": "Cursor AI",
122
- "multimodal": True, # 支持多模态
123
- "vision": True, # 支持视觉识别
124
- "free": True, # Cursor AI免费使用
125
- }
126
- elif self.detected_platform == AIPlatform.CLAUDE:
127
- self.platform_config = {
128
- "name": "Claude (Anthropic)",
129
- "multimodal": True,
130
- "vision": True,
131
- "free": False,
132
- }
133
- elif self.detected_platform == AIPlatform.OPENAI:
134
- self.platform_config = {
135
- "name": "OpenAI GPT-4V",
136
- "multimodal": True,
137
- "vision": True,
138
- "free": False,
139
- }
140
- elif self.detected_platform == AIPlatform.GEMINI:
141
- self.platform_config = {
142
- "name": "Google Gemini",
143
- "multimodal": True,
144
- "vision": True,
145
- "free": True, # Gemini有免费额度
146
- }
147
- else:
148
- self.platform_config = {
149
- "name": "None (基础模式)",
150
- "multimodal": False,
151
- "vision": False,
152
- "free": True,
153
- }
154
-
155
- def is_vision_available(self) -> bool:
156
- """检查是否支持视觉识别"""
157
- return self.platform_config.get("vision", False)
158
-
159
- def is_multimodal_available(self) -> bool:
160
- """检查是否支持多模态"""
161
- return self.platform_config.get("multimodal", False)
162
-
163
- def get_platform_name(self) -> str:
164
- """获取平台名称"""
165
- return self.platform_config.get("name", "Unknown")
166
-
167
- async def analyze_screenshot(
168
- self,
169
- screenshot_path: str,
170
- element_desc: str,
171
- **kwargs
172
- ) -> Optional[Dict[str, Any]]:
173
- """
174
- 分析截图(统一接口)
175
-
176
- Args:
177
- screenshot_path: 截图路径
178
- element_desc: 元素描述
179
- **kwargs: 平台特定参数
180
-
181
- Returns:
182
- 坐标信息或None
183
- """
184
- if not self.is_vision_available():
185
- return None
186
-
187
- if self.detected_platform == AIPlatform.CURSOR:
188
- return await self._analyze_with_cursor(screenshot_path, element_desc, **kwargs)
189
- elif self.detected_platform == AIPlatform.CLAUDE:
190
- return await self._analyze_with_claude(screenshot_path, element_desc, **kwargs)
191
- elif self.detected_platform == AIPlatform.OPENAI:
192
- return await self._analyze_with_openai(screenshot_path, element_desc, **kwargs)
193
- elif self.detected_platform == AIPlatform.GEMINI:
194
- return await self._analyze_with_gemini(screenshot_path, element_desc, **kwargs)
195
-
196
- return None
197
-
198
- async def _analyze_with_cursor(
199
- self,
200
- screenshot_path: str,
201
- element_desc: str,
202
- **kwargs
203
- ) -> Optional[Dict[str, Any]]:
204
- """
205
- 使用 Cursor AI 分析截图
206
-
207
- Cursor AI 通过 MCP 工具调用,返回结果文件路径
208
- """
209
- # Cursor AI 的特殊处理:
210
- # 1. 创建请求文件
211
- # 2. 返回提示信息,让 Cursor AI 通过 MCP 工具分析
212
- # 3. 轮询结果文件
213
-
214
- request_id = kwargs.get("request_id")
215
- if request_id:
216
- # 自动模式:等待 Cursor AI 写入结果文件
217
- result_file = kwargs.get("result_file")
218
- if result_file and Path(result_file).exists():
219
- import json
220
- with open(result_file, 'r', encoding='utf-8') as f:
221
- result_data = json.load(f)
222
- if result_data.get("status") == "completed":
223
- coord = result_data.get("coordinate")
224
- if coord:
225
- return {
226
- "x": coord.get("x"),
227
- "y": coord.get("y"),
228
- "confidence": coord.get("confidence", 90),
229
- "platform": "cursor"
230
- }
231
-
232
- # 手动模式:返回提示信息
233
- return {
234
- "platform": "cursor",
235
- "instruction": f"请使用多模态能力分析截图 {screenshot_path},找到元素 '{element_desc}' 并返回坐标",
236
- "screenshot_path": screenshot_path,
237
- "element_desc": element_desc
238
- }
239
-
240
- async def _analyze_with_claude(
241
- self,
242
- screenshot_path: str,
243
- element_desc: str,
244
- **kwargs
245
- ) -> Optional[Dict[str, Any]]:
246
- """使用 Claude API 分析截图"""
247
- # TODO: 实现 Claude API 调用
248
- # 需要安装 anthropic SDK
249
- try:
250
- from anthropic import Anthropic
251
-
252
- client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
253
-
254
- # 读取截图
255
- with open(screenshot_path, 'rb') as f:
256
- image_data = f.read()
257
-
258
- # 调用 Claude Vision API
259
- message = client.messages.create(
260
- model="claude-3-5-sonnet-20241022",
261
- max_tokens=1024,
262
- messages=[{
263
- "role": "user",
264
- "content": [
265
- {
266
- "type": "image",
267
- "source": {
268
- "type": "base64",
269
- "media_type": "image/png",
270
- "data": image_data.hex() # 需要base64编码
271
- }
272
- },
273
- {
274
- "type": "text",
275
- "text": f"分析这个移动端截图,找到元素 '{element_desc}' 并返回其中心点坐标,格式:{{\"x\": 100, \"y\": 200}}"
276
- }
277
- ]
278
- }]
279
- )
280
-
281
- # 解析响应
282
- # TODO: 解析 Claude 返回的坐标
283
- return None
284
-
285
- except ImportError:
286
- return None
287
- except Exception as e:
288
- print(f"⚠️ Claude API 调用失败: {e}")
289
- return None
290
-
291
- async def _analyze_with_openai(
292
- self,
293
- screenshot_path: str,
294
- element_desc: str,
295
- **kwargs
296
- ) -> Optional[Dict[str, Any]]:
297
- """使用 OpenAI GPT-4V 分析截图"""
298
- # TODO: 实现 OpenAI Vision API 调用
299
- try:
300
- import base64
301
- from openai import OpenAI
302
-
303
- client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
304
-
305
- # 读取并编码截图
306
- with open(screenshot_path, 'rb') as f:
307
- image_data = base64.b64encode(f.read()).decode('utf-8')
308
-
309
- # 调用 GPT-4V
310
- response = client.chat.completions.create(
311
- model="gpt-4-vision-preview",
312
- messages=[{
313
- "role": "user",
314
- "content": [
315
- {
316
- "type": "text",
317
- "text": f"分析这个移动端截图,找到元素 '{element_desc}' 并返回其中心点坐标,格式:{{\"x\": 100, \"y\": 200}}"
318
- },
319
- {
320
- "type": "image_url",
321
- "image_url": {
322
- "url": f"data:image/png;base64,{image_data}"
323
- }
324
- }
325
- ]
326
- }],
327
- max_tokens=300
328
- )
329
-
330
- # 解析响应
331
- # TODO: 解析 OpenAI 返回的坐标
332
- return None
333
-
334
- except ImportError:
335
- return None
336
- except Exception as e:
337
- print(f"⚠️ OpenAI API 调用失败: {e}")
338
- return None
339
-
340
- async def _analyze_with_gemini(
341
- self,
342
- screenshot_path: str,
343
- element_desc: str,
344
- **kwargs
345
- ) -> Optional[Dict[str, Any]]:
346
- """使用 Google Gemini 分析截图"""
347
- # TODO: 实现 Gemini Vision API 调用
348
- return None
349
-
350
- def get_enhanced_tools(self) -> List[Dict[str, Any]]:
351
- """
352
- 获取AI增强的工具列表
353
-
354
- Returns:
355
- AI增强工具的定义列表
356
- """
357
- tools = []
358
-
359
- if self.is_vision_available():
360
- # 视觉识别工具(根据平台调整描述)
361
- platform_name = self.get_platform_name()
362
- tools.append({
363
- "name": "mobile_analyze_screenshot",
364
- "description": f"分析截图并返回元素坐标。使用{platform_name}的多模态能力分析截图,找到指定元素并返回坐标。",
365
- "platform": self.detected_platform.value,
366
- "enhanced": True
367
- })
368
-
369
- return tools
370
-
371
- def get_capabilities(self) -> Dict[str, Any]:
372
- """获取当前平台的AI能力"""
373
- return {
374
- "platform": self.detected_platform.value,
375
- "platform_name": self.get_platform_name(),
376
- "vision": self.is_vision_available(),
377
- "multimodal": self.is_multimodal_available(),
378
- "free": self.platform_config.get("free", False),
379
- "enhanced_tools": [t["name"] for t in self.get_enhanced_tools()]
380
- }
381
-
382
-
383
- # 全局实例
384
- _ai_adapter: Optional[AIPlatformAdapter] = None
385
-
386
-
387
- def get_ai_adapter() -> AIPlatformAdapter:
388
- """获取全局AI适配器实例"""
389
- global _ai_adapter
390
- if _ai_adapter is None:
391
- _ai_adapter = AIPlatformAdapter()
392
- return _ai_adapter
393
-
394
-
395
- def reset_ai_adapter():
396
- """重置AI适配器(用于测试)"""
397
- global _ai_adapter
398
- _ai_adapter = None
399
-