ms-vite-plugin 1.4.74 → 1.4.76
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.
- package/dist/luaBundle.js +1 -1
- package/dist/luaObfuscator/addVararg.js +1 -1
- package/dist/luaObfuscator/flatten.js +1 -1
- package/dist/luaObfuscator/rename.js +1 -1
- package/dist/luaObfuscator/scope.js +1 -1
- package/docs/api/ai.md +525 -0
- package/docs/apicn/ai.md +492 -0
- package/docs/apilua/ai.md +495 -0
- package/docs/apipython/ai.md +466 -0
- package/docs/apipython/overview.md +0 -39
- package/docs/quick/vscode/createProject.md +0 -1
- package/package.json +1 -1
package/docs/apicn/ai.md
ADDED
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
# AI 模块 ($AI)
|
|
2
|
+
|
|
3
|
+
AI 模块让脚本直接在手机上调用大模型:看图回答问题、做是非判断、从屏幕提取结构化数据、多轮对话。
|
|
4
|
+
|
|
5
|
+
支持三种接口协议,覆盖绝大多数模型服务:
|
|
6
|
+
|
|
7
|
+
| `protocol` | 适用服务 |
|
|
8
|
+
| ----------- | ------------------------------------------------------------------------------------- |
|
|
9
|
+
| `openai` | DeepSeek、通义千问、Kimi、智谱、SiliconFlow、本机 Ollama / vLLM 等 |
|
|
10
|
+
| `anthropic` | 国内一般走 openai 兼容口,不必单独配 |
|
|
11
|
+
| `gemini` | 国内一般走 openai 兼容口,不必单独配 |
|
|
12
|
+
|
|
13
|
+
模型配置(地址、Key、模型名)直接写在脚本里,脚本开头 `$AI.设置模型` 一次即可;脚本停止后配置自动清空,不会存到手机上。
|
|
14
|
+
|
|
15
|
+
所有方法同步阻塞,失败时返回 `null` / `false`,原因用 `$AI.获取错误()` 查看。
|
|
16
|
+
|
|
17
|
+
## 快速开始
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
// 1. 脚本开头登记模型(只需一次)。通义千问 Qwen3.5 起原生多模态,看图、问字都能用。
|
|
21
|
+
$AI.设置模型({
|
|
22
|
+
name: "通义千问",
|
|
23
|
+
protocol: "openai",
|
|
24
|
+
baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
|
25
|
+
apiKey: "sk-xxxxxxxx",
|
|
26
|
+
model: "qwen3.5-flash",
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// 2. 直接问
|
|
30
|
+
$打印信息日志($AI.提问("用一句话介绍你自己"));
|
|
31
|
+
|
|
32
|
+
// 3. 看着屏幕判断
|
|
33
|
+
if ($AI.判断("当前是否已经登录成功?", { image: "screen" })) {
|
|
34
|
+
$打印信息日志("已登录");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 4. 从屏幕某个区域提取数据
|
|
38
|
+
const 数据 = $AI.提取("提取验证码", {
|
|
39
|
+
image: "screen",
|
|
40
|
+
x: 100,
|
|
41
|
+
y: 800,
|
|
42
|
+
ex: 600,
|
|
43
|
+
ey: 900,
|
|
44
|
+
schema: { code: "string" },
|
|
45
|
+
});
|
|
46
|
+
if (数据) $打印信息日志(数据.code);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 图片参数
|
|
50
|
+
|
|
51
|
+
图片参数和图片模块**完全一样**,没有单独的截图开关:
|
|
52
|
+
|
|
53
|
+
| 参数 | 含义 |
|
|
54
|
+
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
55
|
+
| `image` | `imageId`,与图片模块所有函数的 `imageId` 参数一样:`$图片.截取屏幕()` 等返回的图片 ID、`"screen"`(当前屏幕)、res 目录或手机绝对路径的图片文件 |
|
|
56
|
+
| `x`, `y`, `ex`, `ey` | 对 `image` 裁剪,同 `$图片.裁剪图片(imageId, x, y, ex, ey)`:左上角 / 右下角坐标,全 0 不裁剪。只写区域不写 `image` 时按 `"screen"` |
|
|
57
|
+
| `images` | 多张图的数组,元素同 `image`,不裁剪 |
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
// 当前全屏
|
|
61
|
+
$AI.提问("屏幕上有几个按钮?", { image: "screen" });
|
|
62
|
+
|
|
63
|
+
// 屏幕区域:左上 (0, 200) 到右下 (750, 600)
|
|
64
|
+
$AI.提问("这一块显示的价格是多少?", { image: "screen", x: 0, y: 200, ex: 750, ey: 600 });
|
|
65
|
+
|
|
66
|
+
// 已有的图片 ID
|
|
67
|
+
const 图片ID = $图片.截取屏幕();
|
|
68
|
+
$AI.提问("描述这张图", { image: 图片ID, x: 0, y: 0, ex: 750, ey: 400 });
|
|
69
|
+
$图片.释放图片(图片ID);
|
|
70
|
+
|
|
71
|
+
// 图片文件
|
|
72
|
+
$AI.提问("这张图里是什么", { image: "sample.png" });
|
|
73
|
+
|
|
74
|
+
// 一次传多张:模板图 + 当前屏幕
|
|
75
|
+
$AI.判断("第二张图里有没有第一张图的图标?", { images: ["icon.png", "screen"] });
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## 费用说明
|
|
79
|
+
|
|
80
|
+
模型按 token 计费,其中图片是大头:一张 iPhone 全屏截图约 1400 ~ 1500 token,文字提问通常只有几十个。
|
|
81
|
+
|
|
82
|
+
- **能裁区域就不发全屏。** 只发需要看的那一块,token 通常能少 5 ~ 10 倍。
|
|
83
|
+
- **循环里保持提示词不变。** 三家服务都有「前缀缓存」:连续请求里开头相同的部分按约 1/10 计费。AI 模块已经把 `system` 排最前、文字排在图片之前,循环里每次只有图片变,`system` 和问题文字都能命中缓存。不要往 `system` 或问题里拼时间、序号这类每次都变的内容。
|
|
84
|
+
- **不同场景用不同模型。** 便宜的文本模型做默认,视觉模型只在需要看图时用(见 [设置模型](#设置模型))。
|
|
85
|
+
|
|
86
|
+
## 数据类型
|
|
87
|
+
|
|
88
|
+
### 模型供应商
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
interface 模型供应商 {
|
|
92
|
+
id: 字符串; // 供应商 id,不传时自动生成
|
|
93
|
+
name: 字符串; // 展示名,例如 "DeepSeek",调用时可用它选模型
|
|
94
|
+
protocol: "openai" | "anthropic" | "gemini";
|
|
95
|
+
baseUrl: 字符串; // 接口根地址,例如 https://api.deepseek.com
|
|
96
|
+
apiKey: 字符串; // API Key;openai 协议连本机模型时可为空
|
|
97
|
+
model: 字符串; // 默认模型名
|
|
98
|
+
headers: 字典<字符串>; // 额外请求头,某些网关需要
|
|
99
|
+
temperature?: 数字; // 默认温度;不传则不发该字段,用模型自己的默认值
|
|
100
|
+
maxTokens?: 数字; // 默认最大输出 token;不传则不发,用模型默认值(Anthropic 必填,缺省 2048)
|
|
101
|
+
reasoningEffort?: "none" | "low" | "medium" | "high" | "xhigh"; // 思考级别,仅 openai 协议;不传不发,用服务商默认
|
|
102
|
+
supportsVision: 布尔值; // 是否支持图片输入,默认 true
|
|
103
|
+
isDefault: 布尔值; // 是否为默认供应商
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 调用选项
|
|
108
|
+
|
|
109
|
+
`提问` / `判断` / `提取` / `对话` 的第二个参数,所有字段可选:
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
interface 调用选项 {
|
|
113
|
+
provider?: 字符串; // 用哪个供应商:id 或 name;不传用默认
|
|
114
|
+
model?: 字符串; // 临时换模型
|
|
115
|
+
temperature?: 数字; // 覆盖默认温度
|
|
116
|
+
maxTokens?: 数字; // 覆盖默认最大输出 token
|
|
117
|
+
timeout?: 数字; // 超时毫秒,默认 90000
|
|
118
|
+
json?: 布尔值; // 要求模型输出 JSON(提取 自动开启)
|
|
119
|
+
system?: 字符串; // 系统提示(对话 不用这个,写在消息里)
|
|
120
|
+
image?: 字符串; // imageId,同图片模块:图片 ID / "screen" / 图片路径
|
|
121
|
+
x?: 数字; // 裁剪区域左上角 X,同 $图片.裁剪图片
|
|
122
|
+
y?: 数字; // 裁剪区域左上角 Y
|
|
123
|
+
ex?: 数字; // 裁剪区域右下角 X,全 0 不裁剪
|
|
124
|
+
ey?: 数字; // 裁剪区域右下角 Y
|
|
125
|
+
images?: 数组<字符串>; // 多张图,元素同 image,不裁剪
|
|
126
|
+
schema?: 字符串 | object; // 仅 提取:期望的 JSON 结构说明
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 对话消息
|
|
131
|
+
|
|
132
|
+
`对话` 的消息项,图片参数与 `调用选项` 相同:
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
interface 对话消息 {
|
|
136
|
+
role: "system" | "user" | "assistant";
|
|
137
|
+
content: 字符串;
|
|
138
|
+
image?: 字符串;
|
|
139
|
+
x?: 数字;
|
|
140
|
+
y?: 数字;
|
|
141
|
+
ex?: 数字;
|
|
142
|
+
ey?: 数字;
|
|
143
|
+
images?: 数组<字符串>;
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## API 参考
|
|
148
|
+
|
|
149
|
+
### 设置模型
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
function 设置模型(配置: Partial<模型供应商>): 模型供应商 | null;
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**参数:**
|
|
156
|
+
|
|
157
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
158
|
+
| ------ | -------------------- | -------- | ------ | ----------------------------------------------------------------------------------- |
|
|
159
|
+
| `配置` | `Partial<模型供应商>` | 是 | - | 新建至少要有 `baseUrl`、`model`(`protocol` 缺省 openai);同 `id` 更新时没传的字段沿用旧值 |
|
|
160
|
+
|
|
161
|
+
**返回值:**
|
|
162
|
+
|
|
163
|
+
| 类型 | 描述 |
|
|
164
|
+
| ------------ | ------------------------------------------------------------------------------- |
|
|
165
|
+
| `模型供应商` | 保存后的完整配置;`protocol` 不是三者之一或缺 `baseUrl` / `model` 时返回 `null` |
|
|
166
|
+
|
|
167
|
+
第一个登记的供应商自动成为默认;`isDefault: true` 会把默认切到它。
|
|
168
|
+
|
|
169
|
+
**示例:**
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
// 只用一个模型(通义能看图)
|
|
173
|
+
$AI.设置模型({
|
|
174
|
+
name: "通义千问",
|
|
175
|
+
protocol: "openai",
|
|
176
|
+
baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
|
177
|
+
apiKey: "sk-xxxxxxxx",
|
|
178
|
+
model: "qwen3.5-flash",
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// 多个模型省钱:便宜的文本模型做默认,视觉模型单独一个,用到时按 name 选
|
|
182
|
+
$AI.设置模型({
|
|
183
|
+
name: "文本",
|
|
184
|
+
protocol: "openai",
|
|
185
|
+
baseUrl: "https://api.deepseek.com",
|
|
186
|
+
apiKey: "sk-xxxxxxxx",
|
|
187
|
+
model: "deepseek-v4-flash",
|
|
188
|
+
supportsVision: false,
|
|
189
|
+
isDefault: true,
|
|
190
|
+
});
|
|
191
|
+
$AI.设置模型({
|
|
192
|
+
name: "视觉",
|
|
193
|
+
protocol: "openai",
|
|
194
|
+
baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
|
195
|
+
apiKey: "sk-xxxxxxxx",
|
|
196
|
+
model: "qwen3.5-flash",
|
|
197
|
+
});
|
|
198
|
+
$AI.提问("把这段话翻译成英文:你好"); // 走默认的「文本」
|
|
199
|
+
$AI.判断("是否出现弹窗?", { image: "screen", provider: "视觉" }); // 看图时才用视觉模型
|
|
200
|
+
|
|
201
|
+
// 同一供应商只换模型,不必再登记
|
|
202
|
+
$AI.提问("复杂推理题……", { model: "deepseek-v4-pro" });
|
|
203
|
+
|
|
204
|
+
// 智谱 GLM(OpenAI 兼容口)
|
|
205
|
+
$AI.设置模型({
|
|
206
|
+
name: "智谱 GLM",
|
|
207
|
+
protocol: "openai",
|
|
208
|
+
baseUrl: "https://open.bigmodel.cn/api/paas/v4",
|
|
209
|
+
apiKey: "sk-xxxxxxxx",
|
|
210
|
+
model: "glm-5.3-flash",
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// 本机 Ollama,不需要 Key
|
|
214
|
+
$AI.设置模型({
|
|
215
|
+
name: "本机",
|
|
216
|
+
protocol: "openai",
|
|
217
|
+
baseUrl: "http://192.168.1.10:11434/v1",
|
|
218
|
+
model: "qwen3:8b",
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### 获取模型列表
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
function 获取模型列表(): 数组<模型供应商>;
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**返回值:**
|
|
229
|
+
|
|
230
|
+
| 类型 | 描述 |
|
|
231
|
+
| ------------------ | -------------------------- |
|
|
232
|
+
| `数组<模型供应商>` | 供应商数组,默认项排在最前 |
|
|
233
|
+
|
|
234
|
+
**示例:**
|
|
235
|
+
|
|
236
|
+
```javascript
|
|
237
|
+
$AI.获取模型列表().forEach((p) => $打印信息日志(`${p.name} -> ${p.model}`));
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### 获取默认模型
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
function 获取默认模型(): 模型供应商 | null;
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**返回值:**
|
|
247
|
+
|
|
248
|
+
| 类型 | 描述 |
|
|
249
|
+
| ------------ | ------------------------------------- |
|
|
250
|
+
| `模型供应商` | 默认供应商;一个都没登记时返回 `null` |
|
|
251
|
+
|
|
252
|
+
### 设置默认模型
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
function 设置默认模型(id: 字符串): 布尔值;
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**参数:**
|
|
259
|
+
|
|
260
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
261
|
+
| ------ | ------ | -------- | ------ | --------- |
|
|
262
|
+
| `id` | 字符串 | 是 | - | 供应商 id 或 name |
|
|
263
|
+
|
|
264
|
+
**返回值:**
|
|
265
|
+
|
|
266
|
+
| 类型 | 描述 |
|
|
267
|
+
| -------- | ------------------ |
|
|
268
|
+
| `布尔值` | id 或 name 存在返回 `true` |
|
|
269
|
+
|
|
270
|
+
### 删除模型
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
function 删除模型(id: 字符串): 布尔值;
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**参数:**
|
|
277
|
+
|
|
278
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
279
|
+
| ------ | ------ | -------- | ------ | --------- |
|
|
280
|
+
| `id` | 字符串 | 是 | - | 供应商 id 或 name |
|
|
281
|
+
|
|
282
|
+
**返回值:**
|
|
283
|
+
|
|
284
|
+
| 类型 | 描述 |
|
|
285
|
+
| -------- | --------------------- |
|
|
286
|
+
| `布尔值` | 存在并删除返回 `true` |
|
|
287
|
+
|
|
288
|
+
删掉的是默认供应商时,默认自动转给剩下的第一个。
|
|
289
|
+
|
|
290
|
+
### 提问
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
function 提问(问题: 字符串, 选项?: 调用选项): 字符串 | null;
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**参数:**
|
|
297
|
+
|
|
298
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
299
|
+
| ------ | ---------- | -------- | ------ | ---------------------------------------------- |
|
|
300
|
+
| `问题` | 字符串 | 是 | - | 问题 |
|
|
301
|
+
| `选项` | `调用选项` | 否 | `{}` | 见 [调用选项](#调用选项),图片参数同图片模块 |
|
|
302
|
+
|
|
303
|
+
**返回值:**
|
|
304
|
+
|
|
305
|
+
| 类型 | 描述 |
|
|
306
|
+
| -------- | --------------------------------------------------- |
|
|
307
|
+
| `字符串` | 模型回复文本;失败返回 `null`,原因看 `获取错误()` |
|
|
308
|
+
|
|
309
|
+
**示例:**
|
|
310
|
+
|
|
311
|
+
```javascript
|
|
312
|
+
// 纯文本
|
|
313
|
+
const 回答 = $AI.提问("北京到上海高铁大概几小时?");
|
|
314
|
+
|
|
315
|
+
// 带系统提示 + 当前屏幕
|
|
316
|
+
const 描述 = $AI.提问("描述当前页面", {
|
|
317
|
+
system: "你是手机自动化助手,回答尽量简短。",
|
|
318
|
+
image: "screen",
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// 只看屏幕某个区域
|
|
322
|
+
const 价格 = $AI.提问("这个区域里的价格是多少?只回答数字", { image: "screen", x: 0, y: 300, ex: 750, ey: 500 });
|
|
323
|
+
|
|
324
|
+
// 失败处理
|
|
325
|
+
const r = $AI.提问("你好");
|
|
326
|
+
if (r === null) $打印错误日志($AI.获取错误());
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### 判断
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
function 判断(问题: 字符串, 选项?: 调用选项): 布尔值;
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
让模型只回答 yes / no,并解析成布尔值。适合做流程分支:「有没有弹窗」「是否到了首页」。
|
|
336
|
+
|
|
337
|
+
**参数:**
|
|
338
|
+
|
|
339
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
340
|
+
| ------ | ---------- | -------- | ------ | ------------ |
|
|
341
|
+
| `问题` | 字符串 | 是 | - | 要判断的问题 |
|
|
342
|
+
| `选项` | `调用选项` | 否 | `{}` | 同 `提问` |
|
|
343
|
+
|
|
344
|
+
**返回值:**
|
|
345
|
+
|
|
346
|
+
| 类型 | 描述 |
|
|
347
|
+
| -------- | ---------------------------------------------------------------------------- |
|
|
348
|
+
| `布尔值` | 模型回答肯定为 `true`;否定或请求失败为 `false`,失败时 `获取错误()` 有内容 |
|
|
349
|
+
|
|
350
|
+
**示例:**
|
|
351
|
+
|
|
352
|
+
```javascript
|
|
353
|
+
if ($AI.判断("屏幕上是否出现了「领取成功」?", { image: "screen" })) {
|
|
354
|
+
$打印信息日志("领取成功");
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// 只看顶部区域,省 token
|
|
358
|
+
while (!$AI.判断("顶部是否显示「首页」?", { image: "screen", x: 0, y: 0, ex: 0, ey: 200 })) {
|
|
359
|
+
$动作.点击(375, 1500);
|
|
360
|
+
sleep(1000);
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### 提取
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
function 提取(要求: 字符串, 选项?: 调用选项): 任意类型 | null;
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
要求模型输出 JSON 并自动解析成对象或数组。`schema` 用来告诉模型你想要的结构。
|
|
371
|
+
|
|
372
|
+
**参数:**
|
|
373
|
+
|
|
374
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
375
|
+
| ------ | ---------- | -------- | ------ | ------------------------------------------ |
|
|
376
|
+
| `要求` | 字符串 | 是 | - | 提取要求 |
|
|
377
|
+
| `选项` | `调用选项` | 否 | `{}` | 同 `提问`,另支持 `schema`(字符串或对象) |
|
|
378
|
+
|
|
379
|
+
**返回值:**
|
|
380
|
+
|
|
381
|
+
| 类型 | 描述 |
|
|
382
|
+
| ----------- | --------------------------------------------------------- |
|
|
383
|
+
| `对象/数组` | 解析后的数据;模型没有输出合法 JSON 或请求失败返回 `null` |
|
|
384
|
+
|
|
385
|
+
**示例:**
|
|
386
|
+
|
|
387
|
+
```javascript
|
|
388
|
+
// 提取验证码
|
|
389
|
+
const d = $AI.提取("提取图中的验证码", {
|
|
390
|
+
image: "screen",
|
|
391
|
+
x: 100,
|
|
392
|
+
y: 800,
|
|
393
|
+
ex: 600,
|
|
394
|
+
ey: 900,
|
|
395
|
+
schema: { code: "string" },
|
|
396
|
+
});
|
|
397
|
+
if (d) $输入法.输入(d.code);
|
|
398
|
+
|
|
399
|
+
// 让模型给坐标(配合点击)
|
|
400
|
+
const 位置 = $AI.提取("找到「立即购买」按钮,给出它的中心点像素坐标", {
|
|
401
|
+
image: "screen",
|
|
402
|
+
schema: { x: "number", y: "number" },
|
|
403
|
+
});
|
|
404
|
+
if (位置) $动作.点击(位置.x, 位置.y);
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### 对话
|
|
408
|
+
|
|
409
|
+
```typescript
|
|
410
|
+
function 对话(消息列表: 数组<对话消息 | 字符串>, 选项?: 调用选项): 字符串 | null;
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
自己维护完整对话历史时用它;`提问` 是它的单轮封装。模块不记会话,每次都要把到目前为止的消息整表传进来。
|
|
414
|
+
|
|
415
|
+
图片写在**那一条 user 消息**上,不要用 `选项.image`。`选项.system` 也不生效,系统提示写成第一条 `{ role: "system", content: "..." }`。
|
|
416
|
+
|
|
417
|
+
失败返回 `null`:不要把空回复推进历史,否则下一轮变成 `user → assistant(null) → user`,Anthropic 会 400。Anthropic 协议下模块会自动合并连续同角色、并在首条是 assistant 时垫一条占位 user;OpenAI 兼容口更宽松,不必为此改脚本。
|
|
418
|
+
|
|
419
|
+
**参数:**
|
|
420
|
+
|
|
421
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
422
|
+
| ---------- | -------------------------- | -------- | ------ | ----------------------------------------------------------------------- |
|
|
423
|
+
| `消息列表` | `数组<对话消息 \| 字符串>` | 是 | - | 消息数组;直接写字符串等于 `user` 消息;图片参数写在消息里 |
|
|
424
|
+
| `选项` | `调用选项` | 否 | `{}` | `provider` / `model` / `temperature` / `maxTokens` / `json` / `timeout` |
|
|
425
|
+
|
|
426
|
+
**返回值:**
|
|
427
|
+
|
|
428
|
+
| 类型 | 描述 |
|
|
429
|
+
| -------- | ------------------------- |
|
|
430
|
+
| `字符串` | 回复文本;失败返回 `null` |
|
|
431
|
+
|
|
432
|
+
**示例:**
|
|
433
|
+
|
|
434
|
+
```javascript
|
|
435
|
+
const 历史 = [{ role: "system", content: "你是手机自动化助手" }];
|
|
436
|
+
|
|
437
|
+
function 问(content, extra) {
|
|
438
|
+
历史.push({ role: "user", content, ...extra });
|
|
439
|
+
const 回复 = $AI.对话(历史);
|
|
440
|
+
if (回复 == null) {
|
|
441
|
+
历史.pop();
|
|
442
|
+
$打印错误日志($AI.获取错误());
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
历史.push({ role: "assistant", content: 回复 });
|
|
446
|
+
return 回复;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
问("看下现在在哪个页面", { image: "screen" });
|
|
450
|
+
问("那下一步该点哪里?");
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### 解析JSON
|
|
454
|
+
|
|
455
|
+
```typescript
|
|
456
|
+
function 解析JSON(文本: 字符串): 任意类型 | null;
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
自动剥掉 Markdown 代码块和前后的解释文字。`提取` 内部就是用它解析。
|
|
460
|
+
|
|
461
|
+
**参数:**
|
|
462
|
+
|
|
463
|
+
| 参数名 | 类型 | 是否必填 | 默认值 | 描述 |
|
|
464
|
+
| ------ | ------ | -------- | ------ | -------- |
|
|
465
|
+
| `文本` | 字符串 | 是 | - | 模型输出 |
|
|
466
|
+
|
|
467
|
+
**返回值:**
|
|
468
|
+
|
|
469
|
+
| 类型 | 描述 |
|
|
470
|
+
| ----------- | ------------------------- |
|
|
471
|
+
| `对象/数组` | 解析结果;失败返回 `null` |
|
|
472
|
+
|
|
473
|
+
### 获取错误
|
|
474
|
+
|
|
475
|
+
```typescript
|
|
476
|
+
function 获取错误(): 字符串 | null;
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
**返回值:**
|
|
480
|
+
|
|
481
|
+
| 类型 | 描述 |
|
|
482
|
+
| -------- | ------------------------------------- |
|
|
483
|
+
| `字符串` | 错误文案;上一次调用成功时返回 `null` |
|
|
484
|
+
|
|
485
|
+
常见错误:未登记供应商、Key 错误 / 余额不足(接口返回的原文)、模型不支持图片、图片无效或裁剪越界、超时、模型没有输出 JSON。
|
|
486
|
+
|
|
487
|
+
**示例:**
|
|
488
|
+
|
|
489
|
+
```javascript
|
|
490
|
+
const t = $AI.提问("你好");
|
|
491
|
+
if (t === null) $打印错误日志("AI 调用失败: " + $AI.获取错误());
|
|
492
|
+
```
|