ai-world-sdk 1.5.5 → 1.5.7
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/cli/commands/image.js +0 -1
- package/dist/cli/commands/plugin.js +58 -6
- package/dist/config.d.ts +3 -3
- package/dist/config.js +2 -2
- package/dist/plugin-management.d.ts +13 -0
- package/dist/plugin-management.js +35 -0
- package/dist/video_generation.d.ts +38 -3
- package/package.json +1 -1
- package/skills/ai-world-sdk/SKILL.md +27 -1
- package/skills/ai-world-sdk/docs/image-generation.md +25 -2
- package/skills/ai-world-sdk/docs/provider-and-models.md +3 -3
- package/skills/ai-world-sdk/docs/video-generation.md +131 -9
|
@@ -185,10 +185,16 @@ function registerPluginCommands(program) {
|
|
|
185
185
|
});
|
|
186
186
|
plugin
|
|
187
187
|
.command('create')
|
|
188
|
-
.argument('
|
|
189
|
-
.requiredOption('--plugin-id <id>')
|
|
190
|
-
.option('--name <name>')
|
|
191
|
-
.option('--description <text>')
|
|
188
|
+
.argument('[zip-file]', '静态文件 zip 包路径(可选)')
|
|
189
|
+
.requiredOption('--plugin-id <id>', '插件 ID')
|
|
190
|
+
.option('--name <name>', '插件名称')
|
|
191
|
+
.option('--description <text>', '插件描述')
|
|
192
|
+
.option('--author <author>', '插件作者')
|
|
193
|
+
.option('--version <ver>', '插件版本')
|
|
194
|
+
.option('--server-zip <path>', 'JS 后端 zip 包路径')
|
|
195
|
+
.option('--backend-entry <entry>', 'JS 后端入口文件(默认 index.js)')
|
|
196
|
+
.option('--backend-websocket', '启用 WebSocket 代理')
|
|
197
|
+
.option('--disable-sdk-update-notice', '禁用 SDK 更新提示')
|
|
192
198
|
.action(async (zipFile, options, cmd) => {
|
|
193
199
|
const commandName = 'plugin create';
|
|
194
200
|
try {
|
|
@@ -200,12 +206,58 @@ function registerPluginCommands(program) {
|
|
|
200
206
|
});
|
|
201
207
|
(0, utils_1.initSDK)(auth);
|
|
202
208
|
const client = new plugin_management_1.PluginManagementClient();
|
|
203
|
-
const staticZip = (0, utils_1.readFileAsFile)(zipFile);
|
|
204
209
|
const res = await client.create({
|
|
205
210
|
pluginId: options.pluginId,
|
|
206
211
|
name: options.name,
|
|
207
212
|
description: options.description,
|
|
208
|
-
|
|
213
|
+
author: options.author,
|
|
214
|
+
version: options.version,
|
|
215
|
+
staticZip: zipFile ? (0, utils_1.readFileAsFile)(zipFile) : undefined,
|
|
216
|
+
serverZip: options.serverZip ? (0, utils_1.readFileAsFile)(options.serverZip) : undefined,
|
|
217
|
+
backendEntry: options.backendEntry,
|
|
218
|
+
backendWebsocket: options.backendWebsocket === true ? true : undefined,
|
|
219
|
+
disableSdkUpdateNotice: options.disableSdkUpdateNotice === true ? true : undefined,
|
|
220
|
+
});
|
|
221
|
+
(0, output_1.output)(res, (0, utils_1.getFormat)(program));
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
(0, utils_1.handleError)(err, commandName);
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
plugin
|
|
228
|
+
.command('update')
|
|
229
|
+
.argument('[zip-file]', '静态文件 zip 包路径(可选)')
|
|
230
|
+
.requiredOption('--plugin-id <id>', '要更新的插件 ID')
|
|
231
|
+
.option('--name <name>', '插件名称')
|
|
232
|
+
.option('--description <text>', '插件描述')
|
|
233
|
+
.option('--author <author>', '插件作者')
|
|
234
|
+
.option('--version <ver>', '插件版本')
|
|
235
|
+
.option('--server-zip <path>', 'JS 后端 zip 包路径')
|
|
236
|
+
.option('--backend-entry <entry>', 'JS 后端入口文件(默认 index.js)')
|
|
237
|
+
.option('--backend-websocket', '启用 WebSocket 代理')
|
|
238
|
+
.option('--disable-sdk-update-notice', '禁用 SDK 更新提示')
|
|
239
|
+
.action(async (zipFile, options, cmd) => {
|
|
240
|
+
const commandName = 'plugin update';
|
|
241
|
+
try {
|
|
242
|
+
const o = collectOpts(cmd);
|
|
243
|
+
const auth = (0, config_1.resolveAuth)({
|
|
244
|
+
baseUrl: o.baseUrl,
|
|
245
|
+
token: o.token,
|
|
246
|
+
pluginId: o.pluginId,
|
|
247
|
+
});
|
|
248
|
+
(0, utils_1.initSDK)(auth);
|
|
249
|
+
const client = new plugin_management_1.PluginManagementClient();
|
|
250
|
+
const res = await client.update({
|
|
251
|
+
pluginId: options.pluginId,
|
|
252
|
+
name: options.name,
|
|
253
|
+
description: options.description,
|
|
254
|
+
author: options.author,
|
|
255
|
+
version: options.version,
|
|
256
|
+
staticZip: zipFile ? (0, utils_1.readFileAsFile)(zipFile) : undefined,
|
|
257
|
+
serverZip: options.serverZip ? (0, utils_1.readFileAsFile)(options.serverZip) : undefined,
|
|
258
|
+
backendEntry: options.backendEntry,
|
|
259
|
+
backendWebsocket: options.backendWebsocket === true ? true : undefined,
|
|
260
|
+
disableSdkUpdateNotice: options.disableSdkUpdateNotice === true ? true : undefined,
|
|
209
261
|
});
|
|
210
262
|
(0, output_1.output)(res, (0, utils_1.getFormat)(program));
|
|
211
263
|
}
|
package/dist/config.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* 注意: {VERSION} 占位符会在构建时被替换为实际版本号
|
|
11
11
|
*/
|
|
12
|
-
export declare const SDK_SIGNATURE = "AI_WORLD_SDK_V:1.5.
|
|
12
|
+
export declare const SDK_SIGNATURE = "AI_WORLD_SDK_V:1.5.7";
|
|
13
13
|
/**
|
|
14
14
|
* 版本兼容性错误
|
|
15
15
|
*/
|
|
@@ -35,8 +35,8 @@ declare class SDKConfig {
|
|
|
35
35
|
private _authCheckPromise;
|
|
36
36
|
private _currentUser;
|
|
37
37
|
private _cliMode;
|
|
38
|
-
readonly sdkSignature = "AI_WORLD_SDK_V:1.5.
|
|
39
|
-
readonly sdkVersion = "1.5.
|
|
38
|
+
readonly sdkSignature = "AI_WORLD_SDK_V:1.5.7";
|
|
39
|
+
readonly sdkVersion = "1.5.7";
|
|
40
40
|
constructor();
|
|
41
41
|
/**
|
|
42
42
|
* Set global base URL
|
package/dist/config.js
CHANGED
|
@@ -7,7 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.sdkConfig = exports.VersionCompatibilityError = exports.SDK_SIGNATURE = void 0;
|
|
8
8
|
// SDK 版本号(构建时自动从 package.json 更新)
|
|
9
9
|
// 此版本号会在运行 npm run build 时自动从 package.json 读取并更新
|
|
10
|
-
const SDK_VERSION = "1.5.
|
|
10
|
+
const SDK_VERSION = "1.5.7";
|
|
11
11
|
/**
|
|
12
12
|
* SDK 特征码 - 用于在构建后的 JS 文件中识别 SDK 版本
|
|
13
13
|
* 格式: AI_WORLD_SDK_V:版本号
|
|
@@ -15,7 +15,7 @@ const SDK_VERSION = "1.5.5";
|
|
|
15
15
|
*
|
|
16
16
|
* 注意: {VERSION} 占位符会在构建时被替换为实际版本号
|
|
17
17
|
*/
|
|
18
|
-
exports.SDK_SIGNATURE = "AI_WORLD_SDK_V:1.5.
|
|
18
|
+
exports.SDK_SIGNATURE = "AI_WORLD_SDK_V:1.5.7";
|
|
19
19
|
/**
|
|
20
20
|
* 版本兼容性错误
|
|
21
21
|
*/
|
|
@@ -49,6 +49,18 @@ export interface CreatePluginData {
|
|
|
49
49
|
backendWebsocket?: boolean;
|
|
50
50
|
disableSdkUpdateNotice?: boolean;
|
|
51
51
|
}
|
|
52
|
+
export interface UpdatePluginData {
|
|
53
|
+
pluginId: string;
|
|
54
|
+
name?: string;
|
|
55
|
+
description?: string;
|
|
56
|
+
author?: string;
|
|
57
|
+
version?: string;
|
|
58
|
+
staticZip?: File | Blob;
|
|
59
|
+
serverZip?: File | Blob;
|
|
60
|
+
backendEntry?: string;
|
|
61
|
+
backendWebsocket?: boolean;
|
|
62
|
+
disableSdkUpdateNotice?: boolean;
|
|
63
|
+
}
|
|
52
64
|
export interface PluginStatus {
|
|
53
65
|
plugin_id: string;
|
|
54
66
|
enabled: boolean;
|
|
@@ -110,6 +122,7 @@ export declare class PluginManagementClient {
|
|
|
110
122
|
get(pluginId: string): Promise<PluginInfo>;
|
|
111
123
|
getStatus(pluginId: string): Promise<PluginStatus>;
|
|
112
124
|
create(data: CreatePluginData): Promise<PluginInfo>;
|
|
125
|
+
update(data: UpdatePluginData): Promise<PluginInfo>;
|
|
113
126
|
delete(pluginId: string): Promise<{
|
|
114
127
|
message: string;
|
|
115
128
|
}>;
|
|
@@ -136,6 +136,41 @@ class PluginManagementClient {
|
|
|
136
136
|
await this.handleErrorResponse(response);
|
|
137
137
|
return (await response.json());
|
|
138
138
|
}
|
|
139
|
+
async update(data) {
|
|
140
|
+
config_1.sdkConfig.ensureVersionCompatible();
|
|
141
|
+
const url = `${this.baseUrl}/api/plugins/update`;
|
|
142
|
+
const formData = new FormData();
|
|
143
|
+
formData.append("plugin_id", data.pluginId);
|
|
144
|
+
if (data.name)
|
|
145
|
+
formData.append("name", data.name);
|
|
146
|
+
if (data.description)
|
|
147
|
+
formData.append("description", data.description);
|
|
148
|
+
if (data.author)
|
|
149
|
+
formData.append("author", data.author);
|
|
150
|
+
if (data.version)
|
|
151
|
+
formData.append("version", data.version);
|
|
152
|
+
if (data.staticZip)
|
|
153
|
+
formData.append("static_zip", data.staticZip);
|
|
154
|
+
if (data.serverZip)
|
|
155
|
+
formData.append("server_zip", data.serverZip);
|
|
156
|
+
if (data.backendEntry)
|
|
157
|
+
formData.append("backend_entry", data.backendEntry);
|
|
158
|
+
if (data.backendWebsocket !== undefined)
|
|
159
|
+
formData.append("backend_websocket", String(data.backendWebsocket));
|
|
160
|
+
if (data.disableSdkUpdateNotice !== undefined)
|
|
161
|
+
formData.append("disable_sdk_update_notice", String(data.disableSdkUpdateNotice));
|
|
162
|
+
const uploadHeaders = { ...this.headers };
|
|
163
|
+
delete uploadHeaders["Content-Type"];
|
|
164
|
+
(0, log_1.logRequest)("POST", url, uploadHeaders);
|
|
165
|
+
const response = await fetch(url, {
|
|
166
|
+
method: "POST",
|
|
167
|
+
headers: uploadHeaders,
|
|
168
|
+
body: formData,
|
|
169
|
+
});
|
|
170
|
+
if (!response.ok)
|
|
171
|
+
await this.handleErrorResponse(response);
|
|
172
|
+
return (await response.json());
|
|
173
|
+
}
|
|
139
174
|
async delete(pluginId) {
|
|
140
175
|
config_1.sdkConfig.ensureVersionCompatible();
|
|
141
176
|
const url = `${this.baseUrl}/api/plugins/${pluginId}`;
|
|
@@ -16,20 +16,55 @@ export interface VideoGenerationContentImage {
|
|
|
16
16
|
image_url: {
|
|
17
17
|
url: string;
|
|
18
18
|
};
|
|
19
|
-
role
|
|
19
|
+
role?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface VideoGenerationContentVideo {
|
|
22
|
+
type: "video_url";
|
|
23
|
+
video_url: {
|
|
24
|
+
url: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export interface VideoGenerationContentAudio {
|
|
28
|
+
type: "audio_url";
|
|
29
|
+
audio_url: {
|
|
30
|
+
url: string;
|
|
31
|
+
};
|
|
20
32
|
}
|
|
21
|
-
export type VideoGenerationContent = VideoGenerationContentText | VideoGenerationContentImage;
|
|
33
|
+
export type VideoGenerationContent = VideoGenerationContentText | VideoGenerationContentImage | VideoGenerationContentVideo | VideoGenerationContentAudio;
|
|
22
34
|
export interface VideoGenerationRequest {
|
|
35
|
+
/** 文本提示词(文本生成视频,与 content 二选一) */
|
|
23
36
|
prompt?: string;
|
|
37
|
+
/** 图像 URL(图像生成视频,与 content 二选一) */
|
|
24
38
|
image_url?: string;
|
|
39
|
+
/** 模型名称。Seedance 1.x: doubao-seedance-1-0-pro-fast-251015; Seedance 2.0: doubao-seedance-2-0-260128, doubao-seedance-2-0-fast-260128 */
|
|
25
40
|
model?: string;
|
|
41
|
+
/**
|
|
42
|
+
* 内容列表(高级用法,直接传递给 SDK)。
|
|
43
|
+
* 支持的类型: text, image_url, video_url, audio_url。
|
|
44
|
+
* 提供时忽略 prompt 和 image_url 字段。
|
|
45
|
+
*
|
|
46
|
+
* 示例 — 文本生成视频:
|
|
47
|
+
* [{ type: "text", text: "A sunset over the ocean" }]
|
|
48
|
+
*
|
|
49
|
+
* 示例 — 图像生成视频(I2V):
|
|
50
|
+
* [{ type: "text", text: "The woman smiles" }, { type: "image_url", image_url: { url: "https://..." } }]
|
|
51
|
+
*
|
|
52
|
+
* 示例 — 首尾帧控制:
|
|
53
|
+
* [{ type: "text", text: "flower blooms" }, { type: "image_url", image_url: { url: "first.jpg" } }, { type: "image_url", image_url: { url: "last.jpg" } }]
|
|
54
|
+
*
|
|
55
|
+
* 示例 — 多模态参考(Seedance 2.0):
|
|
56
|
+
* [{ type: "text", text: "..." }, { type: "image_url", image_url: { url: "..." } }, { type: "video_url", video_url: { url: "..." } }, { type: "audio_url", audio_url: { url: "..." } }]
|
|
57
|
+
*/
|
|
26
58
|
content?: VideoGenerationContent[];
|
|
27
59
|
callback_url?: string;
|
|
28
60
|
return_last_frame?: boolean;
|
|
29
61
|
service_tier?: string;
|
|
30
62
|
execution_expires_after?: number;
|
|
63
|
+
/** 视频时长(秒),Seedance 1.x: 1-10,Seedance 2.0: 5-15 */
|
|
31
64
|
duration?: number;
|
|
32
|
-
|
|
65
|
+
/** 宽高比: "16:9" | "9:16" | "1:1" | "adaptive"(I2V 时自适应原图比例) */
|
|
66
|
+
aspect_ratio?: string;
|
|
67
|
+
/** 分辨率: "720p" | "1080p" | "2k" */
|
|
33
68
|
resolution?: string;
|
|
34
69
|
user?: string;
|
|
35
70
|
}
|
package/package.json
CHANGED
|
@@ -133,6 +133,7 @@ sdkConfig.setPluginId('my-plugin');
|
|
|
133
133
|
- `createProvider(provider, endpointType, pluginId)` 创建 Vercel AI SDK Provider
|
|
134
134
|
- Provider 对照表:`api2img`(推荐) / `gemini` / `aihubmix` / `shubiaobiao` / `aiping` / `openrouter` / `kunpo`
|
|
135
135
|
- **OpenRouter**:使用专用代理端点 `/api/llm/openrouter`,模型 ID 格式为 `provider/model`(如 `openai/gpt-4o-mini`、`anthropic/claude-sonnet-4-20250514`、`google/gemini-2.5-flash-preview`)
|
|
136
|
+
- **OpenRouter Reasoning**:通过 `providerOptions.openrouter.reasoning` 启用模型思考,支持 `effort`(`xhigh`/`high`/`medium`/`low`/`minimal`)和 `max_tokens` 参数,适用于 Claude / DeepSeek-R1 / o1 / o3 / Gemini 等支持思考的模型
|
|
136
137
|
- **KUNPO API**:统一 LLM 网关(https://llm.ziy.cc),兼容 OpenAI 接口,使用专用代理端点 `/api/llm/kunpo`,一个 Key 访问 150+ 模型
|
|
137
138
|
- 常用模型列表和 AI SDK 函数速查
|
|
138
139
|
|
|
@@ -159,6 +160,22 @@ const stream = streamText({
|
|
|
159
160
|
for await (const chunk of stream.textStream) {
|
|
160
161
|
process.stdout.write(chunk);
|
|
161
162
|
}
|
|
163
|
+
|
|
164
|
+
// 启用思考/推理(OpenRouter / KUNPO 均支持)
|
|
165
|
+
const thinkResult = await generateText({
|
|
166
|
+
model: provider.languageModel('anthropic/claude-sonnet-4-20250514'),
|
|
167
|
+
prompt: '证明根号2是无理数',
|
|
168
|
+
providerOptions: {
|
|
169
|
+
openrouter: {
|
|
170
|
+
reasoning: {
|
|
171
|
+
effort: 'high', // 思考深度: xhigh / high / medium / low / minimal
|
|
172
|
+
// max_tokens: 10000, // 可选:限制思考 token 数量
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
console.log('思考过程:', thinkResult.reasoning);
|
|
178
|
+
console.log('最终回答:', thinkResult.text);
|
|
162
179
|
```
|
|
163
180
|
|
|
164
181
|
#### KUNPO API 快速示例
|
|
@@ -247,7 +264,10 @@ for await (const chunk of stream.textStream) {
|
|
|
247
264
|
|
|
248
265
|
### 平台通用 API → `docs/platform-api.md`
|
|
249
266
|
|
|
250
|
-
- `PluginManagementClient` — 插件 CRUD
|
|
267
|
+
- `PluginManagementClient` — 插件 CRUD(`create` / `update` 分离)、启用/禁用/重载/重启、模板管理
|
|
268
|
+
- `create(data)` — 创建新插件(POST `/api/plugins/create`),插件不存在时使用
|
|
269
|
+
- `update(data)` — 更新已有插件(POST `/api/plugins/update`),插件必须已存在,未传入的字段保留原值
|
|
270
|
+
- 两者均支持: pluginId / name / description / author / version / staticZip / serverZip / backendEntry / backendWebsocket / disableSdkUpdateNotice
|
|
251
271
|
- `StatsClient` — AI 接口调用统计/趋势、插件访问统计(管理员)
|
|
252
272
|
- `DashboardClient` — 当前用户统计(无需管理员权限)
|
|
253
273
|
- `SharedResourceClient` — 平台级文件共享(与 `ResourceClient` 的插件级 ACL 不同)
|
|
@@ -285,6 +305,12 @@ ai-world text stream --prompt "请介绍人工智能"
|
|
|
285
305
|
# 查看插件列表
|
|
286
306
|
ai-world plugin list --format table
|
|
287
307
|
|
|
308
|
+
# 创建插件
|
|
309
|
+
ai-world plugin create ./dist.zip --plugin-id my-plugin --name "My Plugin" --version 1.0.0
|
|
310
|
+
|
|
311
|
+
# 更新插件(插件必须已存在,未传入的字段保留原值)
|
|
312
|
+
ai-world plugin update ./dist.zip --plugin-id my-plugin --version 1.1.0
|
|
313
|
+
|
|
288
314
|
# 版本检查
|
|
289
315
|
ai-world version
|
|
290
316
|
```
|
|
@@ -58,12 +58,35 @@ await client.generate({
|
|
|
58
58
|
|
|
59
59
|
## Gemini 图像生成
|
|
60
60
|
|
|
61
|
+
`provider` 在构造函数中传入,而非 `generate()` 方法。
|
|
62
|
+
|
|
61
63
|
```typescript
|
|
62
64
|
import { GeminiImageGenerationClient } from 'ai-world-sdk';
|
|
63
65
|
|
|
64
|
-
|
|
66
|
+
// provider 在构造函数中指定
|
|
67
|
+
const client = new GeminiImageGenerationClient({ provider: 'gemini' });
|
|
65
68
|
const result = await client.generate({
|
|
66
69
|
prompt: '一只可爱的小猫',
|
|
67
|
-
provider: 'gemini',
|
|
68
70
|
});
|
|
71
|
+
// result.images — 生成的图像列表
|
|
69
72
|
```
|
|
73
|
+
|
|
74
|
+
### Gemini 图像对话(chat)
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
const chatResult = await client.chat({
|
|
78
|
+
prompt: '把这只猫变成卡通风格',
|
|
79
|
+
image: 'data:image/png;base64,...',
|
|
80
|
+
model: 'gemini-3-pro-image-preview',
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 参数说明
|
|
85
|
+
|
|
86
|
+
| 参数 | 位置 | 说明 |
|
|
87
|
+
|------|------|------|
|
|
88
|
+
| `provider` | 构造函数 | 图像生成 Provider(如 `'gemini'`) |
|
|
89
|
+
| `prompt` | `generate()` | 文本提示词 |
|
|
90
|
+
| `model` | `generate()` | 模型名称(默认: `gemini-2.0-flash-exp-image-generation`,chat 默认: `gemini-3-pro-image-preview`) |
|
|
91
|
+
| `image` | `generate()` / `chat()` | 输入图像(base64 或 URL) |
|
|
92
|
+
| `aspect_ratio` | `generate()` | 宽高比 |
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
| `aiping` | `anthropic` | 平音 Claude |
|
|
16
16
|
| `gemini` | `gemini` | Google 原生,仅限 Gemini 系列模型 |
|
|
17
17
|
| `openrouter` | `openai` | OpenRouter 聚合服务,SDK 内部自动使用 `createOpenRouter` 和专用代理端点 `/api/llm/openrouter`。模型 ID 格式为 `provider/model`(如 `openai/gpt-4o-mini`、`anthropic/claude-sonnet-4-20250514`) |
|
|
18
|
-
| `kunpo` | `openai` | KUNPO API 统一 LLM 网关(https://llm.ziy.cc),兼容 OpenAI 接口,一个 Key 访问 150+ 模型。SDK 内部使用 `
|
|
18
|
+
| `kunpo` | `openai` | KUNPO API 统一 LLM 网关(https://llm.ziy.cc),兼容 OpenAI 接口,一个 Key 访问 150+ 模型。SDK 内部使用 `createOpenRouter` 并路由到专用代理 `/api/llm/kunpo` |
|
|
19
19
|
|
|
20
20
|
## EndpointType 与模型对应关系
|
|
21
21
|
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
| `openai` | OpenAI 兼容 | 模型兼容 OpenAI 格式,可包括 GPT、以及经聚合的 Gemini/Claude 等(视 provider 能力) |
|
|
27
27
|
| `openai` | OpenRouter 兼容 | 当 provider 为 `openrouter` 时,`endpointType` 传 `openai`,SDK 内部自动切换到 `createOpenRouter` 和专用代理端点 |
|
|
28
28
|
|
|
29
|
-
规则:**anthropic 不是 provider**,仅 **api2img**、**shubiaobiao**、**aiping** 支持 EndpointType 为 `anthropic`(调用 Claude);`gemini` provider 用 `gemini` endpoint;`openrouter` provider 的 `endpointType` 传 `openai`,SDK 内部会自动使用 `@openrouter/ai-sdk-provider` 的 `createOpenRouter` 并路由到专用代理 `/api/llm/openrouter`;`kunpo` provider 的 `endpointType` 传 `openai`,SDK 内部使用 `
|
|
29
|
+
规则:**anthropic 不是 provider**,仅 **api2img**、**shubiaobiao**、**aiping** 支持 EndpointType 为 `anthropic`(调用 Claude);`gemini` provider 用 `gemini` endpoint;`openrouter` provider 的 `endpointType` 传 `openai`,SDK 内部会自动使用 `@openrouter/ai-sdk-provider` 的 `createOpenRouter` 并路由到专用代理 `/api/llm/openrouter`;`kunpo` provider 的 `endpointType` 传 `openai`,SDK 内部使用 `createOpenRouter` 并路由到专用代理 `/api/llm/kunpo`;其余按上表组合。
|
|
30
30
|
|
|
31
31
|
> `doubao` 不通过 `createProvider` 使用,豆包有专用客户端(见 image-generation.md / video-generation.md)。
|
|
32
32
|
|
|
@@ -62,7 +62,7 @@ or.languageModel('openai/gpt-4o-mini');
|
|
|
62
62
|
or.languageModel('anthropic/claude-sonnet-4-20250514');
|
|
63
63
|
or.languageModel('google/gemini-2.5-flash-preview');
|
|
64
64
|
|
|
65
|
-
// KUNPO API(endpointType 传 'openai',SDK 内部使用
|
|
65
|
+
// KUNPO API(endpointType 传 'openai',SDK 内部使用 createOpenRouter + 专用代理 /api/llm/kunpo)
|
|
66
66
|
// 兼容 OpenAI Chat Completions 格式,支持 150+ 模型
|
|
67
67
|
const kp = createProvider('kunpo', 'openai', 'my-plugin');
|
|
68
68
|
kp.languageModel('google/gemini-3.1-pro-preview');
|
|
@@ -2,22 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
## 豆包视频生成(Seedance)
|
|
4
4
|
|
|
5
|
+
参考文档: https://www.volcengine.com/docs/82379/1366799 (1.x) / https://www.volcengine.com/docs/82379/2291680 (2.0)
|
|
6
|
+
具体模型列表: https://www.volcengine.com/docs/82379/1330310
|
|
7
|
+
|
|
8
|
+
### 支持的模型
|
|
9
|
+
|
|
10
|
+
| 模型 | 说明 |
|
|
11
|
+
|------|------|
|
|
12
|
+
| `doubao-seedance-2-0-260128` | Seedance 2.0 标准版 |
|
|
13
|
+
| `doubao-seedance-2-0-fast-260128` | Seedance 2.0 快速版 |
|
|
14
|
+
|
|
15
|
+
### 基本用法 — 文本生成视频
|
|
16
|
+
|
|
5
17
|
```typescript
|
|
6
18
|
import { VideoGenerationClient } from 'ai-world-sdk';
|
|
7
19
|
|
|
8
20
|
const client = new VideoGenerationClient({});
|
|
9
21
|
|
|
10
|
-
// 创建任务
|
|
11
22
|
const task = await client.create({
|
|
12
23
|
prompt: '日落时分的海滩',
|
|
13
|
-
duration: 5,
|
|
14
|
-
aspect_ratio: '16:9',
|
|
24
|
+
duration: 5,
|
|
25
|
+
aspect_ratio: '16:9',
|
|
15
26
|
resolution: '720p',
|
|
16
27
|
});
|
|
17
28
|
|
|
18
|
-
// 轮询直到完成
|
|
19
29
|
const result = await client.poll(task.id, {
|
|
20
|
-
interval:
|
|
30
|
+
interval: 5000,
|
|
21
31
|
timeout: 300000,
|
|
22
32
|
});
|
|
23
33
|
|
|
@@ -26,6 +36,119 @@ if (result.status === 'succeeded') {
|
|
|
26
36
|
}
|
|
27
37
|
```
|
|
28
38
|
|
|
39
|
+
### 使用 content 参数(高级用法)
|
|
40
|
+
|
|
41
|
+
`content` 参数是一个数组,支持以下类型:
|
|
42
|
+
|
|
43
|
+
| type | 说明 | 限制 |
|
|
44
|
+
|------|------|------|
|
|
45
|
+
| `text` | 文本提示词 | 必须包含至少一个 |
|
|
46
|
+
| `image_url` | 图像参考/首帧/尾帧 | 最多 9 张,每张 < 30MB |
|
|
47
|
+
| `video_url` | 视频参考(Seedance 2.0) | 最多 3 个,2-15秒,< 50MB |
|
|
48
|
+
| `audio_url` | 音频参考(Seedance 2.0) | 最多 3 个,MP3,< 15MB |
|
|
49
|
+
|
|
50
|
+
当提供 `content` 时,`prompt` 和 `image_url` 字段将被忽略。
|
|
51
|
+
|
|
52
|
+
#### 文本生成视频(T2V)
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
const task = await client.create({
|
|
56
|
+
model: 'doubao-seedance-2-0-260128',
|
|
57
|
+
content: [
|
|
58
|
+
{ type: 'text', text: 'A golden retriever running through a sunlit wheat field, cinematic' }
|
|
59
|
+
],
|
|
60
|
+
resolution: '1080p',
|
|
61
|
+
aspect_ratio: '16:9',
|
|
62
|
+
duration: 5,
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
#### 图像生成视频(I2V)
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
const task = await client.create({
|
|
70
|
+
model: 'doubao-seedance-2-0-260128',
|
|
71
|
+
content: [
|
|
72
|
+
{ type: 'text', text: 'The woman slowly turns her head and smiles' },
|
|
73
|
+
{ type: 'image_url', image_url: { url: 'https://example.com/portrait.jpg' } }
|
|
74
|
+
],
|
|
75
|
+
aspect_ratio: 'adaptive',
|
|
76
|
+
duration: 5,
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
#### 首尾帧控制
|
|
81
|
+
|
|
82
|
+
提供两张图片,模型自动识别为首尾帧模式,生成中间过渡动画:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
const task = await client.create({
|
|
86
|
+
model: 'doubao-seedance-2-0-260128',
|
|
87
|
+
content: [
|
|
88
|
+
{ type: 'text', text: 'The flower blooms from bud to full open, macro lens' },
|
|
89
|
+
{ type: 'image_url', image_url: { url: 'https://example.com/flower-bud.jpg' } },
|
|
90
|
+
{ type: 'image_url', image_url: { url: 'https://example.com/flower-open.jpg' } }
|
|
91
|
+
],
|
|
92
|
+
aspect_ratio: 'adaptive',
|
|
93
|
+
duration: 8,
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
#### 多模态参考(Seedance 2.0)
|
|
98
|
+
|
|
99
|
+
Seedance 2.0 支持同时传入图像、视频、音频参考:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
const task = await client.create({
|
|
103
|
+
model: 'doubao-seedance-2-0-260128',
|
|
104
|
+
content: [
|
|
105
|
+
{ type: 'text', text: 'Match the visual style and add background audio' },
|
|
106
|
+
{ type: 'image_url', image_url: { url: 'https://example.com/style-ref.jpg' } },
|
|
107
|
+
{ type: 'video_url', video_url: { url: 'https://example.com/motion-ref.mp4' } },
|
|
108
|
+
{ type: 'audio_url', audio_url: { url: 'https://example.com/bgm.mp3' } }
|
|
109
|
+
],
|
|
110
|
+
duration: 10,
|
|
111
|
+
aspect_ratio: '16:9',
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 参数说明
|
|
116
|
+
|
|
117
|
+
| 参数 | 类型 | 说明 |
|
|
118
|
+
|------|------|------|
|
|
119
|
+
| `prompt` | `string` | 文本提示词(简化用法,与 content 二选一) |
|
|
120
|
+
| `image_url` | `string` | 图像 URL(简化用法,与 content 二选一) |
|
|
121
|
+
| `model` | `string` | 模型名称(默认: doubao-seedance-1-0-pro-fast-251015) |
|
|
122
|
+
| `content` | `VideoGenerationContent[]` | 内容列表(高级用法,支持 text/image_url/video_url/audio_url) |
|
|
123
|
+
| `duration` | `number` | 视频时长(秒),1.x: 1-10,2.0: 5-15 |
|
|
124
|
+
| `aspect_ratio` | `string` | 宽高比: "16:9" / "9:16" / "1:1" / "adaptive" |
|
|
125
|
+
| `resolution` | `string` | 分辨率: "720p" / "1080p" / "2k" |
|
|
126
|
+
| `callback_url` | `string` | 回调 URL(任务完成时通知) |
|
|
127
|
+
| `return_last_frame` | `boolean` | 是否返回最后一帧图像(用于链式生成) |
|
|
128
|
+
|
|
129
|
+
### 轮询与链式生成
|
|
130
|
+
|
|
131
|
+
使用 `return_last_frame: true` 获取最后一帧,将其作为下一段视频的首帧,实现长视频链式生成:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const task1 = await client.create({
|
|
135
|
+
prompt: 'Scene 1: sunrise over mountains',
|
|
136
|
+
return_last_frame: true,
|
|
137
|
+
duration: 5,
|
|
138
|
+
});
|
|
139
|
+
const result1 = await client.poll(task1.id);
|
|
140
|
+
|
|
141
|
+
if (result1.status === 'succeeded' && result1.content?.last_frame_url) {
|
|
142
|
+
const task2 = await client.create({
|
|
143
|
+
content: [
|
|
144
|
+
{ type: 'text', text: 'Scene 2: camera zooms into the valley' },
|
|
145
|
+
{ type: 'image_url', image_url: { url: result1.content.last_frame_url } }
|
|
146
|
+
],
|
|
147
|
+
duration: 5,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
29
152
|
## 豆包视频理解
|
|
30
153
|
|
|
31
154
|
使用 `VideoUnderstandingClient` 分析视频内容。基于 Chat Completions API,支持传入视频 URL 进行理解分析。
|
|
@@ -48,7 +171,6 @@ import { VideoUnderstandingClient } from 'ai-world-sdk';
|
|
|
48
171
|
|
|
49
172
|
const client = new VideoUnderstandingClient({});
|
|
50
173
|
|
|
51
|
-
// 一行代码分析视频
|
|
52
174
|
const description = await client.analyzeVideo(
|
|
53
175
|
'https://example.com/video.mp4',
|
|
54
176
|
{ prompt: '请详细描述这个视频的内容' }
|
|
@@ -63,11 +185,11 @@ const response = await client.understand({
|
|
|
63
185
|
video_url: 'https://example.com/video.mp4',
|
|
64
186
|
prompt: '这个视频讲了什么?',
|
|
65
187
|
model: 'doubao-seed-2-0-pro-260215',
|
|
66
|
-
fps: 1,
|
|
188
|
+
fps: 1,
|
|
67
189
|
});
|
|
68
190
|
|
|
69
191
|
console.log(response.choices[0].message.content);
|
|
70
|
-
console.log(response.usage);
|
|
192
|
+
console.log(response.usage);
|
|
71
193
|
```
|
|
72
194
|
|
|
73
195
|
### 流式请求
|
|
@@ -115,7 +237,7 @@ const response = await client.understand({
|
|
|
115
237
|
});
|
|
116
238
|
```
|
|
117
239
|
|
|
118
|
-
###
|
|
240
|
+
### 视频理解参数说明
|
|
119
241
|
|
|
120
242
|
| 参数 | 类型 | 必填 | 说明 |
|
|
121
243
|
|------|------|------|------|
|