Skip to content

Commit 2b7c061

Browse files
committed
v5.0-C 移动端AI分析(提示词+截图分析API+步骤验证+测试脚本生成)
1 parent 1b796f1 commit 2b7c061

2 files changed

Lines changed: 142 additions & 0 deletions

File tree

src/api/routes.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,60 @@ async def close_mobile_session(session_id: str) -> dict:
791791
except Exception as e:
792792
return {"message": f"关闭时出错: {e}"}
793793

794+
@router.post("/mobile/session/{session_id}/analyze", tags=["手机测试"])
795+
async def mobile_analyze(session_id: str, req: dict = None) -> dict:
796+
"""截图并用AI分析手机当前页面。
797+
798+
Body (可选):
799+
context: 额外上下文描述
800+
expected: 预期结果(用于步骤验证模式)
801+
"""
802+
ctrl = _mobile_sessions.get(session_id)
803+
if not ctrl:
804+
raise HTTPException(status_code=404, detail="会话不存在")
805+
if not ai_client:
806+
raise HTTPException(status_code=503, detail="AI客户端未配置")
807+
808+
req = req or {}
809+
try:
810+
# 截图
811+
path = await ctrl.screenshot("ai_analyze")
812+
813+
# AI分析
814+
from src.core.prompts import (
815+
SYSTEM_MOBILE_ANALYZER,
816+
PROMPT_MOBILE_ANALYZE,
817+
PROMPT_MOBILE_VERIFY_STEP,
818+
)
819+
820+
context = req.get("context", "用户手机当前屏幕")
821+
expected = req.get("expected", "")
822+
823+
if expected:
824+
prompt = PROMPT_MOBILE_VERIFY_STEP.format(
825+
expected=expected,
826+
action_description=req.get("action_description", ""),
827+
)
828+
else:
829+
prompt = PROMPT_MOBILE_ANALYZE.format(context=context)
830+
831+
analysis = ai_client.analyze_screenshot(
832+
image_path=str(path),
833+
prompt=prompt,
834+
system_prompt=SYSTEM_MOBILE_ANALYZER,
835+
)
836+
837+
import base64 as b64mod
838+
img_b64 = b64mod.b64encode(path.read_bytes()).decode()
839+
840+
return {
841+
"screenshot_path": str(path),
842+
"screenshot_base64": img_b64,
843+
"analysis": analysis,
844+
}
845+
except Exception as e:
846+
raise HTTPException(status_code=500, detail=f"分析失败: {e}")
847+
794848
@router.get("/mobile/sessions", tags=["手机测试"])
795849
async def list_mobile_sessions() -> dict:
796850
"""列出所有活跃的手机测试会话。"""

src/core/prompts.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,3 +387,91 @@
387387
1. 从HTML中提取所有可交互元素(表单、按钮、链接等),生成 elements 映射
388388
2. 根据页面功能设计测试场景
389389
3. 输出完整的 testpilot.json(JSON格式)"""
390+
391+
392+
# ── 移动端截图分析(v5.0)────────────────────────────
393+
394+
SYSTEM_MOBILE_ANALYZER = """你是 TestPilot AI 的移动端视觉分析引擎。
395+
你的任务是分析手机App截图,识别UI元素、检测Bug、评估用户体验。
396+
397+
你必须严格按照以下JSON格式返回,不要包含任何其他文字:
398+
399+
```json
400+
{
401+
"app_name": "识别到的应用名称",
402+
"screen_type": "页面类型(首页/登录/列表/详情/设置/弹窗/其他)",
403+
"elements": [
404+
{"type": "button", "text": "按钮文字", "position": "位置描述"},
405+
{"type": "input", "text": "输入框提示", "position": "位置描述"},
406+
{"type": "text", "text": "文本内容", "position": "位置描述"}
407+
],
408+
"issues": [
409+
{"severity": "high/medium/low", "description": "问题描述", "suggestion": "修复建议"}
410+
],
411+
"ux_score": 8,
412+
"ux_comments": "用户体验评价",
413+
"matches_expected": true,
414+
"confidence": 0.95
415+
}
416+
```
417+
418+
移动端特有的检查项:
419+
1. 触摸目标是否足够大(至少44x44dp)
420+
2. 文字大小是否适合手机阅读(不小于12sp)
421+
3. 是否有适配刘海屏/底部导航栏
422+
4. 滚动内容是否有合理边距
423+
5. 弹窗/Toast是否遮挡关键内容
424+
6. 深色/浅色模式是否正常
425+
7. 横竖屏切换后布局是否正常
426+
8. 加载状态是否有骨架屏或loading提示"""
427+
428+
PROMPT_MOBILE_ANALYZE = """请分析这张手机App截图:
429+
430+
{context}
431+
432+
请识别页面类型、可交互元素、潜在问题,并给出UX评分(1-10分)。"""
433+
434+
PROMPT_MOBILE_VERIFY_STEP = """请验证这张手机截图是否符合预期:
435+
436+
预期结果:{expected}
437+
操作描述:{action_description}
438+
439+
请判断截图是否符合预期,返回JSON格式结果。"""
440+
441+
SYSTEM_MOBILE_TEST_GENERATOR = """你是 TestPilot AI 的移动端测试脚本生成引擎。
442+
你的任务是根据手机App截图和描述,生成结构化的移动端测试步骤。
443+
444+
你必须严格按照以下JSON格式返回:
445+
446+
```json
447+
{
448+
"test_name": "测试名称",
449+
"platform": "android",
450+
"steps": [
451+
{
452+
"step": 1,
453+
"action": "tap",
454+
"target": "//android.widget.Button[@text='登录']",
455+
"value": "",
456+
"description": "点击登录按钮",
457+
"expected": "弹出登录对话框"
458+
}
459+
]
460+
}
461+
```
462+
463+
支持的 action 类型(移动端):
464+
- tap: 点击元素(target为xpath/id/accessibility_id)
465+
- input: 输入文本(target为选择器,value为文本)
466+
- swipe: 滑动(target为方向up/down/left/right,value为距离)
467+
- long_press: 长按(target为选择器)
468+
- back: 返回(target为空)
469+
- screenshot: 截图验证(target为空)
470+
- navigate: 打开Activity或URL(target为Activity名或URL)
471+
- wait: 等待元素出现(target为选择器)
472+
473+
选择器格式:
474+
- xpath: //android.widget.Button[@text='确定']
475+
- id: id:com.example.app:id/btn_login
476+
- accessibility_id: accessibility_id:登录按钮
477+
- class: class:android.widget.EditText"""

0 commit comments

Comments
 (0)