跳转至

gpy Python API

gpy 是 GhostClickAI 自定义 Python 的内置 API,属于用户手册。本文按 2026-09-09 开发候选契约编写;可用能力以当前客户端、组件和权限为准,不表示所有发布版本或所有平台、设备均已完成真实验证。

import gpy

模块由执行环境注入,不需要也不应从外部包源 pip install gpy。真实旧脚本中的 import gcbppy 指向同一个模块对象,仅用于已有脚本兼容;新脚本统一使用 gpy,没有第二套 API。

gpy 直接复用截图、视觉和输入等底层服务;运行工厂负责适配当前任务上下文,不是借节点处理器拼接或执行另一张蓝图。脚本在独立 Python 3.13 进程中运行,但拥有本机用户权限,不是安全沙箱

开始使用与能力声明

自定义 Python 节点中声明输入、输出和脚本。名字是节点私有变量名,不是蓝图公共变量名;输出只在整个脚本成功且全部类型校验通过后提交。未设置的已声明输出保留默认值。

双击节点后,当前画布切换为分区编辑工作区,不以弹窗承载整个编辑器:中间编辑代码,左右声明输入、输出端口,侧栏可以收起;端口 API 提示按需展开。顶栏提供返回与保存,保存配置不等于运行脚本。

例如,声明整数输入 count 和整数输出 next_count

import gpy

gpy.set_output("next_count", gpy.get_input("count") + 1)

需要宿主服务时,在编辑器勾选对应 SDK 能力。配置 customPythonConfig.sdkCapabilities 是无重复字符串列表;省略或空列表表示未声明宿主能力,只接受下列四项:

声明 函数 运行前准备
capture capture 当前目标的截图服务
match match Python 视觉基础环境与 OpenCV
ocr ocr Python 视觉基础环境、ONNX 与默认 OCR 模型
input input.click/swipe/key/text 当前目标的输入服务

声明用于运行前依赖预检和调用准入,不是权限授权或安全隔离。未声明的宿主调用会被拒绝;子 worker 也不能绕过父节点声明。纯输入输出、媒体构造与普通 Python 计算不要求上述声明。基础视觉依赖在运行前预检;OCR 可按本次请求准备已安装的内置模型,但不会自动下载模型。缺失组件或模型会明确报错,先按客户端提示准备。

输入、输出、类型与日志

函数 / 属性 契约
gpy.inputs() 返回全部声明输入的深拷贝字典
gpy.get_input(name, default=...) 读取输入;未知名字且未给默认值时抛 KeyError
gpy.set_output(name, value) 校验并暂存已声明输出;未知名字抛 KeyError
gpy.vector2(x=0, y=0) 带类型的二维向量字典
gpy.vector3(x=0, y=0, z=0) 带类型的三维向量字典
gpy.vector4(x=0, y=0, z=0, w=0) 带类型的四维向量字典
gpy.color(r=0, g=0, b=0, a=255) 带类型的颜色字典,各分量为 0–255 整数
gpy.log(...) print 相同的日志入口;标准输出和标准错误会被捕获
gpy.task_directory 本次执行的临时工作目录字符串,不是永久路径
端口 typeId Python 值
string str
integer int,不接受布尔值代替整数
number 有限数值,不接受 NaN / 无穷大
bool bool
vector2 / vector3 / vector4 对应 gpy.vector2/3/4 类型值
color gpy.color 类型值
vector2_array pointscoordinateSpacemetadata 的点集,保留坐标空间
array 支持的可序列化数组;需保留类型的嵌套向量/颜色使用构造函数
visual_media 媒体描述字典或 None,不是裸路径或任意 Python 对象

修改输入对象不会自动写回蓝图。类型不符、脚本异常、超时或取消不提交半份输出。日志收集有 16,000 字符上限并带截断提示;不要用日志传大数据,也不要写入凭据或私人素材。

媒体与文件生命周期

