AI云识别
低于 4002 的版本里没有这个模块,from ascript.ios.vlm import ascript_ai
会直接抛 ModuleNotFoundError。请先把 AScript 升级到 4002 或更新的版本。
from ascript.ios.vlm import ascript_ai as ai
iOS 不支持加载插件,所以 AI 识别直接内置在 AScript 中,导入即用。
Android 那边为了兼容老版本,同一套能力是以 ascript_ai 插件的形式提供的,
要先 plug.load("ascript_ai")。两端的功能和参数完全一致,只有导入方式不同,
跨端移植脚本时改这一行即可。
用自然语言描述在屏幕上找东西、问值、问页面状态,推理跑在 AScript AI Studio 云端。
不需要模板图、不需要固定文字、不需要训练模型 —— 直接用一句话描述你要什么。
- 没有模板图、也没有固定文字,只能靠语义描述的目标:"那个红色的关闭按钮"
- 界面改版频繁,写死的坐标和模板图天天失效
- 需要理解页面语义:"当前是不是登录页"、"列表里价格最低的那一项"
- 从屏幕上提取结构化数据:把商品列表读成
[{"name":..., "price":...}] - 图色/OCR 都试过但认不出来的兜底方案
能用 FindImages.find()(有模板图)或 Ocr.paddleocr()(有固定文字)解决的场景,
不要用AI云识别。那些是毫秒级且免费,这个是秒级且按量计费。
AI云识别是给"前两者做不到"的场景兜底的,不是用来替代它们的。
准备工作
1. 获取密钥
登录 AScript AI Studio → 账户中心 → 「API 调用」页面创建密钥。
密钥形如 sk-as- 开头的字符串,明文只在创建时显示一次,请立即保存。丢失只能重新创建。
每个账号最多 20 个密钥。密钥创建时会封存当时的登录凭证,如果账号中心让该凭证失效,
调用会返回 credential_expired,需要重新登录网页并重新创建密钥。
2. 初始化
from ascript.ios.vlm import ascript_ai as ai
ai.init(api_key="sk-as-xxxxxxxx")
也可以设置环境变量 ASCRIPT_AI_KEY,这样脚本里连 init() 都可以省掉。
快速开始
1. 第一个脚本
from ascript.ios.vlm import ascript_ai as ai
ai.init(api_key="sk-as-xxxxxxxx")
r = ai.find("右上角的购物车图标")
print(r)
# {'text': '购物车', 'rect': [960, 120, 1040, 200],
# 'center_x': 1000, 'center_y': 160, 'confidence': 1.0}
find() 的返回结构与 Ocr.paddleocr() 的每一项完全一致
(text / rect / center_x / center_y / confidence),
OCR 认不出来的时候可以直接换过来用。
设了环境变量 ASCRIPT_AI_KEY 的话,连 ai.init() 这行都可以省掉。
2. 找到并点击
最常用的一句。click() 内部会自己截屏、定位、点中心点,找不到返回 False。
ai.click("底部的立即购买按钮")
# 点不到时要有兜底,别默认它一定成功
if not ai.click("同意并继续"):
print("没找到那个按钮,换个描述试试")
想自己控制点击方式(长按、拖拽),就用 find() 拿坐标:
from ascript.ios import action
r = ai.find("列表里第一个商品的缩略图")
if r:
action.click(r["center_x"], r["center_y"], 800) # 长按 800ms
3. 判断页面状态
# 在不在
if ai.exists("登录按钮"):
ai.click("登录按钮")
# 是不是(返回真正的 bool,不是字符串)
if ai.ask_value("当前是不是支付成功页", value_type=bool):
print("下单完成")
# 让模型用自己的话描述(原文,只适合打印给人看)
print(ai.ask("当前是什么页面,用户在做什么"))
ask() 的返回是模型原文,格式会飘,不要拿去做 if 判断。
判断一律走 exists() 或 ask_value(..., value_type=bool)。
4. 从屏幕上取数据
ask_value() 用 Python 类型声明你要什么(参数名 value_type),返回值就是那个类型:
count = ai.ask_value("购物车里有几件商品", value_type=int) # -> 3
total = ai.ask_value("订单总金额是多少", value_type=float) # -> 128.5
title = ai.ask_value("标题栏写的什么", value_type=str) # -> '订单确认'
paid = ai.ask_value("是否已经支付", value_type=bool) # -> False
多个值用 [T]:
names = ai.ask_value("所有商品名称", value_type=[str]) # -> ['面包', '牛奶']
prices = ai.ask_value("每件商品的价格", value_type=[float]) # -> [12.5, 8.0]
返回 None 表示模型说它答不出来,要判一下再用:
n = ai.ask_value("有几条未读消息", value_type=int)
if n is None:
print("看不出来") # 图里没有相关信息
elif n == 0:
print("一条都没有") # 计数为零是真实答案,和上面 不是一回事
else:
print("有 %d 条" % n)
5. 把一张列表读成结构化数据
用带字段名的 dict 声明记录,字段名会一并告诉模型,它才好对号入座:
items = ai.ask_value("列表里所有商品", value_type=[{"name": str, "price": float}])
# -> [{'name': '面包', 'price': 12.5},
# {'name': '牛奶', 'price': 8.0}]
for it in items or []:
print(it["name"], it["price"])
单条记录就不加外面那层 []:
info = ai.ask_value("这个商品的信息",
value_type={"title": str, "price": float, "stock": int})
# -> {'title': '面包', 'price': 12.5, 'stock': 30}
6. 等待页面变化
r = ai.wait("加载完成的商品列表", timeout=20)
if r is None:
print("等超时了")
每轮都是一次完整的云端推理(几秒)并且都要计费,timeout=20 大概只够跑
三五轮。不要图省事写 timeout=300。
7. 只看一块区域:又快又省
rect=[left, top, right, bottom]。这是最值得养成的习惯 ——
裁剪比降采样保真得多,图更小、更快、更省钱,而返回的仍然是完整屏幕坐标,
不用你自己加偏移。
# 只看底部 1/4 屏
ai.find("确定按钮", rect=[0, 1800, 1080, 2400])
# 只看顶部状态栏
ai.ask_value("现在电量百分之多少", value_type=int, rect=[0, 0, 1080, 100])
8. 一次截屏,多次提问
默认每次调用都会自动截一次屏。同一个画面要问好几件事时,自己截一次复用:
from ascript.ios import screen
shot = screen.capture() # 返回 PIL.Image,可直接传给 ai
total = ai.ask_value("总价", value_type=float, image=shot)
count = ai.ask_value("商品件数", value_type=int, image=shot)
addr = ai.ask_value("收货地址", value_type=str, image=shot)
image= 还接受 ndarray 和图片路径,见下文。
iOS 还有个更省事的办法:screen.cache(True) 开启截图缓存后,
后续的 capture() / 找图 / 找色都复用同一张截图,不用自己传来传去。
用完记得 screen.cache(False) 关掉,否则画面变了还在用旧图。
9. 描述不准时,用 hint 补充上下文
ai.find("确定按钮", hint="在底部弹窗里,不是顶部导航栏那个")
ai.ask_value("图中算式的结果", value_type=int, hint="只算红框里那一道")
小目标看不清时再考虑调清晰度(但优先试 rect):
ai.find("底部那个很小的图标", image_tokens=2048)