autool/DroidBot/guiagent_core/prompt_builder.py
2026-06-17 19:44:18 +08:00

217 lines
9.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Prompt Builder - 生成不同平台的系统提示词
Extracted and adapted from GuiAgent/config/prompts.py for modular use in DroidBot.
Added iOS support with scale parameter.
"""
# Resolution placeholder for dynamic replacement
RESOLUTION_PLACEHOLDER = "<RESOLUTION>"
# ==============================================================================
# Action Space Definitions
# ==============================================================================
IOS_ACTION_SPACES = """
tap(center='[x, y]')
long_tap(center='[x, y]', duration_ms='1000')
drag(start_center='[x, y]', end_center='[x, y]')
type(content='')
key_press(key='HOME or BACK or ENTER')
wait()
receive_email()
finished()
login_ios()
solve_slider_captcha(captcha_region='[x1, y1, x2, y2]', slider_position='[x, y]')
solve_image_captcha(captcha_region='[x1, y1, x2, y2]', input_field='[x, y]')
report_stuck_reason(reason_code='0-12', message='reason description')
"""
ANDROID_ACTION_SPACES = """
tap(center='[x, y]')
long_tap(center='[x, y]', duration_ms='1000')
drag(start_center='[x, y]', end_center='[x, y]')
type(content='')
key_press(key='HOME or BACK or ENTER')
wait()
receive_email()
solve_slider_captcha(captcha_region='[x1, y1, x2, y2]', slider_position='[x, y]')
solve_image_captcha(captcha_region='[x1, y1, x2, y2]', input_field='[x, y]')
finished()
report_stuck_reason(reason_code='0-12', message='reason description')
"""
WINDOWS_ACTION_SPACES = """
click(center='[x, y]')
double_click(center='[x, y]')
right_click(center='[x, y]')
drag(start_center='[x, y]', end_center='[x, y]')
type(content='')
key_press(key='ctrl+v or alt+tab or enter')
scroll(start_center='[x, y]', direction='down or up or right or left')
wait()
receive_email()
finished()
"""
def _get_coord_instruction(absolute_mode: bool, resolution_str: str, scale: float = 1.0) -> str:
"""
生成坐标指令
Args:
absolute_mode: 是否使用绝对坐标模式
resolution_str: 分辨率字符串
scale: iOS scale factor (仅用于 iOS)
Returns:
坐标指令字符串
"""
if absolute_mode:
coord_inst = f"- Please return the coordinate values relative to the actual resolution of the screenshot, Width and height coordinate (x,y) from left-top (0, 0) to right-bottom {resolution_str}."
if scale > 1.0:
# iOS specific: add scale information
coord_inst += f" Note: Device scale is {scale}x, screenshot is in physical pixels ({resolution_str}), but coordinates should be in logical points."
return coord_inst
else:
return f"- Width and height coordinate (x,y) from left-top (0, 0) to right-bottom (1000, 1000) Please give the coordinates as 1000-normalized relative coordinates.**"
def _build_base_prompt(action_space: str, coord_instruction: str, extra_notes: str = "") -> str:
"""
构建基础提示词模板
Args:
action_space: 动作空间字符串
coord_instruction: 坐标指令
extra_notes: 额外的注意事项
Returns:
完整的提示词字符串
"""
notes = "- Write your thought in one sentence in `Thought` part."
if extra_notes:
notes += f"\n{extra_notes}"
notes += "\n- Check the conversation history and the current state of the application, do not repeat the same action."
notes += f"\n{coord_instruction}"
notes += "\n- You MUST provide the coordinates of the center of the target element's bounding box **"
# 添加错误恢复策略
notes += """
## Error Recovery Strategy
- 如果收到"✗ 上次操作失败"的反馈:
1. 点击未命中参考绿色圆圈标记判断偏移方向调整坐标偏左则向右移10-30像素偏上则向下移
2. 界面无变化:尝试滚动查看更多内容,或使用 BACK 键返回,或尝试长按等替代操作
3. 输入未生效:先 tap 输入框聚焦等待0.5秒,再 type 输入,最后按 ENTER 确认
4. 连续3次相同错误调用 report_stuck_reason 或尝试完全不同的路径"""
return f"""
You are a GUI agent. You are given a task and your action history, with screenshots. You need to perform the next action to complete the task.
## Action Space
{action_space.strip()}
## Note
{notes}
## Output Format
```
Thought: ...
Action: ...
```
"""
def get_ios_prompt(resolution: tuple = None, scale: float = 1.0, absolute_mode: bool = True) -> str:
"""
生成 iOS 系统提示词
Args:
resolution: 屏幕分辨率 (physical_width, physical_height),如果为 None 则使用占位符
注意:这是截图的物理像素分辨率,不是逻辑分辨率
scale: iOS scale factor (2.0 for @2x, 3.0 for @3x)
absolute_mode: 是否使用绝对坐标iOS 推荐使用 True
Returns:
系统提示词字符串
"""
resolution_str = f"({resolution[0]}, {resolution[1]})" if resolution else RESOLUTION_PLACEHOLDER
coord_instruction = _get_coord_instruction(absolute_mode, resolution_str, scale)
extra_notes = "- Both of `Thought` part and `Action` part need to be filled out."
extra_notes += "\n- IMPORTANT: If you see the iOS Home Screen (SpringBoard with app icons grid), it means you have accidentally left the target app. You MUST immediately call `finished()` to end the session. Do NOT try to re-open the app or perform any other actions on the Home Screen."
extra_notes += "\n- IMPORTANT: 上一次点击(tap/long_tap)或拖拽(drag)的起始坐标会以绿色圆圈标记在截图上。如果你发现多次操作后仍停留在当前页面,请参考绿圈位置判断上次点击是否命中目标元素,并相应调整坐标。"
if scale > 1.0:
extra_notes += f"\n- IMPORTANT: Screenshot resolution is {resolution_str} (physical pixels). Device scale is {scale}x. When you see an element at pixel position (x, y) in the screenshot, the tap coordinate should be (x/{scale}, y/{scale}) in logical points."
return _build_base_prompt(IOS_ACTION_SPACES, coord_instruction, extra_notes)
def get_android_prompt(resolution: tuple = None, absolute_mode: bool = False) -> str:
"""
生成 Android 系统提示词
Args:
resolution: 屏幕分辨率 (width, height),如果为 None 则使用占位符
absolute_mode: 是否使用绝对坐标
Returns:
系统提示词字符串
"""
resolution_str = f"({resolution[0]}, {resolution[1]})" if resolution else RESOLUTION_PLACEHOLDER
coord_instruction = _get_coord_instruction(absolute_mode, resolution_str)
extra_notes = """- Both of `Thought` part and `Action` part need to be filled out.
- 【滑块验证码】当检测到滑块验证码(需要拖动滑块到缺口位置)时,使用 solve_slider_captcha 动作。captcha_region 是验证码图片区域的坐标 [左上角x, 左上角y, 右下角x, 右下角y]仅包含验证码图片区域不包含滑块slider_position 是可拖动滑块按钮的中心坐标 [x, y]。此动作会自动识别缺口位置并拖动滑块完成验证。
- 【图片验证码】当检测到图片验证码(如字母/数字识别码)时,使用 solve_image_captcha 动作。captcha_region 是验证码图片区域坐标input_field 是验证码输入框的中心坐标。此动作会自动识别图片中的文字并输入到指定输入框。"""
return _build_base_prompt(ANDROID_ACTION_SPACES, coord_instruction, extra_notes)
def get_desktop_prompt(resolution: tuple = None, absolute_mode: bool = False) -> str:
"""
生成 Windows 桌面系统提示词
Args:
resolution: 屏幕分辨率 (width, height),如果为 None 则使用占位符
absolute_mode: 是否使用绝对坐标
Returns:
系统提示词字符串
"""
resolution_str = f"({resolution[0]}, {resolution[1]})" if resolution else RESOLUTION_PLACEHOLDER
coord_instruction = _get_coord_instruction(absolute_mode, resolution_str)
return _build_base_prompt(WINDOWS_ACTION_SPACES, coord_instruction)
def get_verification_prompt(category: str) -> str:
"""
生成界面验证提示词,用于二次确认当前界面是否为目标场景。
Args:
category: 目标场景类别 (login, payment, etc.)
Returns:
提示词字符串
"""
return f"""
You are a GUI verification expert. Your task is to judge whether the current screen is relevant to the "{category}" task based on the screenshot.
## Task
1. Analyze the UI elements, text, and layout in the screenshot.
2. Determine if the screen is related to "{category}".
- It IS related if:
- It is the "{category}" page itself (e.g., login form).
- It contains an entry point to "{category}" (e.g., a "Login" button on a welcome screen).
- It is a relevant intermediate step (e.g., account type selection before registering).
- It is a pop-up or overlay that might appear during "{category}" (e.g., permission request).
3. If it IS related, output "YES" and a brief reason.
4. If it is NOT related (e.g., a completely different app, a game screen when asking for login), output "NO" and the reason.
## Output Format
```
Result: YES/NO
Reason: ...
```
"""