函数 输入与返回
gpy.media(path, kind=None) 验证真实文件并返回媒体描述;kindimage / video,省略时探测
gpy.image(width, height, color=(0, 0, 0, 0)) 创建 RGBA 图像,返回媒体描述
gpy.image_from_array(array) NumPy uint8 灰度、RGB 或 RGBA 数组转图像媒体
gpy.open_image(value) 返回独立 Pillow 图像,调用方负责关闭
gpy.video(frames, fps=30) 同尺寸图像媒体或 RGB/RGBA 数组生成视频媒体

媒体构造的图像上限为 6,400 万像素;视频 1–100,000 帧,帧率大于 0 且不超过 240。实际仍受组件、内存、编码器和总超时限制。宿主视觉函数另有更严格限制,见下文。

声明 source 图像输入、result 媒体输出后,可生成缩略图:

import gpy

with gpy.open_image(gpy.get_input("source")) as image:
    image.thumbnail((640, 640))
    path = gpy.task_directory + "/thumbnail.png"
    image.save(path)
gpy.set_output("result", gpy.media(path, "image"))

输出文件必须通过 visual_media 交还客户端。成功交接的受管媒体在父任务作用域关闭前可供下游使用,不因当前 Python 进程结束立刻失效;这不意味着永久保存。需要长期保留时使用软件资源保存/导出功能,复制到用户授权目录。失败输出不会提交,任务临时目录也不能作为外部长效引用。

目标与截图

# 签名说明
# gpy.capture(target, roi=(0, 0, 1, 1))

target 必须是明确、完整的目标信息字符串,最多 8192 字符,使用 android:window:screen: 三种小写前缀。不得为空或带首尾空白、NUL;没有隐式默认目标,未知前缀不会回退主屏。范围属于屏幕目标,不使用 range:exe:

android: 后保留启动/扫描节点输出的完整实例 JSON,不拆成裸 ADB 地址,不手工伪造身份。详见目标信息与截图

capturematchocrroi 都接受两点列表或元组 ((left, top), (right, bottom)),与编辑器生成结果一致;也接受四元素写法 (left, top, right, bottom)。分量是 0–1 有限数,要求左小于右、上小于下;默认全图。截图裁切使用左/上向下取整、右/下向上取整。

capture 返回图像媒体字典,包含 kind='image'、任务内 PNG 的绝对 pathwidthheight、媒体 asset 元数据,以及 sourceGeometrysourcesourceId 来源信息。它可以传给 matchocrset_output,无需转成裸路径。

从编辑器创建识别范围

在 Python 代码区右键选择“创建识别范围”,分两次框选:先选定整个计算域,再在该计算域的静态截图中框选实际 ROI。第二次框选相对于第一次的计算域归一化,左上为 (0, 0)、右下为 (1, 1);完成后在光标处插入 ((x0, y0), (x1, y1))。它只辅助写入坐标,不执行脚本、不发送目标输入,也不把这张截图内嵌为蓝图资源。

计算域必须与运行时传给 gpy.match/ocr 的图像范围一致。gpy.capture 的窗口截图是窗口客户区,不是包含标题栏和边框的窗口外框;拿窗口截图识别时,第一次也要选客户区。若图像已经裁切,应以裁切后的整张图为计算域;不要把桌面整体、窗口外框或编辑器显示留白当作该图的坐标范围。

助手插入的两个角点可以直接作为 roi 传给 gpy.capture/match/ocr,不需要手工展开成四个数。例如声明图像输入 source、勾选 ocr,并确认 source 与框选计算域完全对应:

import gpy

# 将助手插入的两点值放在这里;下列数字仅为示例。
roi = ((0.1, 0.2), (0.8, 0.9))
result = gpy.ocr(gpy.get_input("source"), roi=roi)
gpy.log(result["text"])

图像匹配与 OCR

# 签名说明
# gpy.match(image, template, threshold=.8, max_results=20, roi=(0, 0, 1, 1))
# gpy.ocr(image, language='zh', roi=(0, 0, 1, 1), *, model=None)

imagetemplate 使用图像媒体描述。threshold 为 0–1 有限数,max_results 为 1–100 整数;模板不能大于搜索 ROI。当前签名没有多尺度搜索参数。合法的未命中返回空列表 [],无效媒体或后端错误抛异常,不能当作未命中。

match 返回列表,每项含 score 与下表几何字段。ocr 返回 {text, items, modelInfo},每个 item 含 textconfidence 与相同几何字段。OCR 最多 2000 项,原始结果 JSON 最多 2 MiB。

language 只接受以下四个值;省略 model 或传 None 时按语言选择默认识别模型:

language 默认识别模型
zh(中文) ocr/ch_PP-OCRv5_rec_mobile_infer.onnx
en(英文) ocr/ch_PP-OCRv5_rec_mobile_infer.onnx
ja(日文) ocr/ch_PP-OCRv5_rec_mobile_infer.onnx
ko(韩文) ocr/korean_PP-OCRv5_mobile_rec.onnx

model 是仅限关键字的内置识别模型选择器,只接受表中的两个相对文件名;不接受外部路径、任意模型或未知语言。显式选择会覆盖语言对应的默认识别模型,但不会自动下载缺失文件。中、英、日默认共享同一识别模型,不能把 language='en' 描述成加载了独立英文模型。

modelInfo 返回本次实际选择的 languagedetModelFileNamerecModelFileNameclsModelFileName,模型文件名使用内置相对路径。需要核对所用模型时读取这个结果,不根据语言标签猜测文件。声明图像输入 source 并勾选 ocr 后,例如:

import gpy

result = gpy.ocr(
    gpy.get_input("source"),
    language="en",
    model="ocr/ch_PP-OCRv5_rec_mobile_infer.onnx",
)
gpy.log(result["text"])
gpy.log(result["modelInfo"])
几何字段 含义
rect 当前搜索 ROI 内像素矩形 [left, top, right, bottom],右/下为半开边界
center 当前搜索 ROI 内像素中心 {x, y}
coordinateSpace roi_local_pixels,不是目标全图坐标
sourceRectNormalized 映回原始来源的 0–1 矩形边界
sourceCenterNormalized 映回原始来源、可用于同一目标输入的 0–1 像素索引坐标 {x, y}
sourceGeometry 来源尺寸及当前 ROI 对原始来源的映射

sourceGeometrycoordinateSpace='logical_source_pixels'sourceWidthsourceHeightsourceLeftsourceTopsourceSpanWidthsourceSpanHeight。对已有裁切图再次指定 ROI,会组合映射回最初来源,而不是把局部 PNG 当作整个目标。

矩形归一化以来源宽/高为分母;点击点归一化以宽减一/高减一为分母(单像素维度为 0),二者不能混用。无来源几何的外部图像以自身为来源;自行变换图像后不要保留不再准确的映射并据此点击。目标尺寸或画面已改变时应重新截图和识别。

下面只识别,不发送输入。先声明字符串输入 target、图像输入 template、布尔输出 found 和二维向量输出 position,并勾选 capturematch

import gpy

target = gpy.get_input("target")
image = gpy.capture(target, roi=(0.1, 0.1, 0.9, 0.9))
hits = gpy.match(image, gpy.get_input("template"), threshold=0.85)
gpy.set_output("found", bool(hits))
if hits:
    point = hits[0]["sourceCenterNormalized"]
    gpy.set_output("position", gpy.vector2(point["x"], point["y"]))

下游必须先检查 found,无命中时不得将输出默认坐标当作有效位置。

向目标发送输入

以下函数要求声明 input,且用户已授权操作该目标;创作或编辑脚本授权不自动等于发送输入授权。

# 签名说明
# gpy.input.click(target, position, coordinate_space='normalized')
# gpy.input.swipe(target, start, end, duration_ms=300,
#                 coordinate_space='normalized')
# gpy.input.key(target, key)
# gpy.input.text(target, text)

position/start/end{x, y} 字典或 gpy.vector2coordinate_space 仅接受 normalized / pixels:前者每维 0–1,映射为 round(x * (width - 1))round(y * (height - 1));后者直接使用目标逻辑像素,必须落在实际尺寸内。不要把匹配结果的 ROI 局部 center 直接传给目标输入。

swipe.duration_ms 为 1–60000 整数。key 是目标服务支持的单个键盘键标识,不是任意组合键表达式,不接受 Mouse* 鼠标标识,最多 64 字符。text 是非空字符串,最多 4096 字符,使用现有粘贴模式,不先清空内容,也不自动按 Enter。Android 需要完整实例身份及可用的对应 ADB 输入能力。

clickswipe 返回 {ok: true, position: {x, y}, coordinate_space: 'pixels'},其中滑动的 position 是终点;key/text 返回 {ok: true}。这些只表明服务调用成功,不证明目标应用已完成业务动作。

如果用户已授权点击,且上例的目标仍未变化,可在同一脚本中追加:

# 此片段接在前例后;另需声明 input 能力。
if hits:
    gpy.input.click(target, hits[0]["sourceCenterNormalized"])

受管 worker

# 签名说明
# gpy.workers.run(script, inputs=None, outputs=None,
#                 input_types=None, timeout_millis=None)
# gpy.workers.map(script, items, outputs, input_types=None, max_workers=4)

run 返回输出名称到值的字典。outputs 的值可为类型 ID,或含 typeIddefaultValue 的声明字典;输入可推断类型,歧义值应给 input_types。子 worker 的输出不会隐式写进父节点,父脚本仍需 set_output

import gpy

result = gpy.workers.run(
    script='import gpy\ngpy.set_output("answer", gpy.get_input("n") * 2)',
    inputs={"n": 5},
    outputs={"answer": "integer"},
    input_types={"n": "integer"},
    timeout_millis=1000,
)
gpy.log(result["answer"])

mapitems 是输入字典序列,最多 64 项,按输入顺序返回结果,max_workers 为 1–4。每个父 worker 同时最多 4 个直接子 worker,嵌套最多 2 层,不代表整棵进程树最多 4 个进程。子时限不超过父剩余时限,子异常和超时向父脚本传播。

受管 worker 属于父执行,不是常驻任务。父节点取消、超时、结束或控制通道失去所有者时,受管子进程会被停止并回收;自行创建的非受管后台进程不属于此生命周期保证。子 worker 的宿主调用与根执行共享能力声明和调用额度。

限额、失败与暂停

范围 当前上限 / 行为
节点配置 默认 30000 ms;可设 100–3600000 ms,包含子任务与宿主调用
数据声明 输入、输出各 64 端口;脚本 UTF-8 1 MiB;单个默认值 JSON 1 MiB
协议 单帧 16 MiB,流累计 64 MiB;单次根执行最多 256 次宿主请求,同时最多 4 次
视觉并发 同一视觉服务串行处理;并发视觉调用可报 vision_busy,不因协议允许 4 次就能并发识别
视觉图像 每边最多 8192 像素、总计最多 16 × 1024 × 1024 像素、文件最多 64 MiB
视觉生成文件 每个服务最多 128 个、PNG 合计最多 256 MiB,包含截图及模板快照等

视觉只接受实际尺寸一致的静态单帧图像,不接受视频、动画或 .npy 冒充图片。媒体字段限于 kind/path/width/height/asset/sourceGeometry/source/sourceId,不要塞入任意附加对象。

本地参数错误通常为 TypeError / ValueError,超时为 TimeoutError,宿主服务失败通过 RuntimeError 传回错误信息,例如 component_not_preparedvision_busycancelled;不要依赖未公开的 Python 异常 .code 属性。错误、取消和资源清理必须作为失败处理,不伪造空成功结果。

取消不是所有原生操作瞬时中断的承诺。已发出的窗口截图没有单请求中止接口,停止时会等待该有界请求实际结束,再拒绝结果并清理;默认后端请求最长可达两分钟。观察任务稳定终态和目标输入停止后,再开始替代运行。

暂停会结束正在运行的 Python 进程,不保存或恢复 Python 语句栈。续跑遵循父任务规则,可能重新进入节点;不能盲目重放已发生或结果不明的点击、文字输入、网络请求。停止和超时不回滚已经发生的外部副作用,也不能保证强制结束时 finally 必然执行。

运行中的蓝图使用已加载执行快照,编辑不会热替换当前 Python 正文;详细限制见运行期间编辑蓝图。运行信任、创作资格、购买许可和目标操作授权分别核对,不以 SDK 声明、独立进程或受管 worker 绕过。